Index: pkg/compiler/lib/src/inferrer/inferrer_engine.dart |
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart |
index e325a2f36c2fc3113f954f652a4ab402ff607dc7..3f3c54b3fc0cd39d1ce6b41baf011bc711b16e5c 100644 |
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart |
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart |
@@ -43,11 +43,11 @@ import 'type_system.dart'; |
* then does the inferencing on the graph. |
*/ |
class InferrerEngine { |
- final Map<Element, TypeInformation> defaultTypeOfParameter = |
- new Map<Element, TypeInformation>(); |
+ final Map<ParameterElement, TypeInformation> defaultTypeOfParameter = |
+ new Map<ParameterElement, TypeInformation>(); |
final WorkQueue workQueue = new WorkQueue(); |
final FunctionEntity mainElement; |
- final Set<Element> analyzedElements = new Set<Element>(); |
+ final Set<MemberElement> analyzedElements = new Set<MemberElement>(); |
/// The maximum number of times we allow a node in the graph to |
/// change types. If a node reaches that limit, we give up |
@@ -72,7 +72,8 @@ class InferrerEngine { |
// ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. |
final Map<ir.Node, TypeInformation> concreteKernelTypes = |
new Map<ir.Node, TypeInformation>(); |
- final Set<Element> generativeConstructorsExposingThis = new Set<Element>(); |
+ final Set<ConstructorElement> generativeConstructorsExposingThis = |
+ new Set<ConstructorElement>(); |
/// Data computed internally within elements, like the type-mask of a send a |
/// list allocation, or a for-in loop. |
@@ -224,12 +225,12 @@ class InferrerEngine { |
closedWorld.nativeData.isNativeMember(element); |
} |
- bool checkIfExposesThis(Element element) { |
+ bool checkIfExposesThis(ConstructorElement element) { |
element = element.implementation; |
return generativeConstructorsExposingThis.contains(element); |
} |
- void recordExposesThis(Element element, bool exposesThis) { |
+ void recordExposesThis(ConstructorElement element, bool exposesThis) { |
element = element.implementation; |
if (exposesThis) { |
generativeConstructorsExposingThis.add(element); |
@@ -359,7 +360,7 @@ class InferrerEngine { |
if (debug.VERBOSE) print("traced closure $e as ${true} (bail)"); |
e.functionSignature.forEachParameter((parameter) { |
types |
- .getInferredTypeOf(parameter) |
+ .getInferredTypeOfParameter(parameter) |
.giveUp(this, clearAssignments: false); |
}); |
}); |
@@ -370,7 +371,7 @@ class InferrerEngine { |
.where((e) => !bailedOutOn.contains(e)) |
.forEach((FunctionElement e) { |
e.functionSignature.forEachParameter((parameter) { |
- var info = types.getInferredTypeOf(parameter); |
+ var info = types.getInferredTypeOfParameter(parameter); |
info.maybeResume(); |
workQueue.add(info); |
}); |
@@ -460,7 +461,8 @@ class InferrerEngine { |
if (target is MethodElement) { |
print('${types.getInferredSignatureOf(target)} for ${target}'); |
} else { |
- print('${types.getInferredTypeOf(target).type} for ${target}'); |
+ print( |
+ '${types.getInferredTypeOfMember(target).type} for ${target}'); |
} |
} |
} else if (info is StaticCallSiteTypeInformation) { |
@@ -471,8 +473,8 @@ class InferrerEngine { |
print('${info.type} for some unknown kind of closure'); |
} |
}); |
- analyzedElements.forEach((Element elem) { |
- TypeInformation type = types.getInferredTypeOf(elem); |
+ analyzedElements.forEach((MemberElement elem) { |
+ TypeInformation type = types.getInferredTypeOfMember(elem); |
print('${elem} :: ${type} from ${type.assignments} '); |
}); |
} |
@@ -484,7 +486,7 @@ class InferrerEngine { |
} |
void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { |
- AstElement element = resolvedAst.element.implementation; |
+ MemberElement element = resolvedAst.element.implementation; |
if (analyzedElements.contains(element)) return; |
analyzedElements.add(element); |
@@ -499,7 +501,7 @@ class InferrerEngine { |
addedInGraph++; |
if (element.isField) { |
- VariableElement fieldElement = element; |
+ FieldElement fieldElement = element; |
ast.Node node = resolvedAst.node; |
ast.Node initializer = resolvedAst.body; |
if (element.isFinal || element.isConst) { |
@@ -539,18 +541,18 @@ class InferrerEngine { |
} |
} |
} |
- recordType(element, type); |
+ recordTypeOfField(element, type); |
} else if (!element.isInstanceMember) { |
- recordType(element, types.nullType); |
+ recordTypeOfField(element, types.nullType); |
} |
} else if (initializer == null) { |
// Only update types of static fields if there is no |
// assignment. Instance fields are dealt with in the constructor. |
if (Elements.isStaticOrTopLevelField(element)) { |
- recordTypeOfNonFinalField(node, element, type); |
+ recordTypeOfNonFinalField(element, type); |
} |
} else { |
- recordTypeOfNonFinalField(node, element, type); |
+ recordTypeOfNonFinalField(element, type); |
} |
if (Elements.isStaticOrTopLevelField(element) && |
resolvedAst.body != null && |
@@ -560,7 +562,7 @@ class InferrerEngine { |
// constant handler to figure out if it's a lazy field or not. |
if (argument.asSend() != null || |
(argument.asNewExpression() != null && !argument.isConst)) { |
- recordType(element, types.nullType); |
+ recordTypeOfField(element, types.nullType); |
} |
} |
} else { |
@@ -635,7 +637,7 @@ class InferrerEngine { |
if (callee.name == Identifiers.noSuchMethod_) return; |
if (callee.isField) { |
if (selector.isSetter) { |
- ElementTypeInformation info = types.getInferredTypeOf(callee); |
+ ElementTypeInformation info = types.getInferredTypeOfMember(callee); |
if (remove) { |
info.removeAssignment(arguments.positional[0]); |
} else { |
@@ -648,7 +650,7 @@ class InferrerEngine { |
} else if (selector != null && selector.isGetter) { |
// We are tearing a function off and thus create a closure. |
assert(callee.isFunction); |
- MemberTypeInformation info = types.getInferredTypeOf(callee); |
+ MemberTypeInformation info = types.getInferredTypeOfMember(callee); |
if (remove) { |
info.closurizedCount--; |
} else { |
@@ -663,7 +665,8 @@ class InferrerEngine { |
FunctionElement function = callee.implementation; |
FunctionSignature signature = function.functionSignature; |
signature.forEachParameter((Element parameter) { |
- ParameterTypeInformation info = types.getInferredTypeOf(parameter); |
+ ParameterTypeInformation info = |
+ types.getInferredTypeOfParameter(parameter); |
info.tagAsTearOffClosureParameter(this); |
if (addToQueue) workQueue.add(info); |
}); |
@@ -686,7 +689,7 @@ class InferrerEngine { |
? arguments.positional[parameterIndex] |
: null; |
if (type == null) type = getDefaultTypeOfParameter(parameter); |
- TypeInformation info = types.getInferredTypeOf(parameter); |
+ TypeInformation info = types.getInferredTypeOfParameter(parameter); |
if (remove) { |
info.removeAssignment(type); |
} else { |
@@ -709,7 +712,7 @@ class InferrerEngine { |
assert(parameter.functionDeclaration.isImplementation); |
TypeInformation existing = defaultTypeOfParameter[parameter]; |
defaultTypeOfParameter[parameter] = type; |
- TypeInformation info = types.getInferredTypeOf(parameter); |
+ TypeInformation info = types.getInferredTypeOfParameter(parameter); |
if (existing != null && existing is PlaceholderTypeInformation) { |
// Replace references to [existing] to use [type] instead. |
if (parameter.functionDeclaration.isInstanceMember) { |
@@ -740,7 +743,7 @@ class InferrerEngine { |
* should be present and a default type for each parameter should |
* exist. |
*/ |
- TypeInformation getDefaultTypeOfParameter(Element parameter) { |
+ TypeInformation getDefaultTypeOfParameter(ParameterElement parameter) { |
return defaultTypeOfParameter.putIfAbsent(parameter, () { |
return new PlaceholderTypeInformation(types.currentMember); |
}); |
@@ -754,7 +757,7 @@ class InferrerEngine { |
* TODO(johnniwinther): Remove once default values of synthetic parameters |
* are fixed. |
*/ |
- bool hasAlreadyComputedTypeOfParameterDefault(Element parameter) { |
+ bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter) { |
TypeInformation seen = defaultTypeOfParameter[parameter]; |
return (seen != null && seen is! PlaceholderTypeInformation); |
} |
@@ -762,17 +765,32 @@ class InferrerEngine { |
/** |
* Returns the type of [element]. |
*/ |
- TypeInformation typeOfElement(Entity element) { |
- if (element is FunctionElement) return types.functionType; |
- return types.getInferredTypeOf(element); |
+ TypeInformation typeOfParameter(ParameterElement element) { |
+ return types.getInferredTypeOfParameter(element); |
+ } |
+ |
+ /** |
+ * Returns the type of [element]. |
+ */ |
+ TypeInformation typeOfMember(MemberElement element) { |
+ if (element is MethodElement) return types.functionType; |
+ return types.getInferredTypeOfMember(element); |
+ } |
+ |
+ /** |
+ * Returns the return type of [element]. |
+ */ |
+ @deprecated |
+ TypeInformation returnTypeOfLocalFunction(LocalFunctionElement element) { |
+ return types.getInferredTypeOfLocalFunction(element); |
} |
/** |
* Returns the return type of [element]. |
*/ |
- TypeInformation returnTypeOfElement(Entity element) { |
- if (element is! FunctionElement) return types.dynamicType; |
- return types.getInferredTypeOf(element); |
+ TypeInformation returnTypeOfMember(MemberElement element) { |
+ if (element is! MethodElement) return types.dynamicType; |
+ return types.getInferredTypeOfMember(element); |
} |
/** |
@@ -780,32 +798,49 @@ class InferrerEngine { |
* |
* [nodeHolder] is the element holder of [node]. |
*/ |
- void recordTypeOfFinalField( |
- Spannable node, Entity analyzed, Entity element, TypeInformation type) { |
- types.getInferredTypeOf(element).addAssignment(type); |
+ void recordTypeOfFinalField(FieldElement element, TypeInformation type) { |
+ types.getInferredTypeOfMember(element).addAssignment(type); |
} |
/** |
* Records that [node] sets non-final field [element] to be of type |
* [type]. |
*/ |
- void recordTypeOfNonFinalField( |
- Spannable node, Entity element, TypeInformation type) { |
- types.getInferredTypeOf(element).addAssignment(type); |
+ void recordTypeOfNonFinalField(FieldElement element, TypeInformation type) { |
+ types.getInferredTypeOfMember(element).addAssignment(type); |
} |
/** |
* Records that [element] is of type [type]. |
*/ |
- void recordType(Entity element, TypeInformation type) { |
- types.getInferredTypeOf(element).addAssignment(type); |
+ // TODO(johnniwinther): Merge [recordTypeOfFinalField] and |
+ // [recordTypeOfNonFinalField] with this? |
+ void recordTypeOfField(FieldElement element, TypeInformation type) { |
+ types.getInferredTypeOfMember(element).addAssignment(type); |
+ } |
+ |
+ /** |
+ * Records that the return type [element] is of type [type]. |
+ */ |
+ @deprecated |
+ void recordReturnTypeOfLocalFunction( |
+ LocalFunctionElement element, TypeInformation type) { |
+ TypeInformation info = types.getInferredTypeOfLocalFunction(element); |
+ if (element.name == '==') { |
+ // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. |
+ info.addAssignment(types.boolType); |
+ } |
+ // TODO(ngeoffray): Clean up. We do these checks because |
+ // [SimpleTypesInferrer] deals with two different inferrers. |
+ if (type == null) return; |
+ if (info.assignments.isEmpty) info.addAssignment(type); |
} |
/** |
* Records that the return type [element] is of type [type]. |
*/ |
- void recordReturnType(Element element, TypeInformation type) { |
- TypeInformation info = types.getInferredTypeOf(element); |
+ void recordReturnType(MethodElement element, TypeInformation type) { |
+ TypeInformation info = types.getInferredTypeOfMember(element); |
if (element.name == '==') { |
// Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. |
info.addAssignment(types.boolType); |
@@ -823,9 +858,27 @@ class InferrerEngine { |
* |
* Returns the new type for [analyzedElement]. |
*/ |
- TypeInformation addReturnTypeFor( |
- Element element, TypeInformation unused, TypeInformation newType) { |
- TypeInformation type = types.getInferredTypeOf(element); |
+ @deprecated |
+ TypeInformation addReturnTypeForLocalFunction(LocalFunctionElement element, |
+ TypeInformation unused, TypeInformation newType) { |
+ TypeInformation type = types.getInferredTypeOfLocalFunction(element); |
+ // TODO(ngeoffray): Clean up. We do this check because |
+ // [SimpleTypesInferrer] deals with two different inferrers. |
+ if (element.isGenerativeConstructor) return type; |
+ type.addAssignment(newType); |
+ return type; |
+ } |
+ |
+ /** |
+ * Notifies to the inferrer that [analyzedElement] can have return |
+ * type [newType]. [currentType] is the type the [ElementGraphBuilder] |
+ * currently found. |
+ * |
+ * Returns the new type for [analyzedElement]. |
+ */ |
+ TypeInformation addReturnTypeForMethod( |
+ MethodElement element, TypeInformation unused, TypeInformation newType) { |
+ TypeInformation type = types.getInferredTypeOfMember(element); |
// TODO(ngeoffray): Clean up. We do this check because |
// [SimpleTypesInferrer] deals with two different inferrers. |
if (element.isGenerativeConstructor) return type; |
@@ -843,7 +896,54 @@ class InferrerEngine { |
* |
* [inLoop] tells whether the call happens in a loop. |
*/ |
- TypeInformation registerCalledElement( |
+ @deprecated |
+ TypeInformation registerCalledLocalFunction( |
+ Spannable node, |
+ Selector selector, |
+ TypeMask mask, |
+ Element caller, |
+ LocalFunctionElement callee, |
+ ArgumentsTypes arguments, |
+ SideEffects sideEffects, |
+ bool inLoop) { |
+ return _registerCalledElement( |
+ node, selector, mask, caller, callee, arguments, sideEffects, inLoop); |
+ } |
+ |
+ /** |
+ * Registers that [caller] calls [callee] at location [node], with |
+ * [selector], and [arguments]. Note that [selector] is null for |
+ * forwarding constructors. |
+ * |
+ * [sideEffects] will be updated to incorporate [callee]'s side |
+ * effects. |
+ * |
+ * [inLoop] tells whether the call happens in a loop. |
+ */ |
+ TypeInformation registerCalledMember( |
+ Spannable node, |
+ Selector selector, |
+ TypeMask mask, |
+ Element caller, |
+ MemberElement callee, |
+ ArgumentsTypes arguments, |
+ SideEffects sideEffects, |
+ bool inLoop) { |
+ return _registerCalledElement( |
+ node, selector, mask, caller, callee, arguments, sideEffects, inLoop); |
+ } |
+ |
+ /** |
+ * Registers that [caller] calls [callee] at location [node], with |
+ * [selector], and [arguments]. Note that [selector] is null for |
+ * forwarding constructors. |
+ * |
+ * [sideEffects] will be updated to incorporate [callee]'s side |
+ * effects. |
+ * |
+ * [inLoop] tells whether the call happens in a loop. |
+ */ |
+ TypeInformation _registerCalledElement( |
Spannable node, |
Selector selector, |
TypeMask mask, |
@@ -1043,25 +1143,45 @@ class InferrerEngine { |
types.allocatedLists.values.forEach(cleanup); |
} |
- Iterable<Element> getCallersOf(Element element) { |
+ Iterable<Element> getCallersOf(MemberElement element) { |
if (compiler.disableTypeInference) { |
throw new UnsupportedError( |
"Cannot query the type inferrer when type inference is disabled."); |
} |
- MemberTypeInformation info = types.getInferredTypeOf(element); |
+ MemberTypeInformation info = types.getInferredTypeOfMember(element); |
return info.callers; |
} |
/** |
* Returns the type of [element] when being called with [selector]. |
*/ |
- TypeInformation typeOfElementWithSelector( |
+ TypeInformation typeOfLocalFunctionWithSelector( |
+ LocalFunctionElement element, Selector selector) { |
+ return _typeOfElementWithSelector(element, selector); |
+ } |
+ |
+ /** |
+ * Returns the type of [element] when being called with [selector]. |
+ */ |
+ TypeInformation typeOfMemberWithSelector( |
+ MemberElement element, Selector selector) { |
+ return _typeOfElementWithSelector(element, selector); |
+ } |
+ |
+ /** |
+ * Returns the type of [element] when being called with [selector]. |
+ */ |
+ TypeInformation _typeOfElementWithSelector( |
Element element, Selector selector) { |
if (element.name == Identifiers.noSuchMethod_ && |
selector.name != element.name) { |
// An invocation can resolve to a [noSuchMethod], in which case |
// we get the return type of [noSuchMethod]. |
- return returnTypeOfElement(element); |
+ if (element.isLocal) { |
+ return returnTypeOfLocalFunction(element); |
+ } else { |
+ return returnTypeOfMember(element); |
+ } |
} else if (selector.isGetter) { |
if (element.isFunction) { |
// [functionType] is null if the inferrer did not run. |
@@ -1069,18 +1189,26 @@ class InferrerEngine { |
? types.dynamicType |
: types.functionType; |
} else if (element.isField) { |
- return typeOfElement(element); |
+ return typeOfMember(element); |
} else if (Elements.isUnresolved(element)) { |
return types.dynamicType; |
} else { |
assert(element.isGetter); |
- return returnTypeOfElement(element); |
+ if (element.isLocal) { |
+ return returnTypeOfLocalFunction(element); |
+ } else { |
+ return returnTypeOfMember(element); |
+ } |
} |
} else if (element.isGetter || element.isField) { |
assert(selector.isCall || selector.isSetter); |
return types.dynamicType; |
} else { |
- return returnTypeOfElement(element); |
+ if (element.isLocal) { |
+ return returnTypeOfLocalFunction(element); |
+ } else { |
+ return returnTypeOfMember(element); |
+ } |
} |
} |