Some fixes for UI-as-code type inference
Change-Id: I72711aad365e95f2f1b20d7f23d7765a9581ff4f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96022
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 7891289..dbca328 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -3670,6 +3670,8 @@
*/
final InheritanceManager2 inheritance;
+ final AnalysisOptionsImpl _analysisOptions;
+
/// The object used to resolve the element associated with the current node.
ElementResolver elementResolver;
@@ -3736,13 +3738,14 @@
{Scope nameScope,
bool propagateTypes: true,
reportConstEvaluationErrors: true})
- : super(definingLibrary, source, typeProvider, errorListener,
+ : _analysisOptions = definingLibrary.context.analysisOptions,
+ super(definingLibrary, source, typeProvider, errorListener,
nameScope: nameScope) {
- AnalysisOptions options = definingLibrary.context.analysisOptions;
this.elementResolver = new ElementResolver(this,
reportConstEvaluationErrors: reportConstEvaluationErrors);
this.typeSystem = definingLibrary.context.typeSystem;
bool strongModeHints = false;
+ AnalysisOptions options = _analysisOptions;
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
}
@@ -4903,6 +4906,23 @@
typeProvider.iterableType.instantiate([elementType]);
_pushCollectionTypesDownToAll(node.elements2,
elementType: elementType, iterableType: iterableType);
+ if (!_analysisOptions.experimentStatus.spread_collections &&
+ !_analysisOptions.experimentStatus.control_flow_collections &&
+ node.elements2.isEmpty &&
+ node.typeArguments == null &&
+ node.isMap) {
+ // The node is really an empty set literal with no type arguments.
+ // Rewrite the AST.
+ // ignore: deprecated_member_use_from_same_package
+ SetOrMapLiteral setLiteral = new AstFactoryImpl().setLiteral(
+ node.constKeyword,
+ null,
+ node.leftBracket,
+ null,
+ node.rightBracket);
+ NodeReplacer.replace(node, setLiteral);
+ node = setLiteral;
+ }
} else if (typeArguments.length == 2) {
DartType keyType = typeArguments[0];
DartType valueType = typeArguments[1];
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 66fe369..9b7342a 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -1051,25 +1051,38 @@
@override
void visitSetOrMapLiteral(SetOrMapLiteral node) {
- DartType staticType = node.staticType;
- if (staticType == null) {
- DartType literalType = _inferSetOrMapLiteralType(node);
- if (literalType.element == _typeProvider.mapType.element) {
- (node as SetOrMapLiteralImpl).becomeMap();
- } else {
- assert(literalType.element == _typeProvider.setType.element);
- (node as SetOrMapLiteralImpl).becomeSet();
- }
- _resolver.inferenceContext.recordInference(node, literalType);
- _recordStaticType(node, literalType);
- } else if (staticType is InterfaceType) {
- List<DartType> typeArguments = staticType.typeArguments;
+ var typeArguments = node.typeArguments?.arguments;
+
+ // If we have type arguments, use them.
+ // TODO(paulberry): this logic seems redundant with
+ // ResolverVisitor._fromTypeArguments
+ if (typeArguments != null) {
if (typeArguments.length == 1) {
(node as SetOrMapLiteralImpl).becomeSet();
+ var elementType = _getType(typeArguments[0]) ?? _dynamicType;
+ _recordStaticType(
+ node, _typeProvider.setType.instantiate(<DartType>[elementType]));
+ return;
} else if (typeArguments.length == 2) {
(node as SetOrMapLiteralImpl).becomeMap();
+ var keyType = _getType(typeArguments[0]) ?? _dynamicType;
+ var valueType = _getType(typeArguments[1]) ?? _dynamicType;
+ _recordStaticType(node,
+ _typeProvider.mapType.instantiate(<DartType>[keyType, valueType]));
+ return;
}
+ // If we get here, then a nonsense number of type arguments were provided,
+ // so treat it as though no type arguments were provided.
}
+ DartType literalType = _inferSetOrMapLiteralType(node);
+ if (literalType.element == _typeProvider.mapType.element) {
+ (node as SetOrMapLiteralImpl).becomeMap();
+ } else {
+ assert(literalType.element == _typeProvider.setType.element);
+ (node as SetOrMapLiteralImpl).becomeSet();
+ }
+ _resolver.inferenceContext.recordInference(node, literalType);
+ _recordStaticType(node, literalType);
}
/**
@@ -1954,9 +1967,6 @@
DartType _inferSetOrMapLiteralType(SetOrMapLiteral literal) {
DartType contextType = InferenceContext.getContext(literal);
NodeList<CollectionElement> elements = literal.elements2;
- if (elements.length < 2 && contextType != null) {
- return contextType;
- }
List<_InferredCollectionElementTypeInformation> inferredTypes = [];
bool canBeAMap = true;
bool mustBeAMap = false;
@@ -1976,11 +1986,20 @@
} else if (canBeAMap && mustBeAMap) {
return _toMapType(literal, contextType, inferredTypes);
}
- if (contextType == null) {
- DartType dynamicType = _typeProvider.dynamicType;
- return _typeProvider.mapType.instantiate([dynamicType, dynamicType]);
+ // TODO(paulberry): the following computations should be based on the
+ // greatest closure of the context type.
+ bool contextIsIterable = contextType != null &&
+ _typeSystem.isSubtypeOf(contextType, _typeProvider.iterableObjectType);
+ bool contextIsMap = contextType != null &&
+ _typeSystem.isSubtypeOf(contextType, _typeProvider.mapObjectObjectType);
+ if (contextIsIterable && !contextIsMap) {
+ return _toSetType(literal, contextType, inferredTypes);
+ } else {
+ if (elements.isNotEmpty && (!contextIsMap || contextIsIterable)) {
+ // Ambiguous. TODO(paulberry): report an error.
+ }
+ return _toMapType(literal, contextType, inferredTypes);
}
- return contextType;
}
/**
diff --git a/pkg/analyzer/test/src/summary/top_level_inference_test.dart b/pkg/analyzer/test/src/summary/top_level_inference_test.dart
index b2c8847..b4d8961 100644
--- a/pkg/analyzer/test/src/summary/top_level_inference_test.dart
+++ b/pkg/analyzer/test/src/summary/top_level_inference_test.dart
@@ -374,12 +374,6 @@
@override
List<String> get enabledExperiments =>
[EnableString.spread_collections, EnableString.control_flow_collections];
-
- @failingTest
- @override
- test_initializer_untypedMap() async {
- await super.test_initializer_untypedMap();
- }
}
@reflectiveTest