Fix type inference of map/set literals when the context is a type parameter.

Change-Id: Ic78cfd838e7fce4f362770c0827d71b351711e57
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96340
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 7d6bc69..ca1da1e 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -4775,9 +4775,30 @@
 
   @override
   void visitSetOrMapLiteral(SetOrMapLiteral node) {
-    DartType literalType = _computeSetOrMapContextType(node);
-    // TODO(brianwilkerson) Determine whether we need special handling for type
-    // parameter types. (E-mail sent.)
+    var typeArguments = node.typeArguments?.arguments;
+    InterfaceType literalType;
+    var literalResolution = _computeSetOrMapResolution(node);
+    if (literalResolution.kind == _LiteralResolutionKind.set) {
+      if (typeArguments != null && typeArguments.length == 1) {
+        var elementType = typeArguments[0].type;
+        literalType = typeProvider.setType.instantiate([elementType]);
+      } else {
+        literalType = typeAnalyzer.inferSetTypeDownwards(
+            node, literalResolution.contextType);
+      }
+    } else if (literalResolution.kind == _LiteralResolutionKind.map) {
+      if (typeArguments != null && typeArguments.length == 2) {
+        var keyType = typeArguments[0].type;
+        var valueType = typeArguments[1].type;
+        literalType = typeProvider.mapType.instantiate([keyType, valueType]);
+      } else {
+        literalType = typeAnalyzer.inferMapTypeDownwards(
+            node, literalResolution.contextType);
+      }
+    } else {
+      assert(literalResolution.kind == _LiteralResolutionKind.ambiguous);
+      literalType = null;
+    }
     if (literalType is InterfaceType) {
       List<DartType> typeArguments = literalType.typeArguments;
       if (typeArguments.length == 1) {
@@ -5010,7 +5031,7 @@
   }
 
   /// Compute the context type for the given set or map [literal].
-  DartType _computeSetOrMapContextType(SetOrMapLiteral literal) {
+  _LiteralResolution _computeSetOrMapResolution(SetOrMapLiteral literal) {
     _LiteralResolution typeArgumentsResolution =
         _fromTypeArguments(literal.typeArguments);
     DartType contextType = InferenceContext.getContext(literal);
@@ -5037,29 +5058,32 @@
       // It looks like it needs to be both a map and a set. Attempt to recover.
       if (elementResolution.kind == _LiteralResolutionKind.ambiguous &&
           elementResolution.contextType != null) {
-        return elementResolution.contextType;
+        return elementResolution;
       } else if (typeArgumentsResolution.kind !=
               _LiteralResolutionKind.ambiguous &&
           typeArgumentsResolution.contextType != null) {
-        return typeArgumentsResolution.contextType;
+        return typeArgumentsResolution;
       } else if (contextResolution.kind != _LiteralResolutionKind.ambiguous &&
           contextResolution.contextType != null) {
-        return contextResolution.contextType;
+        return contextResolution;
       }
     } else if (unambiguousResolutions.length >= 2) {
       // If there are three resolutions, the last resolution is guaranteed to be
       // from the elements, which always has a context type of `null` (when it
       // is not ambiguous). So, whether there are 2 or 3 resolutions only the
       // first two are potentially interesting.
-      return unambiguousResolutions[0].contextType ??
-          unambiguousResolutions[1].contextType;
+      return unambiguousResolutions[0].contextType == null
+          ? unambiguousResolutions[1]
+          : unambiguousResolutions[0];
     } else if (unambiguousResolutions.length == 1) {
-      return unambiguousResolutions[0].contextType;
+      return unambiguousResolutions[0];
     } else if (literal.elements2.isEmpty) {
-      return typeProvider.mapType
-          .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]);
+      return _LiteralResolution(
+          _LiteralResolutionKind.map,
+          typeProvider.mapType.instantiate(
+              [typeProvider.dynamicType, typeProvider.dynamicType]));
     }
-    return null;
+    return _LiteralResolution(_LiteralResolutionKind.ambiguous, null);
   }
 
   /// Return a newly created cloner that can be used to clone constant
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index d9ba671..2891951 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -180,6 +180,35 @@
     return inferred;
   }
 
+  ParameterizedType inferMapTypeDownwards(
+      SetOrMapLiteral node, DartType contextType) {
+    if (contextType == null) {
+      return null;
+    }
+
+    var ts = _typeSystem as Dart2TypeSystem;
+    ParameterizedType inferred = ts.inferGenericFunctionOrType(
+        _typeProvider.mapType, [], [], contextType,
+        downwards: true,
+        errorReporter: _resolver.errorReporter,
+        errorNode: node);
+    return inferred;
+  }
+
+  DartType inferSetTypeDownwards(SetOrMapLiteral node, DartType contextType) {
+    if (contextType == null) {
+      return null;
+    }
+
+    var ts = _typeSystem as Dart2TypeSystem;
+    DartType inferred = ts.inferGenericFunctionOrType<InterfaceType>(
+        _typeProvider.setType, [], [], contextType,
+        downwards: true,
+        errorReporter: _resolver.errorReporter,
+        errorNode: node);
+    return inferred;
+  }
+
   /**
    * The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is
    * `String`.</blockquote>
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
index 8a4f760..855600e 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
@@ -51,6 +51,16 @@
     assertType(findNode.listLiteral('['), 'List<dynamic>');
   }
 
+  test_context_noTypeArgs_noElements_typeParameter_dynamic() async {
+    addTestFile('''
+class A<E extends List<dynamic>> {
+  E a = [];
+}
+''');
+    await resolveTestFile();
+    assertType(findNode.listLiteral('['), 'List<dynamic>');
+  }
+
   test_context_typeArgs_expression_conflictingContext() async {
     addTestFile('''
 List<String> a = <int>[0];
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
index 89f9942..389136f 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
@@ -52,6 +52,26 @@
     assertType(setOrMapLiteral('{'), 'Map<String, String>');
   }
 
+  test_context_noTypeArgs_noEntries_typeParameters() async {
+    addTestFile('''
+class A<E extends Map<int, String>> {
+  E a = {};
+}
+''');
+    await resolveTestFile();
+    assertType(setOrMapLiteral('{}'), 'Map<dynamic, dynamic>');
+  }
+
+  test_context_noTypeArgs_noEntries_typeParameters_dynamic() async {
+    addTestFile('''
+class A<E extends Map<dynamic, dynamic>> {
+  E a = {};
+}
+''');
+    await resolveTestFile();
+    assertType(setOrMapLiteral('{}'), 'Map<dynamic, dynamic>');
+  }
+
   test_context_typeArgs_entry_conflictingKey() async {
     addTestFile('''
 Map<String, String> a = <String, String>{0 : 'a'};
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/set_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/set_literal_test.dart
index 8630d09..797764a 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/set_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/set_literal_test.dart
@@ -44,9 +44,6 @@
     assertType(setLiteral('{'), 'Set<String>');
   }
 
-  @FailingTest(
-      issue: 'https://github.com/dart-lang/sdk/issues/35569',
-      reason: 'Failing because Map<dynamic, dynamic> is being inferred.')
   test_context_noTypeArgs_noElements_typeParameter() async {
     addTestFile('''
 class A<E extends Set<int>> {
@@ -57,6 +54,16 @@
     assertType(setLiteral('{}'), 'Set<dynamic>');
   }
 
+  test_context_noTypeArgs_noElements_typeParameter_dynamic() async {
+    addTestFile('''
+class A<E extends Set<dynamic>> {
+  E a = {};
+}
+''');
+    await resolveTestFile();
+    assertType(setLiteral('{}'), 'Set<dynamic>');
+  }
+
   test_context_typeArgs_expression_conflictingExpression() async {
     addTestFile('''
 Set<String> a = <String>{0};