44
55library fasta.procedure_builder;
66
7- import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
7+ import 'dart:core' hide MapEntry;
8+
9+ import 'package:kernel/ast.dart' ;
10+
811import 'package:kernel/type_algebra.dart' ;
912
1013import 'builder.dart'
@@ -19,38 +22,7 @@ import 'builder.dart'
1922 TypeVariableBuilder;
2023
2124import 'extension_builder.dart' ;
22-
23- import 'package:kernel/ast.dart'
24- show
25- Arguments,
26- AsyncMarker,
27- Block,
28- Class,
29- Constructor,
30- ConstructorInvocation,
31- DartType,
32- DynamicType,
33- EmptyStatement,
34- Expression,
35- FunctionNode,
36- Initializer,
37- InterfaceType,
38- Member,
39- Name,
40- Procedure,
41- ProcedureKind,
42- RedirectingInitializer,
43- ReturnStatement,
44- Statement,
45- StaticInvocation,
46- StringLiteral,
47- SuperInitializer,
48- TreeNode,
49- TypeParameter,
50- TypeParameterType,
51- VariableDeclaration,
52- VariableGet,
53- setParents;
25+ import 'type_variable_builder.dart' ;
5426
5527import '../../scanner/token.dart' show Token;
5628
@@ -475,6 +447,10 @@ class ProcedureBuilder extends FunctionBuilder {
475447
476448 bool hadTypesInferred = false ;
477449
450+ /// If this is an extension instance method then [_extensionTearOff] holds
451+ /// the synthetically created tear off function.
452+ Procedure _extensionTearOff;
453+
478454 ProcedureBuilder (
479455 List <MetadataBuilder > metadata,
480456 int modifiers,
@@ -600,7 +576,7 @@ class ProcedureBuilder extends FunctionBuilder {
600576 _procedure.isExternal = isExternal;
601577 _procedure.isConst = isConst;
602578 if (isExtensionMethod) {
603- ExtensionBuilder extension = parent;
579+ ExtensionBuilder extensionBuilder = parent;
604580 procedure.isExtensionMember = true ;
605581 procedure.isStatic = true ;
606582 String kindInfix = '' ;
@@ -625,18 +601,169 @@ class ProcedureBuilder extends FunctionBuilder {
625601 procedure.kind = ProcedureKind .Method ;
626602 }
627603 procedure.name = new Name (
628- '${extension .name }|${kindInfix }${name }' , libraryBuilder.library);
604+ '${extensionBuilder .name }|${kindInfix }${name }' ,
605+ libraryBuilder.library);
629606 } else {
630607 _procedure.isStatic = isStatic;
631608 _procedure.name = new Name (name, libraryBuilder.library);
632609 }
633610 }
611+ if (extensionTearOff != null ) {
612+ _buildExtensionTearOff (libraryBuilder, parent);
613+ }
634614 return _procedure;
635615 }
636616
617+ /// Creates a top level function that creates a tear off of an extension
618+ /// instance method.
619+ ///
620+ /// For this declaration
621+ ///
622+ /// extension E<T> on A<T> {
623+ /// X method<S>(S s, Y y) {}
624+ /// }
625+ ///
626+ /// we create the top level function
627+ ///
628+ /// X E|method<T, S>(A<T> #this, S s, Y y) {}
629+ ///
630+ /// and the tear off function
631+ ///
632+ /// X Function<S>(S, Y) E|get#method<T>(A<T> #this) {
633+ /// return (S s, Y y) => E|method<T, S>(#this, s, y);
634+ /// }
635+ ///
636+ void _buildExtensionTearOff (
637+ SourceLibraryBuilder libraryBuilder, ExtensionBuilder extensionBuilder) {
638+ assert (
639+ _extensionTearOff != null , "No extension tear off created for $this ." );
640+ if (_extensionTearOff.name != null ) return ;
641+
642+ int fileOffset = _procedure.fileOffset;
643+
644+ int extensionTypeParameterCount =
645+ extensionBuilder.typeParameters? .length ?? 0 ;
646+
647+ List <TypeParameter > typeParameters = < TypeParameter > [];
648+
649+ List <DartType > typeArguments = < DartType > [];
650+ for (TypeParameter typeParameter in function.typeParameters) {
651+ TypeParameter newTypeParameter = new TypeParameter (typeParameter.name);
652+ typeParameters.add (newTypeParameter);
653+ typeArguments.add (new TypeParameterType (newTypeParameter));
654+ }
655+
656+ List <TypeParameter > tearOffTypeParameters = < TypeParameter > [];
657+ List <TypeParameter > closureTypeParameters = < TypeParameter > [];
658+ Substitution substitution =
659+ Substitution .fromPairs (function.typeParameters, typeArguments);
660+ for (int index = 0 ; index < typeParameters.length; index++ ) {
661+ TypeParameter newTypeParameter = typeParameters[index];
662+ newTypeParameter.bound =
663+ substitution.substituteType (function.typeParameters[index].bound);
664+ newTypeParameter.defaultType = function.typeParameters[index].defaultType;
665+ if (index < extensionTypeParameterCount) {
666+ tearOffTypeParameters.add (newTypeParameter);
667+ } else {
668+ closureTypeParameters.add (newTypeParameter);
669+ }
670+ }
671+
672+ VariableDeclaration copyParameter (
673+ VariableDeclaration parameter, DartType type,
674+ {bool isOptional}) {
675+ // TODO(johnniwinther): Handle default values.
676+ return new VariableDeclaration (parameter.name,
677+ type: type,
678+ initializer: isOptional ? new NullLiteral () : null ,
679+ isFinal: parameter.isFinal)
680+ ..fileOffset = parameter.fileOffset;
681+ }
682+
683+ VariableDeclaration extensionThis = copyParameter (
684+ function.positionalParameters.first,
685+ substitution.substituteType (function.positionalParameters.first.type),
686+ isOptional: false );
687+
688+ DartType closureReturnType =
689+ substitution.substituteType (function.returnType);
690+ List <VariableDeclaration > closurePositionalParameters = [];
691+ List <Expression > closurePositionalArguments = [];
692+
693+ for (int position = 0 ;
694+ position < function.positionalParameters.length;
695+ position++ ) {
696+ VariableDeclaration parameter = function.positionalParameters[position];
697+ if (position == 0 ) {
698+ /// Pass `this` as a captured variable.
699+ closurePositionalArguments
700+ .add (new VariableGet (extensionThis)..fileOffset = fileOffset);
701+ } else {
702+ DartType type = substitution.substituteType (parameter.type);
703+ VariableDeclaration newParameter = copyParameter (parameter, type,
704+ isOptional: position >= function.requiredParameterCount);
705+ closurePositionalParameters.add (newParameter);
706+ closurePositionalArguments
707+ .add (new VariableGet (newParameter)..fileOffset = fileOffset);
708+ }
709+ }
710+ List <VariableDeclaration > closureNamedParameters = [];
711+ List <NamedExpression > closureNamedArguments = [];
712+ for (VariableDeclaration parameter in function.namedParameters) {
713+ DartType type = substitution.substituteType (parameter.type);
714+ VariableDeclaration newParameter =
715+ copyParameter (parameter, type, isOptional: true );
716+ closureNamedParameters.add (newParameter);
717+ closureNamedArguments.add (new NamedExpression (parameter.name,
718+ new VariableGet (newParameter)..fileOffset = fileOffset));
719+ }
720+
721+ Statement closureBody = new ReturnStatement (
722+ new StaticInvocation (
723+ procedure,
724+ new Arguments (closurePositionalArguments,
725+ types: typeArguments, named: closureNamedArguments))
726+ ..fileOffset = fileOffset)
727+ ..fileOffset = fileOffset;
728+
729+ FunctionExpression closure = new FunctionExpression (new FunctionNode (
730+ closureBody,
731+ typeParameters: closureTypeParameters,
732+ positionalParameters: closurePositionalParameters,
733+ namedParameters: closureNamedParameters,
734+ requiredParameterCount: procedure.function.requiredParameterCount - 1 ,
735+ returnType: closureReturnType,
736+ asyncMarker: procedure.function.asyncMarker,
737+ dartAsyncMarker: procedure.function.dartAsyncMarker))
738+ ..fileOffset = fileOffset;
739+
740+ _extensionTearOff
741+ ..name = new Name (
742+ '${extensionBuilder .name }|get#${name }' , libraryBuilder.library)
743+ ..function = new FunctionNode (
744+ new ReturnStatement (closure)..fileOffset = fileOffset,
745+ typeParameters: tearOffTypeParameters,
746+ positionalParameters: [extensionThis],
747+ requiredParameterCount: 1 ,
748+ returnType: closure.function.functionType)
749+ ..fileUri = fileUri
750+ ..fileOffset = fileOffset;
751+ _extensionTearOff.function.parent = _extensionTearOff;
752+ }
753+
637754 /// The [Procedure] built by this builder.
638755 Procedure get procedure => isPatch ? origin.procedure : _procedure;
639756
757+ /// If this is an extension instance method then [_extensionTearOff] holds
758+ /// the synthetically created tear off function.
759+ Procedure get extensionTearOff {
760+ if (isExtensionInstanceMember && kind == ProcedureKind .Method ) {
761+ _extensionTearOff ?? = new Procedure (null , ProcedureKind .Method , null ,
762+ isStatic: true , isExtensionMember: true );
763+ }
764+ return _extensionTearOff;
765+ }
766+
640767 Member get member => procedure;
641768
642769 @override
@@ -745,7 +872,7 @@ class ConstructorBuilder extends FunctionBuilder {
745872 return false ;
746873 }
747874
748- Constructor build (SourceLibraryBuilder libraryBuilder) {
875+ Member build (SourceLibraryBuilder libraryBuilder) {
749876 if (_constructor.name == null ) {
750877 _constructor.function = buildFunction (libraryBuilder);
751878 _constructor.function.parent = _constructor;
0 commit comments