Make initializing formal access available by default

This CL changes dart2js such that the effect that we used to get with
option '--initializing-formal-access' is now obtained unconditionally,
i.e., that extension is now enabled by default.

dart2js will continue to accept the option, such that scripts passing
the option will not break.

The CL is _not_ intended to be landed at this time, the plan is to
enable the feature in a coordinated manner when all tools are ready.

R=johnniwinther@google.com

Review URL: https://codereview.chromium.org/2141023002 .
This commit is contained in:
Erik Ernst 2016-11-25 10:15:21 +01:00
parent 843bb96813
commit 4912fd1501
13 changed files with 33 additions and 61 deletions

View file

@ -74,9 +74,12 @@ class Flags {
// https://gist.github.com/eernstg/4353d7b4f669745bed3a5423e04a453c.
static const String genericMethodSyntax = '--generic-method-syntax';
// Initializing-formal access is enabled by default and cannot be disabled.
// For backward compatibility the option is still accepted, but it is ignored.
static const String initializingFormalAccess = '--initializing-formal-access';
// Experimental flags.
static const String resolveOnly = '--resolve-only';
static const String initializingFormalAccess = '--initializing-formal-access';
}
class Option {

View file

@ -1241,13 +1241,10 @@ class ConstructorEvaluator extends CompileTimeConstantEvaluator {
if (parameter.isInitializingFormal) {
InitializingFormalElement initializingFormal = parameter;
updateFieldValue(node, initializingFormal.fieldElement, argument);
if (compiler.options.enableInitializingFormalAccess) {
definitions[parameter] = argument;
}
} else {
potentiallyCheckType(parameter, argument);
definitions[parameter] = argument;
}
definitions[parameter] = argument;
});
}

View file

@ -335,7 +335,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
new OptionHandler(Flags.allowMockCompilation, passThrough),
new OptionHandler(Flags.fastStartup, passThrough),
new OptionHandler(Flags.genericMethodSyntax, ignoreOption),
new OptionHandler(Flags.initializingFormalAccess, passThrough),
new OptionHandler(Flags.initializingFormalAccess, ignoreOption),
new OptionHandler('${Flags.minify}|-m', implyCompilation),
new OptionHandler(Flags.preserveUris, passThrough),
new OptionHandler('--force-strip=.*', setStrip),

View file

@ -133,10 +133,6 @@ class CompilerOptions implements DiagnosticOptions {
/// reason for why an assertion fails. (experimental)
final bool enableAssertMessage;
/// Support access to initializing formal constructor arguments, e.g., the
/// use of `x` to initialize `y` in `C(this.x) : y = x`.
final bool enableInitializingFormalAccess;
/// Whether the user specified a flag to allow the use of dart:mirrors. This
/// silences a warning produced by the compiler.
final bool enableExperimentalMirrors;
@ -272,8 +268,6 @@ class CompilerOptions implements DiagnosticOptions {
disableTypeInference: _hasOption(options, Flags.disableTypeInference),
dumpInfo: _hasOption(options, Flags.dumpInfo),
enableAssertMessage: _hasOption(options, Flags.enableAssertMessage),
enableInitializingFormalAccess:
_hasOption(options, Flags.initializingFormalAccess),
enableExperimentalMirrors:
_hasOption(options, Flags.enableExperimentalMirrors),
enableMinification: _hasOption(options, Flags.minify),
@ -340,7 +334,6 @@ class CompilerOptions implements DiagnosticOptions {
bool disableTypeInference: false,
bool dumpInfo: false,
bool enableAssertMessage: false,
bool enableInitializingFormalAccess: false,
bool enableExperimentalMirrors: false,
bool enableMinification: false,
bool enableNativeLiveTypeAnalysis: true,
@ -411,7 +404,6 @@ class CompilerOptions implements DiagnosticOptions {
disableTypeInference: disableTypeInference,
dumpInfo: dumpInfo,
enableAssertMessage: enableAssertMessage,
enableInitializingFormalAccess: enableInitializingFormalAccess,
enableExperimentalMirrors: enableExperimentalMirrors,
enableMinification: enableMinification,
enableNativeLiveTypeAnalysis: enableNativeLiveTypeAnalysis,
@ -461,7 +453,6 @@ class CompilerOptions implements DiagnosticOptions {
this.disableTypeInference: false,
this.dumpInfo: false,
this.enableAssertMessage: false,
this.enableInitializingFormalAccess: false,
this.enableExperimentalMirrors: false,
this.enableMinification: false,
this.enableNativeLiveTypeAnalysis: false,
@ -518,7 +509,6 @@ class CompilerOptions implements DiagnosticOptions {
disableTypeInference,
dumpInfo,
enableAssertMessage,
enableInitializingFormalAccess,
enableExperimentalMirrors,
enableMinification,
enableNativeLiveTypeAnalysis,
@ -576,8 +566,6 @@ class CompilerOptions implements DiagnosticOptions {
disableTypeInference ?? options.disableTypeInference,
dumpInfo: dumpInfo ?? options.dumpInfo,
enableAssertMessage: enableAssertMessage ?? options.enableAssertMessage,
enableInitializingFormalAccess: enableInitializingFormalAccess ??
options.enableInitializingFormalAccess,
enableExperimentalMirrors:
enableExperimentalMirrors ?? options.enableExperimentalMirrors,
enableMinification: enableMinification ?? options.enableMinification,

View file

@ -294,8 +294,7 @@ class InitializerResolver {
* Resolve all initializers of this constructor. In the case of a redirecting
* constructor, the resolved constructor's function element is returned.
*/
ConstructorElement resolveInitializers(
{bool enableInitializingFormalAccess: false}) {
ConstructorElement resolveInitializers() {
Map<dynamic /*String|int*/, ConstantExpression> defaultValues =
<dynamic /*String|int*/, ConstantExpression>{};
ConstructedConstantExpression constructorInvocation;
@ -303,12 +302,10 @@ class InitializerResolver {
// that we can ensure that fields are initialized only once.
FunctionSignature functionParameters = constructor.functionSignature;
Scope oldScope = visitor.scope;
if (enableInitializingFormalAccess) {
// In order to get the correct detection of name clashes between all
// parameters (regular ones and initializing formals) we must extend
// the parameter scope rather than adding a new nested scope.
visitor.scope = new ExtensionScope(visitor.scope);
}
// In order to get the correct detection of name clashes between all
// parameters (regular ones and initializing formals) we must extend
// the parameter scope rather than adding a new nested scope.
visitor.scope = new ExtensionScope(visitor.scope);
Link<Node> parameterNodes = (functionNode.parameters == null)
? const Link<Node>()
: functionNode.parameters.nodes;
@ -349,10 +346,8 @@ class InitializerResolver {
registry.registerStaticUse(new StaticUse.fieldInit(field));
}
checkForDuplicateInitializers(field, element.initializer);
if (enableInitializingFormalAccess) {
visitor.defineLocalVariable(parameterNode, initializingFormal);
visitor.addToScope(initializingFormal);
}
visitor.defineLocalVariable(parameterNode, initializingFormal);
visitor.addToScope(initializingFormal);
if (isConst) {
if (element.isNamed) {
fieldInitializers[field] = new NamedArgumentReference(element.name);

View file

@ -2573,8 +2573,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else {
semantics = new StaticAccess.parameter(element);
}
} else if (element.isInitializingFormal &&
options.enableInitializingFormalAccess) {
} else if (element.isInitializingFormal) {
error = reportAndCreateErroneousElement(node.selector, name.text,
MessageKind.UNDEFINED_STATIC_SETTER_BUT_GETTER, {'name': name});
semantics = new StaticAccess.finalParameter(element);

View file

@ -247,9 +247,7 @@ class ResolverTask extends CompilerTask {
// resolution in case there is an implicit super constructor call.
InitializerResolver resolver =
new InitializerResolver(visitor, element, tree);
FunctionElement redirection = resolver.resolveInitializers(
enableInitializingFormalAccess:
options.enableInitializingFormalAccess);
FunctionElement redirection = resolver.resolveInitializers();
if (redirection != null) {
resolveRedirectingConstructor(resolver, tree, element, redirection);
}

View file

@ -686,11 +686,7 @@ class TypeCheckerVisitor extends Visitor<DartType> {
message: 'Missing element for identifier'));
assert(invariant(
node,
element.isVariable ||
element.isRegularParameter ||
element.isField ||
(element.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess),
element.isVariable || element.isParameter || element.isField,
message: 'Unexpected context element ${element}'));
return element.computeType(resolution);
}
@ -775,10 +771,7 @@ class TypeCheckerVisitor extends Visitor<DartType> {
return access;
}
if (receiverElement != null &&
(receiverElement.isVariable ||
receiverElement.isRegularParameter ||
(receiverElement.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess))) {
(receiverElement.isVariable || receiverElement.isParameter)) {
Link<TypePromotion> typePromotions = typePromotionsMap[receiverElement];
if (typePromotions != null) {
while (!typePromotions.isEmpty) {
@ -1095,10 +1088,7 @@ class TypeCheckerVisitor extends Visitor<DartType> {
}
ElementAccess createPromotedAccess(Element element) {
if (element.isVariable ||
element.isRegularParameter ||
(element.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess)) {
if (element.isVariable || element.isParameter) {
TypePromotion typePromotion = getKnownTypePromotion(element);
if (typePromotion != null) {
return new PromotedAccess(element, typePromotion.type);
@ -1215,11 +1205,7 @@ class TypeCheckerVisitor extends Visitor<DartType> {
}
}
if (variable != null &&
(variable.isVariable ||
variable.isRegularParameter ||
(variable.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess))) {
if (variable != null && (variable.isVariable || variable.isParameter)) {
DartType knownType = getKnownType(variable);
if (!knownType.isDynamic) {
DartType shownType = elements.getType(node.arguments.head);

View file

@ -14,7 +14,7 @@ class TestClass {
TestClass.named(num this.fld1)
// Should cause a compilation error (for the spawned isolate). It is a
// runtime error for the test.
: fld2 = fld1 /// 01: compile-time error
: fld2 = this.fld1 /// 01: compile-time error
;
num fld1;
num fld2;

View file

@ -8,9 +8,14 @@
import "package:expect/expect.dart";
class A {
int x;
String y;
A(this.x) : y = x { y = x; }
num x;
double y;
// Finding the type of an initializing formal: should cause a warning
// in the initializer but not the body, because the former has type
// `int` and the latter has type `num`.
A(int this.x) : y = x {
y = x;
}
}
main() {

View file

@ -106,7 +106,7 @@ initializing_formal_access_test: Skip
initializing_formal_capture_test: Skip
initializing_formal_final_test: Skip
initializing_formal_type_test: Skip
initializing_formal_promotion_test: Skip
parameter_initializer5_test: Skip
# Experimental feature: Syntactic support for generic methods.
# Skip these in dartium, because the test framework can't pass VM flags to

View file

@ -356,7 +356,6 @@ parameter_initializer1_negative_test: CompileTimeError
parameter_initializer2_negative_test: CompileTimeError
parameter_initializer3_negative_test: CompileTimeError
parameter_initializer4_negative_test: CompileTimeError
parameter_initializer5_negative_test: CompileTimeError
parameter_initializer6_negative_test: CompileTimeError
parser_quirks_test: StaticWarning
part2_test: StaticWarning

View file

@ -1,15 +1,17 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// DartOptions=--initializing-formal-access
// VMOptions=--initializing-formal-access
// Fails because this.x parameter is used in initializer expression.
// Use the this.x parameter in an initializer expression.
class Foo {
var x, y;
Foo(this.x): y = x { }
}
main() {
new Foo(12);
}