Skip to content

Commit 82237f9

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Support final joint variables in switch statements
Part of #49749 Change-Id: I741562bd37cd5f93d4a2d1ccadcb869344bc10a2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286926 Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent de44a23 commit 82237f9

13 files changed

+317
-14
lines changed

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,11 @@ class SwitchStatementMemberInfo<Node extends Object, Statement extends Node,
203203
/// might become not consistent.
204204
final Map<String, Variable> variables;
205205

206-
SwitchStatementMemberInfo(this.heads, this.body, this.variables,
207-
{required this.hasLabels});
206+
SwitchStatementMemberInfo(
207+
{required this.heads,
208+
required this.body,
209+
required this.variables,
210+
required this.hasLabels});
208211
}
209212

210213
/// Type analysis logic to be shared between the analyzer and front end. The

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,7 +3669,7 @@ class _MiniAstTypeAnalyzer
36693669
covariant _SwitchStatement node, int caseIndex) {
36703670
_SwitchStatementMember case_ = node.cases[caseIndex];
36713671
return SwitchStatementMemberInfo(
3672-
[
3672+
heads: [
36733673
for (var element in case_.elements)
36743674
if (element is _SwitchHeadCase)
36753675
CaseHeadOrDefaultInfo(
@@ -3684,8 +3684,8 @@ class _MiniAstTypeAnalyzer
36843684
guard: null,
36853685
)
36863686
],
3687-
case_._body.statements,
3688-
case_._candidateVariables,
3687+
body: case_._body.statements,
3688+
variables: case_._candidateVariables,
36893689
hasLabels: case_.hasLabels,
36903690
);
36913691
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,9 +1017,9 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
10171017

10181018
var group = node.memberGroups[index];
10191019
return SwitchStatementMemberInfo(
1020-
group.members.map(ofMember).toList(),
1021-
group.statements,
1022-
group.variables,
1020+
heads: group.members.map(ofMember).toList(),
1021+
body: group.statements,
1022+
variables: group.variables,
10231023
hasLabels: group.hasLabels,
10241024
);
10251025
}

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9822,7 +9822,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
98229822
covariant SwitchStatement node, int caseIndex) {
98239823
SwitchCase case_ = node.cases[caseIndex];
98249824
if (case_ is SwitchCaseImpl) {
9825-
return new SwitchStatementMemberInfo([
9825+
return new SwitchStatementMemberInfo(heads: [
98269826
for (Expression expression in case_.expressions)
98279827
new CaseHeadOrDefaultInfo(
98289828
pattern: expression,
@@ -9833,12 +9833,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
98339833
pattern: null,
98349834
variables: {},
98359835
)
9836-
], [
9836+
], body: [
98379837
case_.body
9838-
], {}, hasLabels: case_.hasLabel);
9838+
], variables: {}, hasLabels: case_.hasLabel);
98399839
} else {
98409840
case_ as PatternSwitchCase;
9841-
return new SwitchStatementMemberInfo([
9841+
return new SwitchStatementMemberInfo(heads: [
98429842
for (PatternGuard patternGuard in case_.patternGuards)
98439843
new CaseHeadOrDefaultInfo(
98449844
pattern: patternGuard.pattern,
@@ -9854,9 +9854,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
98549854
pattern: null,
98559855
variables: {},
98569856
)
9857-
], [
9857+
], body: [
98589858
case_.body
9859-
], {}, hasLabels: case_.hasLabel);
9859+
], variables: {
9860+
for (VariableDeclaration jointVariable in case_.jointVariables)
9861+
jointVariable.name!: jointVariable
9862+
}, hasLabels: case_.hasLabel);
98609863
}
98619864
}
98629865

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 [final int a]:
8+
case final int a:
9+
return a;
10+
case [final String a] || final String a:
11+
return a;
12+
default:
13+
return null;
14+
}
15+
}
16+
17+
main() {
18+
expectEquals(test(0), 0);
19+
expectEquals(test([0]), 0);
20+
expectEquals(test("foo"), "foo");
21+
expectEquals(test(["foo"]), "foo");
22+
expectEquals(test(3.14), null);
23+
}
24+
25+
expectEquals(x, y) {
26+
if (x != y) {
27+
throw "Expected '${x}' to be equal to '${x}'.";
28+
}
29+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
static method test(dynamic x) → dynamic {
6+
#L1:
7+
{
8+
final core::int a;
9+
final core::int a#1;
10+
final core::String a#2;
11+
final dynamic #0#0 = x;
12+
late final core::bool #0#4 = #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
13+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
14+
dynamic #t1;
15+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t2 = a = #0#6{core::int} in true)) && (let final dynamic #t3 = #t1 = a in true) || #0#0 is{ForNonNullableByDefault} core::int && (let final dynamic #t4 = a#1 = #0#0{core::int} in true) && (let final dynamic #t5 = #t1 = a#1 in true)) {
16+
final core::int a = #t1{core::int};
17+
{
18+
return a;
19+
}
20+
}
21+
else
22+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::String && (let final dynamic #t6 = a#2 = #0#6{core::String} in true)) || #0#0 is{ForNonNullableByDefault} core::String && (let final dynamic #t7 = a#2 = #0#0{core::String} in true)) {
23+
{
24+
return a#2;
25+
}
26+
}
27+
else {
28+
{
29+
return null;
30+
}
31+
}
32+
}
33+
}
34+
static method main() → dynamic {
35+
self::expectEquals(self::test(0), 0);
36+
self::expectEquals(self::test(<core::int>[0]), 0);
37+
self::expectEquals(self::test("foo"), "foo");
38+
self::expectEquals(self::test(<core::String>["foo"]), "foo");
39+
self::expectEquals(self::test(3.14), null);
40+
}
41+
static method expectEquals(dynamic x, dynamic y) → dynamic {
42+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
43+
throw "Expected '${x}' to be equal to '${x}'.";
44+
}
45+
}
46+
47+
constants {
48+
#C1 = 1
49+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
static method test(dynamic x) → dynamic {
6+
#L1:
7+
{
8+
final core::int a;
9+
final core::int a#1;
10+
final core::String a#2;
11+
final dynamic #0#0 = x;
12+
function ##0#4#initializer() → core::bool
13+
return #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
14+
late final core::bool #0#4 = ##0#4#initializer(){() → core::bool};
15+
function ##0#6#initializer() → dynamic
16+
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
17+
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
18+
dynamic #t1;
19+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::int && (let final core::int #t2 = a = #0#6{core::int} in true)) && (let final core::int #t3 = #t1 = a in true) || #0#0 is{ForNonNullableByDefault} core::int && (let final core::int #t4 = a#1 = #0#0{core::int} in true) && (let final core::int #t5 = #t1 = a#1 in true)) {
20+
final core::int a = #t1{core::int};
21+
{
22+
return a;
23+
}
24+
}
25+
else
26+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::String && (let final core::String #t6 = a#2 = #0#6{core::String} in true)) || #0#0 is{ForNonNullableByDefault} core::String && (let final core::String #t7 = a#2 = #0#0{core::String} in true)) {
27+
{
28+
return a#2;
29+
}
30+
}
31+
else {
32+
{
33+
return null;
34+
}
35+
}
36+
}
37+
}
38+
static method main() → dynamic {
39+
self::expectEquals(self::test(0), 0);
40+
self::expectEquals(self::test(core::_GrowableList::_literal1<core::int>(0)), 0);
41+
self::expectEquals(self::test("foo"), "foo");
42+
self::expectEquals(self::test(core::_GrowableList::_literal1<core::String>("foo")), "foo");
43+
self::expectEquals(self::test(3.14), null);
44+
}
45+
static method expectEquals(dynamic x, dynamic y) → dynamic {
46+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
47+
throw "Expected '${x}' to be equal to '${x}'.";
48+
}
49+
}
50+
51+
constants {
52+
#C1 = 1
53+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test(dynamic x) {}
2+
main() {}
3+
expectEquals(x, y) {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
expectEquals(x, y) {}
2+
main() {}
3+
test(dynamic x) {}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
static method test(dynamic x) → dynamic {
6+
#L1:
7+
{
8+
final core::int a;
9+
final core::int a#1;
10+
final core::String a#2;
11+
final dynamic #0#0 = x;
12+
late final core::bool #0#4 = #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
13+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
14+
dynamic #t1;
15+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t2 = a = #0#6{core::int} in true)) && (let final dynamic #t3 = #t1 = a in true) || #0#0 is{ForNonNullableByDefault} core::int && (let final dynamic #t4 = a#1 = #0#0{core::int} in true) && (let final dynamic #t5 = #t1 = a#1 in true)) {
16+
final core::int a = #t1{core::int};
17+
{
18+
return a;
19+
}
20+
}
21+
else
22+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::String && (let final dynamic #t6 = a#2 = #0#6{core::String} in true)) || #0#0 is{ForNonNullableByDefault} core::String && (let final dynamic #t7 = a#2 = #0#0{core::String} in true)) {
23+
{
24+
return a#2;
25+
}
26+
}
27+
else {
28+
{
29+
return null;
30+
}
31+
}
32+
}
33+
}
34+
static method main() → dynamic {
35+
self::expectEquals(self::test(0), 0);
36+
self::expectEquals(self::test(<core::int>[0]), 0);
37+
self::expectEquals(self::test("foo"), "foo");
38+
self::expectEquals(self::test(<core::String>["foo"]), "foo");
39+
self::expectEquals(self::test(3.14), null);
40+
}
41+
static method expectEquals(dynamic x, dynamic y) → dynamic {
42+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
43+
throw "Expected '${x}' to be equal to '${x}'.";
44+
}
45+
}
46+
47+
constants {
48+
#C1 = 1
49+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
static method test(dynamic x) → dynamic {
6+
#L1:
7+
{
8+
final core::int a;
9+
final core::int a#1;
10+
final core::String a#2;
11+
final dynamic #0#0 = x;
12+
late final core::bool #0#4 = #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
13+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
14+
dynamic #t1;
15+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t2 = a = #0#6{core::int} in true)) && (let final dynamic #t3 = #t1 = a in true) || #0#0 is{ForNonNullableByDefault} core::int && (let final dynamic #t4 = a#1 = #0#0{core::int} in true) && (let final dynamic #t5 = #t1 = a#1 in true)) {
16+
final core::int a = #t1{core::int};
17+
{
18+
return a;
19+
}
20+
}
21+
else
22+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::String && (let final dynamic #t6 = a#2 = #0#6{core::String} in true)) || #0#0 is{ForNonNullableByDefault} core::String && (let final dynamic #t7 = a#2 = #0#0{core::String} in true)) {
23+
{
24+
return a#2;
25+
}
26+
}
27+
else {
28+
{
29+
return null;
30+
}
31+
}
32+
}
33+
}
34+
static method main() → dynamic {
35+
self::expectEquals(self::test(0), 0);
36+
self::expectEquals(self::test(<core::int>[0]), 0);
37+
self::expectEquals(self::test("foo"), "foo");
38+
self::expectEquals(self::test(<core::String>["foo"]), "foo");
39+
self::expectEquals(self::test(3.14), null);
40+
}
41+
static method expectEquals(dynamic x, dynamic y) → dynamic {
42+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
43+
throw "Expected '${x}' to be equal to '${x}'.";
44+
}
45+
}
46+
47+
constants {
48+
#C1 = 1
49+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
4+
static method test(dynamic x) → dynamic
5+
;
6+
static method main() → dynamic
7+
;
8+
static method expectEquals(dynamic x, dynamic y) → dynamic
9+
;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
static method test(dynamic x) → dynamic {
6+
#L1:
7+
{
8+
final core::int a;
9+
final core::int a#1;
10+
final core::String a#2;
11+
final dynamic #0#0 = x;
12+
function ##0#4#initializer() → core::bool
13+
return #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
14+
late final core::bool #0#4 = ##0#4#initializer(){() → core::bool};
15+
function ##0#6#initializer() → dynamic
16+
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
17+
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
18+
dynamic #t1;
19+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::int && (let final core::int #t2 = a = #0#6{core::int} in true)) && (let final core::int #t3 = #t1 = a in true) || #0#0 is{ForNonNullableByDefault} core::int && (let final core::int #t4 = a#1 = #0#0{core::int} in true) && (let final core::int #t5 = #t1 = a#1 in true)) {
20+
final core::int a = #t1{core::int};
21+
{
22+
return a;
23+
}
24+
}
25+
else
26+
if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#4 && (#0#6 is{ForNonNullableByDefault} core::String && (let final core::String #t6 = a#2 = #0#6{core::String} in true)) || #0#0 is{ForNonNullableByDefault} core::String && (let final core::String #t7 = a#2 = #0#0{core::String} in true)) {
27+
{
28+
return a#2;
29+
}
30+
}
31+
else {
32+
{
33+
return null;
34+
}
35+
}
36+
}
37+
}
38+
static method main() → dynamic {
39+
self::expectEquals(self::test(0), 0);
40+
self::expectEquals(self::test(core::_GrowableList::_literal1<core::int>(0)), 0);
41+
self::expectEquals(self::test("foo"), "foo");
42+
self::expectEquals(self::test(core::_GrowableList::_literal1<core::String>("foo")), "foo");
43+
self::expectEquals(self::test(3.14), null);
44+
}
45+
static method expectEquals(dynamic x, dynamic y) → dynamic {
46+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
47+
throw "Expected '${x}' to be equal to '${x}'.";
48+
}
49+
}
50+
51+
constants {
52+
#C1 = 1
53+
}

0 commit comments

Comments
 (0)