Skip to content

Commit 628dd02

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Support typedefs in object patterns
Part of #49749 Change-Id: I0d29a875a6a0d3bac5c20309a1b4a6c8b48618f5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/277960 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 157641d commit 628dd02

19 files changed

+711
-2
lines changed

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

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8347,8 +8347,37 @@ class BodyBuilder extends StackListenerImpl
83478347
// TODO(cstefantsova): Handle the case of secondIdentifier != null
83488348
handleIdentifier(firstIdentifier, IdentifierContext.typeReference);
83498349
Object? resolvedIdentifier = pop();
8350+
83508351
if (resolvedIdentifier is TypeUseGenerator) {
83518352
TypeDeclarationBuilder typeDeclaration = resolvedIdentifier.declaration;
8353+
8354+
if (typeDeclaration is TypeAliasBuilder) {
8355+
if (typeArguments == null ||
8356+
typeArguments.length ==
8357+
typeDeclaration.typedef.typeParameters.length) {
8358+
TypeDeclarationBuilder? unaliasedTypeDeclaration =
8359+
typeDeclaration.unaliasDeclaration(typeArguments);
8360+
List<TypeBuilder>? unaliasedTypeArguments =
8361+
typeDeclaration.unaliasTypeArguments(typeArguments);
8362+
if (unaliasedTypeDeclaration == null) {
8363+
// TODO(cstefantsova): Make sure an error is reported elsewhere.
8364+
push(new DummyPattern(firstIdentifier.charOffset));
8365+
return;
8366+
} else {
8367+
typeDeclaration = unaliasedTypeDeclaration;
8368+
typeArguments = unaliasedTypeArguments;
8369+
}
8370+
} else {
8371+
addProblem(
8372+
fasta.templateTypeArgumentMismatch
8373+
.withArguments(typeDeclaration.typedef.typeParameters.length),
8374+
firstIdentifier.charOffset,
8375+
noLength);
8376+
push(new DummyPattern(firstIdentifier.charOffset));
8377+
return;
8378+
}
8379+
}
8380+
83528381
if (typeDeclaration is ClassBuilder) {
83538382
List<DartType>? builtTypeArguments;
83548383
if (typeArguments != null) {
@@ -8359,7 +8388,13 @@ class BodyBuilder extends StackListenerImpl
83598388
.add(typeBuilder.build(libraryBuilder, TypeUse.typeArgument));
83608389
}
83618390
} else {
8362-
// TODO(cstefantsova): Report an error.
8391+
addProblem(
8392+
fasta.templateTypeArgumentMismatch
8393+
.withArguments(typeDeclaration.cls.typeParameters.length),
8394+
firstIdentifier.charOffset,
8395+
noLength);
8396+
push(new DummyPattern(firstIdentifier.charOffset));
8397+
return;
83638398
}
83648399
}
83658400
push(new ObjectPattern(
@@ -8368,7 +8403,7 @@ class BodyBuilder extends StackListenerImpl
83688403
builtTypeArguments,
83698404
firstIdentifier.offset));
83708405
} else {
8371-
// TODO(cstefantsova): Handle this case.
8406+
// TODO(cstefantsova): Handle other possibilities.
83728407
push(new DummyPattern(firstIdentifier.charOffset));
83738408
}
83748409
} else {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2022, 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+
class A {}
6+
7+
typedef B<X> = A;
8+
9+
test(dynamic x) {
10+
if (x case A<int>()) {} // Error.
11+
if (x case B()) {} // Ok: the type argument is inferred.
12+
if (x case B<int>()) {} // Ok.
13+
if (x case B<String, num>()) {} // Error.
14+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
6+
// if (x case A<int>()) {} // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
10+
// if (x case B<String, num>()) {} // Error.
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
typedef B<unrelated X extends core::Object? = dynamic> = self::A;
17+
class A extends core::Object {
18+
synthetic constructor •() → self::A
19+
: super core::Object::•()
20+
;
21+
}
22+
static method test(dynamic x) → dynamic {
23+
final dynamic #t1 = x;
24+
final dynamic #t2 = x;
25+
final dynamic #t3 = #t2;
26+
if(#t3 is self::A) {
27+
}
28+
final dynamic #t4 = x;
29+
final dynamic #t5 = #t4;
30+
if(#t5 is self::A) {
31+
}
32+
final dynamic #t6 = x;
33+
}
34+
static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
35+
return new self::A::•();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
6+
// if (x case A<int>()) {} // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
10+
// if (x case B<String, num>()) {} // Error.
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
typedef B<unrelated X extends core::Object? = dynamic> = self::A;
17+
class A extends core::Object {
18+
synthetic constructor •() → self::A
19+
: super core::Object::•()
20+
;
21+
}
22+
static method test(dynamic x) → dynamic {
23+
final dynamic #t1 = x;
24+
final dynamic #t2 = x;
25+
final dynamic #t3 = #t2;
26+
if(#t3 is self::A) {
27+
}
28+
final dynamic #t4 = x;
29+
final dynamic #t5 = #t4;
30+
if(#t5 is self::A) {
31+
}
32+
final dynamic #t6 = x;
33+
}
34+
static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
35+
return new self::A::•();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class A {}
2+
3+
typedef B<X> = A;
4+
test(dynamic x) {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class A {}
2+
3+
test(dynamic x) {}
4+
typedef B<X> = A;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
6+
// if (x case A<int>()) {} // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
10+
// if (x case B<String, num>()) {} // Error.
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
typedef B<unrelated X extends core::Object? = dynamic> = self::A;
17+
class A extends core::Object {
18+
synthetic constructor •() → self::A
19+
: super core::Object::•()
20+
;
21+
}
22+
static method test(dynamic x) → dynamic {
23+
final dynamic #t1 = x;
24+
final dynamic #t2 = x;
25+
final dynamic #t3 = #t2;
26+
if(#t3 is self::A) {
27+
}
28+
final dynamic #t4 = x;
29+
final dynamic #t5 = #t4;
30+
if(#t5 is self::A) {
31+
}
32+
final dynamic #t6 = x;
33+
}
34+
static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
35+
return new self::A::•();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
6+
// if (x case A<int>()) {} // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
10+
// if (x case B<String, num>()) {} // Error.
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
typedef B<unrelated X extends core::Object? = dynamic> = self::A;
17+
class A extends core::Object {
18+
synthetic constructor •() → self::A
19+
: super core::Object::•()
20+
;
21+
}
22+
static method test(dynamic x) → dynamic {
23+
final dynamic #t1 = x;
24+
final dynamic #t2 = x;
25+
final dynamic #t3 = #t2;
26+
if(#t3 is self::A) {
27+
}
28+
final dynamic #t4 = x;
29+
final dynamic #t5 = #t4;
30+
if(#t5 is self::A) {
31+
}
32+
final dynamic #t6 = x;
33+
}
34+
static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
35+
return new self::A::•();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef B<unrelated X extends core::Object? = dynamic> = self::A;
6+
class A extends core::Object {
7+
synthetic constructor •() → self::A
8+
;
9+
}
10+
static method test(dynamic x) → dynamic
11+
;
12+
static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
13+
return new self::A::•();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
6+
// if (x case A<int>()) {} // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
10+
// if (x case B<String, num>()) {} // Error.
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
typedef B<unrelated X extends core::Object? = dynamic> = self::A;
17+
class A extends core::Object {
18+
synthetic constructor •() → self::A
19+
: super core::Object::•()
20+
;
21+
}
22+
static method test(dynamic x) → dynamic {
23+
final dynamic #t1 = x;
24+
final dynamic #t2 = x;
25+
final dynamic #t3 = #t2;
26+
if(#t3 is self::A) {
27+
}
28+
final dynamic #t4 = x;
29+
final dynamic #t5 = #t4;
30+
if(#t5 is self::A) {
31+
}
32+
final dynamic #t6 = x;
33+
}
34+
static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
35+
return new self::A::•();
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2022, 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+
class A {
6+
int foo;
7+
8+
A(this.foo);
9+
}
10+
11+
typedef B = A;
12+
13+
class C<X, Y> {
14+
X x;
15+
Y y;
16+
17+
C(this.x, this.y);
18+
}
19+
20+
typedef D<X> = C<X, X>;
21+
22+
test1(dynamic x) {
23+
if (x case B(:var foo)) {
24+
return foo;
25+
} else {
26+
return null;
27+
}
28+
}
29+
30+
test2(dynamic x) {
31+
if (x case D<String>(:var x)) {
32+
return x;
33+
} else {
34+
return null;
35+
}
36+
}
37+
38+
main() {
39+
expectEquals(0, test1(new A(0)));
40+
expectEquals(1, test1(new B(1)));
41+
expectEquals(null, test1(null));
42+
43+
expectEquals("one", test2(new C("one", "two")));
44+
expectEquals("one", test2(new D("one", "two")));
45+
expectEquals(null, test2(null));
46+
}
47+
48+
expectEquals(x, y) {
49+
if (x != y) {
50+
throw "Expected ${x} to be equal to ${y}.";
51+
}
52+
}

0 commit comments

Comments
 (0)