-
Notifications
You must be signed in to change notification settings - Fork 21
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
by-name argument incorrectly evaluated on :-ending operator #1980
Comments
Imported From: https://issues.scala-lang.org/browse/SI-1980?orig=1 |
Channing Walton (channingwalton) said: scala> object D { def ?: [T](block: => T) = { println("In D"); block } } scala> foo() ?: D scala> D.?:(foo()) Note that the evaluation order appears to be different as the printed statement are in a different order. |
Channing Walton (channingwalton) said: scala> object D { def ?: [T](block: => T) = { println("In D"); block } }
defined module D
scala> foo() ?: D
foo
In D
res5: Int = 5
scala> D.?:(foo())
In D
foo
res6: Int = 5 |
@dubochet said: {
<synthetic> val x$$1 = foo;
c.m2_$$colon(x$$1)
}; Obviously, this compilation scheme forces the evaluation of Fixing this isn't trivial: During parsing, when the expansion described above is triggered, there is no symbol information. Therefore, the type of the argument of |
@paulp said: Yet another justification for it came up sunday when brainstorming about the viability of scala->javascript translation. We decided the most viable approach was likely to involve using scalac on the original source and running it at least past the typer phase, then doing a syntax-based translation from the original parse tree which essentially abandoned all the types. However to do that we need an "original" parse tree, something not presently offered by scalac! And the eclipse and other IDE people would gain much from this as well. And all forms of translation (I would be tempted to pick up scalify again and perform a direct AST->AST translation.) A nice consistent scala pretty printer could be written to go AST->source. The downside would be the creation of some additional AST nodes which would quickly be eliminated, and a (very minor I believe) performance penalty. Defining a canonical AST representation for a given source representation has many many upsides which I think dwarf the downside. |
Eric Willigers (ewilligers) said:
My first thought is that for right-associative operators (i.e. operators ending in a colon ‘:’), right-to-left evaluation makes more sense:- For lazy val three: Int = { println("three"); 3 }
lazy val nil: List[Int] = { println("nil"); Nil }
three :: nil the output could sanely be nil
three instead of the current three
nil I expect this avoids the parser complications. The spec would change from A left-associative binary operation e1 op e2 is interpreted
as e1.op(e2). If op is right associative, the same operation
is interpreted as { val x=e1; e2.op(x ) }, where x is a
fresh name. to the simpler A left-associative binary operation e1 op e2 is interpreted
as e1.op(e2). If op is right associative, the same operation
is interpreted as e2.op(e1) |
@paulp said: scala> val nextid = { var x = 1 ; () => try "x" + x finally x += 1 }
nextid: () => String = <function0>
scala> nextid() #:: nextid() #:: nextid() #:: Stream[String]()
res0: scala.collection.immutable.Stream[String] = Stream(x1, ?)
scala> res1.toList
res1: List[String] = List(x1, x2, x3) If this evaluates right to left you get List(x3, x2, x1), and because whether an argument is by-name or not is not visible at the call site, you always have to worry about it. |
@retronym said: class Broke {
val tempval = new AnyRef {val roleA = new AnyRef with Bar}.roleA
new AnyRef {} -: tempval // when not assigning to anything, no problem
val broke_val = new AnyRef {} -: tempval // type mismatch error only when assigning
trait Foo[AnyRef] { }
trait Bar extends Foo[AnyRef] {
def -:(core: AnyRef): this.type with Foo[core.type] = throw new Exception()
}
} |
@retronym said:
|
@retronym said: |
@ghik said: |
This fixes scala/bug#1980 by changing the desugaring of right-associative operator syntax in the spec such that by-name operands now get the same desugaring as left-associative operators (except for the reversed operands, of course). Only by-value operands are pulled out into intermediate vals to preserve their left-to-right evaluation order. The implementation is as follows: - `Parsers` still performs the `val` desugaring for all calls, except that the generated synthetic names use the new `RIGHT_ASSOC_OP_PREFIX` to identify them later. - When the operator method application is checked in `Typers`, the synthetic val’s `Symbol` is marked as `LAZY` if the parameter is by-name. - The `ValDef` of the marked `Symbol` is eliminated in `RefChecks` and its RHS inlined at the call site. This is rather hackish and there is no particular reason for doing it in `Typers` and `RefChecks` other than the desire to do it early and without the overhead of extra tree transforms.
This fixes scala/bug#1980 by changing the desugaring of right-associative operator syntax in the spec such that by-name operands now get the same desugaring as left-associative operators (except for the reversed operands, of course). Only by-value operands are pulled out into intermediate vals to preserve their left-to-right evaluation order. The implementation is as follows: - `Parsers` still performs the `val` desugaring for all calls, except that the generated synthetic names use the new `RIGHT_ASSOC_OP_PREFIX` to identify them later. - Everything else happens in `Typers`: After typechecking a ValDef resulting from desugaring of a right-associative operator its Symbol and RHS are stored in a Map (without knowing at that point if they are by-name or by-value). - After typechecking a method application with an Ident for one of these Symbols, check if the parameter is by-name in which case it is replaced with the RHS and the Symbol added to a Set. - After typechecking a Block, check for a leading ValDef with the Symbol that was inlined and remove the ValDef. Fixes scala/bug#1980
This fixes scala/bug#1980 as specified in SIP-34 (http://docs.scala-lang.org/sips/right-associative-by-name-operators.html) by changing the desugaring of right-associative operator syntax such that by-name operands now get the same desugaring as left-associative operators (except for the reversed operands, of course). Only by-value operands are pulled out into intermediate vals to preserve their left-to-right evaluation order. The implementation is as follows: - `Parsers` still performs the `val` desugaring for all calls, except that the generated synthetic names use the new `RIGHT_ASSOC_OP_PREFIX` to identify them later. - Everything else happens in `Typers`: After typechecking a ValDef resulting from desugaring of a right-associative operator its Symbol and RHS are stored in a Map (without knowing at that point if they are by-name or by-value). - After typechecking a method application with an Ident for one of these Symbols, check if the parameter is by-name in which case it is replaced with the RHS and the Symbol added to a Set. - After typechecking a Block, check for a leading ValDef with the Symbol that was inlined and remove the ValDef. Fixes scala/bug#1980
But it is not evaluated if invoked directly:
The text was updated successfully, but these errors were encountered: