Skip to content

Commit 54d209c

Browse files
committed
consider more cases about comma
1 parent d571c42 commit 54d209c

1 file changed

Lines changed: 94 additions & 15 deletions

File tree

src/compiler.ts

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4479,10 +4479,12 @@ export class Compiler extends DiagnosticEmitter {
44794479
compound = true;
44804480
let assignmentLeft = left;
44814481
let setupExprs: ExpressionRef[] | null = null;
4482-
if (this.needsCompoundAssignmentSideEffectCache(left)) {
4482+
let cacheTarget = this.getCompoundAssignmentSideEffectCacheTarget(left);
4483+
if (cacheTarget && this.needsCompoundAssignmentSideEffectCache(left)) {
44834484
let flow = this.currentFlow;
4484-
if (left.kind == NodeKind.PropertyAccess) {
4485-
let access = <PropertyAccessExpression>left;
4485+
let rewrittenTarget: Expression;
4486+
if (cacheTarget.kind == NodeKind.PropertyAccess) {
4487+
let access = <PropertyAccessExpression>cacheTarget;
44864488
let receiverExpression = access.expression;
44874489
if (this.expressionHasSideEffects(receiverExpression)) {
44884490
let receiverExpr = this.compileExpression(receiverExpression, Type.auto);
@@ -4492,14 +4494,16 @@ export class Compiler extends DiagnosticEmitter {
44924494
flow.addScopedAlias(receiverName, receiverType, receiverTemp.index);
44934495
flow.setLocalFlag(receiverTemp.index, LocalFlags.Initialized);
44944496
setupExprs = [ module.local_set(receiverTemp.index, receiverExpr, receiverType.isManaged) ];
4495-
assignmentLeft = Node.createPropertyAccessExpression(
4497+
rewrittenTarget = Node.createPropertyAccessExpression(
44964498
Node.createIdentifierExpression(receiverName, receiverExpression.range),
44974499
access.property,
44984500
access.range
44994501
);
4502+
} else {
4503+
rewrittenTarget = cacheTarget;
45004504
}
45014505
} else {
4502-
let access = <ElementAccessExpression>left;
4506+
let access = <ElementAccessExpression>cacheTarget;
45034507
let receiverExpression = access.expression;
45044508
let elementExpression = access.elementExpression;
45054509
let receiverName: string | null = null;
@@ -4527,7 +4531,7 @@ export class Compiler extends DiagnosticEmitter {
45274531
setupExprs.push(module.local_set(elementTemp.index, elementExpr, elementType.isManaged));
45284532
}
45294533

4530-
assignmentLeft = Node.createElementAccessExpression(
4534+
rewrittenTarget = Node.createElementAccessExpression(
45314535
receiverName
45324536
? Node.createIdentifierExpression(receiverName, receiverExpression.range)
45334537
: receiverExpression,
@@ -4537,15 +4541,14 @@ export class Compiler extends DiagnosticEmitter {
45374541
access.range
45384542
);
45394543
}
4544+
assignmentLeft = this.replaceCompoundAssignmentSideEffectCacheTarget(
4545+
left,
4546+
this.wrapCompoundAssignmentCacheSetup(setupExprs, rewrittenTarget)
4547+
);
45404548
}
45414549

45424550
leftExpr = this.compileExpression(assignmentLeft, contextualType.intType);
45434551
leftType = this.currentType;
4544-
if (setupExprs) {
4545-
let wrappedExprs = setupExprs;
4546-
wrappedExprs.push(leftExpr);
4547-
leftExpr = module.block(null, wrappedExprs, leftType.toRef());
4548-
}
45494552

45504553
// check operator overload
45514554
let classReference = leftType.getClassOrWrapper(this.program);
@@ -4916,17 +4919,93 @@ export class Compiler extends DiagnosticEmitter {
49164919
}
49174920

49184921
private needsCompoundAssignmentSideEffectCache(target: Expression): bool {
4919-
if (target.kind == NodeKind.PropertyAccess) {
4920-
return this.expressionHasSideEffects((<PropertyAccessExpression>target).expression);
4922+
let cacheTarget = this.getCompoundAssignmentSideEffectCacheTarget(target);
4923+
if (!cacheTarget) return false;
4924+
if (cacheTarget.kind == NodeKind.PropertyAccess) {
4925+
return this.expressionHasSideEffects((<PropertyAccessExpression>cacheTarget).expression);
49214926
}
4922-
if (target.kind == NodeKind.ElementAccess) {
4923-
let access = <ElementAccessExpression>target;
4927+
if (cacheTarget.kind == NodeKind.ElementAccess) {
4928+
let access = <ElementAccessExpression>cacheTarget;
49244929
return this.expressionHasSideEffects(access.expression)
49254930
|| this.expressionHasSideEffects(access.elementExpression);
49264931
}
49274932
return false;
49284933
}
49294934

4935+
private getCompoundAssignmentSideEffectCacheTarget(target: Expression): Expression | null {
4936+
while (target.kind == NodeKind.Parenthesized) {
4937+
target = (<ParenthesizedExpression>target).expression;
4938+
}
4939+
switch (target.kind) {
4940+
case NodeKind.PropertyAccess:
4941+
case NodeKind.ElementAccess:
4942+
return target;
4943+
case NodeKind.Assertion: {
4944+
let assertion = <AssertionExpression>target;
4945+
if (assertion.assertionKind == AssertionKind.NonNull) {
4946+
return this.getCompoundAssignmentSideEffectCacheTarget(assertion.expression);
4947+
}
4948+
return null;
4949+
}
4950+
case NodeKind.Comma: {
4951+
let expressions = (<CommaExpression>target).expressions;
4952+
return this.getCompoundAssignmentSideEffectCacheTarget(expressions[assert(expressions.length) - 1]);
4953+
}
4954+
default:
4955+
return null;
4956+
}
4957+
}
4958+
4959+
private replaceCompoundAssignmentSideEffectCacheTarget(target: Expression, replacement: Expression): Expression {
4960+
while (target.kind == NodeKind.Parenthesized) {
4961+
target = (<ParenthesizedExpression>target).expression;
4962+
replacement = Node.createParenthesizedExpression(replacement, target.range);
4963+
}
4964+
switch (target.kind) {
4965+
case NodeKind.PropertyAccess:
4966+
case NodeKind.ElementAccess:
4967+
return replacement;
4968+
case NodeKind.Assertion: {
4969+
let assertion = <AssertionExpression>target;
4970+
if (assertion.assertionKind == AssertionKind.NonNull) {
4971+
return Node.createAssertionExpression(
4972+
AssertionKind.NonNull,
4973+
this.replaceCompoundAssignmentSideEffectCacheTarget(assertion.expression, replacement),
4974+
null,
4975+
assertion.range
4976+
);
4977+
}
4978+
return target;
4979+
}
4980+
case NodeKind.Comma: {
4981+
let comma = <CommaExpression>target;
4982+
let expressions = comma.expressions;
4983+
let cloned = new Array<Expression>(expressions.length);
4984+
for (let i = 0, k = expressions.length - 1; i < k; ++i) {
4985+
cloned[i] = unchecked(expressions[i]);
4986+
}
4987+
cloned[assert(expressions.length) - 1] = this.replaceCompoundAssignmentSideEffectCacheTarget(
4988+
expressions[assert(expressions.length) - 1],
4989+
replacement
4990+
);
4991+
return Node.createCommaExpression(cloned, comma.range);
4992+
}
4993+
default:
4994+
return target;
4995+
}
4996+
}
4997+
4998+
private wrapCompoundAssignmentCacheSetup(setupExprs: ExpressionRef[] | null, target: Expression): Expression {
4999+
if (!setupExprs || !setupExprs.length) return target;
5000+
let range = target.range;
5001+
let expressions = new Array<Expression>(setupExprs.length + 1);
5002+
for (let i = 0, k = setupExprs.length; i < k; ++i) {
5003+
expressions[i] = Node.createCompiledExpression(unchecked(setupExprs[i]), Type.void, range);
5004+
}
5005+
expressions[setupExprs.length] = target;
5006+
return Node.createCommaExpression(expressions, range);
5007+
}
5008+
49305009
private expressionHasSideEffects(expression: Expression): bool {
49315010
while (expression.kind == NodeKind.Parenthesized) {
49325011
expression = (<ParenthesizedExpression>expression).expression;

0 commit comments

Comments
 (0)