| Index: pkg/analyzer/lib/src/generated/resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
|
| index 12108087d2fa817137f9ae9bf02f784788283375..8ded6fd4c37bac714ef07b2dfa3be41023c3bae4 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -6,6 +6,8 @@ library engine.resolver;
|
|
|
| import 'dart:collection';
|
|
|
| +import '../task/strong/info.dart' show InferredType, StaticInfo;
|
| +import '../task/strong/rules.dart' show TypeRules;
|
| import 'ast.dart';
|
| import 'constant.dart';
|
| import 'element.dart';
|
| @@ -5755,6 +5757,227 @@ class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ {
|
| }
|
|
|
| /**
|
| + * Maintains and manages contextual type information used for
|
| + * inferring types.
|
| + */
|
| +class InferenceContext {
|
| + // TODO(leafp): Consider replacing these node properties with a
|
| + // hash table help in an instance of this class.
|
| + static const String _typeProperty =
|
| + 'analyzer.src.generated.InferenceContext.contextType';
|
| +
|
| + /**
|
| + * The error listener on which to record inference information.
|
| + */
|
| + final AnalysisErrorListener _errorListener;
|
| +
|
| + /**
|
| + * Type provider, needed for type matching.
|
| + */
|
| + final TypeProvider _typeProvider;
|
| +
|
| + /**
|
| + * The type system in use.
|
| + */
|
| + final TypeSystem _typeSystem;
|
| +
|
| + /**
|
| + * The DDC type rules, used to create the inference info nodes.
|
| + */
|
| + final TypeRules _rules;
|
| +
|
| + /**
|
| + * A stack of return types for all of the enclosing
|
| + * functions and methods.
|
| + */
|
| + List<DartType> _returnStack = <DartType>[];
|
| +
|
| + InferenceContext._(
|
| + this._errorListener, TypeProvider typeProvider, this._typeSystem)
|
| + : _typeProvider = typeProvider,
|
| + _rules = new TypeRules(typeProvider);
|
| +
|
| + /**
|
| + * Get the return type of the current enclosing function, if any.
|
| + */
|
| + DartType get returnContext =>
|
| + (_returnStack.isNotEmpty) ? _returnStack.last : null;
|
| +
|
| + /**
|
| + * Match type [t1] against type [t2] as follows.
|
| + * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
|
| + * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
|
| + * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'`
|
| + * to derive a concrete instantation for I of the form `<T0, ..., Tn>`,
|
| + * such that `I<T0, .., Tn> <: t2`
|
| + */
|
| + List<DartType> matchTypes(DartType t1, DartType t2) =>
|
| + (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null;
|
| +
|
| + /**
|
| + * Pop a return type off of the return stack.
|
| + */
|
| + void popReturnContext() {
|
| + assert(_returnStack.isNotEmpty);
|
| + if (_returnStack.isNotEmpty) {
|
| + _returnStack.removeLast();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Push a [returnType] onto the return stack.
|
| + */
|
| + void pushReturnContext(DartType returnType) {
|
| + _returnStack.add(returnType);
|
| + }
|
| +
|
| + /**
|
| + * Place an info node into the error stream indicating that a
|
| + * [type] has been inferred as the type of [node].
|
| + */
|
| + void recordInference(Expression node, DartType type) {
|
| + StaticInfo info = InferredType.create(_rules, node, type);
|
| + if (info == null) {
|
| + return;
|
| + }
|
| + AnalysisError error = info.toAnalysisError();
|
| + _errorListener.onError(error);
|
| + }
|
| +
|
| + List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
|
| + if (t1 == t2) {
|
| + return t2.typeArguments;
|
| + }
|
| + List<DartType> tArgs1 = t1.typeArguments;
|
| + List<DartType> tArgs2 = t2.typeArguments;
|
| + // If t1 isn't a raw type, bail out
|
| + if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) {
|
| + return null;
|
| + }
|
| +
|
| + // This is our inferred type argument list. We start at all dynamic,
|
| + // and fill in with inferred types when we reach a match.
|
| + List<DartType> actuals =
|
| + new List<DartType>.filled(tArgs1.length, _typeProvider.dynamicType);
|
| +
|
| + // When we find the supertype of t1 with the same
|
| + // classname as t2 (see below), we have the following:
|
| + // If t1 is an instantiation of a class T1<X0, ..., Xn>
|
| + // and t2 is an instantiation of a class T2<Y0, ...., Ym>
|
| + // of the form t2 = T2<S0, ..., Sm>
|
| + // then we want to choose instantiations for the Xi
|
| + // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
|
| + // To find this, we simply instantate T1 with
|
| + // X0, ..., Xn, and then find its superclass
|
| + // T2<T0', ..., Tn'>. We then solve the constraint
|
| + // set T0' <: S0, ..., Tn' <: Sn for the Xi.
|
| + // Currently, we only handle constraints where
|
| + // the Ti' is one of the Xi'. If there are multiple
|
| + // constraints on some Xi, we choose the lower of the
|
| + // two (if it exists).
|
| + bool permute(List<DartType> permutedArgs) {
|
| + if (permutedArgs == null) {
|
| + return false;
|
| + }
|
| + List<TypeParameterElement> ps = t1.typeParameters;
|
| + List<DartType> ts = ps.map((p) => p.type).toList();
|
| + for (int i = 0; i < permutedArgs.length; i++) {
|
| + DartType tVar = permutedArgs[i];
|
| + DartType tActual = tArgs2[i];
|
| + int index = ts.indexOf(tVar);
|
| + if (index >= 0 && _typeSystem.isSubtypeOf(tActual, actuals[index])) {
|
| + actuals[index] = tActual;
|
| + }
|
| + }
|
| + return actuals.any((x) => !x.isDynamic);
|
| + }
|
| +
|
| + // Look for the first supertype of t1 with the same class name as t2.
|
| + bool match(InterfaceType t1, Set<Element> visited) {
|
| + if (t1.element == t2.element) {
|
| + return permute(t1.typeArguments);
|
| + }
|
| +
|
| + if (t1 == _typeProvider.objectType) {
|
| + return false;
|
| + }
|
| +
|
| + Element element = t1.element;
|
| + if (visited == null) {
|
| + visited = new HashSet<Element>();
|
| + }
|
| + if (element == null || !visited.add(element)) {
|
| + return false;
|
| + }
|
| + try {
|
| + if (match(t1.superclass, visited)) {
|
| + return true;
|
| + }
|
| +
|
| + for (final parent in t1.mixins) {
|
| + if (match(parent, visited)) {
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + for (final parent in t1.interfaces) {
|
| + if (match(parent, visited)) {
|
| + return true;
|
| + }
|
| + }
|
| + } finally {
|
| + visited.remove(element);
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + // We have that t1 = T1<dynamic, ..., dynamic>.
|
| + // To match t1 against t2, we use the uninstantiated version
|
| + // of t1, essentially treating it as an instantiation with
|
| + // fresh variables, and solve for the variables.
|
| + // t1.element.type will be of the form T1<X0, ..., Xn>
|
| + if (!match(t1.element.type, null)) {
|
| + return null;
|
| + }
|
| + DartType newT1 = t1.element.type.substitute4(actuals);
|
| + // If we found a solution, return it.
|
| + if (_typeSystem.isSubtypeOf(newT1, t2)) {
|
| + return actuals;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Clear the type information assocated with [node].
|
| + */
|
| + static void clearType(AstNode node) {
|
| + node?.setProperty(_typeProperty, null);
|
| + }
|
| +
|
| + /**
|
| + * Look for contextual type information attached to [node]. Returns
|
| + * the type if found, otherwise null.
|
| + */
|
| + static DartType getType(AstNode node) => node?.getProperty(_typeProperty);
|
| +
|
| + /**
|
| + * Attach contextual type information [type] to [node] for use during
|
| + * inference.
|
| + */
|
| + static void setType(AstNode node, DartType type) {
|
| + node?.setProperty(_typeProperty, type);
|
| + }
|
| +
|
| + /**
|
| + * Attach contextual type information [type] to [node] for use during
|
| + * inference.
|
| + */
|
| + static void setTypeFromNode(AstNode innerNode, AstNode outerNode) {
|
| + setType(innerNode, getType(outerNode));
|
| + }
|
| +}
|
| +
|
| +/**
|
| * Instances of the class `InheritanceManager` manage the knowledge of where class members
|
| * (methods, getters & setters) are inherited from.
|
| */
|
| @@ -10385,8 +10608,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| StaticTypeAnalyzer typeAnalyzer;
|
|
|
| /*
|
| - * The type system in use during resolution.
|
| - */
|
| + * The type system in use during resolution.
|
| + */
|
| TypeSystem typeSystem;
|
|
|
| /**
|
| @@ -10419,6 +10642,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| */
|
| Comment _commentBeforeFunction = null;
|
|
|
| + InferenceContext inferenceContext = null;
|
| +
|
| /**
|
| * The object keeping track of which elements have had their types overridden.
|
| */
|
| @@ -10470,6 +10695,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
| this.elementResolver = new ElementResolver(this);
|
| this.typeSystem = definingLibrary.context.typeSystem;
|
| + this.inferenceContext =
|
| + new InferenceContext._(errorListener, typeProvider, typeSystem);
|
| if (typeAnalyzerFactory == null) {
|
| this.typeAnalyzer = new StaticTypeAnalyzer(this);
|
| } else {
|
| @@ -10742,11 +10969,65 @@ class ResolverVisitor extends ScopedVisitor {
|
| identical(parent, _enclosingFunctionTypeAlias)) {
|
| return null;
|
| }
|
| - return super.visitAnnotation(node);
|
| + safelyVisit(node.name);
|
| + safelyVisit(node.constructorName);
|
| + Element element = node.element;
|
| + if (element is ExecutableElement) {
|
| + InferenceContext.setType(node.arguments, element.type);
|
| + }
|
| + safelyVisit(node.arguments);
|
| + node.accept(elementResolver);
|
| + node.accept(typeAnalyzer);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitArgumentList(ArgumentList node) {
|
| + DartType callerType = InferenceContext.getType(node);
|
| + if (callerType is FunctionType) {
|
| + Map<String, DartType> namedParameterTypes =
|
| + callerType.namedParameterTypes;
|
| + List<DartType> normalParameterTypes = callerType.normalParameterTypes;
|
| + List<DartType> optionalParameterTypes = callerType.optionalParameterTypes;
|
| + int normalCount = normalParameterTypes.length;
|
| + int optionalCount = optionalParameterTypes.length;
|
| +
|
| + NodeList<Expression> arguments = node.arguments;
|
| + Iterable<Expression> positional =
|
| + arguments.takeWhile((l) => l is! NamedExpression);
|
| + Iterable<Expression> required = positional.take(normalCount);
|
| + Iterable<Expression> optional =
|
| + positional.skip(normalCount).take(optionalCount);
|
| + Iterable<Expression> named =
|
| + arguments.skipWhile((l) => l is! NamedExpression);
|
| +
|
| + //TODO(leafp): Consider using the parameter elements here instead.
|
| + //TODO(leafp): Make sure that the parameter elements are getting
|
| + // setup correctly with inference.
|
| + int index = 0;
|
| + for (Expression argument in required) {
|
| + InferenceContext.setType(argument, normalParameterTypes[index++]);
|
| + }
|
| + index = 0;
|
| + for (Expression argument in optional) {
|
| + InferenceContext.setType(argument, optionalParameterTypes[index++]);
|
| + }
|
| +
|
| + for (Expression argument in named) {
|
| + if (argument is NamedExpression) {
|
| + DartType type = namedParameterTypes[argument.name.label.name];
|
| + if (type != null) {
|
| + InferenceContext.setType(argument, type);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return super.visitArgumentList(node);
|
| }
|
|
|
| @override
|
| Object visitAsExpression(AsExpression node) {
|
| + InferenceContext.setType(node.expression, node.type.type);
|
| super.visitAsExpression(node);
|
| // Since an as-statement doesn't actually change the type, we don't
|
| // let it affect the propagated type when it would result in a loss
|
| @@ -10763,6 +11044,33 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| @override
|
| + Object visitAssignmentExpression(AssignmentExpression node) {
|
| + safelyVisit(node.leftHandSide);
|
| + sc.TokenType operator = node.operator.type;
|
| + if (operator == sc.TokenType.EQ ||
|
| + operator == sc.TokenType.QUESTION_QUESTION_EQ) {
|
| + InferenceContext.setType(
|
| + node.rightHandSide, node.leftHandSide.staticType);
|
| + }
|
| + safelyVisit(node.rightHandSide);
|
| + node.accept(elementResolver);
|
| + node.accept(typeAnalyzer);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitAwaitExpression(AwaitExpression node) {
|
| + //TODO(leafp): Handle the implicit union type here
|
| + DartType contextType = InferenceContext.getType(node);
|
| + if (contextType != null) {
|
| + InterfaceType futureT =
|
| + typeProvider.futureType.substitute4([contextType]);
|
| + InferenceContext.setType(node.expression, futureT);
|
| + }
|
| + return super.visitAwaitExpression(node);
|
| + }
|
| +
|
| + @override
|
| Object visitBinaryExpression(BinaryExpression node) {
|
| sc.TokenType operatorType = node.operator.type;
|
| Expression leftOperand = node.leftOperand;
|
| @@ -10802,6 +11110,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
| }
|
| } else {
|
| + // TODO(leafp): Do downwards inference using the declared type
|
| + // of the binary operator.
|
| safelyVisit(leftOperand);
|
| safelyVisit(rightOperand);
|
| }
|
| @@ -10815,9 +11125,11 @@ class ResolverVisitor extends ScopedVisitor {
|
| safelyVisit(_commentBeforeFunction);
|
| _overrideManager.enterScope();
|
| try {
|
| + inferenceContext.pushReturnContext(InferenceContext.getType(node));
|
| super.visitBlockFunctionBody(node);
|
| } finally {
|
| _overrideManager.exitScope();
|
| + inferenceContext.popReturnContext();
|
| }
|
| return null;
|
| }
|
| @@ -10834,6 +11146,12 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| @override
|
| + Object visitCascadeExpression(CascadeExpression node) {
|
| + InferenceContext.setTypeFromNode(node.target, node);
|
| + return super.visitCascadeExpression(node);
|
| + }
|
| +
|
| + @override
|
| Object visitClassDeclaration(ClassDeclaration node) {
|
| //
|
| // Resolve the metadata in the library scope.
|
| @@ -10966,6 +11284,7 @@ class ResolverVisitor extends ScopedVisitor {
|
| _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
|
| thenExpression);
|
| // Visit "then" expression.
|
| + InferenceContext.setTypeFromNode(thenExpression, node);
|
| thenExpression.accept(this);
|
| } finally {
|
| _promoteManager.exitScope();
|
| @@ -10979,6 +11298,7 @@ class ResolverVisitor extends ScopedVisitor {
|
| _overrideManager.enterScope();
|
| try {
|
| _propagateFalseState(condition);
|
| + InferenceContext.setTypeFromNode(elseExpression, node);
|
| elseExpression.accept(this);
|
| } finally {
|
| _overrideManager.exitScope();
|
| @@ -11003,6 +11323,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| ExecutableElement outerFunction = _enclosingFunction;
|
| try {
|
| _enclosingFunction = node.element;
|
| + FunctionType type = _enclosingFunction.type;
|
| + InferenceContext.setType(node.body, type.returnType);
|
| super.visitConstructorDeclaration(node);
|
| } finally {
|
| _enclosingFunction = outerFunction;
|
| @@ -11019,6 +11341,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| // We visit the expression, but do not visit the field name because it needs
|
| // to be visited in the context of the constructor field initializer node.
|
| //
|
| + FieldElement fieldElement = enclosingClass.getField(node.fieldName.name);
|
| + InferenceContext.setType(node.expression, fieldElement?.type);
|
| safelyVisit(node.expression);
|
| node.accept(elementResolver);
|
| node.accept(typeAnalyzer);
|
| @@ -11050,6 +11374,7 @@ class ResolverVisitor extends ScopedVisitor {
|
|
|
| @override
|
| Object visitDefaultFormalParameter(DefaultFormalParameter node) {
|
| + InferenceContext.setType(node.defaultValue, node.parameter.element?.type);
|
| super.visitDefaultFormalParameter(node);
|
| ParameterElement element = node.element;
|
| if (element.initializer != null && node.defaultValue != null) {
|
| @@ -11128,6 +11453,7 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
| _overrideManager.enterScope();
|
| try {
|
| + InferenceContext.setTypeFromNode(node.expression, node);
|
| super.visitExpressionFunctionBody(node);
|
| } finally {
|
| _overrideManager.exitScope();
|
| @@ -11167,9 +11493,16 @@ class ResolverVisitor extends ScopedVisitor {
|
| // cannot be in scope while visiting the iterator.
|
| //
|
| Expression iterable = node.iterable;
|
| - safelyVisit(iterable);
|
| DeclaredIdentifier loopVariable = node.loopVariable;
|
| SimpleIdentifier identifier = node.identifier;
|
| + if (loopVariable?.type?.type != null) {
|
| + InterfaceType targetType = (node.awaitKeyword == null)
|
| + ? typeProvider.iterableType
|
| + : typeProvider.streamType;
|
| + InferenceContext.setType(
|
| + iterable, targetType.substitute4([loopVariable.type.type]));
|
| + }
|
| + safelyVisit(iterable);
|
| safelyVisit(loopVariable);
|
| safelyVisit(identifier);
|
| Statement body = node.body;
|
| @@ -11242,6 +11575,8 @@ class ResolverVisitor extends ScopedVisitor {
|
| try {
|
| SimpleIdentifier functionName = node.name;
|
| _enclosingFunction = functionName.staticElement as ExecutableElement;
|
| + InferenceContext.setType(
|
| + node.functionExpression, _enclosingFunction.type);
|
| super.visitFunctionDeclaration(node);
|
| } finally {
|
| _enclosingFunction = outerFunction;
|
| @@ -11256,6 +11591,11 @@ class ResolverVisitor extends ScopedVisitor {
|
| _enclosingFunction = node.element;
|
| _overrideManager.enterScope();
|
| try {
|
| + DartType functionType = InferenceContext.getType(node);
|
| + if (functionType is FunctionType) {
|
| + _inferFormalParameterList(node.parameters, functionType);
|
| + InferenceContext.setType(node.body, functionType.returnType);
|
| + }
|
| super.visitFunctionExpression(node);
|
| } finally {
|
| _overrideManager.exitScope();
|
| @@ -11271,6 +11611,7 @@ class ResolverVisitor extends ScopedVisitor {
|
| safelyVisit(node.function);
|
| node.accept(elementResolver);
|
| _inferFunctionExpressionsParametersTypes(node.argumentList);
|
| + InferenceContext.setType(node.argumentList, node.function.staticType);
|
| safelyVisit(node.argumentList);
|
| node.accept(typeAnalyzer);
|
| return null;
|
| @@ -11358,16 +11699,106 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| @override
|
| + Object visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| + DartType contextType = InferenceContext.getType(node);
|
| + if (contextType is InterfaceType &&
|
| + contextType.typeArguments != null &&
|
| + contextType.typeArguments.length > 0) {
|
| + TypeName classTypeName = node.constructorName.type;
|
| + if (classTypeName.typeArguments == null) {
|
| + List<DartType> targs =
|
| + inferenceContext.matchTypes(classTypeName.type, contextType);
|
| + if (targs != null && targs.any((t) => !t.isDynamic)) {
|
| + ClassElement classElement = classTypeName.type.element;
|
| + InterfaceType rawType = classElement.type;
|
| + InterfaceType fullType =
|
| + rawType.substitute2(targs, rawType.typeArguments);
|
| + // The element resolver uses the type on the constructor name, so
|
| + // infer it first
|
| + typeAnalyzer.inferConstructorName(node.constructorName, fullType);
|
| + safelyVisit(node.constructorName);
|
| + ConstructorElement invokedConstructor =
|
| + node.constructorName.staticElement;
|
| + FunctionType rawConstructorType = invokedConstructor.type;
|
| + FunctionType constructorType = rawConstructorType.substitute2(
|
| + targs, rawConstructorType.typeArguments);
|
| + InferenceContext.setType(node.argumentList, constructorType);
|
| + safelyVisit(node.argumentList);
|
| + InferenceContext.setType(node, fullType);
|
| + node.accept(elementResolver);
|
| + node.accept(typeAnalyzer);
|
| + return null;
|
| + }
|
| + } else {
|
| + InferenceContext.clearType(node);
|
| + }
|
| + }
|
| + super.visitInstanceCreationExpression(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| Object visitLabel(Label node) => null;
|
|
|
| @override
|
| Object visitLibraryIdentifier(LibraryIdentifier node) => null;
|
|
|
| @override
|
| + Object visitListLiteral(ListLiteral node) {
|
| + DartType contextType = InferenceContext.getType(node);
|
| + if (node.typeArguments == null && contextType is InterfaceType) {
|
| + InterfaceType listD =
|
| + typeProvider.listType.substitute4([typeProvider.dynamicType]);
|
| + List<DartType> targs = inferenceContext.matchTypes(listD, contextType);
|
| + if (targs != null &&
|
| + targs.length == 1 &&
|
| + targs.any((t) => !t.isDynamic)) {
|
| + DartType eType = targs[0];
|
| + InterfaceType listT = typeProvider.listType.substitute4([eType]);
|
| + for (Expression child in node.elements) {
|
| + InferenceContext.setType(child, eType);
|
| + }
|
| + InferenceContext.setType(node, listT);
|
| + } else {
|
| + InferenceContext.clearType(node);
|
| + }
|
| + }
|
| + super.visitListLiteral(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitMapLiteral(MapLiteral node) {
|
| + DartType contextType = InferenceContext.getType(node);
|
| + if (node.typeArguments == null && contextType is InterfaceType) {
|
| + InterfaceType mapD = typeProvider.mapType
|
| + .substitute4([typeProvider.dynamicType, typeProvider.dynamicType]);
|
| + List<DartType> targs = inferenceContext.matchTypes(mapD, contextType);
|
| + if (targs != null &&
|
| + targs.length == 2 &&
|
| + targs.any((t) => !t.isDynamic)) {
|
| + DartType kType = targs[0];
|
| + DartType vType = targs[1];
|
| + InterfaceType mapT = typeProvider.mapType.substitute4([kType, vType]);
|
| + for (MapLiteralEntry entry in node.entries) {
|
| + InferenceContext.setType(entry.key, kType);
|
| + InferenceContext.setType(entry.value, vType);
|
| + }
|
| + InferenceContext.setType(node, mapT);
|
| + } else {
|
| + InferenceContext.clearType(node);
|
| + }
|
| + }
|
| + super.visitMapLiteral(node);
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| Object visitMethodDeclaration(MethodDeclaration node) {
|
| ExecutableElement outerFunction = _enclosingFunction;
|
| try {
|
| _enclosingFunction = node.element;
|
| + InferenceContext.setType(node.body, node.element.type?.returnType);
|
| super.visitMethodDeclaration(node);
|
| } finally {
|
| _enclosingFunction = outerFunction;
|
| @@ -11384,12 +11815,22 @@ class ResolverVisitor extends ScopedVisitor {
|
| safelyVisit(node.target);
|
| node.accept(elementResolver);
|
| _inferFunctionExpressionsParametersTypes(node.argumentList);
|
| + Element methodElement = node.methodName.staticElement;
|
| + if (methodElement is ExecutableElement) {
|
| + InferenceContext.setType(node.argumentList, methodElement.type);
|
| + }
|
| safelyVisit(node.argumentList);
|
| node.accept(typeAnalyzer);
|
| return null;
|
| }
|
|
|
| @override
|
| + Object visitNamedExpression(NamedExpression node) {
|
| + InferenceContext.setType(node.expression, InferenceContext.getType(node));
|
| + return super.visitNamedExpression(node);
|
| + }
|
| +
|
| + @override
|
| Object visitNode(AstNode node) {
|
| node.visitChildren(this);
|
| node.accept(elementResolver);
|
| @@ -11398,6 +11839,12 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| @override
|
| + Object visitParenthesizedExpression(ParenthesizedExpression node) {
|
| + InferenceContext.setType(node.expression, InferenceContext.getType(node));
|
| + return super.visitParenthesizedExpression(node);
|
| + }
|
| +
|
| + @override
|
| Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| //
|
| // We visit the prefix, but do not visit the identifier because it needs to
|
| @@ -11429,6 +11876,7 @@ class ResolverVisitor extends ScopedVisitor {
|
| // because it needs to be visited in the context of the constructor
|
| // invocation.
|
| //
|
| + InferenceContext.setType(node.argumentList, node.staticElement?.type);
|
| safelyVisit(node.argumentList);
|
| node.accept(elementResolver);
|
| node.accept(typeAnalyzer);
|
| @@ -11436,6 +11884,12 @@ class ResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| @override
|
| + Object visitReturnStatement(ReturnStatement node) {
|
| + InferenceContext.setType(node.expression, inferenceContext.returnContext);
|
| + return super.visitReturnStatement(node);
|
| + }
|
| +
|
| + @override
|
| Object visitShowCombinator(ShowCombinator node) => null;
|
|
|
| @override
|
| @@ -11445,6 +11899,7 @@ class ResolverVisitor extends ScopedVisitor {
|
| // because it needs to be visited in the context of the constructor
|
| // invocation.
|
| //
|
| + InferenceContext.setType(node.argumentList, node.staticElement?.type);
|
| safelyVisit(node.argumentList);
|
| node.accept(elementResolver);
|
| node.accept(typeAnalyzer);
|
| @@ -11492,6 +11947,7 @@ class ResolverVisitor extends ScopedVisitor {
|
|
|
| @override
|
| Object visitVariableDeclaration(VariableDeclaration node) {
|
| + InferenceContext.setType(node.initializer, InferenceContext.getType(node));
|
| super.visitVariableDeclaration(node);
|
| VariableElement element = node.element;
|
| if (element.initializer != null && node.initializer != null) {
|
| @@ -11513,6 +11969,13 @@ class ResolverVisitor extends ScopedVisitor {
|
| return null;
|
| }
|
|
|
| + @override visitVariableDeclarationList(VariableDeclarationList node) {
|
| + for (VariableDeclaration decl in node.variables) {
|
| + InferenceContext.setType(decl, node.type?.type);
|
| + }
|
| + super.visitVariableDeclarationList(node);
|
| + }
|
| +
|
| @override
|
| Object visitWhileStatement(WhileStatement node) {
|
| // Note: since we don't call the base class, we have to maintain
|
| @@ -11542,6 +12005,32 @@ class ResolverVisitor extends ScopedVisitor {
|
| return null;
|
| }
|
|
|
| + @override
|
| + Object visitYieldStatement(YieldStatement node) {
|
| + DartType returnType = inferenceContext.returnContext;
|
| + if (returnType != null && _enclosingFunction != null) {
|
| + // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
|
| + // so don't infer
|
| + if (_enclosingFunction.isGenerator) {
|
| + // If this is a yield*, then we just propagate the return type downwards
|
| + DartType type = returnType;
|
| + // If this just a yield, then we need to get the element type
|
| + if (node.star == null) {
|
| + // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
|
| + InterfaceType wrapperD = _enclosingFunction.isSynchronous
|
| + ? typeProvider.iterableDynamicType
|
| + : typeProvider.streamDynamicType;
|
| + // Match the types to instantiate the type arguments if possible
|
| + List<DartType> targs =
|
| + inferenceContext.matchTypes(wrapperD, returnType);
|
| + type = (targs?.length == 1) ? targs[0] : null;
|
| + }
|
| + InferenceContext.setType(node.expression, type);
|
| + }
|
| + }
|
| + return super.visitYieldStatement(node);
|
| + }
|
| +
|
| /**
|
| * Checks each promoted variable in the current scope for compliance with the following
|
| * specification statement:
|
| @@ -11636,6 +12125,14 @@ class ResolverVisitor extends ScopedVisitor {
|
| return null;
|
| }
|
|
|
| + void _inferFormalParameterList(FormalParameterList node, DartType type) {
|
| + if (typeAnalyzer.inferFormalParameterList(node, type)) {
|
| + // TODO(leafp): This gets dropped on the floor if we're in the field
|
| + // inference task. We should probably keep these infos.
|
| + inferenceContext.recordInference(node.parent, type);
|
| + }
|
| + }
|
| +
|
| /**
|
| * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
|
| * required type is [FunctionType], then infer parameters types from [FunctionType].
|
|
|