Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1125)

Unified Diff: pkg/compiler/lib/src/resolution/constructors.dart

Issue 1218793002: Compute constant constructors in resolution. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Cleanup Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/resolution/constructors.dart
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 9c75184413c10311e9494736e6b1b042496978f7..bcf61138159fe86a5b91546b7d4c11f718ab9511 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -6,12 +6,18 @@ part of resolution;
class InitializerResolver {
final ResolverVisitor visitor;
- final Map<Element, Node> initialized;
+ final ConstructorElementX constructor;
+ final FunctionExpression functionNode;
+ final Map<FieldElement, Node> initialized = <FieldElement, Node>{};
+ final Map<FieldElement, ConstantExpression> fieldInitializers =
+ <FieldElement, ConstantExpression>{};
Link<Node> initializers;
- bool hasSuper;
+ bool hasSuper = false;
+ bool isValidAsConstant = true;
- InitializerResolver(this.visitor)
- : initialized = new Map<Element, Node>(), hasSuper = false;
+ bool get isConst => constructor.isConst;
+
+ InitializerResolver(this.visitor, this.constructor, this.functionNode);
ResolutionRegistry get registry => visitor.registry;
@@ -37,6 +43,7 @@ class InitializerResolver {
visitor.compiler.reportInfo(
existing,
MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name});
+ isValidAsConstant = false;
}
void checkForDuplicateInitializers(FieldElementX field, Node init) {
@@ -54,12 +61,13 @@ class InitializerResolver {
initialized[field] = init;
}
- void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
+ void resolveFieldInitializer(SendSet init) {
// init is of the form [this.]field = value.
final Node selector = init.selector;
final String name = selector.asIdentifier().source;
// Lookup target field.
Element target;
+ FieldElement field;
if (isFieldInitializer(init)) {
target = constructor.enclosingClass.lookupLocalMember(name);
if (target == null) {
@@ -72,6 +80,8 @@ class InitializerResolver {
selector.asIdentifier(), constructor.enclosingClass);
} else if (!target.isInstanceMember) {
error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
+ } else {
+ field = target;
}
} else {
error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
@@ -80,38 +90,44 @@ class InitializerResolver {
registry.registerStaticUse(target);
checkForDuplicateInitializers(target, init);
// Resolve initializing value.
- visitor.visitInStaticContext(init.arguments.head);
+ ResolutionResult result = visitor.visitInStaticContext(
+ init.arguments.head,
+ inConstantInitializer: isConst);
+ if (isConst) {
+ if (result.isConstant && field != null) {
+ // TODO(johnniwinther): Report error if `result.constant` is `null`.
+ fieldInitializers[field] = result.constant;
+ } else {
+ isValidAsConstant = false;
+ }
+ }
}
- ClassElement getSuperOrThisLookupTarget(FunctionElement constructor,
- bool isSuperCall,
- Node diagnosticNode) {
- ClassElement lookupTarget = constructor.enclosingClass;
+ InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode,
+ {bool isSuperCall}) {
if (isSuperCall) {
// Calculate correct lookup target and constructor name.
- if (identical(lookupTarget, visitor.compiler.objectClass)) {
+ if (identical(constructor.enclosingClass, visitor.compiler.objectClass)) {
error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
+ isValidAsConstant = false;
} else {
- return lookupTarget.supertype.element;
+ return constructor.enclosingClass.supertype;
}
}
- return lookupTarget;
+ return constructor.enclosingClass.thisType;
}
- Element resolveSuperOrThisForSend(FunctionElement constructor,
- FunctionExpression functionNode,
- Send call) {
+ ResolutionResult resolveSuperOrThisForSend(Send call) {
// Resolve the selector and the arguments.
- visitor.inStaticContext(() {
+ ArgumentsResult argumentsResult = visitor.inStaticContext(() {
visitor.resolveSelector(call, null);
- visitor.resolveArguments(call.argumentsNode);
- });
- Selector selector = registry.getSelector(call);
- bool isSuperCall = Initializers.isSuperConstructorCall(call);
+ return visitor.resolveArguments(call.argumentsNode);
+ }, inConstantInitializer: isConst);
- ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
- isSuperCall,
- call);
+ bool isSuperCall = Initializers.isSuperConstructorCall(call);
+ InterfaceType targetType =
+ getSuperOrThisLookupTarget(call, isSuperCall: isSuperCall);
+ ClassElement lookupTarget = targetType.element;
Selector constructorSelector =
visitor.getRedirectingThisOrSuperConstructorSelector(call);
FunctionElement calledConstructor =
@@ -119,9 +135,8 @@ class InitializerResolver {
final bool isImplicitSuperCall = false;
final String className = lookupTarget.name;
- verifyThatConstructorMatchesCall(constructor,
- calledConstructor,
- selector.callStructure,
+ verifyThatConstructorMatchesCall(calledConstructor,
+ argumentsResult.callStructure,
isImplicitSuperCall,
call,
className,
@@ -129,11 +144,28 @@ class InitializerResolver {
registry.useElement(call, calledConstructor);
registry.registerStaticUse(calledConstructor);
- return calledConstructor;
+ if (isConst) {
+ if (isValidAsConstant &&
+ calledConstructor.isConst &&
+ argumentsResult.isValidAsConstant) {
+ CallStructure callStructure = argumentsResult.callStructure;
+ List<ConstantExpression> arguments = argumentsResult.constantArguments;
+ return new ConstantResult(
+ call,
+ new ConstructedConstantExpression(
+ targetType,
+ calledConstructor,
+ callStructure,
+ arguments),
+ element: calledConstructor);
+ } else {
+ isValidAsConstant = false;
+ }
+ }
+ return new ResolutionResult.forElement(calledConstructor);
}
- void resolveImplicitSuperConstructorSend(FunctionElement constructor,
- FunctionExpression functionNode) {
+ ConstructedConstantExpression resolveImplicitSuperConstructorSend() {
// If the class has a super resolve the implicit super call.
ClassElement classElement = constructor.enclosingClass;
ClassElement superClass = classElement.superclass;
@@ -141,18 +173,16 @@ class InitializerResolver {
assert(superClass != null);
assert(superClass.isResolved);
- final bool isSuperCall = true;
- ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
- isSuperCall,
- functionNode);
+ InterfaceType targetType =
+ getSuperOrThisLookupTarget(functionNode, isSuperCall: true);
+ ClassElement lookupTarget = targetType.element;
Selector constructorSelector = new Selector.callDefaultConstructor();
Element calledConstructor = lookupTarget.lookupConstructor(
constructorSelector.name);
final String className = lookupTarget.name;
final bool isImplicitSuperCall = true;
- verifyThatConstructorMatchesCall(constructor,
- calledConstructor,
+ verifyThatConstructorMatchesCall(calledConstructor,
CallStructure.NO_ARGS,
isImplicitSuperCall,
functionNode,
@@ -160,11 +190,19 @@ class InitializerResolver {
constructorSelector);
registry.registerImplicitSuperCall(calledConstructor);
registry.registerStaticUse(calledConstructor);
+
+ if (isConst && isValidAsConstant) {
+ return new ConstructedConstantExpression(
+ targetType,
+ calledConstructor,
+ CallStructure.NO_ARGS,
+ const <ConstantExpression>[]);
+ }
}
+ return null;
}
void verifyThatConstructorMatchesCall(
- FunctionElement caller,
ConstructorElementX lookedupConstructor,
CallStructure call,
bool isImplicitSuperCall,
@@ -181,6 +219,7 @@ class InitializerResolver {
: MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
visitor.compiler.reportError(
diagnosticNode, kind, {'constructorName': fullConstructorName});
+ isValidAsConstant = false;
} else {
lookedupConstructor.computeSignature(visitor.compiler);
if (!call.signatureApplies(lookedupConstructor.functionSignature)) {
@@ -188,12 +227,14 @@ class InitializerResolver {
? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
: MessageKind.NO_MATCHING_CONSTRUCTOR;
visitor.compiler.reportError(diagnosticNode, kind);
- } else if (caller.isConst
+ isValidAsConstant = false;
+ } else if (constructor.isConst
&& !lookedupConstructor.isConst) {
MessageKind kind = isImplicitSuperCall
? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT
: MessageKind.CONST_CALLS_NON_CONST;
visitor.compiler.reportError(diagnosticNode, kind);
+ isValidAsConstant = false;
}
}
}
@@ -202,16 +243,50 @@ 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(ConstructorElementX constructor,
- FunctionExpression functionNode) {
+ ConstructorElement resolveInitializers() {
+ Map<dynamic/*String|int*/, ConstantExpression> defaultValues =
+ <dynamic/*String|int*/, ConstantExpression>{};
+ ConstructedConstantExpression constructorInvocation;
// Keep track of all "this.param" parameters specified for constructor so
// that we can ensure that fields are initialized only once.
FunctionSignature functionParameters = constructor.functionSignature;
- functionParameters.forEachParameter((ParameterElement element) {
+ functionParameters.forEachParameter((ParameterElementX element) {
+ if (isConst) {
+ if (element.isOptional) {
+ if (element.constantCache == null) {
+ // TODO(johnniwinther): Remove this when all constant expressions
+ // can be computed during resolution.
+ isValidAsConstant = false;
+ } else {
+ ConstantExpression defaultValue = element.constant;
+ if (defaultValue != null) {
+ if (element.isNamed) {
+ defaultValues[element.name] = defaultValue;
+ } else {
+ int index =
+ element.functionDeclaration.parameters.indexOf(element);
+ defaultValues[index] = defaultValue;
+ }
+ } else {
+ isValidAsConstant = false;
+ }
+ }
+ }
+ }
if (element.isInitializingFormal) {
- InitializingFormalElement initializingFormal = element;
- checkForDuplicateInitializers(initializingFormal.fieldElement,
- element.initializer);
+ InitializingFormalElementX initializingFormal = element;
+ FieldElement field = initializingFormal.fieldElement;
+ checkForDuplicateInitializers(field, element.initializer);
+ if (isConst) {
+ if (element.isNamed) {
+ fieldInitializers[field] = new NamedArgumentReference(element.name);
+ } else {
+ int index = element.functionDeclaration.parameters.indexOf(element);
+ fieldInitializers[field] = new PositionalArgumentReference(index);
+ }
+ } else {
+ isValidAsConstant = false;
+ }
}
});
@@ -224,7 +299,7 @@ class InitializerResolver {
for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) {
if (link.head.asSendSet() != null) {
final SendSet init = link.head.asSendSet();
- resolveFieldInitializer(constructor, init);
+ resolveFieldInitializer(init);
} else if (link.head.asSend() != null) {
final Send call = link.head.asSend();
if (call.argumentsNode == null) {
@@ -235,7 +310,14 @@ class InitializerResolver {
if (resolvedSuper) {
error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
}
- resolveSuperOrThisForSend(constructor, functionNode, call);
+ ResolutionResult result = resolveSuperOrThisForSend(call);
+ if (isConst) {
+ if (result.isConstant) {
+ constructorInvocation = result.constant;
+ } else {
+ isValidAsConstant = false;
+ }
+ }
resolvedSuper = true;
} else if (Initializers.isConstructorRedirect(call)) {
// Check that there is no body (Language specification 7.5.1). If the
@@ -256,9 +338,24 @@ class InitializerResolver {
if (parameter.isInitializingFormal) {
Node node = parameter.node;
error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
+ isValidAsConstant = false;
}
});
- return resolveSuperOrThisForSend(constructor, functionNode, call);
+ ResolutionResult result = resolveSuperOrThisForSend(call);
+ if (isConst) {
+ if (result.isConstant) {
+ constructorInvocation = result.constant;
+ } else {
+ isValidAsConstant = false;
+ }
+ if (isConst && isValidAsConstant) {
+ constructor.constantConstructor =
+ new RedirectingGenerativeConstantConstructor(
+ defaultValues,
+ constructorInvocation);
+ }
+ }
+ return result.element;
} else {
visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
return null;
@@ -268,7 +365,14 @@ class InitializerResolver {
}
}
if (!resolvedSuper) {
- resolveImplicitSuperConstructorSend(constructor, functionNode);
+ constructorInvocation = resolveImplicitSuperConstructorSend();
+ }
+ if (isConst && isValidAsConstant) {
+ constructor.constantConstructor = new GenerativeConstantConstructor(
+ constructor.enclosingClass.thisType,
+ defaultValues,
+ fieldInitializers,
+ constructorInvocation);
}
return null; // If there was no redirection always return null.
}

Powered by Google App Engine
This is Rietveld 408576698