Start supporting resolution of the code-as-ui constructs

Change-Id: I8fba9bfcac2339b113de6bc2954821585e7b8ab4
Reviewed-on: https://dart-review.googlesource.com/c/91240
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index db1514c..767e9dd 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2616,6 +2616,64 @@
   }
 
   @override
+  bool visitForStatement2(ForStatement2 node) {
+    bool outerBreakValue = _enclosingBlockContainsBreak;
+    _enclosingBlockContainsBreak = false;
+    ForLoopParts parts = node.forLoopParts;
+    try {
+      if (parts is ForEachParts) {
+        bool iterableExits = _nodeExits(parts.iterable);
+        // Discard whether the for-each body exits; since the for-each iterable
+        // may be empty, execution may never enter the body, so it doesn't matter
+        // if it exits or not.  We still must visit the body, to accurately
+        // manage `_enclosingBlockBreaksLabel`.
+        _nodeExits(node.body);
+        return iterableExits;
+      }
+      VariableDeclarationList variables;
+      Expression initialization;
+      Expression condition;
+      NodeList<Expression> updaters;
+      if (parts is ForPartsWithDeclarations) {
+        variables = parts.variables;
+        condition = parts.condition;
+        updaters = parts.updaters;
+      } else if (parts is ForPartsWithExpression) {
+        initialization = parts.initialization;
+        condition = parts.condition;
+        updaters = parts.updaters;
+      }
+      if (variables != null &&
+          _visitVariableDeclarations(variables.variables)) {
+        return true;
+      }
+      if (initialization != null && _nodeExits(initialization)) {
+        return true;
+      }
+      if (condition != null && _nodeExits(condition)) {
+        return true;
+      }
+      if (_visitExpressions(updaters)) {
+        return true;
+      }
+      bool blockReturns = _nodeExits(node.body);
+      // TODO(jwren) Do we want to take all constant expressions into account?
+      // If for(; true; ) (or for(;;)), and the body doesn't return or the body
+      // doesn't have a break, then return true.
+      bool implicitOrExplictTrue =
+          condition == null || (condition is BooleanLiteral && condition.value);
+      if (implicitOrExplictTrue) {
+        if (blockReturns || !_enclosingBlockContainsBreak) {
+          return true;
+        }
+      }
+      return false;
+    } finally {
+      _enclosingBlockContainsBreak = outerBreakValue;
+    }
+  }
+
+  @override
   bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) =>
       false;
 
@@ -4970,6 +5028,22 @@
   }
 
   @override
+  void visitForStatement2(ForStatement2 node) {
+    _overrideManager.enterScope();
+    try {
+      super.visitForStatement2(node);
+    } finally {
+      _overrideManager.exitScope();
+    }
+  }
+
+  @override
+  void visitForStatement2InScope(ForStatement2 node) {
+    throw new UnsupportedError('Implement this');
+    visitStatementInScope(node.body);
+  }
+
+  @override
   void visitForStatementInScope(ForStatement node) {
     node.variables?.accept(this);
     node.initialization?.accept(this);
@@ -4982,8 +5056,6 @@
     } finally {
       _overrideManager.exitScope();
     }
-    // TODO(brianwilkerson) If the loop can only be exited because the condition
-    // is false, then propagateFalseState(condition);
   }
 
   @override
@@ -5191,6 +5263,29 @@
   }
 
   @override
+  void visitListLiteral2(ListLiteral2 node) {
+    InterfaceType listT;
+
+    if (node.typeArguments != null) {
+      var targs = node.typeArguments.arguments.map((t) => t.type).toList();
+      if (targs.length == 1 && !targs[0].isDynamic) {
+        listT = typeProvider.listType.instantiate([targs[0]]);
+      }
+    } else {
+      listT = typeAnalyzer.inferListType2(node, downwards: true);
+    }
+    if (listT != null) {
+      for (CollectionElement element in node.elements) {
+        _pushCollectionTypesDown(element, listT);
+      }
+      InferenceContext.setType(node, listT);
+    } else {
+      InferenceContext.clearType(node);
+    }
+    super.visitListLiteral2(node);
+  }
+
+  @override
   void visitMapLiteral(MapLiteral node) {
     InterfaceType mapT;
     if (node.typeArguments != null) {
@@ -5225,6 +5320,54 @@
   }
 
   @override
+  void visitMapLiteral2(MapLiteral2 node) {
+    InterfaceType mapT;
+    if (node.typeArguments != null) {
+      var targs = node.typeArguments.arguments.map((t) => t.type).toList();
+      if (targs.length == 2 && targs.any((t) => !t.isDynamic)) {
+        mapT = typeProvider.mapType.instantiate([targs[0], targs[1]]);
+      }
+    } else {
+      mapT = typeAnalyzer.inferMapType2(node, downwards: true);
+      if (mapT != null &&
+          node.typeArguments == null &&
+          node.entries.isEmpty &&
+          typeSystem.isAssignableTo(typeProvider.iterableObjectType, mapT) &&
+          !typeSystem.isAssignableTo(typeProvider.mapObjectObjectType, mapT)) {
+        // The node is really an empty set literal with no type arguments, so
+        // don't try to visit the replaced map literal.
+        return;
+      }
+    }
+    if (mapT != null) {
+      DartType kType = mapT.typeArguments[0];
+      DartType vType = mapT.typeArguments[1];
+
+      void pushTypesDown(MapElement element) {
+        if (element is MapForElement) {
+          pushTypesDown(element.body);
+        } else if (element is MapIfElement) {
+          pushTypesDown(element.thenElement);
+          pushTypesDown(element.elseElement);
+        } else if (element is MapLiteralEntry) {
+          InferenceContext.setType(element.key, kType);
+          InferenceContext.setType(element.value, vType);
+        } else if (element is SpreadElement) {
+          InferenceContext.setType(element.expression, mapT);
+        }
+      }
+
+      for (MapElement element in node.entries) {
+        pushTypesDown(element);
+      }
+      InferenceContext.setType(node, mapT);
+    } else {
+      InferenceContext.clearType(node);
+    }
+    super.visitMapLiteral2(node);
+  }
+
+  @override
   void visitMethodDeclaration(MethodDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
     FunctionBody outerFunctionBody = _currentFunctionBody;
@@ -5385,6 +5528,32 @@
   }
 
   @override
+  void visitSetLiteral2(SetLiteral2 node) {
+    InterfaceType setT;
+
+    TypeArgumentList typeArguments = node.typeArguments;
+    if (typeArguments != null) {
+      if (typeArguments.length == 1) {
+        DartType elementType = typeArguments.arguments[0].type;
+        if (!elementType.isDynamic) {
+          setT = typeProvider.setType.instantiate([elementType]);
+        }
+      }
+    } else {
+      setT = typeAnalyzer.inferSetType2(node, downwards: true);
+    }
+    if (setT != null) {
+      for (CollectionElement element in node.elements) {
+        _pushCollectionTypesDown(element, setT);
+      }
+      InferenceContext.setType(node, setT);
+    } else {
+      InferenceContext.clearType(node);
+    }
+    super.visitSetLiteral2(node);
+  }
+
+  @override
   void visitShowCombinator(ShowCombinator node) {}
 
   @override
@@ -5950,6 +6119,20 @@
     }
   }
 
+  void _pushCollectionTypesDown(
+      CollectionElement element, ParameterizedType collectionType) {
+    if (element is CollectionForElement) {
+      _pushCollectionTypesDown(element.body, collectionType);
+    } else if (element is CollectionIfElement) {
+      _pushCollectionTypesDown(element.thenElement, collectionType);
+      _pushCollectionTypesDown(element.elseElement, collectionType);
+    } else if (element is Expression) {
+      InferenceContext.setType(element, collectionType.typeArguments[0]);
+    } else if (element is SpreadElement) {
+      InferenceContext.setType(element.expression, collectionType);
+    }
+  }
+
   /// Given an [argumentList] and the [parameters] related to the element that
   /// will be invoked using those arguments, compute the list of parameters that
   /// correspond to the list of arguments.
@@ -6397,6 +6580,30 @@
     }
   }
 
+  @override
+  void visitForStatement2(ForStatement2 node) {
+    Scope outerNameScope = nameScope;
+    ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
+    try {
+      nameScope = new EnclosedScope(nameScope);
+      _implicitLabelScope = _implicitLabelScope.nest(node);
+      visitForStatement2InScope(node);
+    } finally {
+      nameScope = outerNameScope;
+      _implicitLabelScope = outerImplicitScope;
+    }
+  }
+
+  /// Visit the given [node] after it's scope has been created. This replaces
+  /// the normal call to the inherited visit method so that ResolverVisitor can
+  /// intervene when type propagation is enabled.
+  void visitForStatement2InScope(ForStatement2 node) {
+    // TODO(brianwilkerson) Investigate the possibility of removing the
+    //  visit...InScope methods now that type propagation is no longer done.
+    node.forLoopParts?.accept(this);
+    visitStatementInScope(node.body);
+  }
+
   /// Visit the given statement after it's scope has been created. This replaces
   /// the normal call to the inherited visit method so that ResolverVisitor can
   /// intervene when type propagation is enabled.
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 88f8f3b..b55d885 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -182,6 +182,40 @@
     return inferred;
   }
 
+  DartType inferListType2(ListLiteral2 node, {bool downwards: false}) {
+    DartType contextType = InferenceContext.getContext(node);
+
+    var ts = _typeSystem as Dart2TypeSystem;
+    List<DartType> elementTypes;
+    List<ParameterElement> parameters;
+
+    if (downwards) {
+      if (contextType == null) {
+        return null;
+      }
+      elementTypes = [];
+      parameters = [];
+    } else {
+      // Also use upwards information to infer the type.
+      elementTypes = node.elements
+          .map((element) => _computeElementType(element))
+          .where((t) => t != null)
+          .toList();
+      TypeParameterType listTypeParam =
+          _typeProvider.listType.typeParameters[0].type;
+      ParameterElementImpl syntheticParamElement =
+          new ParameterElementImpl.synthetic(
+              'element', listTypeParam, ParameterKind.POSITIONAL);
+      parameters = new List.filled(elementTypes.length, syntheticParamElement);
+    }
+    InterfaceType inferred = ts.inferGenericFunctionOrType<InterfaceType>(
+        _typeProvider.listType, parameters, elementTypes, contextType,
+        downwards: downwards,
+        errorReporter: _resolver.errorReporter,
+        errorNode: node);
+    return inferred;
+  }
+
   ParameterizedType inferMapType(MapLiteral node, {bool downwards: false}) {
     DartType contextType = InferenceContext.getContext(node);
     if (contextType != null && _experimentStatus.set_literals) {
@@ -247,6 +281,73 @@
     return inferred;
   }
 
+  ParameterizedType inferMapType2(MapLiteral2 node, {bool downwards: false}) {
+    DartType contextType = InferenceContext.getContext(node);
+    if (contextType != null && _experimentStatus.set_literals) {
+      DartType unwrap(DartType type) {
+        if (type is InterfaceType &&
+            type.isDartAsyncFutureOr &&
+            type.typeArguments.length == 1) {
+          return unwrap(type.typeArguments[0]);
+        }
+        return type;
+      }
+
+      DartType unwrappedContextType = unwrap(contextType);
+      if (node.typeArguments == null &&
+          node.entries.isEmpty &&
+          _typeSystem.isAssignableTo(
+              _typeProvider.iterableObjectType, unwrappedContextType) &&
+          !_typeSystem.isAssignableTo(
+              _typeProvider.mapObjectObjectType, unwrappedContextType)) {
+        // The node is really an empty set literal with no type arguments.
+        // Rewrite the AST and infer the type of the set as appropriate.
+        SetLiteral setLiteral = new AstFactoryImpl().setLiteral(
+            node.constKeyword, null, node.leftBracket, null, node.rightBracket);
+        InferenceContext.setType(setLiteral, contextType);
+        NodeReplacer.replace(node, setLiteral);
+        DartType type = inferSetType(setLiteral, downwards: downwards);
+        setLiteral.staticType = type;
+        return type;
+      }
+    }
+    List<DartType> elementTypes;
+    List<ParameterElement> parameters;
+    if (downwards) {
+      if (contextType == null) {
+        return null;
+      }
+      elementTypes = [];
+      parameters = [];
+    } else {
+      var keyTypes = node.entries
+          .map((entry) => _computeKeyType(entry))
+          .where((t) => t != null);
+      var valueTypes = node.entries
+          .map((entry) => _computeValueType(entry))
+          .where((t) => t != null);
+      var keyTypeParam = _typeProvider.mapType.typeParameters[0].type;
+      var valueTypeParam = _typeProvider.mapType.typeParameters[1].type;
+      var syntheticKeyParameter = new ParameterElementImpl.synthetic(
+          'key', keyTypeParam, ParameterKind.POSITIONAL);
+      var syntheticValueParameter = new ParameterElementImpl.synthetic(
+          'value', valueTypeParam, ParameterKind.POSITIONAL);
+      parameters = new List.filled(keyTypes.length, syntheticKeyParameter,
+          growable: true)
+        ..addAll(new List.filled(valueTypes.length, syntheticValueParameter));
+      elementTypes = new List<DartType>.from(keyTypes)..addAll(valueTypes);
+    }
+
+    // Use both downwards and upwards information to infer the type.
+    var ts = _typeSystem as Dart2TypeSystem;
+    ParameterizedType inferred = ts.inferGenericFunctionOrType(
+        _typeProvider.mapType, parameters, elementTypes, contextType,
+        downwards: downwards,
+        errorReporter: _resolver.errorReporter,
+        errorNode: node);
+    return inferred;
+  }
+
   DartType inferSetType(SetLiteral node, {bool downwards: false}) {
     DartType contextType = InferenceContext.getContext(node);
 
@@ -280,6 +381,41 @@
     return inferred;
   }
 
+  DartType inferSetType2(SetLiteral2 node, {bool downwards: false}) {
+    DartType contextType = InferenceContext.getContext(node);
+
+    var ts = _typeSystem as Dart2TypeSystem;
+    List<DartType> elementTypes;
+    List<ParameterElement> parameters;
+
+    if (downwards) {
+      if (contextType == null) {
+        return null;
+      }
+
+      elementTypes = [];
+      parameters = [];
+    } else {
+      // Also use upwards information to infer the type.
+      elementTypes = node.elements
+          .map((element) => _computeElementType(element))
+          .where((t) => t != null)
+          .toList();
+      TypeParameterType setTypeParam =
+          _typeProvider.setType.typeParameters[0].type;
+      ParameterElementImpl syntheticParamElement =
+          new ParameterElementImpl.synthetic(
+              'element', setTypeParam, ParameterKind.POSITIONAL);
+      parameters = new List.filled(elementTypes.length, syntheticParamElement);
+    }
+    DartType inferred = ts.inferGenericFunctionOrType<InterfaceType>(
+        _typeProvider.setType, parameters, elementTypes, contextType,
+        downwards: downwards,
+        errorReporter: _resolver.errorReporter,
+        errorNode: node);
+    return inferred;
+  }
+
   /**
    * The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is
    * `String`.</blockquote>
@@ -694,6 +830,45 @@
     _recordStaticType(node, listDynamicType);
   }
 
+  @override
+  void visitListLiteral2(ListLiteral2 node) {
+    TypeArgumentList typeArguments = node.typeArguments;
+
+    // If we have explicit arguments, use them
+    if (typeArguments != null) {
+      DartType staticType = _dynamicType;
+      NodeList<TypeAnnotation> arguments = typeArguments.arguments;
+      if (arguments != null && arguments.length == 1) {
+        DartType argumentType = _getType(arguments[0]);
+        if (argumentType != null) {
+          staticType = argumentType;
+        }
+      }
+      _recordStaticType(
+          node, _typeProvider.listType.instantiate(<DartType>[staticType]));
+      return;
+    }
+
+    DartType listDynamicType =
+        _typeProvider.listType.instantiate(<DartType>[_dynamicType]);
+
+    // If there are no type arguments, try to infer some arguments.
+    DartType inferred = inferListType2(node);
+
+    if (inferred != listDynamicType) {
+      // TODO(jmesserly): this results in an "inferred" message even when we
+      // in fact had an error above, because it will still attempt to return
+      // a type. Perhaps we should record inference from TypeSystem if
+      // everything was successful?
+      _resolver.inferenceContext.recordInference(node, inferred);
+      _recordStaticType(node, inferred);
+      return;
+    }
+
+    // If we have no type arguments and couldn't infer any, use dynamic.
+    _recordStaticType(node, listDynamicType);
+  }
+
   /**
    * The Dart Language Specification, 12.7: <blockquote>The static type of a map literal of the form
    * <i><b>const</b> &lt;K, V&gt; {k<sub>1</sub>:e<sub>1</sub>, &hellip;,
@@ -752,6 +927,52 @@
     _recordStaticType(node, mapDynamicType);
   }
 
+  @override
+  void visitMapLiteral2(MapLiteral2 node) {
+    TypeArgumentList typeArguments = node.typeArguments;
+
+    // If we have type arguments, use them
+    if (typeArguments != null) {
+      DartType staticKeyType = _dynamicType;
+      DartType staticValueType = _dynamicType;
+      NodeList<TypeAnnotation> arguments = typeArguments.arguments;
+      if (arguments != null && arguments.length == 2) {
+        DartType entryKeyType = _getType(arguments[0]);
+        if (entryKeyType != null) {
+          staticKeyType = entryKeyType;
+        }
+        DartType entryValueType = _getType(arguments[1]);
+        if (entryValueType != null) {
+          staticValueType = entryValueType;
+        }
+      }
+      _recordStaticType(
+          node,
+          _typeProvider.mapType
+              .instantiate(<DartType>[staticKeyType, staticValueType]));
+      return;
+    }
+
+    DartType mapDynamicType = _typeProvider.mapType
+        .instantiate(<DartType>[_dynamicType, _dynamicType]);
+
+    // If we have no explicit type arguments, try to infer type arguments.
+    ParameterizedType inferred = inferMapType2(node);
+
+    if (inferred != mapDynamicType) {
+      // TODO(jmesserly): this results in an "inferred" message even when we
+      // in fact had an error above, because it will still attempt to return
+      // a type. Perhaps we should record inference from TypeSystem if
+      // everything was successful?
+      _resolver.inferenceContext.recordInference(node, inferred);
+      _recordStaticType(node, inferred);
+      return;
+    }
+
+    // If no type arguments and no inference, use dynamic
+    _recordStaticType(node, mapDynamicType);
+  }
+
   /**
    * The Dart Language Specification, 12.15.1: <blockquote>An ordinary method invocation <i>i</i>
    * has the form <i>o.m(a<sub>1</sub>, &hellip;, a<sub>n</sub>, x<sub>n+1</sub>: a<sub>n+1</sub>,
@@ -1038,6 +1259,45 @@
     _recordStaticType(node, setDynamicType);
   }
 
+  @override
+  void visitSetLiteral2(SetLiteral2 node) {
+    TypeArgumentList typeArguments = node.typeArguments;
+
+    // If we have type arguments, use them
+    if (typeArguments != null) {
+      DartType elementType = _dynamicType;
+      NodeList<TypeAnnotation> arguments = typeArguments.arguments;
+      if (arguments != null && arguments.length == 1) {
+        DartType type = _getType(arguments[0]);
+        if (type != null) {
+          elementType = type;
+        }
+      }
+      _recordStaticType(
+          node, _typeProvider.setType.instantiate(<DartType>[elementType]));
+      return;
+    }
+
+    DartType setDynamicType =
+        _typeProvider.setType.instantiate(<DartType>[_dynamicType]);
+
+    // If we have no explicit type arguments, try to infer type arguments.
+    ParameterizedType inferred = inferSetType2(node);
+
+    if (inferred != setDynamicType) {
+      // TODO(jmesserly): this results in an "inferred" message even when we
+      // in fact had an error above, because it will still attempt to return
+      // a type. Perhaps we should record inference from TypeSystem if
+      // everything was successful?
+      _resolver.inferenceContext.recordInference(node, inferred);
+      _recordStaticType(node, inferred);
+      return;
+    }
+
+    // If no type arguments and no inference, use dynamic
+    _recordStaticType(node, setDynamicType);
+  }
+
   /**
    * The Dart Language Specification, 12.30: <blockquote>Evaluation of an identifier expression
    * <i>e</i> of the form <i>id</i> proceeds as follows:
@@ -1246,6 +1506,30 @@
     return _dynamicType;
   }
 
+  DartType _computeElementType(CollectionElement element) {
+    if (element is CollectionForElement) {
+      return _computeElementType(element.body);
+    } else if (element is CollectionIfElement) {
+      DartType thenType = _computeElementType(element.thenElement);
+      if (element.elseElement == null) {
+        return thenType;
+      }
+      DartType elseType = _computeElementType(element.elseElement);
+      return _typeSystem.leastUpperBound(thenType, elseType);
+    } else if (element is Expression) {
+      return element.staticType;
+    } else if (element is SpreadElement) {
+      DartType collectionType = element.expression.staticType;
+      if (collectionType is ParameterizedType) {
+        List<DartType> typeArguments = collectionType.typeArguments;
+        if (typeArguments.length == 1) {
+          return typeArguments[0];
+        }
+      }
+    }
+    return null;
+  }
+
   /**
    * Compute the return type of the method or function represented by the given
    * type that is being invoked.
@@ -1261,6 +1545,30 @@
     return _dynamicType;
   }
 
+  DartType _computeKeyType(MapElement element) {
+    if (element is MapForElement) {
+      return _computeKeyType(element.body);
+    } else if (element is MapIfElement) {
+      DartType thenType = _computeKeyType(element.thenElement);
+      if (element.elseElement == null) {
+        return thenType;
+      }
+      DartType elseType = _computeKeyType(element.elseElement);
+      return _typeSystem.leastUpperBound(thenType, elseType);
+    } else if (element is MapLiteralEntry) {
+      return element.key.staticType;
+    } else if (element is SpreadElement) {
+      DartType collectionType = element.expression.staticType;
+      if (collectionType is ParameterizedType) {
+        List<DartType> typeArguments = collectionType.typeArguments;
+        if (typeArguments.length == 2) {
+          return typeArguments[0];
+        }
+      }
+    }
+    return null;
+  }
+
   /**
    * Given a function body and its return type, compute the return type of
    * the entire function, taking into account whether the function body
@@ -1327,6 +1635,30 @@
     return returnType.type;
   }
 
+  DartType _computeValueType(MapElement element) {
+    if (element is MapForElement) {
+      return _computeValueType(element.body);
+    } else if (element is MapIfElement) {
+      DartType thenType = _computeValueType(element.thenElement);
+      if (element.elseElement == null) {
+        return thenType;
+      }
+      DartType elseType = _computeValueType(element.elseElement);
+      return _typeSystem.leastUpperBound(thenType, elseType);
+    } else if (element is MapLiteralEntry) {
+      return element.value.staticType;
+    } else if (element is SpreadElement) {
+      DartType collectionType = element.expression.staticType;
+      if (collectionType is ParameterizedType) {
+        List<DartType> typeArguments = collectionType.typeArguments;
+        if (typeArguments.length == 2) {
+          return typeArguments[1];
+        }
+      }
+    }
+    return null;
+  }
+
   DartType _findIteratedType(DartType type, DartType targetType) {
     // TODO(vsm): Use leafp's matchType here?
     // Set by _find if match is found
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 8ba4f84..088deb95 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -934,8 +934,8 @@
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
     // The expected type ought to be `List<int>`, but type inference isn't yet
     // implemented.
-    expect(result.type,
-        typeProvider.listType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.listType.instantiate([typeProvider.intType]));
     expect(result.toListValue().map((e) => e.toIntValue()), [1, 2, 3]);
   }
 
@@ -944,10 +944,8 @@
 const c = [1, if (1 < 0) 2 else 3, 4];
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.listType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.listType.instantiate([typeProvider.intType]));
     expect(result.toListValue().map((e) => e.toIntValue()), [1, 3, 4]);
   }
 
@@ -956,10 +954,8 @@
 const c = [1, if (1 < 0) 2, 3];
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.listType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.listType.instantiate([typeProvider.intType]));
     expect(result.toListValue().map((e) => e.toIntValue()), [1, 3]);
   }
 
@@ -968,10 +964,8 @@
 const c = [1, if (1 > 0) 2 else 3, 4];
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.listType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.listType.instantiate([typeProvider.intType]));
     expect(result.toListValue().map((e) => e.toIntValue()), [1, 2, 4]);
   }
 
@@ -980,10 +974,8 @@
 const c = [1, if (1 > 0) 2, 3];
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.listType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.listType.instantiate([typeProvider.intType]));
     expect(result.toListValue().map((e) => e.toIntValue()), [1, 2, 3]);
   }
 
@@ -992,10 +984,8 @@
 const c = [1, ...[2, 3], 4];
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.listType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.listType.instantiate([typeProvider.intType]));
     expect(result.toListValue().map((e) => e.toIntValue()), [1, 2, 3, 4]);
   }
 
@@ -1006,12 +996,10 @@
 const c = {'a' : 1, if (1 > 0) if (2 > 1) {'b' : 2}, 'c' : 3};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
     expect(
         result.type,
         typeProvider.mapType
-            .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]));
+            .instantiate([typeProvider.intType, typeProvider.intType]));
     Map<DartObject, DartObject> value = result.toMapValue();
     expect(value.keys.map((e) => e.toStringValue()),
         unorderedEquals(['a', 'b', 'c']));
@@ -1023,12 +1011,10 @@
 const c = {'a' : 1, if (1 < 0) 'b' : 2 else 'c' : 3, 'd' : 4};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
     expect(
         result.type,
         typeProvider.mapType
-            .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]));
+            .instantiate([typeProvider.stringType, typeProvider.intType]));
     Map<DartObject, DartObject> value = result.toMapValue();
     expect(value.keys.map((e) => e.toStringValue()),
         unorderedEquals(['a', 'c', 'd']));
@@ -1040,12 +1026,10 @@
 const c = {'a' : 1, if (1 < 0) 'b' : 2, 'c' : 3};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
     expect(
         result.type,
         typeProvider.mapType
-            .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]));
+            .instantiate([typeProvider.stringType, typeProvider.intType]));
     Map<DartObject, DartObject> value = result.toMapValue();
     expect(
         value.keys.map((e) => e.toStringValue()), unorderedEquals(['a', 'c']));
@@ -1057,12 +1041,10 @@
 const c = {'a' : 1, if (1 > 0) 'b' : 2 else 'c' : 3, 'd' : 4};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
     expect(
         result.type,
         typeProvider.mapType
-            .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]));
+            .instantiate([typeProvider.stringType, typeProvider.intType]));
     Map<DartObject, DartObject> value = result.toMapValue();
     expect(value.keys.map((e) => e.toStringValue()),
         unorderedEquals(['a', 'b', 'd']));
@@ -1074,12 +1056,10 @@
 const c = {'a' : 1, if (1 > 0) 'b' : 2, 'c' : 3};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
     expect(
         result.type,
         typeProvider.mapType
-            .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]));
+            .instantiate([typeProvider.stringType, typeProvider.intType]));
     Map<DartObject, DartObject> value = result.toMapValue();
     expect(value.keys.map((e) => e.toStringValue()),
         unorderedEquals(['a', 'b', 'c']));
@@ -1091,12 +1071,10 @@
 const c = {'a' : 1, ...{'b' : 2, 'c' : 3}, 'd' : 4};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `Map<String, int>`, but type inference
-    // isn't yet implemented.
     expect(
         result.type,
         typeProvider.mapType
-            .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]));
+            .instantiate([typeProvider.stringType, typeProvider.intType]));
     Map<DartObject, DartObject> value = result.toMapValue();
     expect(value.keys.map((e) => e.toStringValue()),
         unorderedEquals(['a', 'b', 'c', 'd']));
@@ -1111,10 +1089,8 @@
 const c = {1, if (1 > 0) if (2 > 1) 2, 3};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.setType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.setType.instantiate([typeProvider.intType]));
     expect(result.toSetValue().map((e) => e.toIntValue()), [1, 2, 3]);
   }
 
@@ -1123,10 +1099,8 @@
 const c = {1, if (1 < 0) 2 else 3, 4};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.setType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.setType.instantiate([typeProvider.intType]));
     expect(result.toSetValue().map((e) => e.toIntValue()), [1, 3, 4]);
   }
 
@@ -1135,10 +1109,8 @@
 const c = {1, if (1 < 0) 2, 3};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.setType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.setType.instantiate([typeProvider.intType]));
     expect(result.toSetValue().map((e) => e.toIntValue()), [1, 3]);
   }
 
@@ -1147,10 +1119,8 @@
 const c = {1, if (1 > 0) 2 else 3, 4};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.setType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.setType.instantiate([typeProvider.intType]));
     expect(result.toSetValue().map((e) => e.toIntValue()), [1, 2, 4]);
   }
 
@@ -1159,10 +1129,8 @@
 const c = {1, if (1 > 0) 2, 3};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `List<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.setType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.setType.instantiate([typeProvider.intType]));
     expect(result.toSetValue().map((e) => e.toIntValue()), [1, 2, 3]);
   }
 
@@ -1171,10 +1139,8 @@
 const c = {1, ...{2, 3}, 4};
 ''');
     DartObjectImpl result = _evaluateConstant(compilationUnit, 'c');
-    // The expected type ought to be `Set<int>`, but type inference isn't yet
-    // implemented.
-    expect(result.type,
-        typeProvider.setType.instantiate([typeProvider.dynamicType]));
+    expect(
+        result.type, typeProvider.setType.instantiate([typeProvider.intType]));
     expect(result.toSetValue().map((e) => e.toIntValue()), [1, 2, 3, 4]);
   }
 }