Tests for implicit cast properties; add cast for `<T>[...dynamic]`.

Change-Id: Ia04c75d304dc6673c9f637c9007a8eb60062078c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97461
Auto-Submit: Mike Fairhurst <mfairhurst@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 68d8bd2..ccc800d 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -189,13 +189,12 @@
       var asIterableType = exprType is InterfaceTypeImpl
           ? exprType.asInstanceOf(typeProvider.iterableType.element)
           : null;
-      if (asIterableType != null) {
-        var elementType = asIterableType.typeArguments[0];
-        // Items in the spread will then potentially be downcast to the expected
-        // type.
-        _checkImplicitCast(element.expression, expectedType,
-            from: elementType, forSpread: true);
-      }
+      var elementType =
+          asIterableType == null ? null : asIterableType.typeArguments[0];
+      // Items in the spread will then potentially be downcast to the expected
+      // type.
+      _checkImplicitCast(element.expression, expectedType,
+          from: elementType, forSpread: true);
     }
   }
 
@@ -229,16 +228,16 @@
           ? exprType.asInstanceOf(typeProvider.mapType.element)
           : null;
 
-      if (asMapType != null) {
-        var elementKeyType = asMapType.typeArguments[0];
-        var elementValueType = asMapType.typeArguments[1];
-        // Keys and values in the spread will then potentially be downcast to
-        // the expected types.
-        _checkImplicitCast(element.expression, expectedKeyType,
-            from: elementKeyType, forSpreadKey: true);
-        _checkImplicitCast(element.expression, expectedValueType,
-            from: elementValueType, forSpreadValue: true);
-      }
+      var elementKeyType =
+          asMapType == null ? null : asMapType.typeArguments[0];
+      var elementValueType =
+          asMapType == null ? null : asMapType.typeArguments[1];
+      // Keys and values in the spread will then potentially be downcast to
+      // the expected types.
+      _checkImplicitCast(element.expression, expectedKeyType,
+          from: elementKeyType, forSpreadKey: true);
+      _checkImplicitCast(element.expression, expectedValueType,
+          from: elementValueType, forSpreadValue: true);
     }
   }
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 4b8c461..15570bb 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/ast/standard_resolution_map.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -26,6 +27,7 @@
     defineReflectiveTests(StrongModeLocalInferenceTest);
     defineReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
     defineReflectiveTests(StrongModeTypePropagationTest);
+    defineReflectiveTests(StrongModeSpreadCastsTest);
   });
 }
 
@@ -2823,6 +2825,622 @@
 }
 
 @reflectiveTest
+class StrongModeSpreadCastsTest extends ResolverTestCase {
+  @override
+  List<String> get enabledExperiments => [EnableString.spread_collections];
+
+  @override
+  bool get enableNewAnalysisDriver => true;
+
+  test_implicitCastMetadata_spread_list_elements() async {
+    var source = addSource(r'''
+class C {
+  dynamic dyn;
+  Iterable<int> iInt;
+  Iterable<Object> iObject;
+  Iterable<dynamic> iDynamic;
+  Iterable<Null> iNull;
+  List<int> lInt;
+  List<Object> lObject;
+  List<dynamic> lDynamic;
+  List<Null> lNull;
+
+  void casts() {
+    <int>[...dyn];
+    <num>[...dyn];
+    <int>[...iObject];
+    <int>[...iDynamic];
+    <int>[...lObject];
+    <int>[...lDynamic];
+    <Null>[...dyn];
+    <Null>[...iObject];
+    <Null>[...iDynamic];
+    <Null>[...iInt];
+    <Null>[...lObject];
+    <Null>[...lDynamic];
+    <Null>[...lInt];
+  }
+
+  void noCasts() {
+    [...dyn];
+    <dynamic>[...dyn];
+    <Object>[...dyn];
+    <dynamic>[...iInt];
+    <Object>[...iInt];
+    <Object>[...iNull];
+    <dynamic>[...lInt];
+    <Object>[...lInt];
+    <Object>[...lNull];
+    <dynamic>[...iObject];
+    <Object>[...iObject];
+    <Object>[...iNull];
+    <dynamic>[...lObject];
+    <Object>[...lObject];
+    <Object>[...lNull];
+    <dynamic>[...iDynamic];
+    <Object>[...iDynamic];
+    <Object>[...iNull];
+    <dynamic>[...lDynamic];
+    <Object>[...lDynamic];
+    <Object>[...lNull];
+    <num>[...iInt];
+    <num>[...lInt];
+    <num>[...iNull];
+    <num>[...lNull];
+    <int>[...iInt];
+    <int>[...lInt];
+    <int>[...iNull];
+    <int>[...lNull];
+    <Null>[...iNull];
+    <Null>[...lNull];
+  }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(ExpressionStatement s) {
+      ListLiteral literal = s.expression;
+      SpreadElement spread = literal.elements[0];
+      return spread.expression;
+    }
+
+    DartType getListElementType(ExpressionStatement s) {
+      ListLiteral literal = s.expression;
+      return literal.typeArguments.arguments[0].type;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType, equals(getListElementType(s)));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+
+  test_implicitCastMetadata_spread_list_iterable() async {
+    var source = addSource(r'''
+class C {
+  dynamic dyn;
+  Iterable<int> iInt;
+  Iterable<Object> iObject;
+  Iterable<dynamic> iDynamic;
+  Iterable<Null> iNull;
+  List<int> lInt;
+  List<Object> lObject;
+  List<dynamic> lDynamic;
+  List<Null> lNull;
+
+  void casts() {
+    [...dyn];
+    <int>[...dyn];
+    <num>[...dyn];
+  }
+
+  void noCasts() {
+    [...iInt];
+    [...iObject];
+    [...iDynamic];
+    [...iNull];
+    <Null>[...iInt];
+    <Null>[...iObject];
+    <Null>[...iDynamic];
+    <Null>[...iNull];
+    <int>[...iInt];
+    <int>[...iObject];
+    <int>[...iDynamic];
+    <int>[...iNull];
+    [...lInt];
+    [...lObject];
+    [...lDynamic];
+    [...lNull];
+    <Null>[...lInt];
+    <Null>[...lObject];
+    <Null>[...lDynamic];
+    <Null>[...lNull];
+    <int>[...lInt];
+    <int>[...lObject];
+    <int>[...lDynamic];
+    <int>[...lNull];
+  }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(ExpressionStatement e) {
+      ListLiteral expression = e.expression;
+      SpreadElement spread = expression.elements[0];
+      return spread.expression;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType.toString(), equals('Iterable<dynamic>'));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+
+  test_implicitCastMetadata_spread_map_keys() async {
+    var source = addSource(r'''
+abstract class HashMap<K, V> implements Map<K, V> {}
+class C {
+  dynamic dyn;
+  Map<int, dynamic> mIntDynamic;
+  Map<Object, dynamic> mObjectDynamic;
+  Map<dynamic, dynamic> mDynamicDynamic;
+  Map<Null, dynamic> mNullDynamic;
+  HashMap<int, dynamic> hIntDynamic;
+  HashMap<Object, dynamic> hObjectDynamic;
+  HashMap<dynamic, dynamic> hDynamicDynamic;
+  HashMap<Null, dynamic> hNullDynamic;
+
+  void casts() {
+    Map m0 = <int, dynamic>{...dyn};
+    Map m1 = <num, dynamic>{...dyn};
+    Map m2 = <int, dynamic>{...mObjectDynamic};
+    Map m3 = <int, dynamic>{...mDynamicDynamic};
+    Map m4 = <int, dynamic>{...hObjectDynamic};
+    Map m5 = <int, dynamic>{...hDynamicDynamic};
+    Map m6 = <Null, dynamic>{...dyn};
+    Map m7 = <Null, dynamic>{...mObjectDynamic};
+    Map m8 = <Null, dynamic>{...mDynamicDynamic};
+    Map m9 = <Null, dynamic>{...mIntDynamic};
+    Map m10 = <Null, dynamic>{...hObjectDynamic};
+    Map m11 = <Null, dynamic>{...hDynamicDynamic};
+    Map m12 = <Null, dynamic>{...hIntDynamic};
+  }
+
+  void noCasts() {
+    Map m0 = {...dyn};
+    Map m1 = <dynamic, dynamic>{...dyn};
+    Map m2 = <Object, dynamic>{...dyn};
+    Map m3 = <dynamic, dynamic>{...mIntDynamic};
+    Map m4 = <Object, dynamic>{...mIntDynamic};
+    Map m5 = <Object, dynamic>{...mNullDynamic};
+    Map m6 = <dynamic, dynamic>{...hIntDynamic};
+    Map m7 = <Object, dynamic>{...hIntDynamic};
+    Map m8 = <Object, dynamic>{...hNullDynamic};
+    Map m9 = <dynamic, dynamic>{...mObjectDynamic};
+    Map m10 = <Object, dynamic>{...mObjectDynamic};
+    Map m11 = <Object, dynamic>{...mNullDynamic};
+    Map m12 = <dynamic, dynamic>{...hObjectDynamic};
+    Map m13 = <Object, dynamic>{...hObjectDynamic};
+    Map m14 = <Object, dynamic>{...hNullDynamic};
+    Map m15 = <dynamic, dynamic>{...mDynamicDynamic};
+    Map m16 = <Object, dynamic>{...mDynamicDynamic};
+    Map m17 = <Object, dynamic>{...mNullDynamic};
+    Map m18 = <dynamic, dynamic>{...hDynamicDynamic};
+    Map m19 = <Object, dynamic>{...hDynamicDynamic};
+    Map m20 = <Object, dynamic>{...hNullDynamic};
+    Map m21 = <num, dynamic>{...mIntDynamic};
+    Map m22 = <num, dynamic>{...hIntDynamic};
+    Map m23 = <num, dynamic>{...mNullDynamic};
+    Map m24 = <num, dynamic>{...hNullDynamic};
+    Map m25 = <int, dynamic>{...hIntDynamic};
+    Map m26 = <int, dynamic>{...mIntDynamic};
+    Map m27 = <int, dynamic>{...mNullDynamic};
+    Map m28 = <int, dynamic>{...hNullDynamic};
+    Map m29 = <Null, dynamic>{...mNullDynamic};
+    Map m30 = <Null, dynamic>{...hNullDynamic};
+ }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      SpreadElement spread = literal.elements[0];
+      return spread.expression;
+    }
+
+    DartType getSetElementType(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      return literal.typeArguments.arguments[0].type;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadKeyCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType, equals(getSetElementType(s)));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadKeyCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+
+  test_implicitCastMetadata_spread_map_map() async {
+    var source = addSource(r'''
+abstract class HashMap<K, V> implements Map<K, V> {}
+class C {
+  dynamic dyn;
+  Map<int, int> mIntInt;
+  Map<int, Object> mIntObject;
+  Map<Object, int> mObjectInt;
+  Map<Object, Object> mObjectObject;
+  Map<dynamic, dynamic> mDynamicDynamic;
+  Map<Null, Null> mNullNull;
+  Map<Object, Null> mObjectNull;
+  Map<Null, Object> mNullObject;
+  HashMap<int, int> hIntInt;
+  HashMap<int, Object> hIntObject;
+  HashMap<Object, int> hObjectInt;
+  HashMap<Object, Object> hObjectObject;
+  HashMap<dynamic, dynamic> hDynamicDynamic;
+  HashMap<Null, Null> hNullNull;
+
+  void casts() {
+    Map m0 = {...dyn};
+    Map m1 = <int, int>{...dyn};
+    Map m2 = <num, int>{...dyn};
+    Map m3 = <int, num>{...dyn};
+    Map m4 = <num, num>{...dyn};
+  }
+
+  void noCasts() {
+    Map m0 = {...mIntInt};
+    Map m1 = {...mIntObject};
+    Map m2 = {...mObjectInt};
+    Map m3 = {...mObjectObject};
+    Map m4 = {...mDynamicDynamic};
+    Map m5 = {...mNullObject};
+    Map m6 = {...mObjectNull};
+    Map m7 = {...mNullNull};
+    Map m8 = <Null, Null>{...mIntInt};
+    Map m9 = <Null, Null>{...mObjectObject};
+    Map m10 = <Null, Null>{...mDynamicDynamic};
+    Map m11 = <Null, Null>{...mNullNull};
+    Map m12 = <int, int>{...mIntInt};
+    Map m13 = <int, int>{...mObjectObject};
+    Map m14 = <int, int>{...mDynamicDynamic};
+    Map m15 = <int, int>{...mNullNull};
+    Map m16 = {...hIntInt};
+    Map m17 = {...hObjectObject};
+    Map m18 = {...hDynamicDynamic};
+    Map m19 = {...hNullNull};
+    Map m20 = <Null, Null>{...hIntInt};
+    Map m21 = <Null, Null>{...hObjectObject};
+    Map m22 = <Null, Null>{...hDynamicDynamic};
+    Map m23 = <Null, Null>{...hNullNull};
+    Map m24 = <int, int>{...hIntInt};
+    Map m25 = <int, int>{...hObjectObject};
+    Map m26 = <int, int>{...hDynamicDynamic};
+    Map m27 = <int, int>{...hNullNull};
+  }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      SpreadElement spread = literal.elements[0];
+      return spread.expression;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType.toString(), equals('Map<dynamic, dynamic>'));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+
+  test_implicitCastMetadata_spread_map_values() async {
+    var source = addSource(r'''
+abstract class HashMap<K, V> implements Map<K, V> {}
+class C {
+  dynamic dyn;
+  Map<dynamic, int> mDynamicInt;
+  Map<dynamic, Object> mDynamicObject;
+  Map<dynamic, dynamic> mDynamicDynamic;
+  Map<dynamic, Null> mDynamicNull;
+  HashMap<dynamic, int> hDynamicInt;
+  HashMap<dynamic, Object> hDynamicObject;
+  HashMap<dynamic, dynamic> hDynamicDynamic;
+  HashMap<dynamic, Null> hDynamicNull;
+
+  void casts() {
+    Map m0 = <dynamic, int>{...dyn};
+    Map m1 = <dynamic, num>{...dyn};
+    Map m2 = <dynamic, int>{...mDynamicObject};
+    Map m3 = <dynamic, int>{...mDynamicDynamic};
+    Map m4 = <dynamic, int>{...hDynamicObject};
+    Map m5 = <dynamic, int>{...hDynamicDynamic};
+    Map m6 = <dynamic, Null>{...dyn};
+    Map m7 = <dynamic, Null>{...mDynamicObject};
+    Map m8 = <dynamic, Null>{...mDynamicDynamic};
+    Map m9 = <dynamic, Null>{...mDynamicInt};
+    Map m10 = <dynamic, Null>{...hDynamicObject};
+    Map m11 = <dynamic, Null>{...hDynamicDynamic};
+    Map m12 = <dynamic, Null>{...hDynamicInt};
+  }
+
+  void noCasts() {
+    Map m0 = {...dyn};
+    Map m1 = <dynamic, dynamic>{...dyn};
+    Map m2 = <dynamic, Object>{...dyn};
+    Map m3 = <dynamic, dynamic>{...mDynamicInt};
+    Map m4 = <dynamic, Object>{...mDynamicInt};
+    Map m5 = <dynamic, Object>{...mDynamicNull};
+    Map m6 = <dynamic, dynamic>{...hDynamicInt};
+    Map m7 = <dynamic, Object>{...hDynamicInt};
+    Map m8 = <dynamic, Object>{...hDynamicNull};
+    Map m9 = <dynamic, dynamic>{...mDynamicObject};
+    Map m10 = <dynamic, Object>{...mDynamicObject};
+    Map m11 = <dynamic, Object>{...mDynamicNull};
+    Map m12 = <dynamic, dynamic>{...hDynamicObject};
+    Map m13 = <dynamic, Object>{...hDynamicObject};
+    Map m14 = <dynamic, Object>{...hDynamicNull};
+    Map m15 = <dynamic, dynamic>{...mDynamicDynamic};
+    Map m16 = <dynamic, Object>{...mDynamicDynamic};
+    Map m17 = <dynamic, Object>{...mDynamicNull};
+    Map m18 = <dynamic, dynamic>{...hDynamicDynamic};
+    Map m19 = <dynamic, Object>{...hDynamicDynamic};
+    Map m20 = <dynamic, Object>{...hDynamicNull};
+    Map m21 = <dynamic, num>{...mDynamicInt};
+    Map m22 = <dynamic, num>{...hDynamicInt};
+    Map m23 = <dynamic, num>{...mDynamicNull};
+    Map m24 = <dynamic, num>{...hDynamicNull};
+    Map m25 = <dynamic, int>{...hDynamicInt};
+    Map m26 = <dynamic, int>{...mDynamicInt};
+    Map m27 = <dynamic, int>{...mDynamicNull};
+    Map m28 = <dynamic, int>{...hDynamicNull};
+    Map m29 = <dynamic, Null>{...mDynamicNull};
+    Map m30 = <dynamic, Null>{...hDynamicNull};
+ }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      SpreadElement spread = literal.elements[0];
+      return spread.expression;
+    }
+
+    DartType getValueType(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      return literal.typeArguments.arguments[1].type;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadValueCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType, equals(getValueType(s)));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadValueCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+
+  test_implicitCastMetadata_spread_set_elements() async {
+    var source = addSource(r'''
+class C {
+  dynamic dyn;
+  Iterable<int> iInt;
+  Iterable<Object> iObject;
+  Iterable<dynamic> iDynamic;
+  Iterable<Null> iNull;
+  List<int> lInt;
+  List<Object> lObject;
+  List<dynamic> lDynamic;
+  List<Null> lNull;
+
+  void casts() {
+    Set s0 = <int>{...dyn};
+    Set s1 = <num>{...dyn};
+    Set s2 = <int>{...iObject};
+    Set s3 = <int>{...iDynamic};
+    Set s4 = <int>{...lObject};
+    Set s5 = <int>{...lDynamic};
+    Set s6 = <Null>{...dyn};
+    Set s7 = <Null>{...iObject};
+    Set s8 = <Null>{...iDynamic};
+    Set s9 = <Null>{...iInt};
+    Set s10 = <Null>{...lObject};
+    Set s11 = <Null>{...lDynamic};
+    Set s12 = <Null>{...lInt};
+  }
+
+  void noCasts() {
+    Set s0 = {...dyn};
+    Set s1 = <dynamic>{...dyn};
+    Set s2 = <Object>{...dyn};
+    Set s3 = <dynamic>{...iInt};
+    Set s4 = <Object>{...iInt};
+    Set s5 = <Object>{...iNull};
+    Set s6 = <dynamic>{...lInt};
+    Set s7 = <Object>{...lInt};
+    Set s8 = <Object>{...lNull};
+    Set s9 = <dynamic>{...iObject};
+    Set s10 = <Object>{...iObject};
+    Set s11 = <Object>{...iNull};
+    Set s12 = <dynamic>{...lObject};
+    Set s13 = <Object>{...lObject};
+    Set s14 = <Object>{...lNull};
+    Set s15 = <dynamic>{...iDynamic};
+    Set s16 = <Object>{...iDynamic};
+    Set s17 = <Object>{...iNull};
+    Set s18 = <dynamic>{...lDynamic};
+    Set s19 = <Object>{...lDynamic};
+    Set s20 = <Object>{...lNull};
+    Set s21 = <num>{...iInt};
+    Set s22 = <num>{...lInt};
+    Set s23 = <num>{...iNull};
+    Set s24 = <num>{...lNull};
+    Set s25 = <int>{...iInt};
+    Set s26 = <int>{...lInt};
+    Set s27 = <int>{...iNull};
+    Set s28 = <int>{...lNull};
+    Set s29 = <Null>{...iNull};
+    Set s30 = <Null>{...lNull};
+  }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      SpreadElement spread = literal.elements[0];
+      return spread.expression;
+    }
+
+    DartType getKeyType(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      return literal.typeArguments.arguments[0].type;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType, equals(getKeyType(s)));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitSpreadCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+
+  test_implicitCastMetadata_spread_set_iterable() async {
+    var source = addSource(r'''
+class C {
+  dynamic dyn;
+  Iterable<int> iInt;
+  Iterable<Object> iObject;
+  Iterable<dynamic> iDynamic;
+  Iterable<Null> iNull;
+  List<int> lInt;
+  List<Object> lObject;
+  List<dynamic> lDynamic;
+  List<Null> lNull;
+
+  void casts() {
+    Set s0 = {...dyn};
+    Set s1 = <int>{...dyn};
+    Set s2 = <num>{...dyn};
+  }
+
+  void noCasts() {
+    Set s0 = {...iInt};
+    Set s1 = {...iObject};
+    Set s2 = {...iDynamic};
+    Set s3 = {...iNull};
+    Set s4 = <Null>{...iInt};
+    Set s5 = <Null>{...iObject};
+    Set s6 = <Null>{...iDynamic};
+    Set s7 = <Null>{...iNull};
+    Set s8 = <int>{...iInt};
+    Set s9 = <int>{...iObject};
+    Set s10 = <int>{...iDynamic};
+    Set s11 = <int>{...iNull};
+    Set s12 = {...lInt};
+    Set s13 = {...lObject};
+    Set s14 = {...lDynamic};
+    Set s15 = {...lNull};
+    Set s16 = <Null>{...lInt};
+    Set s17 = <Null>{...lObject};
+    Set s18 = <Null>{...lDynamic};
+    Set s19 = <Null>{...lNull};
+    Set s20 = <int>{...lInt};
+    Set s21 = <int>{...lObject};
+    Set s22 = <int>{...lDynamic};
+  }
+}
+''');
+    var unit = (await computeAnalysisResult(source)).unit;
+    assertNoErrors(source);
+
+    Expression getSpreadExpression(VariableDeclarationStatement s) {
+      VariableDeclaration declaration = s.variables.variables[0];
+      SetOrMapLiteral literal = declaration.initializer;
+      SpreadElement spread = literal.elements[0];
+      return spread.expression;
+    }
+
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitCast(expression);
+      expect(spreadCastType, isNotNull,
+          reason: 'Expression $expression does not have implicit cast');
+      expect(spreadCastType.toString(), equals('Iterable<dynamic>'));
+    }
+    for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
+      var expression = getSpreadExpression(s);
+      var spreadCastType = getImplicitCast(expression);
+      expect(spreadCastType, isNull,
+          reason: 'Expression $expression should not have implicit cast');
+    }
+  }
+}
+
+@reflectiveTest
 class StrongModeStaticTypeAnalyzer2Test extends StaticTypeAnalyzer2TestShared
     with StrongModeStaticTypeAnalyzer2TestCases {
   @override