 Chromium Code Reviews
 Chromium Code Reviews Issue 2092333002:
  fix #25794, infer parameter type from default value, in AST summaries  (Closed) 
  Base URL: git@github.com:dart-lang/sdk.git@master
    
  
    Issue 2092333002:
  fix #25794, infer parameter type from default value, in AST summaries  (Closed) 
  Base URL: git@github.com:dart-lang/sdk.git@master| 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 |