Skip to content

Commit c0381d0

Browse files
johnniwintherCommit Queue
authored andcommitted
[_fe_analyzer_shared] Support enums in macro metadata
Change-Id: Ic6534fcbd48881184d6cb64c556d638f3e1d97b5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391601 Commit-Queue: Johnni Winther <[email protected]> Reviewed-by: Jens Johansen <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent 875a130 commit c0381d0

File tree

7 files changed

+376
-12
lines changed

7 files changed

+376
-12
lines changed

pkg/_fe_analyzer_shared/lib/src/metadata/proto.dart

Lines changed: 115 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,62 @@ class ClassProto extends Proto {
410410
Proto? resolve() => null;
411411
}
412412

413+
/// A [reference] to a class instantiated with [typeArguments].
414+
///
415+
/// The [Proto] includes the [scope] of the class, which is used to resolve
416+
/// access to constructors on the class.
417+
class GenericClassProto extends Proto {
418+
final ClassReference reference;
419+
final TypeDeclarationScope scope;
420+
final List<TypeAnnotation> typeArguments;
421+
422+
GenericClassProto(this.reference, this.scope, this.typeArguments);
423+
424+
@override
425+
String toString() => 'GenericClassProto($reference,$typeArguments)';
426+
427+
@override
428+
Proto access(String? name) {
429+
if (name == null) {
430+
return this;
431+
}
432+
if (name == 'new') {
433+
name = '';
434+
}
435+
return scope.lookup(name, typeArguments);
436+
}
437+
438+
@override
439+
Proto instantiate(List<TypeAnnotation>? typeArguments) {
440+
return typeArguments != null
441+
? throw new UnimplementedError('GenericClassProto.instantiate')
442+
: this;
443+
}
444+
445+
@override
446+
Proto invoke(List<Argument>? arguments) {
447+
return arguments != null ? access('new').invoke(arguments) : this;
448+
}
449+
450+
@override
451+
Expression toExpression() {
452+
return new TypeLiteral(toTypeAnnotation());
453+
}
454+
455+
@override
456+
TypeAnnotation toTypeAnnotation() =>
457+
new NamedTypeAnnotation(reference, typeArguments);
458+
459+
@override
460+
Proto? resolve() {
461+
List<TypeAnnotation>? newTypeArguments =
462+
typeArguments.resolve((a) => a.resolve());
463+
return newTypeArguments == null
464+
? null
465+
: new GenericClassProto(reference, scope, newTypeArguments);
466+
}
467+
}
468+
413469
/// A [reference] to an extension
414470
///
415471
/// The [Proto] includes the [scope] of the extension, which is used to resolve
@@ -460,19 +516,69 @@ class ExtensionProto extends Proto {
460516
Proto? resolve() => null;
461517
}
462518

463-
/// A [reference] to a class instantiated with [typeArguments].
519+
/// A [reference] to an enum
464520
///
465-
/// The [Proto] includes the [scope] of the class, which is used to resolve
466-
/// access to constructors on the class.
467-
class GenericClassProto extends Proto {
468-
final ClassReference reference;
521+
/// The [Proto] includes the [scope] of the enum, which is used to resolve
522+
/// access to static members on the enum.
523+
class EnumProto extends Proto {
524+
final EnumReference reference;
525+
final TypeDeclarationScope scope;
526+
527+
EnumProto(this.reference, this.scope);
528+
529+
@override
530+
String toString() => 'EnumProto($reference)';
531+
532+
@override
533+
Proto access(String? name) {
534+
if (name == null) {
535+
return this;
536+
}
537+
if (name == 'new') {
538+
name = '';
539+
}
540+
return scope.lookup(name);
541+
}
542+
543+
@override
544+
Proto instantiate(List<TypeAnnotation>? typeArguments) {
545+
return typeArguments != null
546+
? new GenericEnumProto(reference, scope, typeArguments)
547+
: this;
548+
}
549+
550+
@override
551+
Proto invoke(List<Argument>? arguments) {
552+
return arguments != null
553+
? new InvalidInvocationProto(this, const [], arguments)
554+
: this;
555+
}
556+
557+
@override
558+
Expression toExpression() {
559+
return new TypeLiteral(toTypeAnnotation());
560+
}
561+
562+
@override
563+
TypeAnnotation toTypeAnnotation() => new NamedTypeAnnotation(reference);
564+
565+
@override
566+
Proto? resolve() => null;
567+
}
568+
569+
/// A [reference] to an enum instantiated with [typeArguments].
570+
///
571+
/// The [Proto] includes the [scope] of the enum, which is used to resolve
572+
/// access to constructors on the enum.
573+
class GenericEnumProto extends Proto {
574+
final EnumReference reference;
469575
final TypeDeclarationScope scope;
470576
final List<TypeAnnotation> typeArguments;
471577

472-
GenericClassProto(this.reference, this.scope, this.typeArguments);
578+
GenericEnumProto(this.reference, this.scope, this.typeArguments);
473579

474580
@override
475-
String toString() => 'GenericClassProto($reference,$typeArguments)';
581+
String toString() => 'GenericEnumProto($reference,$typeArguments)';
476582

477583
@override
478584
Proto access(String? name) {
@@ -488,7 +594,7 @@ class GenericClassProto extends Proto {
488594
@override
489595
Proto instantiate(List<TypeAnnotation>? typeArguments) {
490596
return typeArguments != null
491-
? throw new UnimplementedError('GenericClassProto.instantiate')
597+
? throw new UnimplementedError('$this.instantiate')
492598
: this;
493599
}
494600

@@ -512,7 +618,7 @@ class GenericClassProto extends Proto {
512618
typeArguments.resolve((a) => a.resolve());
513619
return newTypeArguments == null
514620
? null
515-
: new GenericClassProto(reference, scope, newTypeArguments);
621+
: new GenericEnumProto(reference, scope, newTypeArguments);
516622
}
517623
}
518624

pkg/_fe_analyzer_shared/lib/src/metadata/references.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ abstract class ExtensionTypeReference extends Reference {
6666
String toString() => 'ExtensionTypeReference(${name})';
6767
}
6868

69+
abstract class EnumReference extends Reference {
70+
String get name;
71+
72+
@override
73+
String toString() => 'EnumReference(${name})';
74+
}
75+
6976
abstract class FunctionTypeParameterReference extends Reference {
7077
String get name;
7178

pkg/_fe_analyzer_shared/lib/src/metadata/scope.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,32 @@ abstract base class BaseExtensionTypeScope implements TypeDeclarationScope {
111111
}
112112
}
113113

114+
/// Base implementation for creating a [TypeDeclarationScope] for an enum.
115+
abstract base class BaseEnumScope implements TypeDeclarationScope {
116+
EnumReference get enumReference;
117+
118+
// TODO(johnniwinther): Support constructor lookup to support full parsing.
119+
120+
Proto createMemberProto<T>(List<TypeAnnotation>? typeArguments, String name,
121+
T? member, Proto Function(T, String) memberToProto) {
122+
if (member == null) {
123+
if (typeArguments != null) {
124+
return new UnresolvedAccess(
125+
new GenericEnumProto(enumReference, this, typeArguments), name);
126+
} else {
127+
return new UnresolvedAccess(new EnumProto(enumReference, this), name);
128+
}
129+
} else {
130+
if (typeArguments != null) {
131+
return new InvalidAccessProto(
132+
new GenericEnumProto(enumReference, this, typeArguments), name);
133+
} else {
134+
return memberToProto(member, name);
135+
}
136+
}
137+
}
138+
}
139+
114140
/// Base implementation for creating a [TypeDeclarationScope] for a typedef.
115141
abstract base class BaseTypedefScope implements TypeDeclarationScope {
116142
TypedefReference get typedefReference;

pkg/_fe_analyzer_shared/lib/src/testing/metadata_helper.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ class Writer {
288288
_write(reference.name);
289289
case ExtensionTypeReference():
290290
_write(reference.name);
291+
case EnumReference():
292+
_write(reference.name);
291293
case FunctionTypeParameterReference():
292294
_write(reference.name);
293295
}
@@ -620,6 +622,15 @@ class Writer {
620622
_referenceToText(proto.reference);
621623
_typeArgumentsToText(proto.typeArguments);
622624
_write(')');
625+
case EnumProto():
626+
_write('EnumProto(');
627+
_referenceToText(proto.reference);
628+
_write(')');
629+
case GenericEnumProto():
630+
_write('GenericEnumProto(');
631+
_referenceToText(proto.reference);
632+
_typeArgumentsToText(proto.typeArguments);
633+
_write(')');
623634
case ExtensionProto():
624635
_write('ExtensionProto(');
625636
_referenceToText(proto.reference);
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright (c) 2024, 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+
import 'dart:async';
6+
import 'main.dart' as self;
7+
8+
class Helper {
9+
const Helper(a);
10+
}
11+
12+
enum Enum {
13+
a,
14+
b;
15+
16+
static const int variable = 42;
17+
static void method() {}
18+
static void genericMethod<T>() {}
19+
}
20+
21+
enum GenericEnum<T> {
22+
a<int>(),
23+
b<String>()
24+
}
25+
26+
@Enum.a
27+
/*member: enumConstant1:
28+
StaticGet(a)*/
29+
void enumConstant1() {}
30+
31+
@self.Enum.b
32+
/*member: enumConstant2:
33+
StaticGet(b)*/
34+
void enumConstant2() {}
35+
36+
@Enum.variable
37+
/*member: enumConstant3:
38+
StaticGet(variable)*/
39+
void enumConstant3() {}
40+
41+
@self.Enum.variable
42+
/*member: enumConstant4:
43+
StaticGet(variable)*/
44+
void enumConstant4() {}
45+
46+
@Enum.values
47+
/*member: enumConstant5:
48+
StaticGet(values)*/
49+
void enumConstant5() {}
50+
51+
@self.Enum.values
52+
/*member: enumConstant6:
53+
StaticGet(values)*/
54+
void enumConstant6() {}
55+
56+
@GenericEnum.a
57+
/*member: enumConstant7:
58+
StaticGet(a)*/
59+
void enumConstant7() {}
60+
61+
@self.GenericEnum.b
62+
/*member: enumConstant8:
63+
StaticGet(b)*/
64+
void enumConstant8() {}
65+
66+
@Helper(Enum)
67+
/*member: enumConstant9:
68+
TypeLiteral(Enum)*/
69+
void enumConstant9() {}
70+
71+
@Helper(self.Enum)
72+
/*member: enumConstant10:
73+
TypeLiteral(Enum)*/
74+
void enumConstant10() {}
75+
76+
@Helper(Enum.method)
77+
/*member: enumConstant11:
78+
FunctionTearOff(method)*/
79+
void enumConstant11() {}
80+
81+
@Helper(self.Enum.method)
82+
/*member: enumConstant12:
83+
FunctionTearOff(method)*/
84+
void enumConstant12() {}
85+
86+
@Helper(Enum.genericMethod)
87+
/*member: enumConstant13:
88+
FunctionTearOff(genericMethod)*/
89+
void enumConstant13() {}
90+
91+
@Helper(self.Enum.genericMethod)
92+
/*member: enumConstant14:
93+
FunctionTearOff(genericMethod)*/
94+
void enumConstant14() {}
95+
96+
@Helper(Enum.genericMethod<int>)
97+
/*member: enumConstant15:
98+
Instantiation(FunctionTearOff(genericMethod)<int>)*/
99+
void enumConstant15() {}
100+
101+
@Helper(self.Enum.genericMethod<int>)
102+
/*member: enumConstant16:
103+
Instantiation(FunctionTearOff(genericMethod)<int>)*/
104+
void enumConstant16() {}
105+
106+
@Helper(GenericEnum)
107+
/*member: enumConstant17:
108+
TypeLiteral(GenericEnum)*/
109+
void enumConstant17() {}
110+
111+
@Helper(self.GenericEnum)
112+
/*member: enumConstant18:
113+
TypeLiteral(GenericEnum)*/
114+
void enumConstant18() {}
115+
116+
@Helper(GenericEnum<bool>)
117+
/*member: enumConstant19:
118+
TypeLiteral(GenericEnum<bool>)*/
119+
void enumConstant19() {}
120+
121+
@Helper(self.GenericEnum<double>)
122+
/*member: enumConstant20:
123+
TypeLiteral(GenericEnum<double>)*/
124+
void enumConstant20() {}
125+
126+
@Helper(Enum.unresolved)
127+
/*member: enumConstant21:
128+
UnresolvedExpression(UnresolvedAccess(
129+
EnumProto(Enum).unresolved))*/
130+
void enumConstant21() {}
131+
132+
@Helper(self.Enum.unresolved)
133+
/*member: enumConstant22:
134+
UnresolvedExpression(UnresolvedAccess(
135+
EnumProto(Enum).unresolved))*/
136+
void enumConstant22() {}
137+
138+
@Helper(Enum.unresolved<int>)
139+
/*member: enumConstant23:
140+
UnresolvedExpression(UnresolvedInstantiate(
141+
UnresolvedAccess(
142+
EnumProto(Enum).unresolved)<int>))*/
143+
void enumConstant23() {}
144+
145+
@Helper(self.Enum.unresolved<int>)
146+
/*member: enumConstant24:
147+
UnresolvedExpression(UnresolvedInstantiate(
148+
UnresolvedAccess(
149+
EnumProto(Enum).unresolved)<int>))*/
150+
void enumConstant24() {}
151+
152+
153+

0 commit comments

Comments
 (0)