Skip to content

Commit 219fe27

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Front end: Fix follow-on error arising from ill-typed spread element.
When the CFE encounters an ill-typed spread element in an ambiguous set/map literal, it replaces it with a synthetic MapEntry object pointing to an InvalidExpression. If there is no non-synthetic MapEntry in the set/map, and it is decided to disambiguate to a set, then all of the entries are fed into the `convertToElement` method. Before this CL, this method would see the synthetic MapEntry and assume the user had explicitly written a key-value pair in a set literal, so it would try to report the error `Expected ',' before this` at the location of the `:` in the key-value pair. But since the MapEntry was synthetic, there was no `:` and the message was very confusing. This CL changes `convertToElement` so that it detects when a MapEntry has arisen from an error, and avoids creating a follow-on error. Fixes #45174. Bug: #45174 Change-Id: I37dc82a130b4bf858b3fb7411bb9c64f7450bd16 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/188940 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent e9f4d5d commit 219fe27

8 files changed

+41
-25
lines changed

pkg/front_end/lib/src/fasta/kernel/collections.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,14 @@ Expression convertToElement(MapEntry entry, InferenceHelper helper,
755755
onConvertForMapEntry(entry, result);
756756
return result;
757757
}
758+
Expression key = entry.key;
759+
if (key is InvalidExpression) {
760+
Expression value = entry.value;
761+
if (value is NullLiteral && value.fileOffset == TreeNode.noOffset) {
762+
// entry arose from an error. Don't build another error.
763+
return key;
764+
}
765+
}
758766
return helper.buildProblem(
759767
templateExpectedButGot.withArguments(','),
760768
entry.fileOffset,

pkg/front_end/testcases/general/constants/const_collections.dart.weak.expect

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ library;
1515
// const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
1616
// ^
1717
//
18-
// pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Expected ',' before this.
19-
// const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
20-
// ^
21-
//
2218
// pkg/front_end/testcases/general/constants/const_collections.dart:42:38: Error: Both Iterable and Map spread elements encountered in ambiguous literal.
2319
// const Set<String> quxWithMapSpread = {...baz, ...quux};
2420
// ^
@@ -427,7 +423,7 @@ static const field core::Set<core::String*>* nullSet = #C3;
427423
static const field core::Set<core::String*>* baz = #C14;
428424
static const field core::Set<core::String*>* qux = #C17;
429425
static const field core::Set<core::String*>* quxWithNullSpread = invalid-expression "Null value during constant evaluation.";
430-
static const field core::Set<core::String*>* quxWithIntSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Expected ',' before this.
426+
static const field core::Set<core::String*>* quxWithIntSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Unexpected type 'int' of a map spread entry. Expected 'dynamic' or a Map.
431427
const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
432428
^";
433429
static const field core::Set<core::String*>* quxWithMapSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:42:38: Error: Both Iterable and Map spread elements encountered in ambiguous literal.

pkg/front_end/testcases/general/constants/const_collections.dart.weak.outline.expect

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ library;
1515
// const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
1616
// ^
1717
//
18-
// pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Expected ',' before this.
19-
// const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
20-
// ^
21-
//
2218
// pkg/front_end/testcases/general/constants/const_collections.dart:42:38: Error: Both Iterable and Map spread elements encountered in ambiguous literal.
2319
// const Set<String> quxWithMapSpread = {...baz, ...quux};
2420
// ^
@@ -249,7 +245,7 @@ static const field core::Set<core::String*>* nullSet = null;
249245
static const field core::Set<core::String*>* baz = const <core::String*>{"hello", "world"};
250246
static const field core::Set<core::String*>* qux = self::baz + const <core::String*>{"!"};
251247
static const field core::Set<core::String*>* quxWithNullSpread = self::baz + self::nullSet;
252-
static const field core::Set<core::String*>* quxWithIntSpread = self::baz + const <core::String*>{invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Expected ',' before this.
248+
static const field core::Set<core::String*>* quxWithIntSpread = self::baz + const <core::String*>{invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Unexpected type 'int' of a map spread entry. Expected 'dynamic' or a Map.
253249
const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
254250
^"};
255251
static const field core::Set<core::String*>* quxWithMapSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:42:38: Error: Both Iterable and Map spread elements encountered in ambiguous literal.

pkg/front_end/testcases/general/constants/const_collections.dart.weak.transformed.expect

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ library;
1515
// const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
1616
// ^
1717
//
18-
// pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Expected ',' before this.
19-
// const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
20-
// ^
21-
//
2218
// pkg/front_end/testcases/general/constants/const_collections.dart:42:38: Error: Both Iterable and Map spread elements encountered in ambiguous literal.
2319
// const Set<String> quxWithMapSpread = {...baz, ...quux};
2420
// ^
@@ -427,7 +423,7 @@ static const field core::Set<core::String*>* nullSet = #C3;
427423
static const field core::Set<core::String*>* baz = #C14;
428424
static const field core::Set<core::String*>* qux = #C17;
429425
static const field core::Set<core::String*>* quxWithNullSpread = invalid-expression "Null value during constant evaluation.";
430-
static const field core::Set<core::String*>* quxWithIntSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Expected ',' before this.
426+
static const field core::Set<core::String*>* quxWithIntSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:41:50: Error: Unexpected type 'int' of a map spread entry. Expected 'dynamic' or a Map.
431427
const Set<String> quxWithIntSpread = {...baz, ...fortyTwo};
432428
^";
433429
static const field core::Set<core::String*>* quxWithMapSpread = invalid-expression "pkg/front_end/testcases/general/constants/const_collections.dart:42:38: Error: Both Iterable and Map spread elements encountered in ambiguous literal.

pkg/front_end/testcases/general/spread_collection_inference.dart.weak.expect

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,6 @@ library;
8888
// ...null,
8989
// ^
9090
//
91-
// pkg/front_end/testcases/general/spread_collection_inference.dart:137:8: Error: Expected ',' before this.
92-
// ...null,
93-
// ^
94-
//
9591
// pkg/front_end/testcases/general/spread_collection_inference.dart:142:45: Error: Can't spread a value with static type 'Null'.
9692
// Map<String, int> map70 = <String, int>{...null};
9793
// ^
@@ -298,7 +294,7 @@ Try providing type arguments for the literal explicitly to disambiguate it.
298294
} =>#t51;
299295
core::Set<dynamic>* set71ambiguous = block {
300296
final core::Set<dynamic>* #t52 = col::LinkedHashSet::•<dynamic>();
301-
#t52.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/general/spread_collection_inference.dart:137:8: Error: Expected ',' before this.
297+
#t52.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/general/spread_collection_inference.dart:137:8: Error: Can't spread a value with static type 'Null'.
302298
...null,
303299
^");
304300
for (final dynamic #t53 in <dynamic>[]) {

pkg/front_end/testcases/general/spread_collection_inference.dart.weak.transformed.expect

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,6 @@ library;
8888
// ...null,
8989
// ^
9090
//
91-
// pkg/front_end/testcases/general/spread_collection_inference.dart:137:8: Error: Expected ',' before this.
92-
// ...null,
93-
// ^
94-
//
9591
// pkg/front_end/testcases/general/spread_collection_inference.dart:142:45: Error: Can't spread a value with static type 'Null'.
9692
// Map<String, int> map70 = <String, int>{...null};
9793
// ^
@@ -367,7 +363,7 @@ Try providing type arguments for the literal explicitly to disambiguate it.
367363
} =>#t51;
368364
core::Set<dynamic>* set71ambiguous = block {
369365
final core::Set<dynamic>* #t52 = new col::_CompactLinkedHashSet::•<dynamic>();
370-
#t52.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/general/spread_collection_inference.dart:137:8: Error: Expected ',' before this.
366+
#t52.{core::Set::add}{Invariant}(invalid-expression "pkg/front_end/testcases/general/spread_collection_inference.dart:137:8: Error: Can't spread a value with static type 'Null'.
371367
...null,
372368
^");
373369
{
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
f(Object? objectQuestion) {
6+
return {...<int>{}, ...objectQuestion};
7+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8+
// [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER
9+
// ^^^^^^^^^^^^^^
10+
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
11+
// ^
12+
// [cfe] Unexpected type 'Object?' of a map spread entry. Expected 'dynamic' or a Map.
13+
}
14+
15+
main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
f(Object objectQuestion) {
6+
return {...<int>{}, ...objectQuestion};
7+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8+
// [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER
9+
// ^
10+
// [cfe] Unexpected type 'Object' of a map spread entry. Expected 'dynamic' or a Map.
11+
}
12+
13+
main() {}

0 commit comments

Comments
 (0)