diff options
30 files changed, 326 insertions, 44 deletions
@@ -211,6 +211,11 @@ TODO: <!-- Set up Ant contrib tasks so we can use <if><then><else> instead of the clunky `unless` attribute --> <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib-ant.dir}/ant-contrib.jar"/> + <property name="scala.ant.min.version" value="1.8.2"/> + <if><not><antversion atleast="${scala.ant.min.version}"/></not> + <then><fail message="Ant version ${scala.ant.min.version} is required. You are running ${ant.version}"/></then> + </if> + <!-- Add our maven ant tasks --> <path id="maven-ant-tasks.classpath" path="${lib-ant.dir}/maven-ant-tasks-2.1.1.jar" /> <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" /> @@ -1961,6 +1966,30 @@ TODO: </copy> </target> + <!-- + A jar-like task that creates an OSGi source bundle. It adds the required MANIFEST.MF headers that allow + Eclipse to match sources with the corresponding binaries. + --> + <macrodef name="osgi.source.bundle"> + <attribute name="destfile" description="The jar file name"/> + <attribute name="symbolicName" description="The original bundle symbolic name (without .source at the end)"/> + <attribute name="bundleName" description="A value for Bundle-Name, usually a textual description"/> + <element name="file-sets" description="A sequence of fileset elements to be included in the jar" optional="true" implicit="true"/> + + <sequential> + <jar whenmanifestonly="fail" destfile="@{destFile}"> + <file-sets/> + <manifest> + <attribute name="Manifest-Version" value="1.0"/> + <attribute name="Bundle-Name" value="@{bundleName}"/> + <attribute name="Bundle-SymbolicName" value="@{symbolicName}.source"/> + <attribute name="Bundle-Version" value="${osgi.version.number}"/> + <attribute name="Eclipse-SourceBundle" value="@{symbolicName};version="${osgi.version.number}";roots:="."" /> + </manifest> + </jar> + </sequential> + </macrodef> + <target name="dist.src" depends="dist.base"> <mkdir dir="${dist.dir}/src"/> <copy toDir="${dist.dir}/src"> @@ -1968,20 +1997,36 @@ TODO: <file file="${scala-parser-combinators-sources}"/> </copy> - <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scala-library-src.jar"> + <osgi.source.bundle destfile="${dist.dir}/src/scala-library-src.jar" + symbolicName="org.scala-lang.scala-library" + bundleName="Scala Library Sources"> <fileset dir="${src.dir}/library"/> <fileset dir="${src.dir}/continuations/library"/> - </jar> - <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scala-actors-src.jar" basedir="${src.dir}/actors"/> - <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scala-compiler-src.jar"> + </osgi.source.bundle> + <osgi.source.bundle destfile="${dist.dir}/src/scala-actors-src.jar" + symbolicName="org.scala-lang.scala-actors" + bundleName="Scala Actors Sources"> + <fileset dir="${src.dir}/actors"/> + </osgi.source.bundle> + <osgi.source.bundle destfile="${dist.dir}/src/scala-compiler-src.jar" + symbolicName="org.scala-lang.scala-compiler" + bundleName="Scala Compiler Sources"> <fileset dir="${src.dir}/compiler"/> <fileset dir="${src.dir}/repl"/> <fileset dir="${src.dir}/scaladoc"/> <fileset dir="${src.dir}/interactive"/> <fileset dir="${src.dir}/continuations/plugin"/> - </jar> - <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scala-swing-src.jar" basedir="${src.dir}/swing"/> - <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scala-reflect-src.jar" basedir="${src.dir}/reflect"/> + </osgi.source.bundle> + <osgi.source.bundle destfile="${dist.dir}/src/scala-swing-src.jar" + symbolicName="org.scala-lang.scala-swing" + bundleName="Scala Swing Sources"> + <fileset dir="${src.dir}/swing"/> + </osgi.source.bundle> + <osgi.source.bundle destfile="${dist.dir}/src/scala-reflect-src.jar" + symbolicName="org.scala-lang.scala-reflect" + bundleName="Scala Reflect Sources"> + <fileset dir="${src.dir}/reflect"/> + </osgi.source.bundle> <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scalap-src.jar" basedir="${src.dir}/scalap"/> </target> diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 05ad2dbc57..50aad8e043 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1402,7 +1402,7 @@ self => if (in.token == EQUALS) { t match { case Ident(_) | Select(_, _) | Apply(_, _) => - t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) } + t = atPos(t.pos.startOrPoint, in.skipToken()) { gen.mkAssign(t, expr()) } case _ => } } else if (in.token == COLON) { diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 976e578afd..fba74330a6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -191,14 +191,6 @@ abstract class TreeBuilder { } } - /** Create a tree representing an assignment <lhs = rhs> */ - def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match { - case Apply(fn, args) => - Apply(atPos(fn.pos) { Select(fn, nme.update) }, args ::: List(rhs)) - case _ => - Assign(lhs, rhs) - } - /** Tree for `od op`, start is start0 if od.pos is borked. */ def makePostfixSelect(start0: Int, end: Int, od: Tree, op: Name): Tree = { val start = if (od.pos.isDefined) od.pos.startOrPoint else start0 diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 843299398b..a80fee876e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1319,6 +1319,8 @@ abstract class GenICode extends SubComponent { /** Some useful equality helpers. */ def isNull(t: Tree) = cond(t) { case Literal(Constant(null)) => true } + def isLiteral(t: Tree) = cond(t) { case Literal(_) => true } + def isNonNullExpr(t: Tree) = isLiteral(t) || ((t.symbol ne null) && t.symbol.isModule) /* If l or r is constant null, returns the other ; otherwise null */ def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null @@ -1514,6 +1516,23 @@ abstract class GenICode extends SubComponent { val branchesReachable = !ctx1.bb.ignore ctx1.bb emitOnly CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ObjectReference) branchesReachable + } else if (isNonNullExpr(l)) { + // Avoid null check if L is statically non-null. + // + // "" == expr -> "".equals(expr) + // Nil == expr -> Nil.equals(expr) + // + // Common enough (through pattern matching) to treat this specially here rather than + // hoping that -Yconst-opt is enabled. The impossible branches for null checks lead + // to spurious "branch not covered" warnings in Jacoco code coverage. + var ctx1 = genLoad(l, ctx, ObjectReference) + val branchesReachable = !ctx1.bb.ignore + ctx1 = genLoad(r, ctx1, ObjectReference) + ctx1.bb emitOnly( + CALL_METHOD(Object_equals, Dynamic), + CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL) + ) + branchesReachable } else { val eqEqTempLocal = getTempLocal var ctx1 = genLoad(l, ctx, ObjectReference) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5c8f1bd1c7..157c6ba4de 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4874,26 +4874,37 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } // Warn about likely interpolated strings which are missing their interpolators - def warnMissingInterpolator(tree: Literal) { + def warnMissingInterpolator(tree: Literal) = if (!isPastTyper) { // Unfortunately implicit not found strings looks for all the world like // missing interpolators. def isArgToImplicitNotFound = context.enclosingApply.tree match { - case Apply(fn, _) => fn.symbol.enclClass == ImplicitNotFoundClass + case Apply(fn, _) => fn.symbol != null && fn.symbol.enclClass == ImplicitNotFoundClass case _ => false } + def warnAbout(s: String) = { + def names = InterpolatorIdentRegex findAllIn s map (n => TermName(n stripPrefix "$")) + def isSuspiciousExpr = (InterpolatorCodeRegex findFirstIn s).nonEmpty + //def isSuspiciousName = names exists (lookUp _ andThen (_.exists)) + def suspiciousName = names find (lookUp _ andThen (_.exists)) + def lookUp(n: TermName) = context.lookupSymbol(n, !_.alternatives.exists(symRequiresArg)).symbol + def symRequiresArg(s: Symbol) = ( + s.paramss.nonEmpty + && (s.paramss.head.headOption filterNot (_.isImplicit)).isDefined + ) + val suggest = "Did you forget the interpolator?" + if (isSuspiciousExpr) + unit.warning(tree.pos, s"That looks like an interpolated expression! $suggest") + else /* if (isSuspiciousName) */ suspiciousName foreach (n => + unit.warning(tree.pos, s"`$$$n` looks like an interpolated identifier! $suggest") + ) + } tree.value match { case Constant(s: String) => - def names = InterpolatorIdentRegex findAllIn s map (n => newTermName(n stripPrefix "$")) - def suspicious = ( - (InterpolatorCodeRegex findFirstIn s).nonEmpty - || (names exists (n => context.lookupSymbol(n, _ => true).symbol.exists)) - ) val noWarn = ( isArgToImplicitNotFound || !(s contains ' ') // another heuristic - e.g. a string with only "$asInstanceOf" ) - if (!noWarn && suspicious) - unit.warning(tree.pos, "looks like an interpolated String; did you forget the interpolator?") + if (!noWarn) warnAbout(s) case _ => } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index c2d8bcdcd6..0d1fb6be07 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -10,7 +10,7 @@ trait Reifiers { self: Quasiquotes => import global.build.{SyntacticClassDef, SyntacticTraitDef, SyntacticModuleDef, SyntacticDefDef, SyntacticValDef, SyntacticVarDef, SyntacticBlock, SyntacticApplied, SyntacticTypeApplied, - SyntacticFunction, SyntacticNew} + SyntacticFunction, SyntacticNew, SyntacticAssign} import global.treeInfo._ import global.definitions._ import Cardinality._ @@ -71,9 +71,9 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) case SyntacticVarDef(mods, name, tpt, rhs) => reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs) - case SyntacticApplied(fun, argss) if argss.length > 1 => - reifyBuildCall(nme.SyntacticApplied, fun, argss) - case SyntacticApplied(fun, argss @ (_ :+ (_ :+ Placeholder(_, _, DotDotDot)))) => + case SyntacticAssign(lhs, rhs) => + reifyBuildCall(nme.SyntacticAssign, lhs, rhs) + case SyntacticApplied(fun, argss) if argss.nonEmpty => reifyBuildCall(nme.SyntacticApplied, fun, argss) case SyntacticTypeApplied(fun, targs) if targs.nonEmpty => reifyBuildCall(nme.SyntacticTypeApplied, fun, targs) diff --git a/src/interactive/scala/tools/nsc/interactive/Response.scala b/src/interactive/scala/tools/nsc/interactive/Response.scala index 0da400378e..3e84c83e55 100644 --- a/src/interactive/scala/tools/nsc/interactive/Response.scala +++ b/src/interactive/scala/tools/nsc/interactive/Response.scala @@ -55,7 +55,10 @@ class Response[T] { try { wait() } catch { - case exc: InterruptedException => raise(exc) + case exc: InterruptedException => { + Thread.currentThread().interrupt() + raise(exc) + } } } data.get @@ -73,7 +76,10 @@ class Response[T] { try { wait(timeout - (current - start)) } catch { - case exc: InterruptedException => raise(exc) + case exc: InterruptedException => { + Thread.currentThread().interrupt() + raise(exc) + } } current = System.currentTimeMillis } diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index ec6de84a9d..4e3f3c6c81 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -473,6 +473,13 @@ object Future { */ def successful[T](result: T): Future[T] = Promise.successful(result).future + /** Creates an already completed Future with the specified result or exception. + * + * @tparam T the type of the value in the promise + * @return the newly created `Future` object + */ + def fromTry[T](result: Try[T]): Future[T] = Promise.fromTry(result).future + /** Starts an asynchronous computation and returns a `Future` object with the result of that computation. * * The result becomes available once the asynchronous computation is completed. diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala index cfb1dda01f..eb8044ed3b 100644 --- a/src/library/scala/concurrent/Promise.scala +++ b/src/library/scala/concurrent/Promise.scala @@ -128,12 +128,19 @@ object Promise { * @tparam T the type of the value in the promise * @return the newly created `Promise` object */ - def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception)) + def failed[T](exception: Throwable): Promise[T] = fromTry(Failure(exception)) /** Creates an already completed Promise with the specified result. * * @tparam T the type of the value in the promise * @return the newly created `Promise` object */ - def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result)) + def successful[T](result: T): Promise[T] = fromTry(Success(result)) + + /** Creates an already completed Promise with the specified result or exception. + * + * @tparam T the type of the value in the promise + * @return the newly created `Promise` object + */ + def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result) } diff --git a/src/library/scala/sys/process/ProcessBuilder.scala b/src/library/scala/sys/process/ProcessBuilder.scala index a144d51609..feced71dae 100644 --- a/src/library/scala/sys/process/ProcessBuilder.scala +++ b/src/library/scala/sys/process/ProcessBuilder.scala @@ -123,7 +123,7 @@ import ProcessBuilder._ * 1. `#&&` conditionally executes the second command if the previous one finished with * exit value 0. It mirrors shell's `&&`. * 1. `#||` conditionally executes the third command if the exit value of the previous - * command is different than zero. It mirrors shell's `&&`. + * command is different than zero. It mirrors shell's `||`. * * Finally, `!` at the end executes the commands, and returns the exit value. * Whatever is printed will be sent to the Scala process standard output. If diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 60c2a81947..551c27bf9c 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -193,5 +193,12 @@ private[reflect] trait BuildUtils { self: Universe => def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef def unapply(tree: Tree): Option[(Modifiers, TermName, Tree, Tree)] } + + val SyntacticAssign: SyntacticAssignExtractor + + trait SyntacticAssignExtractor { + def apply(lhs: Tree, rhs: Tree): Tree + def unapply(tree: Tree): Option[(Tree, Tree)] + } } } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index de24b88397..e5c7dc44af 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -140,7 +140,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticApplied extends SyntacticAppliedExtractor { def apply(tree: Tree, argss: List[List[Tree]]): Tree = - argss.foldLeft(tree) { Apply(_, _) } + argss.foldLeft(tree) { (f, args) => Apply(f, args.map(treeInfo.assignmentToMaybeNamedArg)) } def unapply(tree: Tree): Some[(Tree, List[List[Tree]])] = { val treeInfo.Applied(fun, targs, argss) = tree @@ -401,6 +401,16 @@ trait BuildUtils { self: SymbolTable => object SyntacticValDef extends SyntacticValDefBase { val isMutable = false } object SyntacticVarDef extends SyntacticValDefBase { val isMutable = true } + + object SyntacticAssign extends SyntacticAssignExtractor { + def apply(lhs: Tree, rhs: Tree): Tree = gen.mkAssign(lhs, rhs) + def unapply(tree: Tree): Option[(Tree, Tree)] = tree match { + case Assign(lhs, rhs) => Some((lhs, rhs)) + case AssignOrNamedArg(lhs, rhs) => Some((lhs, rhs)) + case Apply(Select(fn, nme.update), args :+ rhs) => Some((atPos(fn.pos)(Apply(fn, args)), rhs)) + case _ => None + } + } } val build: BuildApi = new BuildImpl diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 6407a3979c..f4eae5590a 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -602,6 +602,7 @@ trait StdNames { val SelectFromTypeTree: NameType = "SelectFromTypeTree" val StringContext: NameType = "StringContext" val SyntacticApplied: NameType = "SyntacticApplied" + val SyntacticAssign: NameType = "SyntacticAssign" val SyntacticBlock: NameType = "SyntacticBlock" val SyntacticClassDef: NameType = "SyntacticClassDef" val SyntacticDefDef: NameType = "SyntacticDefDef" diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index a8af3e0f0e..a9f2807e9f 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -434,4 +434,12 @@ abstract class TreeGen extends macros.TreeBuilder { case head :: Nil => head case _ => gen.mkBlock(stats) } + + /** Create a tree representing an assignment <lhs = rhs> */ + def mkAssign(lhs: Tree, rhs: Tree): Tree = lhs match { + case Apply(fn, args) => + Apply(atPos(fn.pos)(Select(fn, nme.update)), args :+ rhs) + case _ => + Assign(lhs, rhs) + } } diff --git a/test/files/neg/forgot-interpolator.check b/test/files/neg/forgot-interpolator.check index f6de4d7b3a..a96431841f 100644 --- a/test/files/neg/forgot-interpolator.check +++ b/test/files/neg/forgot-interpolator.check @@ -1,9 +1,24 @@ -forgot-interpolator.scala:4: warning: looks like an interpolated String; did you forget the interpolator? +forgot-interpolator.scala:4: warning: `$bippy` looks like an interpolated identifier! Did you forget the interpolator? def f = "Put the $bippy in the $bippy!" // warn ^ -forgot-interpolator.scala:14: warning: looks like an interpolated String; did you forget the interpolator? +forgot-interpolator.scala:14: warning: That looks like an interpolated expression! Did you forget the interpolator? def f = """Put the ${println("bippy")} in the bippy!""" // warn ^ +forgot-interpolator.scala:30: warning: `$beppo` looks like an interpolated identifier! Did you forget the interpolator? + def f = "$beppo was a marx bros who saw dollars." // warn + ^ +forgot-interpolator.scala:34: warning: `$aleppo` looks like an interpolated identifier! Did you forget the interpolator? + def f = "$aleppo is a pepper and a city." // warn + ^ +forgot-interpolator.scala:40: warning: `$bar` looks like an interpolated identifier! Did you forget the interpolator? + def f = "$bar is private, shall we warn just in case?" // warn + ^ +forgot-interpolator.scala:45: warning: `$hippo` looks like an interpolated identifier! Did you forget the interpolator? + def h = "$hippo takes an implicit" // warn + ^ +forgot-interpolator.scala:37: warning: private method in class Bar is never used + private def bar = 8 + ^ error: No warnings can be incurred under -Xfatal-warnings. -two warnings found +7 warnings found one error found diff --git a/test/files/neg/forgot-interpolator.scala b/test/files/neg/forgot-interpolator.scala index d67db82643..5067f1dce9 100644 --- a/test/files/neg/forgot-interpolator.scala +++ b/test/files/neg/forgot-interpolator.scala @@ -13,3 +13,35 @@ class B { class C { def f = """Put the ${println("bippy")} in the bippy!""" // warn } + +package object test { + def aleppo = 9 + def greppo(n: Int) = ??? + def zappos(n: Int)(implicit ord: math.Ordering[Int]) = ??? + def hippo(implicit n: Int) = ??? +} + +package test { + // not sure if overloading is kosher in pkg obj yet + class Doo { + def beppo(i: Int) = 8 * i + def beppo = 8 + class Dah extends Doo { + def f = "$beppo was a marx bros who saw dollars." // warn + } + } + class E { + def f = "$aleppo is a pepper and a city." // warn + } + class Bar { + private def bar = 8 + } + class Baz extends Bar { + def f = "$bar is private, shall we warn just in case?" // warn + } + class G { + def g = "$greppo takes an arg" // no warn + def z = "$zappos takes an arg too" // no warn + def h = "$hippo takes an implicit" // warn + } +} diff --git a/test/files/neg/macro-quasiquotes.check b/test/files/neg/macro-quasiquotes.check index a2d48723b5..96ef75dd32 100644 --- a/test/files/neg/macro-quasiquotes.check +++ b/test/files/neg/macro-quasiquotes.check @@ -1,6 +1,6 @@ Macros_1.scala:14: error: macro implementation has wrong shape: required: (x: Impls.this.c.Expr[Int]): Impls.this.c.Expr[Any] - found : (x: Impls.this.c.universe.Block): Impls.this.c.universe.Apply + found : (x: Impls.this.c.universe.Block): Impls.this.c.universe.Tree type mismatch for parameter x: Impls.this.c.Expr[Int] does not conform to Impls.this.c.universe.Block def m3(x: Int) = macro Impls.impl3 ^ diff --git a/test/files/neg/t7848-interp-warn.check b/test/files/neg/t7848-interp-warn.check new file mode 100644 index 0000000000..cbdc9f4c27 --- /dev/null +++ b/test/files/neg/t7848-interp-warn.check @@ -0,0 +1,9 @@ +t7848-interp-warn.scala:7: warning: `$foo` looks like an interpolated identifier! Did you forget the interpolator? + "An important $foo message!" + ^ +t7848-interp-warn.scala:11: warning: That looks like an interpolated expression! Did you forget the interpolator? + "A doubly important ${foo * 2} message!" + ^ +error: No warnings can be incurred under -Xfatal-warnings. +two warnings found +one error found diff --git a/test/files/neg/t7848-interp-warn.flags b/test/files/neg/t7848-interp-warn.flags new file mode 100644 index 0000000000..7949c2afa2 --- /dev/null +++ b/test/files/neg/t7848-interp-warn.flags @@ -0,0 +1 @@ +-Xlint -Xfatal-warnings diff --git a/test/files/neg/t7848-interp-warn.scala b/test/files/neg/t7848-interp-warn.scala new file mode 100644 index 0000000000..bb3eeff60c --- /dev/null +++ b/test/files/neg/t7848-interp-warn.scala @@ -0,0 +1,13 @@ + +package test + +object Test { + def f = { + val foo = "bar" + "An important $foo message!" + } + def g = { + val foo = "bar" + "A doubly important ${foo * 2} message!" + } +} diff --git a/test/files/pos/t7864.flags b/test/files/pos/t7864.flags new file mode 100644 index 0000000000..7ccd56103a --- /dev/null +++ b/test/files/pos/t7864.flags @@ -0,0 +1 @@ +-Xlint
\ No newline at end of file diff --git a/test/files/pos/t7864.scala b/test/files/pos/t7864.scala new file mode 100644 index 0000000000..b2d8911a17 --- /dev/null +++ b/test/files/pos/t7864.scala @@ -0,0 +1,5 @@ +object Test { + val f = 0; + ({ toString; (x: Any) => x})("$f ") +} + diff --git a/test/files/run/t6719.check b/test/files/run/t6719.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/t6719.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/t6719.scala b/test/files/run/t6719.scala new file mode 100644 index 0000000000..847929a95d --- /dev/null +++ b/test/files/run/t6719.scala @@ -0,0 +1,8 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, ToolBoxError} +object Test extends App { + val tb = cm.mkToolBox() + val tree = tb.parse("(); val res = 0") + println(tb.eval(tree)) +}
\ No newline at end of file diff --git a/test/files/run/t7852.check b/test/files/run/t7852.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/run/t7852.check diff --git a/test/files/run/t7852.flags b/test/files/run/t7852.flags new file mode 100644 index 0000000000..f6262fd3e0 --- /dev/null +++ b/test/files/run/t7852.flags @@ -0,0 +1 @@ +-Ynooptimise diff --git a/test/files/run/t7852.scala b/test/files/run/t7852.scala new file mode 100644 index 0000000000..c93db718fd --- /dev/null +++ b/test/files/run/t7852.scala @@ -0,0 +1,39 @@ +import scala.tools.partest.BytecodeTest +import scala.tools.asm +import scala.tools.asm.util._ +import scala.tools.nsc.util.stringFromWriter +import scala.collection.JavaConverters._ + +object Test extends BytecodeTest { + val nullChecks = Set(asm.Opcodes.IFNONNULL, asm.Opcodes.IFNULL) + + def show: Unit = { + def test(methodName: String, expected: Int) { + val classNode = loadClassNode("Lean") + val methodNode = getMethod(classNode, methodName) + val got = countNullChecks(methodNode.instructions) + assert(got == expected, s"expected $expected but got $got comparisons") + } + test("string", expected = 0) + test("module", expected = 0) + test("moduleIndirect", expected = 2) + } + + def countNullChecks(insnList: asm.tree.InsnList): Int = + insnList.iterator.asScala.map(_.getOpcode).count(nullChecks) +} + +class Lean { + def string { + "" == toString + } + + def module { + Nil == (toString: Any) + } + + def moduleIndirect { + val n: Nil.type = null + n == (toString: Any) // still need null checks here. + } +} diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index c6cca85c81..753ad1aa59 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -167,4 +167,28 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { val x = q"val x: Int = 1" assertThrows[IllegalArgumentException] { q"($x) => x" } } + + property("assign variable") = test { + val v = q"v" + val value = q"foo" + assertEqAst(q"$v = $value", "v = foo") + } + + property("assign update 1") = test { + val v = q"v" + val args = q"1" :: q"2" :: Nil + val value = q"foo" + assertEqAst(q"$v(..$args) = $value", "v(1, 2) = foo") + } + + property("assign update 2") = test { + val a = q"v(0)" + val value = q"foo" + assertEqAst(q"$a = $value", "v(0) = foo") + } + + property("assign or named arg") = test { + val assignx = q"x = 1" + assertEqAst(q"f($assignx)", "f(x = 1)") + } } diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index 45c7ee4bb7..22d4b1ce4f 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -91,4 +91,24 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction matches("new { val early = 1} with Parent[Int] { body }") matches("new Foo { selfie => }") } + + property("exhaustive assign pattern") = test { + def matches(tree: Tree) { val q"$rhs = $lhs" = tree } + matches(parse("left = right")) + matches(parse("arr(1) = 2")) + matches(AssignOrNamedArg(EmptyTree, EmptyTree)) + } + + property("deconstruct update 1") = test { + val q"$obj(..$args) = $value" = q"foo(bar) = baz" + assert(obj ≈ q"foo") + assert(args ≈ List(q"bar")) + assert(value ≈ q"baz") + } + + property("deconstruct update 2") = test { + val q"$left = $value" = q"foo(bar) = baz" + assert(left ≈ q"foo(bar)") + assert(value ≈ q"baz") + } } diff --git a/versions.properties b/versions.properties index 2b8c1de7b7..865ce3e995 100644 --- a/versions.properties +++ b/versions.properties @@ -1,7 +1,7 @@ -starr.version=2.11.0-M4 +starr.version=2.11.0-M5 # the below is used for depending on dependencies like partest -scala.binary.version=2.11.0-M4 -partest.version.number=1.0-RC4 -scala-xml.version.number=1.0-RC3 -scala-parser-combinators.version.number=1.0-RC1 +scala.binary.version=2.11.0-M5 +partest.version.number=1.0-RC5 +scala-xml.version.number=1.0-RC4 +scala-parser-combinators.version.number=1.0-RC2 |