Skip to content

Commit

Permalink
[cfe] Build extension methods as toplevel members
Browse files Browse the repository at this point in the history
+ add an 'isExtensionMethod' property to Procedure.

Change-Id: I8fb1af1802570c827bf3ccbbb9d710eb2a6981ab
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112081
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
johnniwinther authored and commit-bot@chromium.org committed Aug 8, 2019
1 parent 7bde331 commit e9a9d94
Show file tree
Hide file tree
Showing 25 changed files with 291 additions and 190 deletions.
21 changes: 19 additions & 2 deletions pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,15 @@ class ProcedureBuilder extends FunctionBuilder {
return false;
}

/// Returns `true` if this procedure is declared in an extension declaration.
bool get isExtensionMethod {
if (parent is ClassBuilder) {
ClassBuilder cls = parent;
return cls.isExtension;
}
return false;
}

Procedure build(SourceLibraryBuilder library) {
// TODO(ahe): I think we may call this twice on parts. Investigate.
if (procedure.name == null) {
Expand All @@ -496,10 +505,18 @@ class ProcedureBuilder extends FunctionBuilder {
procedure.function.fileOffset = charOpenParenOffset;
procedure.function.fileEndOffset = procedure.fileEndOffset;
procedure.isAbstract = isAbstract;
procedure.isStatic = isStatic;
procedure.isExternal = isExternal;
procedure.isConst = isConst;
procedure.name = new Name(name, library.target);
if (isExtensionMethod) {
ClassBuilder extension = parent;
procedure.isStatic = false;
procedure.isExtensionMethod = true;
procedure.kind = ProcedureKind.Method;
procedure.name = new Name('${extension.name}|${name}', library.target);
} else {
procedure.isStatic = isStatic;
procedure.name = new Name(name, library.target);
}
}
return procedure;
}
Expand Down
10 changes: 7 additions & 3 deletions pkg/front_end/lib/src/fasta/source/source_class_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,13 @@ class SourceClassBuilder extends ClassBuilder
}
} else if (declaration is FunctionBuilder) {
Member function = declaration.build(library);
function.parent = cls;
if (!declaration.isPatch && declaration.next == null) {
cls.addMember(function);
if (isExtension) {
library.target.addMember(function);
} else {
function.parent = cls;
if (!declaration.isPatch && declaration.next == null) {
cls.addMember(function);
}
}
} else {
unhandled("${declaration.runtimeType}", "buildBuilders",
Expand Down
36 changes: 25 additions & 11 deletions pkg/front_end/lib/src/testing/id_testing_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,36 @@ ClassBuilder lookupClassBuilder(CompilerResult compilerResult, Class cls,
return clsBuilder;
}

/// Look up the [MemberBuilder] for [member] through the [ClassBuilder] for
/// [cls] using [memberName] as its name.
MemberBuilder lookupClassMemberBuilder(
CompilerResult compilerResult, Class cls, Member member, String memberName,
{bool required: true}) {
ClassBuilder classBuilder =
lookupClassBuilder(compilerResult, cls, required: required);
MemberBuilder memberBuilder;
if (classBuilder != null) {
if (member is Constructor) {
memberBuilder = classBuilder.constructors.local[memberName];
} else if (member is Procedure && member.isSetter) {
memberBuilder = classBuilder.scope.setters[memberName];
} else {
memberBuilder = classBuilder.scope.local[memberName];
}
}
if (memberBuilder == null && required) {
throw new ArgumentError("MemberBuilder for $member not found.");
}
return memberBuilder;
}

MemberBuilder lookupMemberBuilder(CompilerResult compilerResult, Member member,
{bool required: true}) {
MemberBuilder memberBuilder;
if (member.enclosingClass != null) {
ClassBuilder classBuilder = lookupClassBuilder(
compilerResult, member.enclosingClass,
memberBuilder = lookupClassMemberBuilder(
compilerResult, member.enclosingClass, member, member.name.name,
required: required);
if (classBuilder != null) {
if (member is Constructor) {
memberBuilder = classBuilder.constructors.local[member.name.name];
} else if (member is Procedure && member.isSetter) {
memberBuilder = classBuilder.scope.setters[member.name.name];
} else {
memberBuilder = classBuilder.scope.local[member.name.name];
}
}
} else {
DeclarationBuilder libraryBuilder = lookupLibraryDeclarationBuilder(
compilerResult, member.enclosingLibrary);
Expand Down
12 changes: 6 additions & 6 deletions pkg/front_end/test/extensions/data/explicit_this.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ class A1 {
cls-supertype=Object
*/
extension A2 on A1 {
/*member: A2.method2:
/*member: A2|method2:
builder-name=method2,
builder-params=[#this],
member-name=method2,
member-name=A2|method2,
member-params=[#this]
*/
void method2() => this.method1();

/*member: A2.method3:
/*member: A2|method3:
builder-name=method3,
builder-params=[#this],
member-name=method3,
member-name=A2|method3,
member-params=[#this]
*/
Object method3() => this.field;

/*member: A2.method4:
/*member: A2|method4:
builder-name=method4,
builder-params=[#this,o],
member-name=method4,
member-name=A2|method4,
member-params=[#this,o]
*/
void method4(Object o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
cls-type-params=[T]
*/
extension GeneralGeneric<T> on T {
/*member: GeneralGeneric.method:
/*member: GeneralGeneric|method:
builder-name=method,
builder-params=[#this],
builder-type-params=[T],
member-name=method,
member-name=GeneralGeneric|method,
member-params=[#this],
member-type-params=[#T]
*/
Expand Down
12 changes: 6 additions & 6 deletions pkg/front_end/test/extensions/data/implicit_this.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ class A1 {
cls-supertype=Object
*/
extension A2 on A1 {
/*member: A2.method2:
/*member: A2|method2:
builder-name=method2,
builder-params=[#this],
member-name=method2,
member-name=A2|method2,
member-params=[#this]
*/
void method2() => method1();

/*member: A2.method3:
/*member: A2|method3:
builder-name=method3,
builder-params=[#this],
member-name=method3,
member-name=A2|method3,
member-params=[#this]
*/
Object method3() => field;

/*member: A2.method4:
/*member: A2|method4:
builder-name=method4,
builder-params=[#this,o],
member-name=method4,
member-name=A2|method4,
member-params=[#this,o]
*/
void method4(Object o) {
Expand Down
24 changes: 12 additions & 12 deletions pkg/front_end/test/extensions/data/instance_members.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ class A1 {}
cls-supertype=Object
*/
extension A2 on A1 {
/*member: A2.method1:
/*member: A2|method1:
builder-name=method1,
builder-params=[#this],
member-name=method1,
member-name=A2|method1,
member-params=[#this]
*/
A1 method1() {
return this;
}

/*member: A2.method2:
/*member: A2|method2:
builder-name=method2,
builder-params=[#this,o],
builder-type-params=[T],
member-name=method2,
member-name=A2|method2,
member-params=[#this,o],
member-type-params=[T]
*/
Expand All @@ -35,12 +35,12 @@ extension A2 on A1 {
return this;
}

/*member: A2.method3:
/*member: A2|method3:
builder-name=method3,
builder-params=[#this],
builder-pos-params=[o],
builder-type-params=[T],
member-name=method3,
member-name=A2|method3,
member-params=[#this],
member-pos-params=[o],
member-type-params=[T]
Expand All @@ -50,12 +50,12 @@ extension A2 on A1 {
return this;
}

/*member: A2.method4:
/*member: A2|method4:
builder-name=method4,
builder-params=[#this],
builder-named-params=[o],
builder-type-params=[T],
member-name=method4,
member-name=A2|method4,
member-params=[#this],
member-named-params=[o],
member-type-params=[T]
Expand All @@ -78,23 +78,23 @@ class B1<T> {}
cls-type-params=[T]
*/
extension B2<T> on B1<T> {
/*member: B2.method1:
/*member: B2|method1:
builder-name=method1,
builder-params=[#this],
builder-type-params=[T],
member-name=method1,
member-name=B2|method1,
member-params=[#this],
member-type-params=[#T]
*/
B1<T> method1() {
return this;
}

/*member: B2.method2:
/*member: B2|method2:
builder-name=method2,
builder-params=[#this,o],
builder-type-params=[T,S],
member-name=method2,
member-name=B2|method2,
member-params=[#this,o],
member-type-params=[#T,S]
*/
Expand Down
16 changes: 8 additions & 8 deletions pkg/front_end/test/extensions/data/static_members.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ class A1 {}
cls-supertype=Object
*/
extension A2 on A1 {
/*member: A2.method1:
/*member: A2|method1:
builder-name=method1,
builder-params=[o],
member-name=method1,
member-name=A2|method1,
member-params=[o]
*/
static A1 method1(A1 o) => o;

/*member: A2.method2:
/*member: A2|method2:
builder-name=method2,
builder-params=[o],
builder-type-params=[T],
member-name=method2,
member-name=A2|method2,
member-params=[o],
member-type-params=[T]
*/
Expand All @@ -43,19 +43,19 @@ class B1<T> {}
cls-type-params=[T]
*/
extension B2<T> on B1<T> {
/*member: B2.method1:
/*member: B2|method1:
builder-name=method1,
builder-params=[o],
member-name=method1,
member-name=B2|method1,
member-params=[o]
*/
static B1 method1(B1 o) => o;

/*member: B2.method2:
/*member: B2|method2:
builder-name=method2,
builder-params=[o],
builder-type-params=[S],
member-name=method2,
member-name=B2|method2,
member-params=[o],
member-type-params=[S]
*/
Expand Down
4 changes: 2 additions & 2 deletions pkg/front_end/test/extensions/data/super.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ class A1 {
cls-supertype=Object
*/
extension A2 on A1 {
/*member: A2.method2:
/*member: A2|method2:
builder-name=method2,
builder-params=[#this],
member-name=method2,
member-name=A2|method2,
member-params=[#this]
*/
method2() {
Expand Down
8 changes: 4 additions & 4 deletions pkg/front_end/test/extensions/data/type_variables.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ class A1<T> {}
cls-type-params=[T]
*/
extension A2<T> on A1<T> {
/*member: A2.method1:
/*member: A2|method1:
builder-name=method1,
builder-params=[#this],
builder-type-params=[T,S extends T],
member-name=method1,
member-name=A2|method1,
member-params=[#this],
member-type-params=[#T,S extends #T]
*/
A1<T> method1<S extends T>() {
return this;
}

/*member: A2.method2:
/*member: A2|method2:
builder-name=method2,
builder-params=[#this,o],
builder-type-params=[T,S extends A1<T>],
member-name=method2,
member-name=A2|method2,
member-params=[#this,o],
member-type-params=[#T,S extends A1<#T>]
*/
Expand Down
Loading

0 comments on commit e9a9d94

Please sign in to comment.