44
55library fasta.procedure_builder;
66
7- // Note: we're deliberately using AsyncMarker and ProcedureKind from kernel
8- // outside the kernel-specific builders. This is simpler than creating
9- // additional enums.
10- import 'package:kernel/ast.dart'
11- show AsyncMarker, ProcedureKind, VariableDeclaration;
12-
137import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
148import 'package:kernel/type_algebra.dart' ;
159
@@ -30,6 +24,7 @@ import 'package:kernel/ast.dart'
3024 show
3125 Arguments,
3226 AsyncMarker,
27+ Block,
3328 Class,
3429 Constructor,
3530 ConstructorInvocation,
@@ -45,6 +40,7 @@ import 'package:kernel/ast.dart'
4540 Procedure,
4641 ProcedureKind,
4742 RedirectingInitializer,
43+ ReturnStatement,
4844 Statement,
4945 StaticInvocation,
5046 StringLiteral,
@@ -53,6 +49,7 @@ import 'package:kernel/ast.dart'
5349 TypeParameter,
5450 TypeParameterType,
5551 VariableDeclaration,
52+ VariableGet,
5653 setParents;
5754
5855import '../../scanner/token.dart' show Token;
@@ -235,7 +232,7 @@ abstract class FunctionBuilder extends MemberBuilder {
235232
236233 FunctionNode function;
237234
238- Statement actualBody ;
235+ Statement _body ;
239236
240237 FunctionBuilder get actualOrigin;
241238
@@ -247,7 +244,7 @@ abstract class FunctionBuilder extends MemberBuilder {
247244// newBody.fileOffset, fileUri);
248245// }
249246// }
250- actualBody = newBody;
247+ _body = newBody;
251248 if (function != null ) {
252249 // A forwarding semi-stub is a method that is abstract in the source code,
253250 // but which needs to have a forwarding stub body in order to ensure that
@@ -264,18 +261,18 @@ abstract class FunctionBuilder extends MemberBuilder {
264261 }
265262
266263 void setRedirectingFactoryBody (Member target, List <DartType > typeArguments) {
267- if (actualBody != null ) {
268- unexpected ("null" , "${actualBody .runtimeType }" , charOffset, fileUri);
264+ if (_body != null ) {
265+ unexpected ("null" , "${_body .runtimeType }" , charOffset, fileUri);
269266 }
270- actualBody = new RedirectingFactoryBody (target, typeArguments);
271- function.body = actualBody ;
272- actualBody ? .parent = function;
267+ _body = new RedirectingFactoryBody (target, typeArguments);
268+ function.body = _body ;
269+ _body ? .parent = function;
273270 if (isPatch) {
274271 actualOrigin.setRedirectingFactoryBody (target, typeArguments);
275272 }
276273 }
277274
278- Statement get body => actualBody ?? = new EmptyStatement ();
275+ Statement get body => _body ?? = new EmptyStatement ();
279276
280277 bool get isNative => nativeMethodName != null ;
281278
@@ -506,10 +503,63 @@ class ProcedureBuilder extends FunctionBuilder {
506503 AsyncMarker get asyncModifier => actualAsyncModifier;
507504
508505 Statement get body {
509- if (actualBody == null && ! isAbstract && ! isExternal) {
510- actualBody = new EmptyStatement ();
506+ if (_body == null && ! isAbstract && ! isExternal) {
507+ _body = new EmptyStatement ();
508+ }
509+ return _body;
510+ }
511+
512+ /// If this is an extension instance setter, wrap the setter body to return
513+ /// the rhs value from the method.
514+ ///
515+ /// That is, this setter
516+ ///
517+ /// extension E on A {
518+ /// void set property(B value) {
519+ /// value++;
520+ /// }
521+ /// }
522+ ///
523+ /// is converted into this top level method
524+ ///
525+ /// B E|property(A #this, B value) {
526+ /// final #t1 = value;
527+ /// value++;
528+ /// return #t1;
529+ /// }
530+ ///
531+ void _updateExtensionSetterBody () {
532+ if (isExtensionInstanceMember && isSetter) {
533+ // TODO(johnniwinther): Avoid the synthetic variable if the parameter is
534+ // never modified.
535+ VariableDeclaration value = procedure.function.positionalParameters[1 ];
536+ procedure.function.returnType = value.type;
537+ Statement body = procedure.function.body;
538+ List <Statement > statements = [];
539+ Block block = new Block (statements);
540+ VariableDeclaration variableDeclaration =
541+ new VariableDeclarationJudgment .forValue (
542+ new VariableGet (value)..fileOffset = procedure.fileOffset)
543+ ..type = value.type;
544+ statements.add (variableDeclaration);
545+ if (body is Block ) {
546+ statements.addAll (body.statements);
547+ } else {
548+ statements.add (body);
549+ }
550+ ReturnStatement returnStatement = new ReturnStatement (
551+ new VariableGet (variableDeclaration)
552+ ..fileOffset = procedure.fileEndOffset);
553+ statements.add (returnStatement);
554+ setParents (block.statements, block);
555+ procedure.function.body = block;
556+ block.parent = procedure.function;
511557 }
512- return actualBody;
558+ }
559+
560+ void set body (Statement newBody) {
561+ super .body = newBody;
562+ _updateExtensionSetterBody ();
513563 }
514564
515565 void set asyncModifier (AsyncMarker newModifier) {
@@ -896,12 +946,12 @@ class RedirectingFactoryBuilder extends ProcedureBuilder {
896946 nativeMethodName);
897947
898948 @override
899- Statement get body => actualBody ;
949+ Statement get body => _body ;
900950
901951 @override
902952 void setRedirectingFactoryBody (Member target, List <DartType > typeArguments) {
903- if (actualBody != null ) {
904- unexpected ("null" , "${actualBody .runtimeType }" , charOffset, fileUri);
953+ if (_body != null ) {
954+ unexpected ("null" , "${_body .runtimeType }" , charOffset, fileUri);
905955 }
906956
907957 // Ensure that constant factories only have constant targets/bodies.
@@ -910,9 +960,9 @@ class RedirectingFactoryBuilder extends ProcedureBuilder {
910960 noLength, fileUri);
911961 }
912962
913- actualBody = new RedirectingFactoryBody (target, typeArguments);
914- function.body = actualBody ;
915- actualBody ? .parent = function;
963+ _body = new RedirectingFactoryBody (target, typeArguments);
964+ function.body = _body ;
965+ _body ? .parent = function;
916966 if (isPatch) {
917967 if (function.typeParameters != null ) {
918968 Map <TypeParameter , DartType > substitution = < TypeParameter , DartType > {};
0 commit comments