From 2864c7f2d744661b2ffc528c1180ad0596a07483 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 23 Jul 2013 17:52:56 +0200 Subject: brings JavaMirrors up to speed with ClassfileParser Apparently there are still discrepancies between how the vanilla compiler turns class files into symbols and how the reflective compiler does it. Working on bringing these guys in sync, one bug at a time. --- src/reflect/scala/reflect/runtime/JavaMirrors.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 55f08f0586..9ecc5c6084 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -673,8 +673,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val parents = try { parentsLevel += 1 val jsuperclazz = jclazz.getGenericSuperclass - val superclazz = if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz) - superclazz :: (jclazz.getGenericInterfaces.toList map typeToScala) + val ifaces = jclazz.getGenericInterfaces.toList map typeToScala + val isAnnotation = (jclazz.getModifiers & JAVA_ACC_ANNOTATION) != 0 + if (isAnnotation) AnnotationClass.tpe :: ClassfileAnnotationClass.tpe :: ifaces + else (if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz)) :: ifaces } finally { parentsLevel -= 1 } @@ -686,6 +688,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def enter(sym: Symbol, mods: Int) = (if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym + def enterEmptyCtorIfNecessary(): Unit = { + if (jclazz.getConstructors.isEmpty) + clazz.info.decls.enter(clazz.newClassConstructor(NoPosition)) + } + for (jinner <- jclazz.getDeclaredClasses) { jclassAsScala(jinner) // inner class is entered as a side-effect // no need to call enter explicitly @@ -702,6 +709,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni for (jconstr <- jclazz.getConstructors) enter(jconstrAsScala(jconstr), jconstr.getModifiers) + enterEmptyCtorIfNecessary() + } :: pendingLoadActions if (parentsLevel == 0) { -- cgit v1.2.3 From cd4198789cf99984df0ec3acf8351f19ef96d20e Mon Sep 17 00:00:00 2001 From: Antoine Gourlay Date: Wed, 24 Jul 2013 01:19:56 +0200 Subject: SI-4907 SI-4615 scala.bat honors -J and -D options. This makes scala.bat parse and use -J and -D arguments. Specifically: - Parameters starting with -J are stripped of the prefix, unquoted if necessary and appended to %JAVA_OPTS% or default values. - Parameters starting with -D are unquoted if necessary and then appended to the others. The right-hand side of a property can be quoted or not. - All of those are given to `java` before any other parameters. - The above only happens on parameter preceding the first parameter that does not start with "-" (usually a class name). - The exact arguments passed to scala.bat are also given as-is to the scala launcher (including -J and -D arguments). set JAVA_OPTS=-Xmx512m scala -J-Xmx128m -Dprop1=42 -Dprop2="hello world" "-Dprop3=bar" "-J-Xms64m" Test foo will result in java -Xmx512m -Xmx128m -Dprop1=42 -Dprop2="hello world" -Dprop3=bar -Xms64m [cp, scala main] -J-Xmx128m -Dprop1=42 -Dprop2="hello world" "-Dprop3=bar" "-J-Xms64m" Test foo --- .../scala/tools/ant/templates/tool-windows.tmpl | 68 +++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index bd6cf561b9..189127443c 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -22,13 +22,74 @@ if "%~1"=="-toolcp" ( goto another_param ) -set _LINE_PARAMS=%1 +rem We keep in _JAVA_PARAMS all -J-prefixed and -D-prefixed arguments +set _JAVA_PARAMS= + +if [%1]==[] goto param_afterloop +set _TEST_PARAM=%~1 +if not "%_TEST_PARAM:~0,1%"=="-" goto param_afterloop + +rem ignore -e "scala code" +if "%_TEST_PARAM:~0,2%"=="-e" ( + shift + shift + if [%1]==[] goto param_afterloop +) + +set _TEST_PARAM=%~1 +if "%_TEST_PARAM:~0,2%"=="-J" ( + set _JAVA_PARAMS=%_TEST_PARAM:~2% +) + +if "%_TEST_PARAM:~0,2%"=="-D" ( + rem test if this was double-quoted property "-Dprop=42" + for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO ( + if not "%%G" == "%_TEST_PARAM%" ( + rem double quoted: "-Dprop=42" -> -Dprop="42" + set _JAVA_PARAMS=%%G="%%H" + ) else if [%2] neq [] ( + rem it was a normal property: -Dprop=42 or -Drop="42" + set _JAVA_PARAMS=%_TEST_PARAM%=%2 + shift + ) + ) +) + :param_loop shift + if [%1]==[] goto param_afterloop -set _LINE_PARAMS=%_LINE_PARAMS% %1 +set _TEST_PARAM=%~1 +if not "%_TEST_PARAM:~0,1%"=="-" goto param_afterloop + +rem ignore -e "scala code" +if "%_TEST_PARAM:~0,2%"=="-e" ( + shift + shift + if [%1]==[] goto param_afterloop +) + +set _TEST_PARAM=%~1 +if "%_TEST_PARAM:~0,2%"=="-J" ( + set _JAVA_PARAMS=%_JAVA_PARAMS% %_TEST_PARAM:~2% +) + +if "%_TEST_PARAM:~0,2%"=="-D" ( + rem test if this was double-quoted property "-Dprop=42" + for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO ( + if not "%%G" == "%_TEST_PARAM%" ( + rem double quoted: "-Dprop=42" -> -Dprop="42" + set _JAVA_PARAMS=%_JAVA_PARAMS% %%G="%%H" + ) else if [%2] neq [] ( + rem it was a normal property: -Dprop=42 or -Drop="42" + set _JAVA_PARAMS=%_JAVA_PARAMS% %_TEST_PARAM%=%2 + shift + ) + ) +) goto param_loop :param_afterloop + if "%OS%" NEQ "Windows_NT" ( echo "Warning, your version of Windows is not supported. Attempting to start scala anyway." ) @@ -51,6 +112,9 @@ rem We use the value of the JAVA_OPTS environment variable if defined set _JAVA_OPTS=%JAVA_OPTS% if not defined _JAVA_OPTS set _JAVA_OPTS=@javaflags@ +rem We append _JAVA_PARAMS java arguments to JAVA_OPTS if necessary +if defined _JAVA_PARAMS set _JAVA_OPTS=%_JAVA_OPTS% %_JAVA_PARAMS% + set _TOOL_CLASSPATH=@classpath@ if "%_TOOL_CLASSPATH%"=="" ( for %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f" -- cgit v1.2.3 From 36524c21964696ec71170970c6a65f9bb7aec8f0 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Wed, 7 Aug 2013 11:19:40 +0200 Subject: SI-7331 tb.parse returns unpositioned trees This commit gets rid off code wrapping that was previously used by toolbox to get into correct parsing mode. Instead combination of templateStats/accept(EOF) is used. This is the same solution as the one used in repl and built-in scriptRunner This pull request doesn't attempt to generalize this approach in any way and re-use it all over the place due to the caution of possible accidental compatibility breakage. I plan to do it separately against master. Additionally there are a few more changes that make importers be aware of positions and a test for that (via @jedesah). --- src/compiler/scala/tools/reflect/ToolBoxFactory.scala | 10 +++++----- src/reflect/scala/reflect/internal/Importers.scala | 7 ++++++- test/files/run/t7331a.check | 2 ++ test/files/run/t7331a.scala | 10 ++++++++++ test/files/run/t7331b.check | 3 +++ test/files/run/t7331b.scala | 11 +++++++++++ test/files/run/t7331c.check | 3 +++ test/files/run/t7331c.scala | 11 +++++++++++ 8 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 test/files/run/t7331a.check create mode 100644 test/files/run/t7331a.scala create mode 100644 test/files/run/t7331b.check create mode 100644 test/files/run/t7331b.scala create mode 100644 test/files/run/t7331c.check create mode 100644 test/files/run/t7331c.scala (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 64b8870619..ec61f7a945 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -8,6 +8,7 @@ import scala.tools.nsc.typechecker.Modes import scala.tools.nsc.io.VirtualDirectory import scala.tools.nsc.interpreter.AbstractFileClassLoader import scala.tools.nsc.util.FreshNameCreator +import scala.tools.nsc.ast.parser.Tokens.EOF import scala.reflect.internal.Flags._ import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile} import java.lang.{Class => jClass} @@ -273,14 +274,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def parse(code: String): Tree = { val run = new Run reporter.reset() - val wrappedCode = "object wrapper {" + EOL + code + EOL + "}" - val file = new BatchSourceFile("", wrappedCode) + val file = new BatchSourceFile("", code) val unit = new CompilationUnit(file) phase = run.parserPhase val parser = new syntaxAnalyzer.UnitParser(unit) - val wrappedTree = parser.parse() + val parsed = parser.templateStats() + parser.accept(EOF) throwIfErrors() - val PackageDef(_, List(ModuleDef(_, _, Template(_, _, _ :: parsed)))) = wrappedTree parsed match { case expr :: Nil => expr case stats :+ expr => Block(stats, expr) @@ -402,7 +402,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def compile(tree: u.Tree): () => Any = { if (compiler.settings.verbose.value) println("importing "+tree) - var ctree: compiler.Tree = importer.importTree(tree) + val ctree: compiler.Tree = importer.importTree(tree) if (compiler.settings.verbose.value) println("compiling "+ctree) compiler.compile(ctree) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 43902c1930..9a8dee1f15 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -443,7 +443,12 @@ trait Importers extends api.Importers { self: SymbolTable => } }) tryFixup() - mytree + // we have to be careful with position import as some shared trees + // like EmptyTree, emptyValDef don't support position assignment + if (tree.pos != NoPosition) + mytree.setPos(importPosition(tree.pos)) + else + mytree } def importValDef(tree: from.ValDef): ValDef = importTree(tree).asInstanceOf[ValDef] diff --git a/test/files/run/t7331a.check b/test/files/run/t7331a.check new file mode 100644 index 0000000000..a59b400344 --- /dev/null +++ b/test/files/run/t7331a.check @@ -0,0 +1,2 @@ +source-,line-1,offset=0 +2 \ No newline at end of file diff --git a/test/files/run/t7331a.scala b/test/files/run/t7331a.scala new file mode 100644 index 0000000000..1851945e63 --- /dev/null +++ b/test/files/run/t7331a.scala @@ -0,0 +1,10 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox + +object Test extends App { + val tb = cm.mkToolBox() + val tree = tb.parse("x") + println(tree.pos) + println(tree.pos.source.content.length) +} \ No newline at end of file diff --git a/test/files/run/t7331b.check b/test/files/run/t7331b.check new file mode 100644 index 0000000000..7034a95a3f --- /dev/null +++ b/test/files/run/t7331b.check @@ -0,0 +1,3 @@ +reflective compilation has failed: + +')' expected but eof found. diff --git a/test/files/run/t7331b.scala b/test/files/run/t7331b.scala new file mode 100644 index 0000000000..052656d11b --- /dev/null +++ b/test/files/run/t7331b.scala @@ -0,0 +1,11 @@ +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() + try tb.parse("f(x") + catch { + case ToolBoxError(msg, _) => println(msg) + } +} \ No newline at end of file diff --git a/test/files/run/t7331c.check b/test/files/run/t7331c.check new file mode 100644 index 0000000000..af9f1b1ad9 --- /dev/null +++ b/test/files/run/t7331c.check @@ -0,0 +1,3 @@ +ClassDef(Modifiers(), newTypeName("C"), List(), Template(List(Select(Ident(scala), newTypeName("AnyRef"))), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(()))))))) +source-,line-1,offset=6 +NoPosition diff --git a/test/files/run/t7331c.scala b/test/files/run/t7331c.scala new file mode 100644 index 0000000000..75873afcd0 --- /dev/null +++ b/test/files/run/t7331c.scala @@ -0,0 +1,11 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox + +object Test extends App { + val tb = cm.mkToolBox() + val tree = tb.parse("class C").asInstanceOf[ClassDef] + println(showRaw(tree)) + println(tree.pos) + println(tree.impl.self.pos) +} \ No newline at end of file -- cgit v1.2.3 From 1dac5ef13ded3257f471ce9d3fbbdd9d421cfd06 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 2 Aug 2013 01:02:16 +0200 Subject: showRaw now prints symbols of def trees A very useful addition that came in handy when hacking macro annotations --- src/reflect/scala/reflect/internal/Printers.scala | 2 ++ test/files/run/t6392b.check | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 80d247c0ea..35cb749ede 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -564,6 +564,8 @@ trait Printers extends api.Printers { self: SymbolTable => case refTree: RefTree => if (tree.symbol.name != refTree.name) print("[", tree.symbol, " aka ", refTree.name, "]") else print(tree.symbol) + case defTree: DefTree => + print(tree.symbol) case _ => print(tree.symbol.name) } diff --git a/test/files/run/t6392b.check b/test/files/run/t6392b.check index e9c7ecaa34..b7872f0e08 100644 --- a/test/files/run/t6392b.check +++ b/test/files/run/t6392b.check @@ -1 +1 @@ -ModuleDef(Modifiers(), newTermName("C"), Template(List(Select(Ident(scala#PK), newTypeName("AnyRef")#TPE)), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(newTypeName("C")), tpnme.EMPTY), nme.CONSTRUCTOR#PCTOR), List())), Literal(Constant(()))))))) +ModuleDef(Modifiers(), newTermName("C")#MOD, Template(List(Select(Ident(scala#PK), newTypeName("AnyRef")#TPE)), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR#PCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(newTypeName("C")), tpnme.EMPTY), nme.CONSTRUCTOR#PCTOR), List())), Literal(Constant(()))))))) -- cgit v1.2.3 From 5626c7403e44380c6e3610cae8f68f3d2b52eb70 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 30 Jul 2013 11:37:59 +0200 Subject: [nomaster] macro errors now always have positions Back then when I implemented macros for inclusion in trunk (Spring 2012), partest didn't support the _1, _2, ... convention for neg tests, so I had to use toolboxes to test macro-generated exceptions. Unfortunately toolboxes aren't very good with positions (mostly because their inputs are almost always constructed without corresponding sources) so I didn't notice that errors signalizing about macro-generated exceptions actually don't carry positions with them because of a typo. This patch fixes the oversight, but it doesn't need to be ported to master, because over there everything's already fixed by one of the backports from macro paradise. --- src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 2 +- test/files/neg/macro-abort.check | 4 ++++ test/files/neg/macro-abort/Macros_1.scala | 9 +++++++++ test/files/neg/macro-abort/Test_2.scala | 3 +++ test/files/neg/macro-exception.check | 7 +++++++ test/files/neg/macro-exception/Macros_1.scala | 9 +++++++++ test/files/neg/macro-exception/Test_2.scala | 3 +++ 7 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/macro-abort.check create mode 100644 test/files/neg/macro-abort/Macros_1.scala create mode 100644 test/files/neg/macro-abort/Test_2.scala create mode 100644 test/files/neg/macro-exception.check create mode 100644 test/files/neg/macro-exception/Macros_1.scala create mode 100644 test/files/neg/macro-exception/Test_2.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index b9cff5b2d3..5d6d094b44 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -697,7 +697,7 @@ trait ContextErrors { def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg macroLogLite("macro expansion has failed: %s".format(msgForLog)) val errorPos = if (pos != NoPosition) pos else (if (expandee.pos != NoPosition) expandee.pos else enclosingMacroPosition) - if (msg != null) context.error(pos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions + if (msg != null) context.error(errorPos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions setError(expandee) throw MacroExpansionException } diff --git a/test/files/neg/macro-abort.check b/test/files/neg/macro-abort.check new file mode 100644 index 0000000000..1e58add533 --- /dev/null +++ b/test/files/neg/macro-abort.check @@ -0,0 +1,4 @@ +Test_2.scala:2: error: aborted + Macros.abort + ^ +one error found diff --git a/test/files/neg/macro-abort/Macros_1.scala b/test/files/neg/macro-abort/Macros_1.scala new file mode 100644 index 0000000000..676c112098 --- /dev/null +++ b/test/files/neg/macro-abort/Macros_1.scala @@ -0,0 +1,9 @@ +import scala.language.experimental.macros +import scala.reflect.macros.Context + +object Macros { + def impl(c: Context) = { + c.abort(c.enclosingPosition, "aborted") + } + def abort = macro impl +} \ No newline at end of file diff --git a/test/files/neg/macro-abort/Test_2.scala b/test/files/neg/macro-abort/Test_2.scala new file mode 100644 index 0000000000..1d0a7a25dc --- /dev/null +++ b/test/files/neg/macro-abort/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends App { + Macros.abort +} \ No newline at end of file diff --git a/test/files/neg/macro-exception.check b/test/files/neg/macro-exception.check new file mode 100644 index 0000000000..cee8b32ebd --- /dev/null +++ b/test/files/neg/macro-exception.check @@ -0,0 +1,7 @@ +Test_2.scala:2: error: exception during macro expansion: +java.lang.Exception + at Macros$.impl(Macros_1.scala:6) + + Macros.exception + ^ +one error found diff --git a/test/files/neg/macro-exception/Macros_1.scala b/test/files/neg/macro-exception/Macros_1.scala new file mode 100644 index 0000000000..60e4020aec --- /dev/null +++ b/test/files/neg/macro-exception/Macros_1.scala @@ -0,0 +1,9 @@ +import scala.language.experimental.macros +import scala.reflect.macros.Context + +object Macros { + def impl(c: Context) = { + throw new Exception() + } + def exception = macro impl +} \ No newline at end of file diff --git a/test/files/neg/macro-exception/Test_2.scala b/test/files/neg/macro-exception/Test_2.scala new file mode 100644 index 0000000000..d82b21f2b2 --- /dev/null +++ b/test/files/neg/macro-exception/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends App { + Macros.exception +} \ No newline at end of file -- cgit v1.2.3 From 26a86793596c331ec19a8a584c6ff66d8d2acaef Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 2 Aug 2013 14:27:42 +0200 Subject: currentRun.compiles now correctly works in toolboxes Another random bug uncovered and extinguished when hacking macro annots. --- .../scala/tools/reflect/ToolBoxFactory.scala | 5 +++- test/files/run/toolbox_current_run_compiles.check | 2 ++ test/files/run/toolbox_current_run_compiles.scala | 28 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/files/run/toolbox_current_run_compiles.check create mode 100644 test/files/run/toolbox_current_run_compiles.scala (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index ec61f7a945..b9541ece5d 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -15,6 +15,7 @@ import java.lang.{Class => jClass} import scala.compat.Platform.EOL import scala.reflect.NameTransformer import scala.reflect.api.JavaUniverse +import scala.reflect.io.NoAbstractFile abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => @@ -138,7 +139,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _) def wrapper (tree: => Tree) = wrapper1(wrapper2(tree)) - phase = (new Run).typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled + val run = new Run + run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works + phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions reporter.reset() diff --git a/test/files/run/toolbox_current_run_compiles.check b/test/files/run/toolbox_current_run_compiles.check new file mode 100644 index 0000000000..da29283aaa --- /dev/null +++ b/test/files/run/toolbox_current_run_compiles.check @@ -0,0 +1,2 @@ +true +false diff --git a/test/files/run/toolbox_current_run_compiles.scala b/test/files/run/toolbox_current_run_compiles.scala new file mode 100644 index 0000000000..b48c998e64 --- /dev/null +++ b/test/files/run/toolbox_current_run_compiles.scala @@ -0,0 +1,28 @@ +package pkg { + import scala.reflect.macros.Context + import scala.language.experimental.macros + + object Macros { + def impl[T: c.WeakTypeTag](c: Context) = { + import c.universe._ + val sym = c.weakTypeOf[T].typeSymbol + val g = c.universe.asInstanceOf[scala.tools.nsc.Global] + c.Expr[Boolean](Literal(Constant(g.currentRun.compiles(sym.asInstanceOf[g.Symbol])))) + } + def compiles[T] = macro impl[T] + } +} + +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{universe => ru} +import scala.tools.reflect.ToolBox + +object Test extends App { + val cm = ru.runtimeMirror(getClass.getClassLoader) + val toolbox = cm.mkToolBox() + toolbox.eval(toolbox.parse("""{ + class C + println(pkg.Macros.compiles[C]) + println(pkg.Macros.compiles[Object]) + }""")) +} \ No newline at end of file -- cgit v1.2.3 From 1d28fe6c808fb9b257a2a3b24abb911bf7697d2b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 9 Aug 2013 14:24:48 +0200 Subject: [nomaster] SI-7733 reflective packages now more consistent with scalac Previously PackageScopes from scala.reflect ignored all classes that had $'s in non-rightmost positions in their names. Unfortunately this behaviour is inconsistent with how scalac does things, and I reconciled this as usual, by pulling corresponding logic into scala-reflect.jar and sharing it between runtime reflection and compiler. This change has seprate pull requests for 2.10.x and 2.11.0. The latter deprecates `scala.tools.nsc.util.ClassPath.isTraitImplementation` whereas the former (which you're looking at right now) does not, because we can't deprecated members in minor releases. --- bincompat-backward.whitelist.conf | 8 ++++++++ bincompat-forward.whitelist.conf | 16 ++++++++++++++++ src/compiler/scala/tools/nsc/util/ClassPath.scala | 5 +++-- src/compiler/scala/tools/nsc/util/MsilClassPath.scala | 3 ++- src/reflect/scala/reflect/runtime/JavaMirrors.scala | 4 ++-- src/reflect/scala/reflect/runtime/ReflectionUtils.scala | 6 ++++++ src/reflect/scala/reflect/runtime/SymbolLoaders.scala | 11 ++--------- test/files/run/t7733.check | 1 + test/files/run/t7733/Separate_1.scala | 5 +++++ test/files/run/t7733/Test_2.scala | 9 +++++++++ 10 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 test/files/run/t7733.check create mode 100644 test/files/run/t7733/Separate_1.scala create mode 100644 test/files/run/t7733/Test_2.scala (limited to 'src') diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index 267631f908..31262e047e 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -239,6 +239,14 @@ filter { { matchName="scala.reflect.internal.StdAttachments.isMacroExpansionSuppressed" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse.isInvalidClassName" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SymbolLoaders.isInvalidClassName" + problemName=MissingMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index b3af372b15..c6b7b38e8d 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -515,6 +515,22 @@ filter { { matchName="scala.reflect.runtime.JavaMirrors#JavaMirror#FromJavaClassCompleter.scala$reflect$runtime$JavaMirrors$JavaMirror$FromJavaClassCompleter$$enterEmptyCtorIfNecessary$1" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClass" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClassfile" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.ReflectionUtils.isTraitImplementation" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.SymbolLoaders.isInvalidClassName" + problemName=MissingMethodProblem } ] } diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 471e2653cf..a62c87e713 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -16,6 +16,7 @@ import Jar.isJarOrZip import File.pathSeparator import java.net.MalformedURLException import java.util.regex.PatternSyntaxException +import scala.reflect.runtime.ReflectionUtils /**

* This module provides star expansion of '-classpath' option arguments, behaves the same as @@ -100,7 +101,7 @@ object ClassPath { } /** A useful name filter. */ - def isTraitImplementation(name: String) = name endsWith "$class.class" + def isTraitImplementation(name: String) = ReflectionUtils.isTraitImplementation(name) def specToURL(spec: String): Option[URL] = try Some(new URL(spec)) @@ -161,7 +162,7 @@ object ClassPath { } object DefaultJavaContext extends JavaContext { - override def isValidName(name: String) = !isTraitImplementation(name) + override def isValidName(name: String) = !ReflectionUtils.scalacShouldntLoadClassfile(name) } private def endsClass(s: String) = s.length > 6 && s.substring(s.length - 6) == ".class" diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala index aa3b7c286d..77a19d3ead 100644 --- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -15,7 +15,8 @@ import scala.util.Sorting import scala.collection.mutable import scala.tools.nsc.io.{ AbstractFile, MsilFile } import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly } -import ClassPath.{ ClassPathContext, isTraitImplementation } +import ClassPath.ClassPathContext +import scala.reflect.runtime.ReflectionUtils.isTraitImplementation /** Keeping the MSIL classpath code in its own file is important to make sure * we don't accidentally introduce a dependency on msil.jar in the jvm. diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 9ecc5c6084..22fe7f098c 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -19,7 +19,7 @@ import scala.collection.mutable.{ HashMap, ListBuffer } import internal.Flags._ //import scala.tools.nsc.util.ScalaClassLoader //import scala.tools.nsc.util.ScalaClassLoader._ -import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance} +import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance, scalacShouldntLoadClass} import scala.language.existentials import scala.runtime.{ScalaRunTime, BoxesRunTime} import scala.reflect.internal.util.Collections._ @@ -956,7 +956,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val cls = if (jclazz.isMemberClass && !nme.isImplClassName(jname)) lookupClass - else if (jclazz.isLocalClass0 || isInvalidClassName(jname)) + else if (jclazz.isLocalClass0 || scalacShouldntLoadClass(jname)) // local classes and implementation classes not preserved by unpickling - treat as Java // // upd. but only if they cannot be loaded as top-level classes diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index 33ad6d2430..ffed3cc38e 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -76,4 +76,10 @@ private[scala] object ReflectionUtils { accessor setAccessible true accessor invoke outer } + + def isTraitImplementation(fileName: String) = fileName endsWith "$class.class" + + def scalacShouldntLoadClassfile(fileName: String) = isTraitImplementation(fileName) + + def scalacShouldntLoadClass(name: scala.reflect.internal.SymbolTable#Name) = scalacShouldntLoadClassfile(name + ".class") } diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 61663f6181..b895092639 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -4,6 +4,7 @@ package runtime import internal.Flags import java.lang.{Class => jClass, Package => jPackage} import scala.collection.mutable +import scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClass private[reflect] trait SymbolLoaders { self: SymbolTable => @@ -89,14 +90,6 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => } } - /** Is the given name valid for a top-level class? We exclude names with embedded $-signs, because - * these are nested classes or anonymous classes, - */ - def isInvalidClassName(name: Name) = { - val dp = name pos '$' - 0 < dp && dp < (name.length - 1) - } - class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand with SynchronizedScope { assert(pkgClass.isType) @@ -106,7 +99,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => val e = super.lookupEntry(name) if (e != null) e - else if (isInvalidClassName(name) || (negatives contains name)) + else if (scalacShouldntLoadClass(name) || (negatives contains name)) null else { val path = diff --git a/test/files/run/t7733.check b/test/files/run/t7733.check new file mode 100644 index 0000000000..19765bd501 --- /dev/null +++ b/test/files/run/t7733.check @@ -0,0 +1 @@ +null diff --git a/test/files/run/t7733/Separate_1.scala b/test/files/run/t7733/Separate_1.scala new file mode 100644 index 0000000000..a326ecd53e --- /dev/null +++ b/test/files/run/t7733/Separate_1.scala @@ -0,0 +1,5 @@ +package test + +class Separate { + for (i <- 1 to 10) println(i) +} \ No newline at end of file diff --git a/test/files/run/t7733/Test_2.scala b/test/files/run/t7733/Test_2.scala new file mode 100644 index 0000000000..28358574ec --- /dev/null +++ b/test/files/run/t7733/Test_2.scala @@ -0,0 +1,9 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox + +object Test extends App { + val tb = cm.mkToolBox() + val code = tb.parse("{ val x: test.Separate$$anonfun$1 = null; x }") + println(tb.eval(code)) +} \ No newline at end of file -- cgit v1.2.3 From ebb01e05cbe4541838efa189196fe7a49ddb82cf Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 11 Aug 2013 23:17:08 +0200 Subject: SI-7020 Determinism for pattern matcher warnings Use LinkedHashSet for the DPLL algorithm for determistic counter example generation. Before, the test compiled with: [info] v2.10.2 => /Users/jason/usr/scala-v2.10.2-0-g60d462e test/files/neg/t7020.scala:3: warning: match may not be exhaustive. It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 5, 6, 7))), List(_, _) List(5) match { ^ test/files/neg/t7020.scala:10: warning: match may not be exhaustive. It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 5, 6, 7))), List(_, _) List(5) match { ^ test/files/neg/t7020.scala:17: warning: match may not be exhaustive. It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 6, 7)), _), List(1, _), List(2, _), List(4, _), List(5, _), List(6, _), List(7, _), List(??, _) List(5) match { ^ test/files/neg/t7020.scala:24: warning: match may not be exhaustive. It would fail on the following input: List(_, _) List(5) match { ^ --- .../scala/tools/nsc/transform/patmat/Solving.scala | 9 ++++--- test/files/neg/t7020.check | 17 ++++++++++++ test/files/neg/t7020.flags | 1 + test/files/neg/t7020.scala | 30 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 test/files/neg/t7020.check create mode 100644 test/files/neg/t7020.flags create mode 100644 test/files/neg/t7020.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala index 843f831ea1..ec66bf6f20 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala @@ -208,15 +208,16 @@ trait Solving extends Logic { withLit(findModelFor(dropUnit(f, unitLit)), unitLit) case _ => // partition symbols according to whether they appear in positive and/or negative literals - val pos = new mutable.HashSet[Sym]() - val neg = new mutable.HashSet[Sym]() + // SI-7020 Linked- for deterministic counter examples. + val pos = new mutable.LinkedHashSet[Sym]() + val neg = new mutable.LinkedHashSet[Sym]() f.foreach{_.foreach{ lit => if (lit.pos) pos += lit.sym else neg += lit.sym }} // appearing in both positive and negative - val impures = pos intersect neg + val impures: mutable.LinkedHashSet[Sym] = pos intersect neg // appearing only in either positive/negative positions - val pures = (pos ++ neg) -- impures + val pures: mutable.LinkedHashSet[Sym] = (pos ++ neg) -- impures if (pures nonEmpty) { val pureSym = pures.head diff --git a/test/files/neg/t7020.check b/test/files/neg/t7020.check new file mode 100644 index 0000000000..a869b12363 --- /dev/null +++ b/test/files/neg/t7020.check @@ -0,0 +1,17 @@ +t7020.scala:3: error: match may not be exhaustive. +It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 5, 6, 7))), List(_, _) + List(5) match { + ^ +t7020.scala:10: error: match may not be exhaustive. +It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 5, 6, 7))), List(_, _) + List(5) match { + ^ +t7020.scala:17: error: match may not be exhaustive. +It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 5, 6, 7))), List(_, _) + List(5) match { + ^ +t7020.scala:24: error: match may not be exhaustive. +It would fail on the following inputs: List((x: Int forSome x not in (1, 2, 4, 5, 6, 7))), List(_, _) + List(5) match { + ^ +four errors found diff --git a/test/files/neg/t7020.flags b/test/files/neg/t7020.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t7020.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t7020.scala b/test/files/neg/t7020.scala new file mode 100644 index 0000000000..cc5421bab1 --- /dev/null +++ b/test/files/neg/t7020.scala @@ -0,0 +1,30 @@ +object Test { + // warning was non-deterministic + List(5) match { + case 1 :: Nil | 2 :: Nil => + case (x@(4 | 5 | 6)) :: Nil => + case 7 :: Nil => + case Nil => + } + + List(5) match { + case 1 :: Nil | 2 :: Nil => + case (x@(4 | 5 | 6)) :: Nil => + case 7 :: Nil => + case Nil => + } + + List(5) match { + case 1 :: Nil | 2 :: Nil => + case (x@(4 | 5 | 6)) :: Nil => + case 7 :: Nil => + case Nil => + } + + List(5) match { + case 1 :: Nil | 2 :: Nil => + case (x@(4 | 5 | 6)) :: Nil => + case 7 :: Nil => + case Nil => + } +} -- cgit v1.2.3 From 5724cae9efe168094f5f3d176f2606b9c43de6dc Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sat, 10 Aug 2013 09:29:58 +0200 Subject: SI-7694 @uncheckedBounds, an opt-out from type bounds checking Synthetic defs introduced by transforms like named/default arguments, ANF (in scala-async) often introduce a type tree (the tpt of the temporary) that are based on the types of expressions. These types are scrutinized in RefChecks to check that type parameter bounds are satisfied. However, the type of the expression might be based on slack a LUB that fails to capture constraints between type parameters. This slackness is noted in `mergePrefixAndArgs`: // Martin: I removed this, because incomplete. Not sure there is a // good way to fix it. For the moment we just err on the conservative // side, i.e. with a bound that is too high. The synthesizer can now opt out of bounds by annotating the type as follows: val temp: ( @uncheckedBounds) = expr This facility is now used in named/default arguments for the temporaries used for the reciever and arguments. The annotation is hidden under scala.reflect.internal, rather than in the more prominent scala.annotation.unchecked, to reflect the intention that it should only be used in tree transformers. The library component of this change and test case will be included in the next commit. Why split like this? It shows that the 2.10.3 compiler will work with 2.10.2 scala-reflect.jar. --- bincompat-backward.whitelist.conf | 4 ++ bincompat-forward.whitelist.conf | 16 +++++++ .../tools/nsc/typechecker/NamesDefaults.scala | 9 ++-- .../scala/tools/nsc/typechecker/RefChecks.scala | 51 ++++++++++++++++++---- .../scala/reflect/internal/Definitions.scala | 1 + src/reflect/scala/reflect/internal/Types.scala | 6 +++ 6 files changed, 74 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index 31262e047e..3012ce4eeb 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -247,6 +247,10 @@ filter { { matchName="scala.reflect.runtime.SymbolLoaders.isInvalidClassName" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Types.uncheckedBounds" + problemName=MissingMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index c6b7b38e8d..c92538b35a 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -531,6 +531,22 @@ filter { { matchName="scala.reflect.runtime.SymbolLoaders.isInvalidClassName" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.SymbolTable.uncheckedBounds" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Types.uncheckedBounds" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Definitions#DefinitionsClass.UncheckedBoundsClass" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.annotations.uncheckedBounds" + problemName=MissingClassProblem } ] } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index f3736f1519..bd2cac81ea 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -164,7 +164,7 @@ trait NamesDefaults { self: Analyzer => // never used for constructor calls, they always have a stable qualifier def blockWithQualifier(qual: Tree, selected: Name) = { - val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos) setInfo qual.tpe + val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos) setInfo uncheckedBounds(qual.tpe) blockTyper.context.scope enter sym val vd = atPos(sym.pos)(ValDef(sym, qual) setType NoType) // it stays in Vegas: SI-5720, SI-5727 @@ -289,9 +289,10 @@ trait NamesDefaults { self: Analyzer => // We have to deconst or types inferred from literal arguments will be Constant(_), e.g. pos/z1730.scala. gen.stableTypeFor(arg).filter(_ <:< paramTpe).getOrElse(arg.tpe).deconst ) - val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos) setInfo ( - if (byName) functionType(Nil, argTpe) else argTpe - ) + val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos) setInfo { + val tp = if (byName) functionType(Nil, argTpe) else argTpe + uncheckedBounds(tp) + } Some((context.scope.enter(s), byName, repeated)) }) map2(symPs, args) { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 9c374e85ea..db899b44f9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1513,17 +1513,35 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans false } - private def checkTypeRef(tp: Type, tree: Tree) = tp match { + private def checkTypeRef(tp: Type, tree: Tree, skipBounds: Boolean) = tp match { case TypeRef(pre, sym, args) => checkDeprecated(sym, tree.pos) if(sym.isJavaDefined) sym.typeParams foreach (_.cookJavaRawInfo()) - if (!tp.isHigherKinded) + if (!tp.isHigherKinded && !skipBounds) checkBounds(tree, pre, sym.owner, sym.typeParams, args) case _ => } - private def checkAnnotations(tpes: List[Type], tree: Tree) = tpes foreach (tp => checkTypeRef(tp, tree)) + private def checkTypeRefBounds(tp: Type, tree: Tree) = { + var skipBounds = false + tp match { + case AnnotatedType(ann :: Nil, underlying, selfSym) if ann.symbol == UncheckedBoundsClass => + skipBounds = true + underlying + case TypeRef(pre, sym, args) => + if (!tp.isHigherKinded && !skipBounds) + checkBounds(tree, pre, sym.owner, sym.typeParams, args) + tp + case _ => + tp + } + } + + private def checkAnnotations(tpes: List[Type], tree: Tree) = tpes foreach { tp => + checkTypeRef(tp, tree, skipBounds = false) + checkTypeRefBounds(tp, tree) + } private def doTypeTraversal(tree: Tree)(f: Type => Unit) = if (!inPattern) tree.tpe foreach f private def applyRefchecksToAnnotations(tree: Tree): Unit = { @@ -1551,8 +1569,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } doTypeTraversal(tree) { - case AnnotatedType(annots, _, _) => applyChecks(annots) - case _ => + case tp @ AnnotatedType(annots, _, _) => + applyChecks(annots) + case tp => } case _ => } @@ -1735,13 +1754,27 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } val existentialParams = new ListBuffer[Symbol] - doTypeTraversal(tree) { // check all bounds, except those that are existential type parameters - case ExistentialType(tparams, tpe) => + var skipBounds = false + // check all bounds, except those that are existential type parameters + // or those within typed annotated with @uncheckedBounds + doTypeTraversal(tree) { + case tp @ ExistentialType(tparams, tpe) => existentialParams ++= tparams - case t: TypeRef => - checkTypeRef(deriveTypeWithWildcards(existentialParams.toList)(t), tree) + case ann: AnnotatedType if ann.hasAnnotation(UncheckedBoundsClass) => + // SI-7694 Allow code synthetizers to disable checking of bounds for TypeTrees based on inferred LUBs + // which might not conform to the constraints. + skipBounds = true + case tp: TypeRef => + val tpWithWildcards = deriveTypeWithWildcards(existentialParams.toList)(tp) + checkTypeRef(tpWithWildcards, tree, skipBounds) case _ => } + if (skipBounds) { + tree.tpe = tree.tpe.map { + _.filterAnnotations(_.symbol != UncheckedBoundsClass) + } + } + tree case TypeApply(fn, args) => diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 629d82d254..09d7af82d1 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -983,6 +983,7 @@ trait Definitions extends api.StandardDefinitions { lazy val ThrowsClass = requiredClass[scala.throws[_]] lazy val TransientAttr = requiredClass[scala.transient] lazy val UncheckedClass = requiredClass[scala.unchecked] + lazy val UncheckedBoundsClass = getClassIfDefined("scala.reflect.internal.annotations.uncheckedBounds") lazy val UnspecializedClass = requiredClass[scala.annotation.unspecialized] lazy val VolatileAttr = requiredClass[scala.volatile] diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index fc3f5de77f..563578344d 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -7314,6 +7314,12 @@ trait Types extends api.Types { self: SymbolTable => else (ps :+ SerializableClass.tpe).toList ) + /** Adds the @uncheckedBound annotation if the given `tp` has type arguments */ + final def uncheckedBounds(tp: Type): Type = { + if (tp.typeArgs.isEmpty || UncheckedBoundsClass == NoSymbol) tp // second condition for backwards compatibilty with older scala-reflect.jar + else tp.withAnnotation(AnnotationInfo marker UncheckedBoundsClass.tpe) + } + /** Members of the given class, other than those inherited * from Any or AnyRef. */ -- cgit v1.2.3 From e65321cb29758518573902041001d203d924c8bc Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sat, 10 Aug 2013 09:31:30 +0200 Subject: SI-7694 Add @uncheckedBounds to the library Followup to the previous commit that added the compiler support for opting out of bounds checking. With both pieces, we can test that the temporaries introduced by the named/default arguments transform don't trigger bounds violations. --- .../internal/annotations/uncheckedBounds.scala | 13 +++++++ test/files/neg/t7694b.check | 7 ++++ test/files/pos/t7694.scala | 40 ++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala create mode 100644 test/files/neg/t7694b.check create mode 100644 test/files/pos/t7694.scala (limited to 'src') diff --git a/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala b/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala new file mode 100644 index 0000000000..a44bb54734 --- /dev/null +++ b/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala @@ -0,0 +1,13 @@ +package scala.reflect +package internal +package annotations + +/** + * An annotation that designates the annotated type should not be checked for violations of + * type parameter bounds in the `refchecks` phase of the compiler. This can be used by synthesized + * code the uses an inferred type of an expression as the type of an artifict val/def (for example, + * a temporary value introduced by an ANF transform). See [[https://issues.scala-lang.org/browse/SI-7694]]. + * + * @since 2.10.3 + */ +final class uncheckedBounds extends scala.annotation.StaticAnnotation diff --git a/test/files/neg/t7694b.check b/test/files/neg/t7694b.check new file mode 100644 index 0000000000..ea3d7736f8 --- /dev/null +++ b/test/files/neg/t7694b.check @@ -0,0 +1,7 @@ +t7694b.scala:8: error: type arguments [_3,_4] do not conform to trait L's type parameter bounds [A2,B2 <: A2] + def d = if (true) (null: L[A, A]) else (null: L[B, B]) + ^ +t7694b.scala:9: error: type arguments [_1,_2] do not conform to trait L's type parameter bounds [A2,B2 <: A2] + val v = if (true) (null: L[A, A]) else (null: L[B, B]) + ^ +two errors found diff --git a/test/files/pos/t7694.scala b/test/files/pos/t7694.scala new file mode 100644 index 0000000000..9852d5ec79 --- /dev/null +++ b/test/files/pos/t7694.scala @@ -0,0 +1,40 @@ +trait A +trait B + +trait L[A2, B2 <: A2] { + def bar(a: Any, b: Any) = 0 +} + +object Lub { + // use named args transforms to include TypeTree() in the AST before refchecks. + def foo(a: L[_, _], b: Any) = 0 + + foo(b = 0, a = if (true) (null: L[A, A]) else (null: L[B, B])) + + (if (true) (null: L[A, A]) else (null: L[B, B])).bar(b = 0, a = 0) +} + +/* +The LUB ends up as: + +TypeRef( + TypeSymbol( + abstract trait L#7038[A2#7039, B2#7040 <: A2#7039] extends AnyRef#2197 + + ) + args = List( + AbstractTypeRef( + AbstractType( + type _1#13680 >: A#7036 with B#7037 <: Object#1752 + ) + ) + AbstractTypeRef( + AbstractType( + type _2#13681 >: A#7036 with B#7037 <: Object#1752 + ) + ) + ) +) + +Note that type _2#13681 is *not* bound by _1#13680 +*/ -- cgit v1.2.3 From f91242c6959471b6c463538be8876a2cba29f3d3 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Sat, 15 Jun 2013 12:20:45 -0400 Subject: SI-7014 Annot arg may refer to annotated class's member This only reduces the crasher to a warning. --- .../scala/tools/nsc/symtab/classfile/ClassfileParser.scala | 11 ++++++++--- test/files/pos/t7014/ThreadSafety.java | 9 +++++++++ test/files/pos/t7014/ThreadSafetyLevel.java | 8 ++++++++ test/files/pos/t7014/t7014.scala | 4 ++++ 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 test/files/pos/t7014/ThreadSafety.java create mode 100644 test/files/pos/t7014/ThreadSafetyLevel.java create mode 100644 test/files/pos/t7014/t7014.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 4e5204f283..2a8fe0428c 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -952,9 +952,14 @@ abstract class ClassfileParser { case ENUM_TAG => val t = pool.getType(index) val n = pool.getName(in.nextChar) - val s = t.typeSymbol.companionModule.info.decls.lookup(n) - assert(s != NoSymbol, t) - Some(LiteralAnnotArg(Constant(s))) + val module = t.typeSymbol.companionModule + val s = module.info.decls.lookup(n) + if (s != NoSymbol) Some(LiteralAnnotArg(Constant(s))) + else { + warning(s"""While parsing annotations in ${in.file}, could not find $n in enum $module.\nThis is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (SI-7014).""") + None + } + case ARRAY_TAG => val arr = new ArrayBuffer[ClassfileAnnotArg]() var hasError = false diff --git a/test/files/pos/t7014/ThreadSafety.java b/test/files/pos/t7014/ThreadSafety.java new file mode 100644 index 0000000000..ed508804e3 --- /dev/null +++ b/test/files/pos/t7014/ThreadSafety.java @@ -0,0 +1,9 @@ +package t7014; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) // must be exactly RUNTIME retention (those we parse) +public @interface ThreadSafety { + ThreadSafetyLevel level(); +} \ No newline at end of file diff --git a/test/files/pos/t7014/ThreadSafetyLevel.java b/test/files/pos/t7014/ThreadSafetyLevel.java new file mode 100644 index 0000000000..4df1dc787a --- /dev/null +++ b/test/files/pos/t7014/ThreadSafetyLevel.java @@ -0,0 +1,8 @@ +package t7014; // package needed due to other bug in scalac's java parser + +// since we parse eagerly, we have not yet parsed the classfile when parsing the annotation, +// and on doing so, fail to find a symbol for the COMPLETELY_THREADSAFE reference +// from the annotation's argument to the enum's member +// for now, let's just not crash -- should implement lazy completing at some point +@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) +public enum ThreadSafetyLevel { COMPLETELY_THREADSAFE } diff --git a/test/files/pos/t7014/t7014.scala b/test/files/pos/t7014/t7014.scala new file mode 100644 index 0000000000..faec4c7740 --- /dev/null +++ b/test/files/pos/t7014/t7014.scala @@ -0,0 +1,4 @@ +package t7014 + +import ThreadSafetyLevel.COMPLETELY_THREADSAFE // refer to annotation so it gets parsed + \ No newline at end of file -- cgit v1.2.3 From 75b44a6f723762cc3ebc911483beb2aec4cfee78 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 25 Dec 2012 14:09:33 +0100 Subject: [nomaster] macro expansions are now auto-duplicated The fix still requires macro developers to be careful about sharing trees by references, because attributed DefTrees will still bring trouble. However this is an improvement, because it doesn't make matters worse and automatically fixes situations similar to one in the test. A much more thorough discussion with a number of open questions left: http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc Was fixed ages ago in master in one of the paradise backports. Never got to 2.10.x, but it's very useful, so I'm backporting it now. --- bincompat-backward.whitelist.conf | 16 ++++++++++++ bincompat-forward.whitelist.conf | 24 ++++++++++++++++++ .../scala/tools/nsc/typechecker/Macros.scala | 8 +++--- src/reflect/scala/reflect/internal/Trees.scala | 7 ++++-- test/files/run/macro-auto-duplicate.check | 1 + test/files/run/macro-auto-duplicate/Macros_1.scala | 17 +++++++++++++ test/files/run/macro-auto-duplicate/Test_2.scala | 3 +++ test/files/run/macro-duplicate.check | 0 test/files/run/macro-duplicate.flags | 1 + .../files/run/macro-duplicate/Impls_Macros_1.scala | 29 ++++++++++++++++++++++ test/files/run/macro-duplicate/Test_2.scala | 6 +++++ 11 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 test/files/run/macro-auto-duplicate.check create mode 100644 test/files/run/macro-auto-duplicate/Macros_1.scala create mode 100644 test/files/run/macro-auto-duplicate/Test_2.scala create mode 100644 test/files/run/macro-duplicate.check create mode 100644 test/files/run/macro-duplicate.flags create mode 100644 test/files/run/macro-duplicate/Impls_Macros_1.scala create mode 100644 test/files/run/macro-duplicate/Test_2.scala (limited to 'src') diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index 267631f908..1771ef12bd 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -240,5 +240,21 @@ filter { matchName="scala.reflect.internal.StdAttachments.isMacroExpansionSuppressed" problemName=MissingMethodProblem } + { + matchName="scala.reflect.internal.Trees.scala$reflect$internal$Trees$$duplicator" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Trees.duplicateAndKeepPositions" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Trees.scala$reflect$internal$Trees$$duplicator" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.SymbolTable.scala$reflect$internal$Trees$$duplicator" + problemName=IncompatibleResultTypeProblem + } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index b3af372b15..1ffc2a0553 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -516,5 +516,29 @@ filter { matchName="scala.reflect.runtime.JavaMirrors#JavaMirror#FromJavaClassCompleter.scala$reflect$runtime$JavaMirrors$JavaMirror$FromJavaClassCompleter$$enterEmptyCtorIfNecessary$1" problemName=MissingMethodProblem } + { + matchName="scala.reflect.internal.Trees$Duplicator" + problemName=MissingClassProblem + }, + { + matchName="scala.reflect.internal.Trees.duplicateAndKeepPositions" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Trees.scala$reflect$internal$Trees$$duplicator" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.Trees.scala$reflect$internal$Trees$$duplicator" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.SymbolTable.duplicateAndKeepPositions" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.SymbolTable.scala$reflect$internal$Trees$$duplicator" + problemName=IncompatibleResultTypeProblem + } ] } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 816f977890..d6ec5f2cb0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -713,9 +713,11 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { var expectedTpe = expandee.tpe if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType - var typechecked = typecheck("macro def return type", expanded, expectedTpe) - typechecked = typecheck("expected type", typechecked, pt) - typechecked + // also see http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc + val expanded0 = duplicateAndKeepPositions(expanded) + val expanded1 = typecheck("macro def return type", expanded0, expectedTpe) + val expanded2 = typecheck("expected type", expanded1, pt) + expanded2 } finally { popMacroContext() } diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 2585b541ed..53b9b1d88e 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1526,15 +1526,18 @@ trait Trees extends api.Trees { self: SymbolTable => } } - private lazy val duplicator = new Transformer { + private lazy val duplicator = new Duplicator(focusPositions = true) + private class Duplicator(focusPositions: Boolean) extends Transformer { override val treeCopy = newStrictTreeCopier override def transform(t: Tree) = { val t1 = super.transform(t) - if ((t1 ne t) && t1.pos.isRange) t1 setPos t.pos.focus + if ((t1 ne t) && t1.pos.isRange && focusPositions) t1 setPos t.pos.focus t1 } } + def duplicateAndKeepPositions(tree: Tree) = new Duplicator(focusPositions = false) transform tree + // ------ copiers ------------------------------------------- def copyDefDef(tree: Tree)( diff --git a/test/files/run/macro-auto-duplicate.check b/test/files/run/macro-auto-duplicate.check new file mode 100644 index 0000000000..d81cc0710e --- /dev/null +++ b/test/files/run/macro-auto-duplicate.check @@ -0,0 +1 @@ +42 diff --git a/test/files/run/macro-auto-duplicate/Macros_1.scala b/test/files/run/macro-auto-duplicate/Macros_1.scala new file mode 100644 index 0000000000..e3df05ba50 --- /dev/null +++ b/test/files/run/macro-auto-duplicate/Macros_1.scala @@ -0,0 +1,17 @@ +import scala.reflect.macros.Context +import language.experimental.macros + +object Macros { + def impl(c: Context) = { + import c.universe._ + val x = Ident(newTermName("x")) + def defAndUseX(rhs: Tree) = { + Block(List(ValDef(NoMods, newTermName("x"), TypeTree(), rhs)), x) + } + val xi4 = defAndUseX(Literal(Constant(4))) + val xs2 = defAndUseX(Literal(Constant("2"))) + c.Expr[String](Apply(Select(xi4, newTermName("$plus")), List(xs2))) + } + + def foo = macro impl +} \ No newline at end of file diff --git a/test/files/run/macro-auto-duplicate/Test_2.scala b/test/files/run/macro-auto-duplicate/Test_2.scala new file mode 100644 index 0000000000..f697da6020 --- /dev/null +++ b/test/files/run/macro-auto-duplicate/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends App { + println(Macros.foo) +} \ No newline at end of file diff --git a/test/files/run/macro-duplicate.check b/test/files/run/macro-duplicate.check new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/files/run/macro-duplicate.flags b/test/files/run/macro-duplicate.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/run/macro-duplicate.flags @@ -0,0 +1 @@ +-language:experimental.macros \ No newline at end of file diff --git a/test/files/run/macro-duplicate/Impls_Macros_1.scala b/test/files/run/macro-duplicate/Impls_Macros_1.scala new file mode 100644 index 0000000000..de81923330 --- /dev/null +++ b/test/files/run/macro-duplicate/Impls_Macros_1.scala @@ -0,0 +1,29 @@ +import scala.reflect.macros.Context + +object Macros { + def impl(c: Context) = { + import c.universe._ + val Expr(Block((cdef: ClassDef) :: Nil, _)) = reify { class C { def x = 2 } } + val cdef1 = + new Transformer { + override def transform(tree: Tree): Tree = tree match { + case Template(_, _, ctor :: defs) => + val defs1 = defs collect { + case ddef @ DefDef(mods, name, tparams, vparamss, tpt, body) => + val future = Select(Select(Select(Ident(newTermName("scala")), newTermName("concurrent")), newTermName("package")), newTermName("future")) + val Future = Select(Select(Ident(newTermName("scala")), newTermName("concurrent")), newTypeName("Future")) + val tpt1 = if (tpt.isEmpty) tpt else AppliedTypeTree(Future, List(tpt)) + val body1 = Apply(future, List(body)) + val name1 = newTermName("async" + name.toString.capitalize) + DefDef(mods, name1, tparams, vparamss, tpt1, body1) + } + Template(Nil, emptyValDef, ctor +: defs ::: defs1) + case _ => + super.transform(tree) + } + } transform cdef + c.Expr[Unit](Block(cdef1 :: Nil, Literal(Constant(())))) + } + + def foo = macro impl +} \ No newline at end of file diff --git a/test/files/run/macro-duplicate/Test_2.scala b/test/files/run/macro-duplicate/Test_2.scala new file mode 100644 index 0000000000..6dbd4382d3 --- /dev/null +++ b/test/files/run/macro-duplicate/Test_2.scala @@ -0,0 +1,6 @@ +import scala.concurrent._ +import ExecutionContext.Implicits.global + +object Test extends App { + Macros.foo +} \ No newline at end of file -- cgit v1.2.3 From 3222add79cb873ee42a1459edcea1c9cb61d8ec9 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 14 Aug 2013 23:50:00 +0200 Subject: SI-7752 Don't disambiguate type parameters of overloaded alts These are passed through from `InferencerContextErrors#applyErrorMsg` to `withDisambiguation` as the `locals` parameter, which is promptly ignored. This looks to be an unintended change in 39938bcc299. Without this patch, the enclosed test case enters a pathalogical disambiguation session, that not only flirts with unpleasant big-O complexities, but also flails about appending "(in method foo)" only to find that *all* occurences of the same-named type parameter come from some method named "foo". [snipping error message 40 seconds in the making] method foo), O(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo), P(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo), Q(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo), R(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo), S(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo), T, U(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo), V) cannot be applied to (Int) foo((1)) --- .../tools/nsc/typechecker/TypeDiagnostics.scala | 11 +++++---- test/files/neg/t7752.check | 27 ++++++++++++++++++++++ test/files/neg/t7752.scala | 26 +++++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 test/files/neg/t7752.check create mode 100644 test/files/neg/t7752.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 4950a7efef..2270e812eb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -366,11 +366,14 @@ trait TypeDiagnostics { val strings = mutable.Map[String, Set[TypeDiag]]() withDefaultValue Set() val names = mutable.Map[Name, Set[TypeDiag]]() withDefaultValue Set() - def record(t: Type, sym: Symbol) = { - val diag = TypeDiag(t, sym) + val localsSet = locals.toSet - strings("" + t) += diag - names(sym.name) += diag + def record(t: Type, sym: Symbol) = { + if (!localsSet(sym)) { + val diag = TypeDiag(t, sym) + strings("" + t) += diag + names(sym.name) += diag + } } for (tpe <- types ; t <- tpe) { t match { diff --git a/test/files/neg/t7752.check b/test/files/neg/t7752.check new file mode 100644 index 0000000000..0a015d3f37 --- /dev/null +++ b/test/files/neg/t7752.check @@ -0,0 +1,27 @@ +t7752.scala:25: error: overloaded method value foo with alternatives: + [A](heading: String, rows: A*)(A,) + [A, B](heading: (String, String), rows: (A, B)*)(A, B) + [A, B, C](heading: (String, String, String), rows: (A, B, C)*)(A, B, C) + [A, B, C, D](heading: (String, String, String, String), rows: (A, B, C, D)*)(A, B, C, D) + [A, B, C, D, E](heading: (String, String, String, String, String), rows: (A, B, C, D, E)*)(A, B, C, D, E) + [A, B, C, D, E, F](heading: (String, String, String, String, String, String), rows: (A, B, C, D, E, F)*)(A, B, C, D, E, F) + [A, B, C, D, E, F, G](heading: (String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G)*)(A, B, C, D, E, F, G) + [A, B, C, D, E, F, G, H](heading: (String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H)*)(A, B, C, D, E, F, G, H) + [A, B, C, D, E, F, G, H, I](heading: (String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I)*)(A, B, C, D, E, F, G, H, I) + [A, B, C, D, E, F, G, H, I, J](heading: (String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J)*)(A, B, C, D, E, F, G, H, I, J) + [A, B, C, D, E, F, G, H, I, J, K](heading: (String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K)*)(A, B, C, D, E, F, G, H, I, J, K) + [A, B, C, D, E, F, G, H, I, J, K, L](heading: (String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L)*)(A, B, C, D, E, F, G, H, I, J, K, L) + [A, B, C, D, E, F, G, H, I, J, K, L, M](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M)*)(A, B, C, D, E, F, G, H, I, J, K, L, M) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) + [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V)*)(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) + cannot be applied to (Int) + foo((1)) + ^ +one error found diff --git a/test/files/neg/t7752.scala b/test/files/neg/t7752.scala new file mode 100644 index 0000000000..40ba2103b1 --- /dev/null +++ b/test/files/neg/t7752.scala @@ -0,0 +1,26 @@ +object Test { + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V)*): Tuple22[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)*): Tuple21[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T)*): Tuple20[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S)*): Tuple19[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)*): Tuple18[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)*): Tuple17[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)*): Tuple16[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)*): Tuple15[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M, N](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M, N)*): Tuple14[A,B,C,D,E,F,G,H,I,J,K,L,M,N] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L, M](heading: (String, String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L, M)*): Tuple13[A,B,C,D,E,F,G,H,I,J,K,L,M] = null + def foo[A, B, C, D, E, F, G, H, I, J, K, L](heading: (String, String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K, L)*): Tuple12[A,B,C,D,E,F,G,H,I,J,K,L] = null + def foo[A, B, C, D, E, F, G, H, I, J, K](heading: (String, String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J, K)*): Tuple11[A,B,C,D,E,F,G,H,I,J,K] = null + def foo[A, B, C, D, E, F, G, H, I, J](heading: (String, String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I, J)*): Tuple10[A,B,C,D,E,F,G,H,I,J] = null + def foo[A, B, C, D, E, F, G, H, I](heading: (String, String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H, I)*): Tuple9[A,B,C,D,E,F,G,H,I] = null + def foo[A, B, C, D, E, F, G, H](heading: (String, String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G, H)*): Tuple8[A,B,C,D,E,F,G,H] = null + def foo[A, B, C, D, E, F, G](heading: (String, String, String, String, String, String, String), rows: (A, B, C, D, E, F, G)*): Tuple7[A,B,C,D,E,F,G] = null + def foo[A, B, C, D, E, F](heading: (String, String, String, String, String, String), rows: (A, B, C, D, E, F)*): Tuple6[A,B,C,D,E,F] = null + def foo[A, B, C, D, E](heading: (String, String, String, String, String), rows: (A, B, C, D, E)*): Tuple5[A,B,C,D,E] = null + def foo[A, B, C, D](heading: (String, String, String, String), rows: (A, B, C, D)*): Tuple4[A,B,C,D] = null + def foo[A, B, C](heading: (String, String, String), rows: (A, B, C)*): Tuple3[A,B,C] = null + def foo[A, B](heading: (String, String), rows: (A, B)*): Tuple2[A,B] = null + def foo[A](heading: String, rows: A*): Tuple1[A] = null + + foo((1)) +} \ No newline at end of file -- cgit v1.2.3 From 42e0f73311cfaf0883b85a1a41f400c3eb3cae96 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 16 Aug 2013 11:30:33 +0200 Subject: SI-7716 Exclude patmat synthetics from bounds checking Consider this pattern match translation, that occurs *before* refchecks: scala> val e: java.lang.Enum[_] = java.util.concurrent.TimeUnit.SECONDS scala> e match { case x => x } :9: error: type arguments [_$1] do not conform to class Enum's type parameter bounds [E <: Enum[E]] e match { case x => x } ^ [[syntax trees at end of refchecks]] // package $line5 { case val x1: Enum[_$1] = $line3.$read.$iw.$iw.e; case4(){ matchEnd3(x1) }; matchEnd3(x: Enum[_$1]){ x } RefChecks turns a blind eye to the non-conformant type `Enum[_$1]` in the label defs because of `65340ed4ad2e`. (Incidentally, that is far too broad, as I've noted in SI-7756.) This commit extends this exception to cover the synthetic ValDef `x1`. Commit log watchers might notice the similarities to SI-7694. --- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 4 +++- test/files/pos/t7716.scala | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/t7716.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index db899b44f9..09c4878b2f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1826,9 +1826,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case LabelDef(_, _, _) if treeInfo.hasSynthCaseSymbol(result) => val old = inPattern inPattern = true - val res = deriveLabelDef(result)(transform) + val res = deriveLabelDef(result)(transform) // TODO SI-7756 Too broad! The code from the original case body should be fully refchecked! inPattern = old res + case ValDef(_, _, _, _) if treeInfo.hasSynthCaseSymbol(result) => + deriveValDef(result)(transform) // SI-7716 Don't refcheck the tpt of the synthetic val that holds the selector. case _ => super.transform(result) } diff --git a/test/files/pos/t7716.scala b/test/files/pos/t7716.scala new file mode 100644 index 0000000000..40117051ed --- /dev/null +++ b/test/files/pos/t7716.scala @@ -0,0 +1,16 @@ +object Test { + def test: Unit = { + val e: java.lang.Enum[_] = java.util.concurrent.TimeUnit.SECONDS + e match { case x => println(x) } + + + trait TA[X <: CharSequence] + val ta: TA[_] = new TA[String] {} + + ta match { + case _ => println("hi") + } + + def f(ta: TA[_]) = ta match { case _ => "hi" } + } +} -- cgit v1.2.3 From ab8a223c6c01c1a725c9892c04952f6451aedf0d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 16 Aug 2013 18:01:39 +0200 Subject: SI-7603 Fix thread safety of FlagTranslation This is outside of the Global cake, so we can't assume single threaded access. A var was introduced in af3daf6fdb that can lead to incorrect flag interpretation. The reported bug was triggered in a multi-project SBT build. Java Annotations read from classfiles were occasionally conferred the TRAIT|INFERFACE|ABSTRACT flag set, leading to "@Foo is abstract, cannot be instatiated" later down the line. --- .../reflect/internal/ClassfileConstants.scala | 36 +++++++++------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index c198271fb1..eb70ff3f17 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -335,13 +335,8 @@ object ClassfileConstants { abstract class FlagTranslation { import Flags._ - private var isAnnotation = false - private var isClass = false - private def initFields(flags: Int) = { - isAnnotation = (flags & JAVA_ACC_ANNOTATION) != 0 - isClass = false - } - private def translateFlag(jflag: Int): Long = (jflag: @switch) match { + private def isAnnotation(flags: Int): Boolean = (flags & JAVA_ACC_ANNOTATION) != 0 + private def translateFlag(jflag: Int, isAnnotation: Boolean, isClass: Boolean): Long = (jflag: @switch) match { case JAVA_ACC_PRIVATE => PRIVATE case JAVA_ACC_PROTECTED => PROTECTED case JAVA_ACC_FINAL => FINAL @@ -351,31 +346,28 @@ object ClassfileConstants { case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT case _ => 0L } - private def translateFlags(jflags: Int, baseFlags: Long): Long = { + private def translateFlags(jflags: Int, baseFlags: Long, isAnnotation: Boolean, isClass: Boolean): Long = { + def translateFlag0(jflags: Int): Long = translateFlag(jflags, isAnnotation, isClass) var res: Long = JAVA | baseFlags /** fast, elegant, maintainable, pick any two... */ - res |= translateFlag(jflags & JAVA_ACC_PRIVATE) - res |= translateFlag(jflags & JAVA_ACC_PROTECTED) - res |= translateFlag(jflags & JAVA_ACC_FINAL) - res |= translateFlag(jflags & JAVA_ACC_SYNTHETIC) - res |= translateFlag(jflags & JAVA_ACC_STATIC) - res |= translateFlag(jflags & JAVA_ACC_ABSTRACT) - res |= translateFlag(jflags & JAVA_ACC_INTERFACE) + res |= translateFlag0(jflags & JAVA_ACC_PRIVATE) + res |= translateFlag0(jflags & JAVA_ACC_PROTECTED) + res |= translateFlag0(jflags & JAVA_ACC_FINAL) + res |= translateFlag0(jflags & JAVA_ACC_SYNTHETIC) + res |= translateFlag0(jflags & JAVA_ACC_STATIC) + res |= translateFlag0(jflags & JAVA_ACC_ABSTRACT) + res |= translateFlag0(jflags & JAVA_ACC_INTERFACE) res } def classFlags(jflags: Int): Long = { - initFields(jflags) - isClass = true - translateFlags(jflags, 0) + translateFlags(jflags, 0, isAnnotation(jflags), isClass = true) } def fieldFlags(jflags: Int): Long = { - initFields(jflags) - translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0) + translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0 , isAnnotation(jflags), isClass = false) } def methodFlags(jflags: Int): Long = { - initFields(jflags) - translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE else 0) + translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE else 0, isAnnotation(jflags), isClass = false) } } object FlagTranslation extends FlagTranslation { } -- cgit v1.2.3 From 076a92b8e15ddb26c0f668c5656b8a5c891ea059 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Fri, 16 Aug 2013 18:06:19 +0200 Subject: SI-7603 Remove diagnostic code for annotation error We've fingered the true culprit in the previous commit. --- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 8f542af417..bb938074cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1425,14 +1425,6 @@ trait Namers extends MethodSynthesis { annCtx.setReportErrors() // need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892. AnnotationInfo lazily { - if (typer.context ne ctx) - log(sm"""|The var `typer.context` in ${Namer.this} was mutated before the annotation ${ann} was forced. - | - |current value = ${typer.context} - |original value = $ctx - | - |This confirms the hypothesis for the cause of SI-7603. If you see this message, please comment on that ticket.""") - beforeTyper(newTyper(annCtx) typedAnnotation ann) } } -- cgit v1.2.3