Skip to content

Commit 17bf9d1

Browse files
committed
Delay disambiguating maps and sets until we know whether there are any conflicts
Change-Id: If55d8ab011047107f34a05a08e60ee54eabc0b44 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95668 Reviewed-by: Paul Berry <[email protected]>
1 parent 079309f commit 17bf9d1

File tree

5 files changed

+74
-88
lines changed

5 files changed

+74
-88
lines changed

pkg/analyzer/lib/src/dart/ast/ast.dart

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8995,7 +8995,7 @@ class SetOrMapLiteralImpl extends TypedLiteralImpl implements SetOrMapLiteral {
89958995
this.leftBracket, List<CollectionElement> elements, this.rightBracket)
89968996
: super(constKeyword, typeArguments) {
89978997
_elements = new NodeListImpl<CollectionElement>(this, elements);
8998-
_resolvedKind = _computeResolvedKind(typeArguments, _elements);
8998+
_resolvedKind = _SetOrMapKind.unresolved;
89998999
}
90009000

90019001
/// Temporary constructor to support MapLiteral2Impl.
@@ -9073,49 +9073,6 @@ class SetOrMapLiteralImpl extends TypedLiteralImpl implements SetOrMapLiteral {
90739073
super.visitChildren(visitor);
90749074
_elements.accept(visitor);
90759075
}
9076-
9077-
_SetOrMapKind _computeResolvedKind(TypeArgumentListImpl typeArguments,
9078-
NodeList<CollectionElement> elements) {
9079-
int argCount = typeArguments?.arguments?.length ?? 0;
9080-
if (argCount == 1) {
9081-
return _SetOrMapKind.set;
9082-
} else if (argCount == 2) {
9083-
return _SetOrMapKind.map;
9084-
}
9085-
_SetOrMapKind kind = _SetOrMapKind.unresolved;
9086-
for (var element in elements) {
9087-
_SetOrMapKind elementKind = _kindOf(element);
9088-
if (kind == _SetOrMapKind.unresolved) {
9089-
kind = elementKind;
9090-
} else if (elementKind != _SetOrMapKind.unresolved &&
9091-
elementKind != kind) {
9092-
return _SetOrMapKind.unresolved;
9093-
}
9094-
}
9095-
return kind;
9096-
}
9097-
9098-
_SetOrMapKind _kindOf(CollectionElement element) {
9099-
if (element is ForElement) {
9100-
return _kindOf(element.body);
9101-
} else if (element is IfElement) {
9102-
if (element.elseElement == null) {
9103-
return _kindOf(element.thenElement);
9104-
}
9105-
_SetOrMapKind thenKind = _kindOf(element.thenElement);
9106-
_SetOrMapKind elseKind = _kindOf(element.elseElement);
9107-
if (thenKind == _SetOrMapKind.unresolved || thenKind == elseKind) {
9108-
return elseKind;
9109-
} else if (elseKind == _SetOrMapKind.unresolved) {
9110-
return thenKind;
9111-
}
9112-
} else if (element is Expression) {
9113-
return _SetOrMapKind.set;
9114-
} else if (element is MapLiteralEntry) {
9115-
return _SetOrMapKind.map;
9116-
}
9117-
return _SetOrMapKind.unresolved;
9118-
}
91199076
}
91209077

91219078
/// A combinator that restricts the names being imported to those in a given

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4198,29 +4198,34 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
41984198
assert(mapType is InterfaceTypeImpl);
41994199

42004200
List<DartType> typeArguments = (mapType as InterfaceTypeImpl).typeArguments;
4201-
assert(typeArguments.length == 2);
4202-
DartType keyType = typeArguments[0];
4203-
DartType valueType = typeArguments[1];
4204-
4205-
bool isConst = literal.isConst;
4206-
NodeList<CollectionElement> entries = literal.elements2;
4207-
for (CollectionElement entry in entries) {
4208-
if (isConst) {
4209-
// TODO(paulberry): this error should be based on the actual type of the
4210-
// map entries, not the static type. See dartbug.com/21119.
4211-
_checkForMapElementTypeNotAssignableWithKeyOrValueType(
4212-
entry,
4213-
keyType,
4214-
valueType,
4215-
CheckedModeCompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
4216-
CheckedModeCompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE);
4217-
} else {
4218-
_checkForMapElementTypeNotAssignableWithKeyOrValueType(
4219-
entry,
4220-
keyType,
4221-
valueType,
4222-
StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
4223-
StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE);
4201+
// It is possible for the number of type arguments to be inconsistent when
4202+
// the literal is ambiguous and a non-map type was selected.
4203+
// TODO(brianwilkerson) Unify this and _checkForSetElementTypeNotAssignable3
4204+
// to better handle recovery situations.
4205+
if (typeArguments.length == 2) {
4206+
DartType keyType = typeArguments[0];
4207+
DartType valueType = typeArguments[1];
4208+
4209+
bool isConst = literal.isConst;
4210+
NodeList<CollectionElement> entries = literal.elements2;
4211+
for (CollectionElement entry in entries) {
4212+
if (isConst) {
4213+
// TODO(paulberry): this error should be based on the actual type of
4214+
// the map entries, not the static type. See dartbug.com/21119.
4215+
_checkForMapElementTypeNotAssignableWithKeyOrValueType(
4216+
entry,
4217+
keyType,
4218+
valueType,
4219+
CheckedModeCompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
4220+
CheckedModeCompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE);
4221+
} else {
4222+
_checkForMapElementTypeNotAssignableWithKeyOrValueType(
4223+
entry,
4224+
keyType,
4225+
valueType,
4226+
StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
4227+
StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE);
4228+
}
42244229
}
42254230
}
42264231
}
@@ -5491,23 +5496,29 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
54915496
assert(setType is InterfaceTypeImpl);
54925497

54935498
List<DartType> typeArguments = (setType as InterfaceTypeImpl).typeArguments;
5494-
assert(typeArguments.length == 1);
5495-
5496-
DartType setElementType = typeArguments[0];
5497-
5498-
// Check every set element.
5499-
bool isConst = literal.isConst;
5500-
for (CollectionElement element in literal.elements2) {
5501-
if (isConst) {
5502-
// TODO(paulberry): this error should be based on the actual type of the
5503-
// element, not the static type. See dartbug.com/21119.
5504-
_checkForCollectionElementTypeNotAssignableWithElementType(
5505-
element,
5506-
setElementType,
5507-
CheckedModeCompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE);
5508-
} else {
5509-
_checkForCollectionElementTypeNotAssignableWithElementType(element,
5510-
setElementType, StaticWarningCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE);
5499+
// It is possible for the number of type arguments to be inconsistent when
5500+
// the literal is ambiguous and a non-set type was selected.
5501+
// TODO(brianwilkerson) Unify this and _checkForMapTypeNotAssignable3 to
5502+
// better handle recovery situations.
5503+
if (typeArguments.length == 1) {
5504+
DartType setElementType = typeArguments[0];
5505+
5506+
// Check every set element.
5507+
bool isConst = literal.isConst;
5508+
for (CollectionElement element in literal.elements2) {
5509+
if (isConst) {
5510+
// TODO(paulberry): this error should be based on the actual type of
5511+
// the element, not the static type. See dartbug.com/21119.
5512+
_checkForCollectionElementTypeNotAssignableWithElementType(
5513+
element,
5514+
setElementType,
5515+
CheckedModeCompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE);
5516+
} else {
5517+
_checkForCollectionElementTypeNotAssignableWithElementType(
5518+
element,
5519+
setElementType,
5520+
StaticWarningCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE);
5521+
}
55115522
}
55125523
}
55135524
}

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4892,14 +4892,12 @@ class ResolverVisitor extends ScopedVisitor {
48924892
if (literalType != null) {
48934893
List<DartType> typeArguments = literalType.typeArguments;
48944894
if (typeArguments.length == 1) {
4895-
(node as SetOrMapLiteralImpl).becomeSet();
48964895
DartType elementType = literalType.typeArguments[0];
48974896
DartType iterableType =
48984897
typeProvider.iterableType.instantiate([elementType]);
48994898
_pushCollectionTypesDownToAll(node.elements2,
49004899
elementType: elementType, iterableType: iterableType);
49014900
} else if (typeArguments.length == 2) {
4902-
(node as SetOrMapLiteralImpl).becomeMap();
49034901
DartType keyType = typeArguments[0];
49044902
DartType valueType = typeArguments[1];
49054903
_pushCollectionTypesDownToAll(node.elements2,

pkg/analyzer/lib/src/generated/static_type_analyzer.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,8 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
10471047

10481048
@override
10491049
void visitSetOrMapLiteral(SetOrMapLiteral node) {
1050-
if (node.staticType == null) {
1050+
DartType staticType = node.staticType;
1051+
if (staticType == null) {
10511052
DartType literalType = _inferSetOrMapLiteralType(node);
10521053
if (literalType.element == _typeProvider.mapType.element) {
10531054
(node as SetOrMapLiteralImpl).becomeMap();
@@ -1057,6 +1058,13 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
10571058
}
10581059
_resolver.inferenceContext.recordInference(node, literalType);
10591060
_recordStaticType(node, literalType);
1061+
} else if (staticType is InterfaceType) {
1062+
List<DartType> typeArguments = staticType.typeArguments;
1063+
if (typeArguments.length == 1) {
1064+
(node as SetOrMapLiteralImpl).becomeSet();
1065+
} else if (typeArguments.length == 2) {
1066+
(node as SetOrMapLiteralImpl).becomeMap();
1067+
}
10601068
}
10611069
}
10621070

@@ -1948,12 +1956,16 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
19481956

19491957
DartType _inferSetOrMapLiteralType(SetOrMapLiteral literal) {
19501958
DartType contextType = InferenceContext.getContext(literal);
1959+
NodeList<CollectionElement> elements = literal.elements2;
1960+
if (elements.length < 2 && contextType != null) {
1961+
return contextType;
1962+
}
19511963
List<_InferredCollectionElementTypeInformation> inferredTypes = [];
19521964
bool canBeAMap = true;
19531965
bool mustBeAMap = false;
19541966
bool canBeASet = true;
19551967
bool mustBeASet = false;
1956-
for (CollectionElement element in literal.elements2) {
1968+
for (CollectionElement element in elements) {
19571969
_InferredCollectionElementTypeInformation inferredType =
19581970
_inferCollectionElementType(element);
19591971
inferredTypes.add(inferredType);

pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ var a = <int, int>{1 : 2};
116116
assertType(setOrMapLiteral('{'), 'Map<int, int>');
117117
}
118118

119+
test_noContext_typeArgs_expression_conflict() async {
120+
addTestFile('''
121+
var a = <int, String>{1};
122+
''');
123+
await resolveTestFile();
124+
assertType(setOrMapLiteral('{'), 'Map<int, String>');
125+
}
126+
119127
test_noContext_typeArgs_noEntries() async {
120128
addTestFile('''
121129
var a = <num, String>{};

0 commit comments

Comments
 (0)