-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #2808: Modify lifting of infix operations #3841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -664,12 +664,7 @@ class Typer extends Namer | |
|
||
def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") { | ||
val (exprCtx, stats1) = typedBlockStats(tree.stats) | ||
val ept = | ||
if (tree.isInstanceOf[untpd.InfixOpBlock]) | ||
// Right-binding infix operations are expanded to InfixBlocks, which may be followed by arguments. | ||
// Example: `(a /: bs)(op)` expands to `{ val x = a; bs./:(x) } (op)` where `{...}` is an InfixBlock. | ||
pt | ||
else pt.notApplied | ||
val ept = pt.notApplied | ||
val expr1 = typedExpr(tree.expr, ept)(exprCtx) | ||
ensureNoLocalRefs( | ||
cpy.Block(tree)(stats1, expr1).withType(expr1.tpe), pt, localSyms(stats1)) | ||
|
@@ -1679,6 +1674,31 @@ class Typer extends Namer | |
res | ||
} | ||
|
||
/** Translate infix operation expression `l op r` to | ||
* | ||
* l.op(r) if `op` is left-associative | ||
* { val x = l; r.op(l) } if `op` is right-associative call-by-value and `l` is impure | ||
* r.op(l) if `op` is right-associative call-by-name or `l` is pure | ||
*/ | ||
def typedInfixOp(tree: untpd.InfixOp, pt: Type)(implicit ctx: Context): Tree = { | ||
val untpd.InfixOp(l, op, r) = tree | ||
val app = typedApply(desugar.binop(l, op, r), pt) | ||
if (untpd.isLeftAssoc(op.name)) app | ||
else { | ||
val defs = new mutable.ListBuffer[Tree] | ||
def lift(app: Tree): Tree = (app: @unchecked) match { | ||
case Apply(fn, args) => | ||
if (app.tpe.isError) app | ||
else tpd.cpy.Apply(app)(fn, LiftImpure.liftArgs(defs, fn.tpe, args)) | ||
case Assign(lhs, rhs) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No,
gives x = x.+(y) I added a comment to typedApply pointing this out. |
||
tpd.cpy.Assign(app)(lhs, lift(rhs)) | ||
case Block(stats, expr) => | ||
tpd.cpy.Block(app)(stats, lift(expr)) | ||
} | ||
Applications.wrapDefs(defs, lift(app)) | ||
} | ||
} | ||
|
||
/** Retrieve symbol attached to given tree */ | ||
protected def retrieveSym(tree: untpd.Tree)(implicit ctx: Context) = tree.removeAttachment(SymOfTree) match { | ||
case Some(sym) => | ||
|
@@ -1765,6 +1785,7 @@ class Typer extends Namer | |
case tree: untpd.TypedSplice => typedTypedSplice(tree) | ||
case tree: untpd.UnApply => typedUnApply(tree, pt) | ||
case tree: untpd.DependentTypeTree => typed(untpd.TypeTree().withPos(tree.pos), pt) | ||
case tree: untpd.InfixOp if ctx.mode.isExpr => typedInfixOp(tree, pt) | ||
case tree @ untpd.PostfixOp(qual, Ident(nme.WILDCARD)) => typedAsFunction(tree, pt) | ||
case untpd.EmptyTree => tpd.EmptyTree | ||
case _ => typedUnadapted(desugar(tree), pt) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class C {} | ||
|
||
object Test { | ||
def foo1() = { println("foo1") ; 5 } | ||
val c = new C | ||
foo1() m1_: c // error | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
foo1 | ||
foo3 | ||
foo1 | ||
bar | ||
bar | ||
foo3 | ||
bar | ||
bar |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
class C { | ||
def m1_:(f: Int) = () | ||
def m2_:(f: => Int) = () | ||
def m3_:(f: Int)(implicit c: C) = () | ||
def m4_:(f: => Int)(implicit c: C) = () | ||
|
||
} | ||
|
||
object Test { | ||
def foo1() = { println("foo1") ; 5 } | ||
def foo2() = { println("foo2") ; 5 } | ||
def foo3() = { println("foo3") ; 5 } | ||
def foo4() = { println("foo4") ; 5 } | ||
|
||
def main(args: Array[String]): Unit = { | ||
implicit val c = new C | ||
foo1() m1_: c // foo1 | ||
foo2() m2_: c | ||
foo3() m3_: c // foo3 | ||
foo4() m4_: c | ||
|
||
def bar() = { println("bar"); c } | ||
foo1() m1_: bar() // foo1 | ||
// bar | ||
foo2() m2_: bar() // bar | ||
foo3() m3_: bar() // foo3 | ||
// bar | ||
foo4() m4_: bar() // bar | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InfixOpBlock is no longer used and could be removed.