Skip to content

Commit bf16a40

Browse files
johnniwintherCommit Queue
authored andcommitted
[_fe_analyzer_shared] Support extensions in macro metadata
Change-Id: I06d3eeab53d8f739ec75dc5795ce46b57ef6f05b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391400 Reviewed-by: Jens Johansen <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 35db90a commit bf16a40

File tree

7 files changed

+223
-2
lines changed

7 files changed

+223
-2
lines changed

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

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

413+
/// A [reference] to an extension
414+
///
415+
/// The [Proto] includes the [scope] of the extension, which is used to resolve
416+
/// access to static members on the extension.
417+
class ExtensionProto extends Proto {
418+
final ExtensionReference reference;
419+
final TypeDeclarationScope scope;
420+
421+
ExtensionProto(this.reference, this.scope);
422+
423+
@override
424+
String toString() => 'ExtensionProto($reference)';
425+
426+
@override
427+
Proto access(String? name) {
428+
if (name == null) {
429+
return this;
430+
}
431+
if (name == 'new') {
432+
name = '';
433+
}
434+
return scope.lookup(name);
435+
}
436+
437+
@override
438+
Proto instantiate(List<TypeAnnotation>? typeArguments) {
439+
return typeArguments != null
440+
? new InvalidInstantiationProto(this, typeArguments)
441+
: this;
442+
}
443+
444+
@override
445+
Proto invoke(List<Argument>? arguments) {
446+
return arguments != null
447+
? new InvalidInvocationProto(this, const [], arguments)
448+
: this;
449+
}
450+
451+
@override
452+
Expression toExpression() {
453+
return new InvalidExpression();
454+
}
455+
456+
@override
457+
TypeAnnotation toTypeAnnotation() => new InvalidTypeAnnotation();
458+
459+
@override
460+
Proto? resolve() => null;
461+
}
462+
413463
/// A [reference] to a class instantiated with [typeArguments].
414464
///
415465
/// The [Proto] includes the [scope] of the class, which is used to resolve

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ abstract class TypedefReference extends Reference {
5252
String toString() => 'TypedefReference(${name})';
5353
}
5454

55+
abstract class ExtensionReference extends Reference {
56+
String get name;
57+
58+
@override
59+
String toString() => 'ExtensionReference(${name})';
60+
}
61+
5562
abstract class FunctionTypeParameterReference extends Reference {
5663
String get name;
5764

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,26 @@ abstract base class BaseClassScope implements TypeDeclarationScope {
5555
}
5656
}
5757

58+
/// Base implementation for creating a [TypeDeclarationScope] for an extension.
59+
abstract base class BaseExtensionScope implements TypeDeclarationScope {
60+
ExtensionReference get extensionReference;
61+
62+
Proto createMemberProto<T>(List<TypeAnnotation>? typeArguments, String name,
63+
T? member, Proto Function(T, String) memberToProto) {
64+
if (typeArguments != null) {
65+
return new UnresolvedAccess(
66+
new InvalidInstantiationProto(
67+
new ExtensionProto(extensionReference, this), typeArguments),
68+
name);
69+
} else if (member == null) {
70+
return new UnresolvedAccess(
71+
new ExtensionProto(extensionReference, this), name);
72+
} else {
73+
return memberToProto(member, name);
74+
}
75+
}
76+
}
77+
5878
/// Base implementation for creating a [TypeDeclarationScope] for a typedef.
5979
abstract base class BaseTypedefScope implements TypeDeclarationScope {
6080
TypedefReference get typedefReference;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ class Writer {
284284
_write(reference.name);
285285
case TypedefReference():
286286
_write(reference.name);
287+
case ExtensionReference():
288+
_write(reference.name);
287289
case FunctionTypeParameterReference():
288290
_write(reference.name);
289291
}
@@ -616,6 +618,10 @@ class Writer {
616618
_referenceToText(proto.reference);
617619
_typeArgumentsToText(proto.typeArguments);
618620
_write(')');
621+
case ExtensionProto():
622+
_write('ExtensionProto(');
623+
_referenceToText(proto.reference);
624+
_write(')');
619625
case TypedefProto():
620626
_write('TypedefProto(');
621627
_referenceToText(proto.reference);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
extension Extension on int {
13+
static const variable = 0;
14+
15+
static void method() {}
16+
17+
static void genericMethod<T>() {}
18+
}
19+
20+
@Extension.variable
21+
/*member: extensionConstant1:
22+
StaticGet(variable)*/
23+
void extensionConstant1() {}
24+
25+
@self.Extension.variable
26+
/*member: extensionConstant2:
27+
StaticGet(variable)*/
28+
void extensionConstant2() {}
29+
30+
@Extension.unresolved
31+
/*member: extensionConstant3:
32+
UnresolvedExpression(UnresolvedAccess(
33+
ExtensionProto(Extension).unresolved))*/
34+
void extensionConstant3() {}
35+
36+
@self.Extension.unresolved
37+
/*member: extensionConstant4:
38+
UnresolvedExpression(UnresolvedAccess(
39+
ExtensionProto(Extension).unresolved))*/
40+
void extensionConstant4() {}
41+
42+
@Helper(Extension.method)
43+
/*member: extensionConstant5:
44+
FunctionTearOff(method)*/
45+
void extensionConstant5() {}
46+
47+
@Helper(self.Extension.method)
48+
/*member: extensionConstant6:
49+
FunctionTearOff(method)*/
50+
void extensionConstant6() {}
51+
52+
@Helper(Extension.genericMethod)
53+
/*member: extensionConstant7:
54+
FunctionTearOff(genericMethod)*/
55+
void extensionConstant7() {}
56+
57+
@Helper(self.Extension.genericMethod)
58+
/*member: extensionConstant8:
59+
FunctionTearOff(genericMethod)*/
60+
void extensionConstant8() {}
61+
62+
@Helper(Extension.genericMethod<int>)
63+
/*member: extensionConstant9:
64+
Instantiation(FunctionTearOff(genericMethod)<int>)*/
65+
void extensionConstant9() {}
66+
67+
@Helper(self.Extension.genericMethod<int>)
68+
/*member: extensionConstant10:
69+
Instantiation(FunctionTearOff(genericMethod)<int>)*/
70+
void extensionConstant10() {}
71+
72+
@Helper(Extension.unresolved<int>)
73+
/*member: extensionConstant11:
74+
UnresolvedExpression(UnresolvedInstantiate(
75+
UnresolvedAccess(
76+
ExtensionProto(Extension).unresolved)<int>))*/
77+
void extensionConstant11() {}

pkg/analyzer/lib/src/summary2/macro_metadata.dart

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,13 @@ shared.Proto _elementToProto(Element element, String name) {
5252
} else if (element is TypeAliasElement) {
5353
var reference = _TypedefReference(element);
5454
return shared.TypedefProto(reference, _TypedefScope(element, reference));
55+
} else if (element is ExtensionElement) {
56+
var reference = _ExtensionReference(element);
57+
return shared.ExtensionProto(
58+
reference, _ExtensionScope(element, reference));
5559
}
5660

57-
// TODO(johnniwinther): Support extension and extension types.
61+
// TODO(johnniwinther): Support extension types.
5862
throw UnsupportedError(
5963
"Unsupported element $element (${element.runtimeType}) for '$name'.");
6064
}
@@ -106,6 +110,32 @@ class _DynamicReference extends shared.TypeReference {
106110
String get name => 'dynamic';
107111
}
108112

113+
class _ExtensionReference extends shared.ExtensionReference {
114+
final ExtensionElement _element;
115+
116+
_ExtensionReference(this._element);
117+
118+
@override
119+
String get name => _element.name!;
120+
}
121+
122+
final class _ExtensionScope extends shared.BaseExtensionScope {
123+
final ExtensionElement _extensionElement;
124+
125+
@override
126+
final _ExtensionReference extensionReference;
127+
128+
_ExtensionScope(this._extensionElement, this.extensionReference);
129+
130+
@override
131+
shared.Proto lookup(String name,
132+
[List<shared.TypeAnnotation>? typeArguments]) {
133+
Element? member = _extensionElement.augmented.getField(name);
134+
member ??= _extensionElement.augmented.getMethod(name);
135+
return createMemberProto(typeArguments, name, member, _elementToProto);
136+
}
137+
}
138+
109139
class _FunctionReference extends shared.FunctionReference {
110140
final ExecutableElement _element;
111141

pkg/front_end/lib/src/kernel/macro/metadata.dart

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,13 @@ shared.Proto builderToProto(Builder builder, String name) {
5959
shared.TypedefReference typedefReference = new TypedefReference(builder);
6060
return new shared.TypedefProto(
6161
typedefReference, new TypedefScope(builder, typedefReference));
62+
} else if (builder is ExtensionBuilder) {
63+
shared.ExtensionReference extensionReference =
64+
new ExtensionReference(builder);
65+
return new shared.ExtensionProto(
66+
extensionReference, new ExtensionScope(builder, extensionReference));
6267
} else {
63-
// TODO(johnniwinther): Support extension and extension types.
68+
// TODO(johnniwinther): Support extension types.
6469
throw new UnsupportedError("Unsupported builder $builder for $name");
6570
}
6671
}
@@ -139,6 +144,22 @@ final class ClassScope extends shared.BaseClassScope {
139144
}
140145
}
141146

147+
// Coverage-ignore(suite): Not run.
148+
final class ExtensionScope extends shared.BaseExtensionScope {
149+
final ExtensionBuilder builder;
150+
@override
151+
final shared.ExtensionReference extensionReference;
152+
153+
ExtensionScope(this.builder, this.extensionReference);
154+
155+
@override
156+
shared.Proto lookup(String name,
157+
[List<shared.TypeAnnotation>? typeArguments]) {
158+
Builder? member = builder.lookupLocalMember(name, setter: false);
159+
return createMemberProto(typeArguments, name, member, builderToProto);
160+
}
161+
}
162+
142163
// Coverage-ignore(suite): Not run.
143164
final class TypedefScope extends shared.BaseTypedefScope {
144165
final TypeAliasBuilder builder;
@@ -243,6 +264,16 @@ class ClassReference extends shared.ClassReference {
243264
String get name => builder.name;
244265
}
245266

267+
// Coverage-ignore(suite): Not run.
268+
class ExtensionReference extends shared.ExtensionReference {
269+
final ExtensionBuilder builder;
270+
271+
ExtensionReference(this.builder);
272+
273+
@override
274+
String get name => builder.name;
275+
}
276+
246277
// Coverage-ignore(suite): Not run.
247278
class TypedefReference extends shared.TypedefReference {
248279
final TypeAliasBuilder builder;

0 commit comments

Comments
 (0)