Skip to content

Commit

Permalink
SI-6331 Avoid typing an If tree with a constant type.
Browse files Browse the repository at this point in the history
The fast path in typedIf added in 8552740 avoided lubbing the if/else branch types
if they are identical, but this fails to deconst the type. This could lead to the entire
if expression being replaced by a constant.

Also introduces a new tool in partest for nicer checkfiles.

// in Test.scala
trace(if (t) -0d else 0d)

// in Test.check
trace> if (Test.this.t)
  -0.0
else
  0.0
res: Double = -0.0
  • Loading branch information
retronym committed Sep 8, 2012
1 parent 5b9b394 commit c619f94
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -4067,7 +4067,7 @@ trait Typers extends Modes with Adaptations with Tags {
if ( opt.virtPatmat && !isPastTyper
&& thenp1.tpe.annotations.isEmpty && elsep1.tpe.annotations.isEmpty // annotated types need to be lubbed regardless (at least, continations break if you by pass them like this)
&& thenTp =:= elseTp
) (thenp1.tpe, false) // use unpacked type
) (thenp1.tpe.deconst, false) // use unpacked type. Important to deconst, as is done in ptOrLub, otherwise `if (???) 0 else 0` evaluates to 0 (SI-6331)
// TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala
else ptOrLub(thenp1.tpe :: elsep1.tpe :: Nil, pt)

Expand Down
27 changes: 27 additions & 0 deletions src/partest/scala/tools/partest/package.scala
Expand Up @@ -73,4 +73,31 @@ package object partest {

def isPartestDebug: Boolean =
propOrEmpty("partest.debug") == "true"


import language.experimental.macros

/**
* `trace("".isEmpty)` will return `true` and as a side effect print the following to standard out.
* {{{
* trace> "".isEmpty
* res: Boolean = true
*
* }}}
*
* An alternative to [[scala.tools.partest.ReplTest]] that avoids the inconvenience of embedding
* test code in a string.
*/
def trace[A](a: A) = macro traceImpl[A]

import scala.reflect.macros.Context
def traceImpl[A: c.AbsTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = {
import c.universe._
val exprCode = c.literal(show(a.tree))
val exprType = c.literal(show(a.actualType))
reify {
println(s"trace> ${exprCode.splice}\nres: ${exprType.splice} = ${a.splice}\n")
a.splice
}
}
}
30 changes: 30 additions & 0 deletions test/files/run/t6331b.check
@@ -0,0 +1,30 @@
trace> if (Test.this.t)
-0.0
else
0.0
res: Double = -0.0

trace> if (Test.this.t)
0.0
else
-0.0
res: Double = 0.0

trace> Test.this.intercept.apply[Any](if (scala.this.Predef.???)
-0.0
else
0.0)
res: Any = class scala.NotImplementedError

trace> Test.this.intercept.apply[Any](if (scala.this.Predef.???)
0.0
else
0.0)
res: Any = class scala.NotImplementedError

trace> Test.this.intercept.apply[Any](if (scala.this.Predef.???)
()
else
())
res: Any = class scala.NotImplementedError

20 changes: 20 additions & 0 deletions test/files/run/t6331b.scala
@@ -0,0 +1,20 @@
import scala.tools.partest._
import java.io._
import scala.tools.nsc._
import scala.tools.nsc.util.CommandLineParser
import scala.tools.nsc.{Global, Settings, CompilerCommand}
import scala.tools.nsc.reporters.ConsoleReporter

import scala.tools.partest.trace
import scala.util.control.Exception._


object Test extends App {
def intercept = allCatch.withApply(_.getClass)
val t: Boolean = true
trace(if (t) -0d else 0d)
trace(if (t) 0d else -0d)
trace(intercept(if (???) -0d else 0d))
trace(intercept(if (???) 0d else 0d))
trace(intercept(if (???) () else ()))
}

0 comments on commit c619f94

Please sign in to comment.