Skip to content

Commit c747272

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Report mismatching joint variables on the first use
Closes #51929 Part of #49749 Change-Id: Ib20bdb5eb9b0b5c1e8b34cfbac6498e642350875 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292782 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent d1d2327 commit c747272

20 files changed

+150
-96
lines changed

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

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7979,8 +7979,10 @@ class BodyBuilder extends StackListenerImpl
79797979
List<VariableDeclaration>? jointPatternVariablesWithMismatchingFinality =
79807980
pop() as List<VariableDeclaration>?;
79817981

7982+
List<int>? jointVariableFirstUseOffsets;
79827983
if (jointPatternVariables != null) {
7983-
List<VariableDeclaration>? usedJointPatternVariables;
7984+
List<VariableDeclaration> usedJointPatternVariables = [];
7985+
Map<VariableDeclaration, int> firstUseOffsets = {};
79847986
Scope? jointVariablesScope = scope;
79857987
while (jointVariablesScope != null &&
79867988
jointVariablesScope.kind != ScopeKind.jointVariables) {
@@ -7989,26 +7991,30 @@ class BodyBuilder extends StackListenerImpl
79897991
assert(jointVariablesScope != null,
79907992
"Can't find the scope the joint variables are declared in.");
79917993
for (VariableDeclaration variable in jointPatternVariables) {
7992-
if (jointVariablesScope?.usedNames?.containsKey(variable.name!) ??
7993-
false) {
7994-
(usedJointPatternVariables ??= <VariableDeclaration>[]).add(variable);
7994+
int? firstUseOffset = jointVariablesScope?.usedNames?[variable.name!];
7995+
if (firstUseOffset != null) {
7996+
usedJointPatternVariables.add(variable);
7997+
firstUseOffsets[variable] = firstUseOffset;
79957998
}
79967999
}
79978000
jointPatternVariables = usedJointPatternVariables;
7998-
}
7999-
if (jointPatternVariables != null &&
8000-
jointPatternVariablesWithMismatchingFinality != null) {
8001-
for (VariableDeclaration jointVariable in jointPatternVariables) {
8002-
if (jointPatternVariablesWithMismatchingFinality
8003-
.contains(jointVariable)) {
8004-
String jointVariableName = jointVariable.name!;
8005-
addProblem(
8006-
fasta.templateJointPatternVariablesMismatch
8007-
.withArguments(jointVariableName),
8008-
jointVariable.fileOffset,
8009-
jointVariableName.length);
8001+
if (jointPatternVariablesWithMismatchingFinality != null) {
8002+
for (VariableDeclaration jointVariable in jointPatternVariables) {
8003+
if (jointPatternVariablesWithMismatchingFinality
8004+
.contains(jointVariable)) {
8005+
String jointVariableName = jointVariable.name!;
8006+
addProblem(
8007+
fasta.templateJointPatternVariablesMismatch
8008+
.withArguments(jointVariableName),
8009+
firstUseOffsets[jointVariable]!,
8010+
jointVariableName.length);
8011+
}
80108012
}
80118013
}
8014+
jointVariableFirstUseOffsets = [
8015+
for (VariableDeclaration variable in jointPatternVariables)
8016+
firstUseOffsets[variable]!
8017+
];
80128018
}
80138019

80148020
exitLocalScope(expectedScopeKinds: const [
@@ -8043,7 +8049,8 @@ class BodyBuilder extends StackListenerImpl
80438049
firstToken.charOffset, caseOffsets, patternGuards, block,
80448050
isDefault: defaultKeyword != null,
80458051
hasLabel: labels != null,
8046-
jointVariables: jointPatternVariables ?? []));
8052+
jointVariables: jointPatternVariables ?? [],
8053+
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets));
80478054
} else {
80488055
List<Expression> expressions = <Expression>[];
80498056
List<int> caseOffsets = [];
@@ -8117,7 +8124,8 @@ class BodyBuilder extends StackListenerImpl
81178124
switchCase.body,
81188125
isDefault: switchCase.isDefault,
81198126
hasLabel: switchCase.hasLabel,
8120-
jointVariables: []);
8127+
jointVariables: [],
8128+
jointVariableFirstUseOffsets: null);
81218129
}
81228130
List<Statement>? users = labelUsers[index];
81238131
if (users != null) {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,11 +1076,13 @@ class Forest {
10761076
List<int> caseOffsets, List<PatternGuard> patternGuards, Statement body,
10771077
{required bool isDefault,
10781078
required bool hasLabel,
1079-
required List<VariableDeclaration> jointVariables}) {
1079+
required List<VariableDeclaration> jointVariables,
1080+
required List<int>? jointVariableFirstUseOffsets}) {
10801081
return new PatternSwitchCase(caseOffsets, patternGuards, body,
10811082
isDefault: isDefault,
10821083
hasLabel: hasLabel,
1083-
jointVariables: jointVariables)
1084+
jointVariables: jointVariables,
1085+
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets)
10841086
..fileOffset = fileOffset;
10851087
}
10861088

pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8401,13 +8401,15 @@ class InferenceVisitorImpl extends InferenceVisitorBase
84018401
jointVariable.type = inferredVariableTypes[jointVariable.name!]!;
84028402
}
84038403
} else {
8404-
for (VariableDeclaration jointVariable in switchCase.jointVariables) {
8404+
for (int i = 0; i < switchCase.jointVariables.length; ++i) {
8405+
VariableDeclaration jointVariable = switchCase.jointVariables[i];
84058406
if (jointVariable.type !=
84068407
inferredVariableTypes[jointVariable.name!]) {
84078408
jointVariable.initializer = helper.buildProblem(
84088409
templateJointPatternVariablesMismatch
84098410
.withArguments(jointVariable.name!),
8410-
jointVariable.fileOffset,
8411+
switchCase.jointVariableFirstUseOffsets?[i] ??
8412+
jointVariable.fileOffset,
84118413
noLength)
84128414
..parent = jointVariable;
84138415
}

pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,10 @@ void _testPatternSwitchStatement() {
313313
testStatement(
314314
new PatternSwitchStatement(expression, [
315315
new PatternSwitchCase([0], [case0], emptyBlock,
316-
isDefault: false, hasLabel: false, jointVariables: [])
316+
isDefault: false,
317+
hasLabel: false,
318+
jointVariables: [],
319+
jointVariableFirstUseOffsets: null)
317320
]),
318321
'''
319322
switch (null) {
@@ -325,7 +328,10 @@ switch (null) { case 0: }''');
325328
testStatement(
326329
new PatternSwitchStatement(expression, [
327330
new PatternSwitchCase([], [], emptyBlock,
328-
hasLabel: false, isDefault: true, jointVariables: [])
331+
hasLabel: false,
332+
isDefault: true,
333+
jointVariables: [],
334+
jointVariableFirstUseOffsets: null)
329335
]),
330336
'''
331337
switch (null) {
@@ -337,9 +343,15 @@ switch (null) { default: }''');
337343
testStatement(
338344
new PatternSwitchStatement(expression, [
339345
new PatternSwitchCase([0, 1], [case0, case1], returnBlock1,
340-
hasLabel: false, isDefault: false, jointVariables: []),
346+
hasLabel: false,
347+
isDefault: false,
348+
jointVariables: [],
349+
jointVariableFirstUseOffsets: null),
341350
new PatternSwitchCase([2], [case2], returnBlock2,
342-
hasLabel: true, isDefault: true, jointVariables: [])
351+
hasLabel: true,
352+
isDefault: true,
353+
jointVariables: [],
354+
jointVariableFirstUseOffsets: null)
343355
]),
344356
'''
345357
switch (null) {

pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart.strong.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ library /*isNonNullableByDefault*/;
22
//
33
// Problems in library:
44
//
5-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:10:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6-
// case int y when y == 0: // Error
5+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:12:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// return y;
77
// ^
88
//
99
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:13:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
@@ -14,8 +14,8 @@ library /*isNonNullableByDefault*/;
1414
// case int y || [final int y] when y == 0: // Error.
1515
// ^
1616
//
17-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18-
// case int y when y == 0: // Error
17+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18+
// return y;
1919
// ^
2020
//
2121
import self as self;
@@ -33,8 +33,8 @@ static method test(dynamic x) → dynamic {
3333
lowered hoisted core::int y#case#0;
3434
lowered hoisted dynamic y#case#1;
3535
if(#0#0 is{ForNonNullableByDefault} core::int && (let final dynamic #t3 = y#case#0 = #0#0{core::int} in true) && y#case#0 =={core::num::==}{(core::Object) → core::bool} 0 && (let final dynamic #t4 = #t1 = y#case#0 in true) || #0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (let final dynamic #t5 = y#case#1 = #0#6 in true) && y#case#1 =={core::Object::==}{(core::Object) → core::bool} 0 && (let final dynamic #t6 = #t1 = y#case#1 in true)) {
36-
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
37-
case int y when y == 0: // Error
36+
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
37+
return y;
3838
^";
3939
{
4040
return y;

pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart.strong.transformed.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ library /*isNonNullableByDefault*/;
22
//
33
// Problems in library:
44
//
5-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:10:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6-
// case int y when y == 0: // Error
5+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:12:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// return y;
77
// ^
88
//
99
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:13:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
@@ -14,8 +14,8 @@ library /*isNonNullableByDefault*/;
1414
// case int y || [final int y] when y == 0: // Error.
1515
// ^
1616
//
17-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18-
// case int y when y == 0: // Error
17+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18+
// return y;
1919
// ^
2020
//
2121
import self as self;
@@ -37,8 +37,8 @@ static method test(dynamic x) → dynamic {
3737
lowered hoisted core::int y#case#0;
3838
lowered hoisted dynamic y#case#1;
3939
if(#0#0 is{ForNonNullableByDefault} core::int && (let final core::int #t3 = y#case#0 = #0#0{core::int} in true) && y#case#0 =={core::num::==}{(core::Object) → core::bool} 0 && (let final core::int #t4 = #t1 = y#case#0 in true) || #0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (let final dynamic #t5 = y#case#1 = #0#6 in true) && y#case#1 =={core::Object::==}{(core::Object) → core::bool} 0 && (let final dynamic #t6 = #t1 = y#case#1 in true)) {
40-
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
41-
case int y when y == 0: // Error
40+
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
41+
return y;
4242
^";
4343
{
4444
return y;

pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart.weak.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ library /*isNonNullableByDefault*/;
22
//
33
// Problems in library:
44
//
5-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:10:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6-
// case int y when y == 0: // Error
5+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:12:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// return y;
77
// ^
88
//
99
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:13:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
@@ -14,8 +14,8 @@ library /*isNonNullableByDefault*/;
1414
// case int y || [final int y] when y == 0: // Error.
1515
// ^
1616
//
17-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18-
// case int y when y == 0: // Error
17+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18+
// return y;
1919
// ^
2020
//
2121
import self as self;
@@ -33,8 +33,8 @@ static method test(dynamic x) → dynamic {
3333
lowered hoisted core::int y#case#0;
3434
lowered hoisted dynamic y#case#1;
3535
if(#0#0 is{ForNonNullableByDefault} core::int && (let final dynamic #t3 = y#case#0 = #0#0{core::int} in true) && y#case#0 =={core::num::==}{(core::Object) → core::bool} 0 && (let final dynamic #t4 = #t1 = y#case#0 in true) || #0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (let final dynamic #t5 = y#case#1 = #0#6 in true) && y#case#1 =={core::Object::==}{(core::Object) → core::bool} 0 && (let final dynamic #t6 = #t1 = y#case#1 in true)) {
36-
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
37-
case int y when y == 0: // Error
36+
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
37+
return y;
3838
^";
3939
{
4040
return y;

pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart.weak.modular.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ library /*isNonNullableByDefault*/;
22
//
33
// Problems in library:
44
//
5-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:10:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6-
// case int y when y == 0: // Error
5+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:12:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// return y;
77
// ^
88
//
99
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:13:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
@@ -14,8 +14,8 @@ library /*isNonNullableByDefault*/;
1414
// case int y || [final int y] when y == 0: // Error.
1515
// ^
1616
//
17-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18-
// case int y when y == 0: // Error
17+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18+
// return y;
1919
// ^
2020
//
2121
import self as self;
@@ -33,8 +33,8 @@ static method test(dynamic x) → dynamic {
3333
lowered hoisted core::int y#case#0;
3434
lowered hoisted dynamic y#case#1;
3535
if(#0#0 is{ForNonNullableByDefault} core::int && (let final dynamic #t3 = y#case#0 = #0#0{core::int} in true) && y#case#0 =={core::num::==}{(core::Object) → core::bool} 0 && (let final dynamic #t4 = #t1 = y#case#0 in true) || #0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (let final dynamic #t5 = y#case#1 = #0#6 in true) && y#case#1 =={core::Object::==}{(core::Object) → core::bool} 0 && (let final dynamic #t6 = #t1 = y#case#1 in true)) {
36-
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
37-
case int y when y == 0: // Error
36+
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
37+
return y;
3838
^";
3939
{
4040
return y;

pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart.weak.transformed.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ library /*isNonNullableByDefault*/;
22
//
33
// Problems in library:
44
//
5-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:10:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6-
// case int y when y == 0: // Error
5+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:12:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// return y;
77
// ^
88
//
99
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:13:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
@@ -14,8 +14,8 @@ library /*isNonNullableByDefault*/;
1414
// case int y || [final int y] when y == 0: // Error.
1515
// ^
1616
//
17-
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18-
// case int y when y == 0: // Error
17+
// pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
18+
// return y;
1919
// ^
2020
//
2121
import self as self;
@@ -37,8 +37,8 @@ static method test(dynamic x) → dynamic {
3737
lowered hoisted core::int y#case#0;
3838
lowered hoisted dynamic y#case#1;
3939
if(#0#0 is{ForNonNullableByDefault} core::int && (let final core::int #t3 = y#case#0 = #0#0{core::int} in true) && y#case#0 =={core::num::==}{(core::Object) → core::bool} 0 && (let final core::int #t4 = #t1 = y#case#0 in true) || #0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (let final dynamic #t5 = y#case#1 = #0#6 in true) && y#case#1 =={core::Object::==}{(core::Object) → core::bool} 0 && (let final dynamic #t6 = #t1 = y#case#1 in true)) {
40-
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:7:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
41-
case int y when y == 0: // Error
40+
core::int y = invalid-expression "pkg/front_end/testcases/patterns/mismatching_joint_pattern_variables.dart:9:14: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
41+
return y;
4242
^";
4343
{
4444
return y;

0 commit comments

Comments
 (0)