Skip to content

Commit a147d4e

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Handle simple use of extension instance members
Change-Id: Ic1a949c0dca9327763e01458211e477de13c222f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/114504 Reviewed-by: Dmitry Stefantsov <[email protected]>
1 parent e9fdeb2 commit a147d4e

32 files changed

+1224
-129
lines changed

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

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44

55
library 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-
137
import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
148
import '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

5855
import '../../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>{};

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,8 @@ class InferenceVisitor
577577
// To replicate analyzer behavior, we base type inference on the write
578578
// member. TODO(paulberry): would it be better to use the read member
579579
// when doing compound assignment?
580-
FunctionType calleeType = inferrer.getCalleeFunctionType(
581-
inferrer.getCalleeType(writeTarget, receiverType), false);
580+
FunctionType calleeType =
581+
inferrer.getFunctionType(writeTarget, receiverType, false);
582582
DartType expectedIndexTypeForWrite;
583583
DartType indexContext = const UnknownType();
584584
DartType writeContext = const UnknownType();
@@ -604,8 +604,8 @@ class InferenceVisitor
604604
if (read != null) {
605605
ObjectAccessTarget readMember = inferrer
606606
.findMethodInvocationMember(receiverType, read, instrumented: false);
607-
FunctionType calleeFunctionType = inferrer.getCalleeFunctionType(
608-
inferrer.getCalleeType(readMember, receiverType), false);
607+
FunctionType calleeFunctionType =
608+
inferrer.getFunctionType(readMember, receiverType, false);
609609
inferrer.ensureAssignable(
610610
getPositionalParameterType(calleeFunctionType, 0),
611611
indexType,
@@ -1681,7 +1681,7 @@ class InferenceVisitor
16811681
if (node.read != null) {
16821682
ObjectAccessTarget readTarget = inferrer
16831683
.findPropertyGetMember(receiverType, node.read, instrumented: false);
1684-
readType = inferrer.getCalleeType(readTarget, receiverType);
1684+
readType = inferrer.getGetterType(readTarget, receiverType);
16851685
inferrer.handlePropertyGetContravariance(
16861686
node.receiver,
16871687
readTarget,
@@ -1702,16 +1702,29 @@ class InferenceVisitor
17021702
DartType inferredType =
17031703
node._inferRhs(inferrer, readType, writeContext).inferredType;
17041704
node.nullAwareGuard?.staticType = node.inferredType;
1705-
node._replaceWithDesugared();
1706-
return new ExpressionInferenceResult(inferredType);
1705+
Expression replacement;
1706+
if (writeTarget.isExtensionMember) {
1707+
node.parent.replaceChild(
1708+
node,
1709+
replacement = inferrer.helper.forest.createStaticInvocation(
1710+
node.fileOffset,
1711+
writeTarget.member,
1712+
inferrer.helper.forest.createArguments(
1713+
node.fileOffset, [node.receiver, node.rhs])));
1714+
inferrer.storeInferredType(replacement, inferredType);
1715+
} else {
1716+
node._replaceWithDesugared();
1717+
}
1718+
1719+
return new ExpressionInferenceResult(inferredType, replacement);
17071720
}
17081721

17091722
@override
17101723
ExpressionInferenceResult visitPropertyGet(
17111724
PropertyGet node, DartType typeContext) {
17121725
return inferrer.inferPropertyGet(
17131726
node, node.receiver, node.fileOffset, typeContext,
1714-
desugaredGet: node);
1727+
desugaredGet: node, allowExtensionMethods: true);
17151728
}
17161729

17171730
void visitRedirectingInitializerJudgment(

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ abstract class ComplexAssignmentJudgment extends SyntheticExpressionJudgment {
293293
Expression read;
294294

295295
/// The expression appearing on the RHS of the assignment.
296-
final Expression rhs;
296+
Expression rhs;
297297

298298
/// The expression that performs the write (e.g. `a.[]=(b, a.[](b) + 1)` in
299299
/// `++a[b]`).
@@ -367,8 +367,8 @@ abstract class ComplexAssignmentJudgment extends SyntheticExpressionJudgment {
367367
combinerTarget.member, readType);
368368
}
369369
DartType rhsType;
370-
FunctionType combinerType = inferrer.getCalleeFunctionType(
371-
inferrer.getCalleeType(combinerTarget, readType), false);
370+
FunctionType combinerType =
371+
inferrer.getFunctionType(combinerTarget, readType, false);
372372
if (isPreIncDec || isPostIncDec) {
373373
rhsType = inferrer.coreTypes.intClass.rawType;
374374
} else {
@@ -378,8 +378,12 @@ abstract class ComplexAssignmentJudgment extends SyntheticExpressionJudgment {
378378
assert(identical(combiner.arguments.positional.first, rhs));
379379
// Analyzer uses a null context for the RHS here.
380380
// TODO(paulberry): improve on this.
381-
inferrer.inferExpression(rhs, const UnknownType(), true);
382-
rhsType = getInferredType(rhs, inferrer);
381+
ExpressionInferenceResult rhsResult =
382+
inferrer.inferExpression(rhs, const UnknownType(), true);
383+
if (rhsResult.replacement != null) {
384+
rhs = rhsResult.replacement;
385+
}
386+
rhsType = rhsResult.inferredType;
383387
// Do not use rhs after this point because it may be a Shadow node
384388
// that has been replaced in the tree with its desugaring.
385389
DartType expectedType = getPositionalParameterType(combinerType, 0);
@@ -413,6 +417,9 @@ abstract class ComplexAssignmentJudgment extends SyntheticExpressionJudgment {
413417
ExpressionInferenceResult rhsResult = inferrer.inferExpression(
414418
rhs, writeContext ?? const UnknownType(), true,
415419
isVoidAllowed: true);
420+
if (rhsResult.replacement != null) {
421+
rhs = rhsResult.replacement;
422+
}
416423
DartType rhsType = rhsResult.inferredType;
417424
Expression replacedRhs = inferrer.ensureAssignable(
418425
writeContext, rhsType, rhs, writeOffset,

pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ import 'package:kernel/core_types.dart' show CoreTypes;
88

99
import '../fasta_codes.dart' show LocatedMessage, Message;
1010

11+
import '../kernel/forest.dart';
12+
1113
abstract class InferenceHelper {
1214
CoreTypes get coreTypes;
1315

1416
Uri get uri;
1517

18+
Forest get forest;
19+
1620
set transformSetLiterals(bool value);
1721

1822
Expression buildProblem(Message message, int charOffset, int length,

0 commit comments

Comments
 (0)