Index: pkg/analyzer/lib/src/summary/link.dart |
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart |
index 57dccf1191c88f3731f2a2cb3bb331b329eeebcb..63195a2414e5405c1dd266db15f1269bd44f9fb9 100644 |
--- a/pkg/analyzer/lib/src/summary/link.dart |
+++ b/pkg/analyzer/lib/src/summary/link.dart |
@@ -1241,6 +1241,9 @@ class CompilationUnitElementInBuildUnit extends CompilationUnitElementForLink { |
for (TopLevelVariableElementForLink variable in topLevelVariables) { |
variable.link(this); |
} |
+ for (TopLevelFunctionElementForLink function in functions) { |
+ function.link(this); |
+ } |
} |
for (ClassElementForLink classElement in types) { |
classElement.link(this); |
@@ -2976,6 +2979,116 @@ class FunctionElementForLink_Initializer extends Object |
} |
/** |
+ * Element representing the initializer expression of a parameter. |
+ */ |
+class FunctionElementForLink_ParameterInitializer extends Object |
Jennifer Messerly
2016/06/25 00:37:46
this is almost entirely a copy+paste of FunctionEl
|
+ with ReferenceableElementForLink, TypeParameterizedElementMixin |
+ implements FunctionElementForLink_Local { |
+ /** |
+ * The variable for which this element is the initializer. |
+ */ |
+ final ParameterElementForLink _param; |
+ |
+ /** |
+ * The type inference node for this function, or `null` if it hasn't been |
+ * computed yet. |
+ */ |
+ TypeInferenceNode _typeInferenceNode; |
+ |
+ List<FunctionElementForLink_Local_NonSynthetic> _functions; |
+ DartType _inferredReturnType; |
+ |
+ FunctionElementForLink_ParameterInitializer(this._param); |
+ |
+ @override |
+ TypeInferenceNode get asTypeInferenceNode => |
+ _typeInferenceNode ??= new TypeInferenceNode(this); |
+ |
+ @override |
+ CompilationUnitElementForLink get compilationUnit => |
+ _param.compilationUnit; |
+ |
+ @override |
+ ParameterElementForLink get enclosingElement => _param; |
+ |
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => |
+ _param.getAncestor((e) => e is ClassElementForLink); |
Jennifer Messerly
2016/06/25 00:37:47
I think this was the only actual change
|
+ |
+ @override |
+ CompilationUnitElementForLink get enclosingUnit => _param.compilationUnit; |
+ |
+ @override |
+ List<FunctionElementForLink_Local_NonSynthetic> get functions => |
+ _functions ??= _param._unlinkedParam.initializer.localFunctions |
+ .map((UnlinkedExecutable ex) => |
+ new FunctionElementForLink_Local_NonSynthetic( |
+ _param.compilationUnit, this, ex)) |
+ .toList(); |
+ |
+ @override |
+ DartType get returnType { |
+ // If this is a variable whose type needs inferring, infer it. |
+ if (_param.hasImplicitType) { |
+ return _param.inferredType; |
+ } else { |
+ // There's no reason linking should need to access the type of |
+ // this FunctionElement, since the variable doesn't need its |
+ // type inferred. |
+ assert(false); |
+ // But for robustness, return the dynamic type. |
+ return DynamicTypeImpl.instance; |
+ } |
+ } |
+ |
+ @override |
+ void set returnType(DartType newType) { |
+ // InstanceMemberInferrer stores the new type both here and on the variable |
+ // element. We don't need to record both values, so we ignore it here. |
+ } |
+ |
+ @override |
+ TypeParameterizedElementMixin get typeParameterContext => this; |
+ |
+ @override |
+ List<UnlinkedTypeParam> get unlinkedTypeParams => const []; |
+ |
+ @override |
+ bool get _hasTypeBeenInferred => _inferredReturnType != null; |
+ |
+ @override |
+ UnlinkedExecutable get _unlinkedExecutable => |
+ _param._unlinkedParam.initializer; |
+ |
+ @override |
+ FunctionElementForLink_Local getLocalFunction(int index) { |
+ List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions; |
+ return index < functions.length ? functions[index] : null; |
+ } |
+ |
+ /** |
+ * Store the results of type inference for this initializer in |
+ * [compilationUnit]. |
+ */ |
+ void link(CompilationUnitElementInBuildUnit compilationUnit) { |
+ compilationUnit._storeLinkedType(_unlinkedExecutable.inferredReturnTypeSlot, |
+ _inferredReturnType, typeParameterContext); |
+ for (FunctionElementForLink_Local_NonSynthetic function in functions) { |
+ function.link(compilationUnit); |
+ } |
+ } |
+ |
+ @override |
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
+ |
+ @override |
+ void _setInferredType(DartType type) { |
+ assert(!_hasTypeBeenInferred); |
+ _inferredReturnType = type; |
+ _param._inferredType = _dynamicIfNull(type); |
+ } |
+} |
+ |
+/** |
* Element representing a local function (possibly a closure). |
*/ |
abstract class FunctionElementForLink_Local |
@@ -3888,6 +4001,15 @@ class ParameterElementForLink implements ParameterElementImpl { |
@override |
final ParameterParentElementForLink enclosingElement; |
+ /** |
+ * If this variable has an initializer and an implicit type, and the enclosing |
+ * library is part of the build unit being linked, the variable's node in the |
+ * type inference dependency graph. Otherwise `null`. |
+ */ |
+ TypeInferenceNode _typeInferenceNode; |
+ |
+ FunctionElementForLink_ParameterInitializer _initializer; |
+ |
DartType _inferredType; |
DartType _declaredType; |
@@ -3895,6 +4017,19 @@ class ParameterElementForLink implements ParameterElementImpl { |
this._typeParameterContext, this.compilationUnit, this._parameterIndex) { |
if (_unlinkedParam.initializer?.bodyExpr != null) { |
_constNode = new ConstParameterNode(this); |
+ if (hasImplicitType) { |
+ _typeInferenceNode = initializer.asTypeInferenceNode; |
+ } |
+ } |
+ } |
+ |
+ @override |
+ FunctionElementForLink_ParameterInitializer get initializer { |
+ if (_unlinkedParam.initializer == null) { |
+ return null; |
+ } else { |
+ return _initializer ??= |
+ new FunctionElementForLink_ParameterInitializer(this); |
} |
} |
@@ -3921,32 +4056,58 @@ class ParameterElementForLink implements ParameterElementImpl { |
return null; |
} |
- @override |
- DartType get type { |
- if (_inferredType != null) { |
- return _inferredType; |
- } else if (_declaredType == null) { |
- if (_unlinkedParam.isFunctionTyped) { |
- _declaredType = new FunctionTypeImpl( |
- new FunctionElementForLink_FunctionTypedParam( |
- this, _typeParameterContext, _unlinkedParam.parameters)); |
- } else if (_unlinkedParam.type == null) { |
- if (!compilationUnit.isInBuildUnit) { |
- _inferredType = compilationUnit.getLinkedType( |
- _unlinkedParam.inferredTypeSlot, _typeParameterContext); |
- return _inferredType; |
- } else { |
- _declaredType = DynamicTypeImpl.instance; |
+ /** |
+ * If the variable has an explicitly declared return type, return it. |
+ * Otherwise return `null`. |
+ */ |
+ DartType get declaredType { |
Jennifer Messerly
2016/06/25 00:37:47
this pattern more or less copy+paste from Variable
|
+ if (hasImplicitType) { |
+ return null; |
+ } else if (_declaredType != null) { |
+ return _declaredType; |
+ } else if (_unlinkedParam.isFunctionTyped) { |
+ return _declaredType = new FunctionTypeImpl( |
+ new FunctionElementForLink_FunctionTypedParam( |
+ this, _typeParameterContext, _unlinkedParam.parameters)); |
+ } else { |
+ return _declaredType = compilationUnit.resolveTypeRef( |
+ _unlinkedParam.type, _typeParameterContext); |
+ } |
+ } |
+ |
+ /** |
+ * Return the inferred type of the parameter element. |
+ * |
+ * Should only be called if no type was explicitly declared. |
+ */ |
+ DartType get inferredType { |
+ // We should only try to infer a type when none is explicitly declared. |
+ assert(_unlinkedParam.type == null); |
+ if (_inferredType == null) { |
+ if (_typeInferenceNode != null) { |
+ assert(Linker._initializerTypeInferenceCycle == null); |
+ Linker._initializerTypeInferenceCycle = |
+ compilationUnit.library.libraryCycleForLink; |
+ try { |
+ new TypeInferenceDependencyWalker().walk(_typeInferenceNode); |
Jennifer Messerly
2016/06/25 00:37:46
Aside -- I'm reusing logic from the static/top-lev
|
+ assert(_inferredType != null); |
+ } finally { |
+ Linker._initializerTypeInferenceCycle = null; |
} |
+ } else if (compilationUnit.isInBuildUnit) { |
+ _inferredType = DynamicTypeImpl.instance; |
} else { |
- _declaredType = compilationUnit.resolveTypeRef( |
- _unlinkedParam.type, _typeParameterContext); |
+ _inferredType = compilationUnit.getLinkedType( |
+ _unlinkedParam.inferredTypeSlot, _typeParameterContext); |
} |
} |
- return _declaredType; |
+ return _inferredType; |
} |
@override |
+ DartType get type => declaredType ?? inferredType; |
+ |
+ @override |
void set type(DartType inferredType) { |
assert(_inferredType == null); |
_inferredType = inferredType; |
@@ -3957,8 +4118,11 @@ class ParameterElementForLink implements ParameterElementImpl { |
* [compilationUnit]. |
*/ |
void link(CompilationUnitElementInBuildUnit compilationUnit) { |
Jennifer Messerly
2016/06/25 00:37:46
"link" method seems like the thing that actually f
|
- compilationUnit._storeLinkedType( |
- _unlinkedParam.inferredTypeSlot, _inferredType, _typeParameterContext); |
+ if (hasImplicitType) { |
+ compilationUnit._storeLinkedType( |
+ _unlinkedParam.inferredTypeSlot, inferredType, _typeParameterContext); |
+ initializer?.link(compilationUnit); |
+ } |
} |
@override |