@@ -1306,6 +1306,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1306
1306
else
1307
1307
tpd.SyntheticValDef (TempResultName .fresh(), e)
1308
1308
1309
+ /** Returns `(n, Some(d))` where `n` is the name of a synthetic val `d` that binds the result of
1310
+ * `e` if evaluating `e` is impure. Otherwise, returns `(e, None)`.
1311
+ */
1312
+ def hoisted (e : tpd.Tree )(using Context ): (tpd.Tree , Option [tpd.ValDef ]) =
1313
+ if exprPurity(e) >= TreeInfo .Pure then
1314
+ (e, None )
1315
+ else
1316
+ val d = tpd.SyntheticValDef (TempResultName .fresh(), e)
1317
+ (tpd.Ident (d.namedType), Some (d))
1318
+
1309
1319
/** Returns a builder for computing trees representing assignments to `lhs`. */
1310
1320
def formPartialAssignmentTo (lhs : untpd.Tree )(using Context ): PartialAssignment [LValue ] =
1311
1321
lhs match
@@ -1363,7 +1373,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1363
1373
1364
1374
core match
1365
1375
case Apply (f, _) if f.symbol.is(ExtensionMethod ) =>
1366
- formPartialAssignmentToExtensionApply(f, reassignmentToVal ).getOrElse(reassignmentToVal())
1376
+ formPartialAssignmentToExtensionApply(core ).getOrElse(reassignmentToVal())
1367
1377
1368
1378
case _ => core.tpe match
1369
1379
case r : TermRef =>
@@ -1399,63 +1409,60 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1399
1409
case _ =>
1400
1410
reassignmentToVal()
1401
1411
1402
- /** Returns a builder for computing trees representing assignments to `lhs`, which denotes the
1403
- * use of a setter defined in an extension.
1404
- */
1412
+ /** Returns a builder for making trees representing assignments to `lhs`, which denotes a setter
1413
+ * defined in an extension.
1414
+ */
1405
1415
def formPartialAssignmentToExtensionApply (
1406
- lhs : Tree , reassignmentToVal : () => PartialAssignment [ LValue ]
1416
+ lhs : Tree
1407
1417
)(using Context ): Option [PartialAssignment [LValue ]] =
1408
- def formAssignment ( v : LValue ) : PartialAssignment [ LValue ] =
1409
- PartialAssignment (v) { (l, r ) =>
1410
- // QUESTION: Why do we need `IgnoredProto(pt)`=
1411
- // typed(l.formAssignment(r), IgnoredProto(e))
1412
- l.formAssignment(r)
1413
- }
1414
-
1415
- lhs match
1416
- case f @ Ident ( name : TermName ) =>
1417
- // We need to make sure that the prefix of this extension getter is retained when we
1418
- // transform it into a setter. Otherwise, we could end up resolving an unrelated setter
1419
- // from another extension. See tests/pos/i18713.scala for an example.
1420
- val v : SelectLValue = f.tpe match
1421
- case TermRef ( q : TermRef , _) =>
1422
- SelectLValue (temporary(ref(q)), f.symbol.name)
1423
- case TermRef ( q : ThisType , _ ) =>
1424
- SelectLValue (temporary( This (q.cls)), f.symbol.name )
1425
- case TermRef ( NoPrefix , _) =>
1426
- SelectLValue (f, name.setterName)
1427
- Some (formAssignment(v))
1428
-
1429
- case f @ Select (q, name : TermName ) =>
1430
- Some (formAssignment( SelectLValue (temporary(q), name.setterName)))
1431
-
1432
- case f @ TypeApply (f1, tas ) =>
1433
- formPartialAssignmentToExtensionApply(f1, reassignmentToVal).map { (partialAssignment) =>
1434
- val s = partialAssignment.lhs.toRValue
1435
- val t = untpd.cpy. TypeApply (f)(s, tas.map((ta ) => untpd. TypedSplice (ta)) )
1436
- formAssignment( ApplyLValue (temporary(typed(t)), List ()))
1437
- }
1438
-
1439
- case f @ Apply (f1, as) =>
1440
- formPartialAssignmentToExtensionApply(f1, reassignmentToVal).map { (partialAssignment) =>
1441
- val applyKind = f1 match
1418
+ /** Returns the setter corresponding to `lhs`, which is a getter, along hoisted definitions. */
1419
+ def formSetter ( lhs : Tree , captures : List [ Tree ]) : (untpd. Tree , List [ Tree ] ) =
1420
+ lhs match
1421
+ case f @ Ident ( name : TermName ) =>
1422
+ // We need to make sure that the prefix of this extension getter is retained when we
1423
+ // transform it into a setter. Otherwise, we could end up resolving an unrelated setter
1424
+ // from another extension. See tests/pos/i18713.scala for an example.
1425
+ f.tpe match
1426
+ case TermRef ( q : TermRef , _ ) =>
1427
+ formSetter(ref(q).select(f.symbol).withSpan(f.span), captures)
1428
+ case TermRef ( q : ThisType , _) =>
1429
+ formSetter( This (q.cls).select(f.symbol).withSpan(f.span), captures)
1430
+ case TermRef ( NoPrefix , _) =>
1431
+ (untpd.cpy. Ident (f)(name.setterName), captures)
1432
+
1433
+ case f @ Select (q, name : TermName ) =>
1434
+ val (v, d) = hoisted(q )
1435
+ (untpd.cpy. Select (f)(untpd. TypedSplice (v), name.setterName), captures ++ d)
1436
+
1437
+ case f @ TypeApply (g, ts) =>
1438
+ val (s, cs) = formSetter(g, captures)
1439
+ (untpd.cpy. TypeApply (f)(s, ts.map((t ) => untpd. TypedSplice (t))), cs)
1440
+
1441
+ case f @ Apply (g, as) =>
1442
+ var (s, newCaptures ) = formSetter(g, captures)
1443
+ var arguments = List [untpd. Tree ]()
1444
+ for a <- as do
1445
+ val (v, d ) = hoisted(a )
1446
+ arguments = untpd. TypedSplice (v, isExtensionReceiver = true ) +: arguments
1447
+ newCaptures = newCaptures ++ d
1448
+
1449
+ val setter = untpd.cpy. Apply (f)(s, arguments)
1450
+
1451
+ g match
1442
1452
case _ : Apply =>
1443
1453
// Current apply is to implicit arguments. Note that we cannot copy the apply kind
1444
1454
// of `f` since `f` is a typed tree and apply kinds are not preserved for those.
1445
- ApplyKind .Using
1455
+ (setter.setApplyKind( ApplyKind .Using ), newCaptures)
1446
1456
case _ =>
1447
- ApplyKind . Regular
1457
+ (setter, newCaptures)
1448
1458
1449
- val arguments = as.map { (a) =>
1450
- val x = untpd.TypedSplice (a, isExtensionReceiver = true )
1451
- temporary(typed(x))
1452
- }
1453
- val s = partialAssignment.lhs.toRValue
1454
- formAssignment(ApplyLValue (temporary(typed(s)), arguments, applyKind))
1455
- }
1459
+ case _ =>
1460
+ (EmptyTree , List ())
1456
1461
1457
- case _ =>
1458
- None
1462
+ val (setter, captures) = formSetter(lhs, List ())
1463
+ if setter.isEmpty then None else
1464
+ val cs = captures.collect { case d : tpd.ValDef => d }
1465
+ Some (PartialAssignment (UnappliedSetter (setter, cs)) { (l, r) => l.formAssignment(r) })
1459
1466
1460
1467
def typedAssign (tree : untpd.Assign , pt : Type )(using Context ): Tree =
1461
1468
tree.lhs match
0 commit comments