@@ -7836,10 +7836,12 @@ class BodyBuilder extends StackListenerImpl
7836
7836
7837
7837
List <VariableDeclaration >? jointPatternVariables;
7838
7838
List <VariableDeclaration >? jointPatternVariablesWithMismatchingFinality;
7839
+ List <VariableDeclaration >? jointPatternVariablesNotInAll;
7839
7840
enterLocalScope (switchCaseScope! );
7840
7841
if (expressionCount > 1 ) {
7841
- for (ExpressionOrPatternGuardCase expressionOrPattern
7842
- in expressionOrPatterns) {
7842
+ for (int i = 0 ; i < expressionOrPatterns.length; i++ ) {
7843
+ ExpressionOrPatternGuardCase expressionOrPattern =
7844
+ expressionOrPatterns[i];
7843
7845
PatternGuard ? patternGuard = expressionOrPattern.patternGuard;
7844
7846
if (patternGuard != null ) {
7845
7847
if (jointPatternVariables == null ) {
@@ -7850,6 +7852,12 @@ class BodyBuilder extends StackListenerImpl
7850
7852
variable.fileOffset, variable.name! )
7851
7853
..isFinal = variable.isFinal
7852
7854
];
7855
+ if (i != 0 ) {
7856
+ // The previous heads were non-pattern ones, so no variables can
7857
+ // be joined.
7858
+ (jointPatternVariablesNotInAll ?? = [])
7859
+ .addAll (jointPatternVariables);
7860
+ }
7853
7861
} else {
7854
7862
Map <String , VariableDeclaration > patternVariablesByName = {
7855
7863
for (VariableDeclaration variable
@@ -7859,19 +7867,34 @@ class BodyBuilder extends StackListenerImpl
7859
7867
for (VariableDeclaration jointVariable in jointPatternVariables) {
7860
7868
String jointVariableName = jointVariable.name! ;
7861
7869
VariableDeclaration ? patternVariable =
7862
- patternVariablesByName[ jointVariableName] ;
7870
+ patternVariablesByName. remove ( jointVariableName) ;
7863
7871
if (patternVariable != null ) {
7864
7872
if (patternVariable.isFinal != jointVariable.isFinal) {
7865
7873
(jointPatternVariablesWithMismatchingFinality ?? = [])
7866
7874
.add (jointVariable);
7867
7875
}
7876
+ } else {
7877
+ (jointPatternVariablesNotInAll ?? = []).add (jointVariable);
7878
+ }
7879
+ }
7880
+ if (patternVariablesByName.isNotEmpty) {
7881
+ for (VariableDeclaration variable
7882
+ in patternVariablesByName.values) {
7883
+ VariableDeclaration jointVariable = forest
7884
+ .createVariableDeclaration (
7885
+ variable.fileOffset, variable.name! )
7886
+ ..isFinal = variable.isFinal;
7887
+ (jointPatternVariablesNotInAll ?? = []).add (jointVariable);
7888
+ jointPatternVariables.add (jointVariable);
7868
7889
}
7869
7890
}
7870
7891
}
7871
7892
} else {
7872
7893
// It's a non-pattern head, so no variables can be joined.
7873
- jointPatternVariables = null ;
7874
- break ;
7894
+ if (jointPatternVariables != null ) {
7895
+ (jointPatternVariablesNotInAll ?? = [])
7896
+ .addAll (jointPatternVariables);
7897
+ }
7875
7898
}
7876
7899
}
7877
7900
if (jointPatternVariables != null ) {
@@ -7895,11 +7918,17 @@ class BodyBuilder extends StackListenerImpl
7895
7918
exitLocalScope (expectedScopeKinds: const [ScopeKind .caseHead]);
7896
7919
enterLocalScope (switchCaseScope);
7897
7920
}
7921
+ push (jointPatternVariablesNotInAll ?? NullValues .VariableDeclarationList );
7898
7922
push (jointPatternVariablesWithMismatchingFinality ??
7899
7923
NullValues .VariableDeclarationList );
7900
7924
push (jointPatternVariables ?? NullValues .VariableDeclarationList );
7901
7925
7926
+ createAndEnterLocalScope (
7927
+ debugName: "switch-case-body" , kind: ScopeKind .switchCaseBody);
7928
+
7902
7929
assert (checkState (firstToken, [
7930
+ ValueKinds .Scope ,
7931
+ ValueKinds .VariableDeclarationListOrNull ,
7903
7932
ValueKinds .VariableDeclarationListOrNull ,
7904
7933
ValueKinds .VariableDeclarationListOrNull ,
7905
7934
ValueKinds .Scope ,
@@ -7986,56 +8015,87 @@ class BodyBuilder extends StackListenerImpl
7986
8015
debugEvent ("SwitchCase" );
7987
8016
assert (checkState (firstToken, [
7988
8017
...repeatedKind (ValueKinds .Statement , statementCount),
8018
+ ValueKinds .Scope ,
8019
+ ValueKinds .VariableDeclarationListOrNull ,
7989
8020
ValueKinds .VariableDeclarationListOrNull ,
7990
8021
ValueKinds .VariableDeclarationListOrNull ,
7991
8022
ValueKinds .Scope ,
7992
8023
ValueKinds .LabelListOrNull ,
7993
8024
ValueKinds .Bool ,
7994
8025
ValueKinds .ExpressionOrPatternGuardCaseList ,
7995
8026
]));
8027
+
7996
8028
// We always create a block here so that we later know that there's always
7997
8029
// one synthetic block when we finish compiling the switch statement and
7998
8030
// check this switch case to see if it falls through to the next case.
7999
8031
Statement block = popBlock (statementCount, firstToken, null );
8032
+ exitLocalScope (expectedScopeKinds: const [ScopeKind .switchCaseBody]);
8000
8033
List <VariableDeclaration >? jointPatternVariables =
8001
8034
pop () as List <VariableDeclaration >? ;
8002
8035
List <VariableDeclaration >? jointPatternVariablesWithMismatchingFinality =
8003
8036
pop () as List <VariableDeclaration >? ;
8037
+ List <VariableDeclaration >? jointPatternVariablesNotInAll =
8038
+ pop () as List <VariableDeclaration >? ;
8004
8039
8040
+ // The current scope should be the scope of the body of the switch case
8041
+ // because we want to lookup the first use of the pattern variables
8042
+ // specifically in the body of the case, as opposed to, for example, the
8043
+ // guard in one of the heads of the case.
8044
+ assert (
8045
+ scope.kind == ScopeKind .switchCase ||
8046
+ scope.kind == ScopeKind .jointVariables,
8047
+ "Expected the current scope to be of kind '${ScopeKind .switchCase }' "
8048
+ "or '${ScopeKind .jointVariables }', but got '${scope .kind }." );
8049
+ Map <String , int >? usedNamesOffsets = scope.usedNames;
8050
+
8051
+ bool hasDefaultOrLabels = defaultKeyword != null || labelCount > 0 ;
8052
+
8053
+ List <VariableDeclaration >? usedJointPatternVariables;
8005
8054
List <int >? jointVariableFirstUseOffsets;
8006
8055
if (jointPatternVariables != null ) {
8007
- List < VariableDeclaration > usedJointPatternVariables = [];
8056
+ usedJointPatternVariables = [];
8008
8057
Map <VariableDeclaration , int > firstUseOffsets = {};
8009
- Scope ? jointVariablesScope = scope;
8010
- while (jointVariablesScope != null &&
8011
- jointVariablesScope.kind != ScopeKind .jointVariables) {
8012
- jointVariablesScope = jointVariablesScope.parent;
8013
- }
8014
- assert (jointVariablesScope != null ,
8015
- "Can't find the scope the joint variables are declared in." );
8016
8058
for (VariableDeclaration variable in jointPatternVariables) {
8017
- int ? firstUseOffset = jointVariablesScope ? .usedNames ? [variable.name! ];
8059
+ int ? firstUseOffset = usedNamesOffsets ? [variable.name! ];
8018
8060
if (firstUseOffset != null ) {
8019
8061
usedJointPatternVariables.add (variable);
8020
8062
firstUseOffsets[variable] = firstUseOffset;
8021
8063
}
8022
8064
}
8023
- jointPatternVariables = usedJointPatternVariables;
8024
- if (jointPatternVariablesWithMismatchingFinality != null ) {
8025
- for (VariableDeclaration jointVariable in jointPatternVariables) {
8065
+ if (jointPatternVariablesWithMismatchingFinality != null ||
8066
+ jointPatternVariablesNotInAll != null ||
8067
+ hasDefaultOrLabels) {
8068
+ for (VariableDeclaration jointVariable in usedJointPatternVariables) {
8026
8069
if (jointPatternVariablesWithMismatchingFinality
8027
- .contains (jointVariable)) {
8070
+ ? .contains (jointVariable) ??
8071
+ false ) {
8028
8072
String jointVariableName = jointVariable.name! ;
8029
8073
addProblem (
8030
8074
fasta.templateJointPatternVariablesMismatch
8031
8075
.withArguments (jointVariableName),
8032
8076
firstUseOffsets[jointVariable]! ,
8033
8077
jointVariableName.length);
8034
8078
}
8079
+ if (jointPatternVariablesNotInAll? .contains (jointVariable) ?? false ) {
8080
+ String jointVariableName = jointVariable.name! ;
8081
+ addProblem (
8082
+ fasta.templateJointPatternVariableNotInAll
8083
+ .withArguments (jointVariableName),
8084
+ firstUseOffsets[jointVariable]! ,
8085
+ jointVariableName.length);
8086
+ }
8087
+ if (hasDefaultOrLabels) {
8088
+ String jointVariableName = jointVariable.name! ;
8089
+ addProblem (
8090
+ fasta.templateJointPatternVariableWithLabelDefault
8091
+ .withArguments (jointVariableName),
8092
+ firstUseOffsets[jointVariable]! ,
8093
+ jointVariableName.length);
8094
+ }
8035
8095
}
8036
8096
}
8037
8097
jointVariableFirstUseOffsets = [
8038
- for (VariableDeclaration variable in jointPatternVariables )
8098
+ for (VariableDeclaration variable in usedJointPatternVariables )
8039
8099
firstUseOffsets[variable]!
8040
8100
];
8041
8101
}
@@ -8051,6 +8111,28 @@ class BodyBuilder extends StackListenerImpl
8051
8111
bool containsPatterns = pop () as bool ;
8052
8112
List <ExpressionOrPatternGuardCase > expressionsOrPatternGuards =
8053
8113
pop () as List <ExpressionOrPatternGuardCase >;
8114
+
8115
+ if (expressionCount == 1 &&
8116
+ containsPatterns &&
8117
+ hasDefaultOrLabels &&
8118
+ usedNamesOffsets != null ) {
8119
+ PatternGuard ? patternGuard =
8120
+ expressionsOrPatternGuards.first.patternGuard;
8121
+ if (patternGuard != null ) {
8122
+ for (VariableDeclaration variable
8123
+ in patternGuard.pattern.declaredVariables) {
8124
+ String variableName = variable.name! ;
8125
+ int ? offset = usedNamesOffsets[variableName];
8126
+ if (offset != null ) {
8127
+ addProblem (
8128
+ fasta.templateJointPatternVariableWithLabelDefault
8129
+ .withArguments (variableName),
8130
+ offset,
8131
+ variableName.length);
8132
+ }
8133
+ }
8134
+ }
8135
+ }
8054
8136
if (containsPatterns || libraryFeatures.patterns.isEnabled) {
8055
8137
// If patterns are enabled, we always use the pattern switch encoding.
8056
8138
// Otherwise, we use pattern switch encoding to handle the erroneous case
@@ -8072,7 +8154,7 @@ class BodyBuilder extends StackListenerImpl
8072
8154
firstToken.charOffset, caseOffsets, patternGuards, block,
8073
8155
isDefault: defaultKeyword != null ,
8074
8156
hasLabel: labels != null ,
8075
- jointVariables: jointPatternVariables ?? [],
8157
+ jointVariables: usedJointPatternVariables ?? [],
8076
8158
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets));
8077
8159
} else {
8078
8160
List <Expression > expressions = < Expression > [];
0 commit comments