Skip to content

Commit b3b6533

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Create ClassBuilder for extension declarations
Change-Id: Ic372b89588ed9ec3afc43f7db7e3d38a81846ad5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109264 Reviewed-by: Dan Rubel <[email protected]>
1 parent 7075ae7 commit b3b6533

25 files changed

+693
-51
lines changed

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,8 @@ class AstBuilder extends StackListener {
813813
}
814814

815815
@override
816-
void endExtensionDeclaration(Token onKeyword, Token token) {
816+
void endExtensionDeclaration(
817+
Token extensionKeyword, Token onKeyword, Token token) {
817818
TypeAnnotation type = pop();
818819
extensionDeclaration
819820
..extendedType = type

pkg/analyzer/test/generated/parser_fasta_listener.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,9 @@ class ForwardingTestListener extends ForwardingListener {
704704
}
705705

706706
@override
707-
void endExtensionDeclaration(Token onKeyword, Token token) {
708-
super.endExtensionDeclaration(onKeyword, token);
707+
void endExtensionDeclaration(
708+
Token extensionKeyword, Token onKeyword, Token token) {
709+
super.endExtensionDeclaration(extensionKeyword, onKeyword, token);
709710
end('ExtensionDeclaration');
710711
}
711712

pkg/front_end/analysis_options.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
# BSD-style license that can be found in the LICENSE file.
44

55
analyzer:
6+
enable-experiment: [extension-methods]
67
exclude:
8+
- test/extensions/data/**
79
- testcases/**
810
errors:
911
# Allow having TODOs in the code

pkg/front_end/lib/src/fasta/builder/class_builder.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,21 @@ import '../fasta_codes.dart'
2424

2525
abstract class ClassBuilder<T extends TypeBuilder, R>
2626
extends TypeDeclarationBuilder<T, R> {
27+
/// The type variables declared on a class, extension or mixin declaration.
2728
List<TypeVariableBuilder> typeVariables;
2829

30+
/// The type in the `extends` clause of a class declaration.
31+
///
32+
/// Currently this also holds the synthesized super class for a mixin
33+
/// declaration.
2934
T supertype;
3035

36+
/// The type in the `implements` clause of a class or mixin declaration.
3137
List<T> interfaces;
3238

39+
/// The types in the `on` clause of an extension or mixin declaration.
40+
List<T> onTypes;
41+
3342
final Scope scope;
3443

3544
final Scope constructors;
@@ -47,6 +56,7 @@ abstract class ClassBuilder<T extends TypeBuilder, R>
4756
this.typeVariables,
4857
this.supertype,
4958
this.interfaces,
59+
this.onTypes,
5060
this.scope,
5161
this.constructors,
5262
LibraryBuilder parent,

pkg/front_end/lib/src/fasta/builder/modifier_builder.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import '../modifier.dart'
99
abstractMask,
1010
constMask,
1111
covariantMask,
12+
extensionDeclarationMask,
1213
externalMask,
1314
finalMask,
1415
hasConstConstructorMask,
1516
hasInitializerMask,
1617
initializingFormalMask,
18+
mixinDeclarationMask,
1719
namedMixinApplicationMask,
1820
staticMask;
1921

@@ -53,6 +55,10 @@ abstract class ModifierBuilder extends Declaration {
5355

5456
bool get hasConstConstructor => (modifiers & hasConstConstructorMask) != 0;
5557

58+
bool get isMixin => (modifiers & mixinDeclarationMask) != 0;
59+
60+
bool get isExtension => (modifiers & extensionDeclarationMask) != 0;
61+
5662
bool get isClassMember => false;
5763

5864
String get name;

pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class DillClassBuilder extends KernelClassBuilder {
3737
null,
3838
null,
3939
null,
40+
null,
4041
new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
4142
parent.scope, "class ${cls.name}", isModifiable: false),
4243
new Scope(<String, MemberBuilder>{}, null, null, cls.name,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,13 @@ abstract class KernelClassBuilder
136136
List<TypeVariableBuilder> typeVariables,
137137
TypeBuilder supertype,
138138
List<TypeBuilder> interfaces,
139+
List<TypeBuilder> onTypes,
139140
Scope scope,
140141
Scope constructors,
141142
LibraryBuilder parent,
142143
int charOffset)
143144
: super(metadata, modifiers, name, typeVariables, supertype, interfaces,
144-
scope, constructors, parent, charOffset);
145+
onTypes, scope, constructors, parent, charOffset);
145146

146147
Class get cls;
147148

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ class KernelEnumBuilder extends SourceClassBuilder
9393
int startCharOffset,
9494
int charOffset,
9595
int charEndOffset)
96-
: super(metadata, 0, name, null, null, null, scope, constructors, parent,
97-
null, startCharOffset, charOffset, charEndOffset,
96+
: super(metadata, 0, name, null, null, null, null, scope, constructors,
97+
parent, null, startCharOffset, charOffset, charEndOffset,
9898
cls: cls);
9999

100100
factory KernelEnumBuilder(

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

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -279,13 +279,13 @@ class KernelLibraryBuilder extends SourceLibraryBuilder<TypeBuilder, Library> {
279279
List<TypeVariableBuilder> typeVariables,
280280
TypeBuilder supertype,
281281
List<TypeBuilder> interfaces,
282-
int startCharOffset,
283-
int charOffset,
284-
int charEndOffset,
282+
int startOffset,
283+
int nameOffset,
284+
int endOffset,
285285
int supertypeOffset) {
286286
// Nested declaration began in `OutlineBuilder.beginClassDeclaration`.
287-
var declaration = endNestedDeclaration(className)
288-
..resolveTypes(typeVariables, this);
287+
DeclarationBuilder<TypeBuilder> declaration =
288+
endNestedDeclaration(className)..resolveTypes(typeVariables, this);
289289
assert(declaration.parent == libraryDeclaration);
290290
Map<String, MemberBuilder> members = declaration.members;
291291
Map<String, MemberBuilder> constructors = declaration.constructors;
@@ -312,17 +312,20 @@ class KernelLibraryBuilder extends SourceLibraryBuilder<TypeBuilder, Library> {
312312
modifiers,
313313
className,
314314
typeVariables,
315-
applyMixins(supertype, startCharOffset, charOffset, charEndOffset,
316-
className, isMixinDeclaration,
315+
applyMixins(supertype, startOffset, nameOffset, endOffset, className,
316+
isMixinDeclaration,
317317
typeVariables: typeVariables),
318318
interfaces,
319+
// TODO(johnniwinther): Add the `on` clause types of a mixin declaration
320+
// here.
321+
null,
319322
classScope,
320323
constructorScope,
321324
this,
322325
new List<ConstructorReferenceBuilder>.from(constructorReferences),
323-
startCharOffset,
324-
charOffset,
325-
charEndOffset,
326+
startOffset,
327+
nameOffset,
328+
endOffset,
326329
isMixinDeclaration: isMixinDeclaration);
327330
loader.target.metadataCollector
328331
?.setDocumentationComment(cls.target, documentationComment);
@@ -355,7 +358,7 @@ class KernelLibraryBuilder extends SourceLibraryBuilder<TypeBuilder, Library> {
355358
members.forEach(setParentAndCheckConflicts);
356359
constructors.forEach(setParentAndCheckConflicts);
357360
setters.forEach(setParentAndCheckConflicts);
358-
addBuilder(className, cls, charOffset);
361+
addBuilder(className, cls, nameOffset);
359362
}
360363

361364
Map<String, TypeVariableBuilder> checkTypeVariables(
@@ -389,6 +392,91 @@ class KernelLibraryBuilder extends SourceLibraryBuilder<TypeBuilder, Library> {
389392
return typeVariablesByName;
390393
}
391394

395+
@override
396+
void addExtensionDeclaration(
397+
String documentationComment,
398+
List<MetadataBuilder> metadata,
399+
int modifiers,
400+
String extensionName,
401+
List<TypeVariableBuilder> typeVariables,
402+
TypeBuilder type,
403+
int startOffset,
404+
int nameOffset,
405+
int endOffset) {
406+
// Nested declaration began in `OutlineBuilder.beginExtensionDeclaration`.
407+
DeclarationBuilder<TypeBuilder> declaration =
408+
endNestedDeclaration(extensionName)..resolveTypes(typeVariables, this);
409+
assert(declaration.parent == libraryDeclaration);
410+
Map<String, MemberBuilder> members = declaration.members;
411+
Map<String, MemberBuilder> constructors = declaration.constructors;
412+
Map<String, MemberBuilder> setters = declaration.setters;
413+
414+
Scope classScope = new Scope(members, setters,
415+
scope.withTypeVariables(typeVariables), "extension $extensionName",
416+
isModifiable: false);
417+
418+
// When looking up a constructor, we don't consider type variables or the
419+
// library scope.
420+
Scope constructorScope =
421+
new Scope(constructors, null, null, extensionName, isModifiable: false);
422+
bool isMixinDeclaration = false;
423+
if (modifiers & mixinDeclarationMask != 0) {
424+
isMixinDeclaration = true;
425+
modifiers = (modifiers & ~mixinDeclarationMask) | abstractMask;
426+
}
427+
if (declaration.hasConstConstructor) {
428+
modifiers |= hasConstConstructorMask;
429+
}
430+
ClassBuilder cls = new SourceClassBuilder(
431+
metadata,
432+
modifiers,
433+
extensionName,
434+
typeVariables,
435+
null, // No explicit supertype.
436+
null, // No implemented interfaces.
437+
[type],
438+
classScope,
439+
constructorScope,
440+
this,
441+
new List<ConstructorReferenceBuilder>.from(constructorReferences),
442+
startOffset,
443+
nameOffset,
444+
endOffset,
445+
isMixinDeclaration: isMixinDeclaration);
446+
loader.target.metadataCollector
447+
?.setDocumentationComment(cls.target, documentationComment);
448+
449+
constructorReferences.clear();
450+
Map<String, TypeVariableBuilder> typeVariablesByName =
451+
checkTypeVariables(typeVariables, cls);
452+
void setParent(String name, MemberBuilder member) {
453+
while (member != null) {
454+
member.parent = cls;
455+
member = member.next;
456+
}
457+
}
458+
459+
void setParentAndCheckConflicts(String name, MemberBuilder member) {
460+
if (typeVariablesByName != null) {
461+
TypeVariableBuilder tv = typeVariablesByName[name];
462+
if (tv != null) {
463+
cls.addProblem(templateConflictsWithTypeVariable.withArguments(name),
464+
member.charOffset, name.length,
465+
context: [
466+
messageConflictsWithTypeVariableCause.withLocation(
467+
tv.fileUri, tv.charOffset, name.length)
468+
]);
469+
}
470+
}
471+
setParent(name, member);
472+
}
473+
474+
members.forEach(setParentAndCheckConflicts);
475+
constructors.forEach(setParentAndCheckConflicts);
476+
setters.forEach(setParentAndCheckConflicts);
477+
addBuilder(extensionName, cls, nameOffset);
478+
}
479+
392480
TypeBuilder applyMixins(TypeBuilder type, int startCharOffset, int charOffset,
393481
int charEndOffset, String subclassName, bool isMixinDeclaration,
394482
{String documentationComment,
@@ -578,6 +666,7 @@ class KernelLibraryBuilder extends SourceLibraryBuilder<TypeBuilder, Library> {
578666
isNamedMixinApplication
579667
? interfaces
580668
: isMixinDeclaration ? [supertype, mixin] : null,
669+
null, // No `on` clause types.
581670
new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
582671
scope.withTypeVariables(typeVariables),
583672
"mixin $fullname ", isModifiable: false),

pkg/front_end/lib/src/fasta/modifier.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ const int namedMixinApplicationMask = staticMask << 1;
3636
/// keyword.
3737
const int mixinDeclarationMask = namedMixinApplicationMask << 1;
3838

39+
/// Not a modifier, used for extension declarations.
40+
const int extensionDeclarationMask = mixinDeclarationMask << 1;
41+
3942
/// Not a modifier, used by fields to track if they have an initializer.
40-
const int hasInitializerMask = mixinDeclarationMask << 1;
43+
const int hasInitializerMask = extensionDeclarationMask << 1;
4144

4245
/// Not a modifier, used by formal parameters to track if they are initializing.
4346
const int initializingFormalMask = hasInitializerMask << 1;

0 commit comments

Comments
 (0)