Skip to content

Commit d758cf1

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Report more errors on mismatching joint variables
Part of #49749 Change-Id: Ie3dd75209f40681590e378138cbe2b86a5e1619f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292361 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 7cfab4e commit d758cf1

File tree

32 files changed

+633
-50
lines changed

32 files changed

+633
-50
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7498,6 +7498,32 @@ Message _withArgumentsInvokeNonFunction(String name) {
74987498
arguments: {'name': name});
74997499
}
75007500

7501+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7502+
const Template<
7503+
Message Function(
7504+
String
7505+
name)> templateJointPatternVariablesMismatch = const Template<
7506+
Message Function(String name)>(
7507+
problemMessageTemplate:
7508+
r"""Variable pattern '#name' doesn't have the same type or finality in all cases.""",
7509+
withArguments: _withArgumentsJointPatternVariablesMismatch);
7510+
7511+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7512+
const Code<Message Function(String name)> codeJointPatternVariablesMismatch =
7513+
const Code<Message Function(String name)>(
7514+
"JointPatternVariablesMismatch",
7515+
);
7516+
7517+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7518+
Message _withArgumentsJointPatternVariablesMismatch(String name) {
7519+
if (name.isEmpty) throw 'No name provided';
7520+
name = demangleMixinApplicationName(name);
7521+
return new Message(codeJointPatternVariablesMismatch,
7522+
problemMessage:
7523+
"""Variable pattern '${name}' doesn't have the same type or finality in all cases.""",
7524+
arguments: {'name': name});
7525+
}
7526+
75017527
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
75027528
const Code<Null> codeJsInteropAnonymousFactoryPositionalParameters =
75037529
messageJsInteropAnonymousFactoryPositionalParameters;
@@ -13047,31 +13073,6 @@ const MessageCode messageVariablePatternKeywordInDeclarationContext =
1304713073
r"""Variable patterns in declaration context can't specify 'var' or 'final' keyword.""",
1304813074
correctionMessage: r"""Try removing the keyword.""");
1304913075

13050-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
13051-
const Template<Message Function(String name)>
13052-
templateVariablePatternTypeMismatchInSwitchHeads =
13053-
const Template<Message Function(String name)>(
13054-
problemMessageTemplate:
13055-
r"""Variable pattern '#name' doesn't have the same type in all cases.""",
13056-
withArguments: _withArgumentsVariablePatternTypeMismatchInSwitchHeads);
13057-
13058-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
13059-
const Code<Message Function(String name)>
13060-
codeVariablePatternTypeMismatchInSwitchHeads =
13061-
const Code<Message Function(String name)>(
13062-
"VariablePatternTypeMismatchInSwitchHeads",
13063-
);
13064-
13065-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
13066-
Message _withArgumentsVariablePatternTypeMismatchInSwitchHeads(String name) {
13067-
if (name.isEmpty) throw 'No name provided';
13068-
name = demangleMixinApplicationName(name);
13069-
return new Message(codeVariablePatternTypeMismatchInSwitchHeads,
13070-
problemMessage:
13071-
"""Variable pattern '${name}' doesn't have the same type in all cases.""",
13072-
arguments: {'name': name});
13073-
}
13074-
1307513076
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
1307613077
const Code<Null> codeVerificationErrorOriginContext =
1307713078
messageVerificationErrorOriginContext;

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

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6943,7 +6943,7 @@ class BodyBuilder extends StackListenerImpl
69436943
}
69446944

69456945
@override
6946-
// TODO: Handle directly.
6946+
// TODO: Handle directly.
69476947
void handleNamedRecordField(Token colon) => handleNamedArgument(colon);
69486948

69496949
@override
@@ -7812,6 +7812,7 @@ class BodyBuilder extends StackListenerImpl
78127812
push(labels ?? NullValues.Labels);
78137813

78147814
List<VariableDeclaration>? jointPatternVariables;
7815+
List<VariableDeclaration>? jointPatternVariablesWithMismatchingFinality;
78157816
enterLocalScope(switchCaseScope!);
78167817
if (expressionCount > 1) {
78177818
for (ExpressionOrPatternGuardCase expressionOrPattern
@@ -7832,16 +7833,17 @@ class BodyBuilder extends StackListenerImpl
78327833
in patternGuard.pattern.declaredVariables)
78337834
variable.name!: variable
78347835
};
7835-
List<VariableDeclaration> sharedVariables = [];
78367836
for (VariableDeclaration jointVariable in jointPatternVariables) {
7837+
String jointVariableName = jointVariable.name!;
78377838
VariableDeclaration? patternVariable =
7838-
patternVariablesByName[jointVariable.name!];
7839-
if (patternVariable != null &&
7840-
patternVariable.isFinal == jointVariable.isFinal) {
7841-
sharedVariables.add(jointVariable);
7839+
patternVariablesByName[jointVariableName];
7840+
if (patternVariable != null) {
7841+
if (patternVariable.isFinal != jointVariable.isFinal) {
7842+
(jointPatternVariablesWithMismatchingFinality ??= [])
7843+
.add(jointVariable);
7844+
}
78427845
}
78437846
}
7844-
jointPatternVariables = sharedVariables;
78457847
}
78467848
} else {
78477849
// It's a non-pattern head, so no variables can be joined.
@@ -7870,9 +7872,12 @@ class BodyBuilder extends StackListenerImpl
78707872
exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
78717873
enterLocalScope(switchCaseScope);
78727874
}
7875+
push(jointPatternVariablesWithMismatchingFinality ??
7876+
NullValues.VariableDeclarationList);
78737877
push(jointPatternVariables ?? NullValues.VariableDeclarationList);
78747878

78757879
assert(checkState(firstToken, [
7880+
ValueKinds.VariableDeclarationListOrNull,
78767881
ValueKinds.VariableDeclarationListOrNull,
78777882
ValueKinds.Scope,
78787883
ValueKinds.LabelListOrNull,
@@ -7959,6 +7964,7 @@ class BodyBuilder extends StackListenerImpl
79597964
assert(checkState(firstToken, [
79607965
...repeatedKind(ValueKinds.Statement, statementCount),
79617966
ValueKinds.VariableDeclarationListOrNull,
7967+
ValueKinds.VariableDeclarationListOrNull,
79627968
ValueKinds.Scope,
79637969
ValueKinds.LabelListOrNull,
79647970
ValueKinds.Bool,
@@ -7970,6 +7976,8 @@ class BodyBuilder extends StackListenerImpl
79707976
Statement block = popBlock(statementCount, firstToken, null);
79717977
List<VariableDeclaration>? jointPatternVariables =
79727978
pop() as List<VariableDeclaration>?;
7979+
List<VariableDeclaration>? jointPatternVariablesWithMismatchingFinality =
7980+
pop() as List<VariableDeclaration>?;
79737981

79747982
if (jointPatternVariables != null) {
79757983
List<VariableDeclaration>? usedJointPatternVariables;
@@ -7988,6 +7996,20 @@ class BodyBuilder extends StackListenerImpl
79887996
}
79897997
jointPatternVariables = usedJointPatternVariables;
79907998
}
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);
8010+
}
8011+
}
8012+
}
79918013

79928014
exitLocalScope(expectedScopeKinds: const [
79938015
ScopeKind.switchCase,

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8403,9 +8403,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
84038403
} else {
84048404
for (VariableDeclaration jointVariable in switchCase.jointVariables) {
84058405
if (jointVariable.type !=
8406-
inferredVariableTypes[jointVariable.name!]!) {
8406+
inferredVariableTypes[jointVariable.name!]) {
84078407
jointVariable.initializer = helper.buildProblem(
8408-
templateVariablePatternTypeMismatchInSwitchHeads
8408+
templateJointPatternVariablesMismatch
84098409
.withArguments(jointVariable.name!),
84108410
jointVariable.fileOffset,
84118411
noLength)
@@ -10040,6 +10040,30 @@ class InferenceVisitorImpl extends InferenceVisitorBase
1004010040
node.left = (rewrite as Pattern)..parent = node;
1004110041
}
1004210042

10043+
Map<String, VariableDeclaration> leftDeclaredVariablesByName = {
10044+
for (VariableDeclaration variable in node.left.declaredVariables)
10045+
variable.name!: variable
10046+
};
10047+
Set<String> jointVariableNames = {
10048+
for (VariableDeclaration variable in node.orPatternJointVariables)
10049+
variable.name!
10050+
};
10051+
for (VariableDeclaration rightVariable in node.right.declaredVariables) {
10052+
String rightVariableName = rightVariable.name!;
10053+
VariableDeclaration? leftVariable =
10054+
leftDeclaredVariablesByName[rightVariableName];
10055+
if (leftVariable != null &&
10056+
jointVariableNames.contains(rightVariableName) &&
10057+
(leftVariable.type != rightVariable.type ||
10058+
leftVariable.isFinal != rightVariable.isFinal)) {
10059+
helper.addProblem(
10060+
templateJointPatternVariablesMismatch
10061+
.withArguments(rightVariableName),
10062+
leftVariable.fileOffset,
10063+
rightVariableName.length);
10064+
}
10065+
}
10066+
1004310067
pushRewrite(replacement ?? node);
1004410068

1004510069
assert(checkStack(node, stackBase, [

pkg/front_end/messages.status

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ InvalidVoid/part_wrapped_script1: Fail
564564
InvalidVoid/part_wrapped_script2: Fail
565565
InvalidVoid/script1: Fail
566566
InvalidVoid/script2: Fail
567+
JointPatternVariablesMismatch/analyzerCode: Fail
567568
JsInteropAnonymousFactoryPositionalParameters/analyzerCode: Fail # Web compiler specific
568569
JsInteropAnonymousFactoryPositionalParameters/example: Fail # Web compiler specific
569570
JsInteropDartClassExtendsJSClass/analyzerCode: Fail # Web compiler specific
@@ -868,8 +869,8 @@ RequiredNamedParameterHasDefaultValueError/analyzerCode: Fail
868869
RequiredNamedParameterHasDefaultValueError/example: Fail
869870
RequiredNamedParameterHasDefaultValueWarning/analyzerCode: Fail
870871
RequiredNamedParameterHasDefaultValueWarning/example: Fail
871-
RestPatternMoreThanOne/analyzerCode: Fail
872872
RestPatternInMapPattern/analyzerCode: Fail
873+
RestPatternMoreThanOne/analyzerCode: Fail
873874
RethrowNotCatch/example: Fail
874875
ReturnTypeFunctionExpression/analyzerCode: Fail
875876
ReturnTypeFunctionExpression/example: Fail
@@ -1004,7 +1005,6 @@ VarAsTypeName/part_wrapped_script1: Fail
10041005
VarAsTypeName/script1: Fail # Too many problems
10051006
VariableCouldBeNullDueToWrite/analyzerCode: Fail
10061007
VariableCouldBeNullDueToWrite/example: Fail
1007-
VariablePatternTypeMismatchInSwitchHeads/analyzerCode: Fail
10081008
WeakReferenceMismatchReturnAndArgumentTypes/analyzerCode: Fail
10091009
WeakReferenceMismatchReturnAndArgumentTypes/example: Fail
10101010
WeakReferenceNotOneArgument/analyzerCode: Fail

pkg/front_end/messages.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6384,8 +6384,8 @@ UnspecifiedGetterNameInObjectPattern:
63846384
abstract class A { int get foo;}
63856385
test(dynamic x) { if (x case A(: 0)) {} }
63866386
6387-
VariablePatternTypeMismatchInSwitchHeads:
6388-
problemMessage: "Variable pattern '#name' doesn't have the same type in all cases."
6387+
JointPatternVariablesMismatch:
6388+
problemMessage: "Variable pattern '#name' doesn't have the same type or finality in all cases."
63896389
experiments: patterns
63906390
script: |
63916391
test(dynamic x) { switch (x) { case [int a]: case [double a] : return a; default: return null; } }

pkg/front_end/test/spell_checking_list_messages.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ exhaustively
4545
exportable
4646
f
4747
ffi
48+
finality
4849
flutter_runner
4950
futureor
5051
guides

pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ test1(dynamic x) {
77
}
88

99
test2(dynamic x) {
10-
if (x case [int y, var _] || [var _, String y]) {
10+
if (x case [int y, var _] || [var _, String y]) { // Error
1111
return y;
1212
} else {
1313
return null;

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:10:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// if (x case [int y, var _] || [var _, String y]) { // Error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:26:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
10+
// if (x case [int y, var _, _] || [var _, String y, _] || [var _, bool y, _]) {
11+
// ^
12+
//
213
import self as self;
314
import "dart:core" as core;
415

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:10:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// if (x case [int y, var _] || [var _, String y]) { // Error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:26:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
10+
// if (x case [int y, var _, _] || [var _, String y, _] || [var _, bool y, _]) {
11+
// ^
12+
//
213
import self as self;
314
import "dart:core" as core;
415

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:10:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// if (x case [int y, var _] || [var _, String y]) { // Error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:26:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
10+
// if (x case [int y, var _, _] || [var _, String y, _] || [var _, bool y, _]) {
11+
// ^
12+
//
213
import self as self;
314
import "dart:core" as core;
415

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:10:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// if (x case [int y, var _] || [var _, String y]) { // Error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:26:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
10+
// if (x case [int y, var _, _] || [var _, String y, _] || [var _, bool y, _]) {
11+
// ^
12+
//
213
import self as self;
314
import "dart:core" as core;
415

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:10:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
6+
// if (x case [int y, var _] || [var _, String y]) { // Error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/logical_or_inside_if_case.dart:26:19: Error: Variable pattern 'y' doesn't have the same type or finality in all cases.
10+
// if (x case [int y, var _, _] || [var _, String y, _] || [var _, bool y, _]) {
11+
// ^
12+
//
213
import self as self;
314
import "dart:core" as core;
415

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2023, 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+
test(dynamic x) {
6+
switch (x) {
7+
case int y when y == 0: // Error
8+
case [var y] when y == 0:
9+
return y;
10+
case int y when y == 0: // Error
11+
case [final int y] when y == 0:
12+
return y;
13+
case int y || [var y] when y == 0: // Error.
14+
return y;
15+
case int y || [final int y] when y == 0: // Error.
16+
return y;
17+
default:
18+
return null;
19+
}
20+
}

0 commit comments

Comments
 (0)