diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-09-28 09:59:46 -0700 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-09-28 09:59:46 -0700 |
commit | dea6c342da2ed9c297e40a00625b819e9452c1b5 (patch) | |
tree | 70b13842e325bafd48e5494c844078f35b02f5b7 | |
parent | 41f37bc428a309b9766f545da0179f270ea01d77 (diff) | |
parent | 886c4061222773d76f3ee3f4ff1469f9d4a48eaf (diff) | |
download | scala-dea6c342da2ed9c297e40a00625b819e9452c1b5.tar.gz scala-dea6c342da2ed9c297e40a00625b819e9452c1b5.tar.bz2 scala-dea6c342da2ed9c297e40a00625b819e9452c1b5.zip |
Merge pull request #1417 from paulp/210-merge
Merging 2.10.x into master.
134 files changed, 1859 insertions, 955 deletions
@@ -1749,7 +1749,7 @@ OSGi Artifacts </target> <target name="osgi.bundles" depends="osgi.init" unless="osgi.bundles.available"> - <stopwatch name="osgi.bundle.timer"/> + <stopwatch name="osgi.bundle.timer"/> <make-bundle name="scala-library" version="${osgi.version.number}" /> <make-bundle name="scala-actors" version="${osgi.version.number}" /> <make-bundle name="scala-actors-migration" version="${osgi.version.number}" /> @@ -1757,7 +1757,7 @@ OSGi Artifacts <make-bundle name="scala-compiler" version="${osgi.version.number}" /> <make-plugin-bundle name="continuations" version="${osgi.version.number}" /> <touch file="${build-osgi.dir}/bundles.complete" verbose="no"/> - <stopwatch name="osgi.bundle.timer" action="total"/> + <stopwatch name="osgi.bundle.timer" action="total"/> </target> <target name="osgi.bundles.swing" depends="osgi.init" if="has.java6" unless="osgi.bundles.available"> @@ -1801,7 +1801,7 @@ OSGi Artifacts </compilationpath> </scalacfork> <touch file="${build-osgi.dir}/test-compile.complete" verbose="no"/> - <stopwatch name="osgi.test.comp.timer" action="total"/> + <stopwatch name="osgi.test.comp.timer" action="total"/> </target> <target name="osgi.test" depends="osgi.test.comp"> @@ -1821,7 +1821,7 @@ OSGi Artifacts </batchtest> <formatter type="brief" usefile="false" /> </junit> - <stopwatch name="osgi.test.timer" action="total"/> + <stopwatch name="osgi.test.timer" action="total"/> </target> <target name="osgi.clean"> @@ -2322,6 +2322,7 @@ DOCUMENTATION <include name="swing/**"/> <include name="actors/**"/> <include name="actors-migration/**"/> + <include name="reflect/**"/> </source-includes> </doc-uptodate-check> </target> @@ -2336,7 +2337,7 @@ DOCUMENTATION docfooter="epfl" docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1" docUncompilable="${src.dir}/library-aux" - skipPackages="scala.reflect.macros.internal" + skipPackages="scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.runtime:scala.reflect.io" sourcepath="${src.dir}" classpathref="pack.classpath" addparams="${scalac.args.all}" @@ -2716,14 +2717,14 @@ DISTRIBUTION <macrodef name="copy-bundle"> <attribute name="name" /> <sequential> - <copy file="${build-osgi.dir}/org.scala-lang.@{name}.jar" + <copy file="${build-osgi.dir}/org.scala-lang.@{name}.jar" tofile="${dist.dir}/lib/@{name}.jar"/> </sequential> </macrodef> <macrodef name="copy-plugin-bundle"> <attribute name="name" /> <sequential> - <copy file="${build-osgi.dir}/org.scala-lang.plugins.@{name}.jar" + <copy file="${build-osgi.dir}/org.scala-lang.plugins.@{name}.jar" tofile="${dist.dir}/misc/scala-devel/plugins/@{name}.jar"/> </sequential> </macrodef> diff --git a/src/compiler/scala/reflect/macros/runtime/Aliases.scala b/src/compiler/scala/reflect/macros/runtime/Aliases.scala index 30e72997f7..ff870e728e 100644 --- a/src/compiler/scala/reflect/macros/runtime/Aliases.scala +++ b/src/compiler/scala/reflect/macros/runtime/Aliases.scala @@ -10,17 +10,20 @@ trait Aliases { override type TermName = universe.TermName override type TypeName = universe.TypeName override type Tree = universe.Tree - // override type Position = universe.Position + override type Position = universe.Position override type Scope = universe.Scope override type Modifiers = universe.Modifiers override type Expr[+T] = universe.Expr[T] override val Expr = universe.Expr + def Expr[T: WeakTypeTag](tree: Tree): Expr[T] = universe.Expr[T](mirror, universe.FixedMirrorTreeCreator(mirror, tree)) override type WeakTypeTag[T] = universe.WeakTypeTag[T] override type TypeTag[T] = universe.TypeTag[T] override val WeakTypeTag = universe.WeakTypeTag override val TypeTag = universe.TypeTag + def WeakTypeTag[T](tpe: Type): WeakTypeTag[T] = universe.WeakTypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) + def TypeTag[T](tpe: Type): TypeTag[T] = universe.TypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) override def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag override def typeTag[T](implicit ttag: TypeTag[T]) = ttag override def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe diff --git a/src/compiler/scala/reflect/macros/runtime/CapturedVariables.scala b/src/compiler/scala/reflect/macros/runtime/CapturedVariables.scala deleted file mode 100644 index 78fb7100b0..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/CapturedVariables.scala +++ /dev/null @@ -1,15 +0,0 @@ -package scala.reflect.macros -package runtime - -trait CapturedVariables { - self: Context => - - import mirror._ - import universe._ - - def captureVariable(vble: Symbol): Unit = universe.captureVariable(vble) - - def referenceCapturedVariable(vble: Symbol): Tree = universe.referenceCapturedVariable(vble) - - def capturedVariableType(vble: Symbol): Type = universe.capturedVariableType(vble) -}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/Context.scala b/src/compiler/scala/reflect/macros/runtime/Context.scala index 8bbfef44a3..8e8b0fcea1 100644 --- a/src/compiler/scala/reflect/macros/runtime/Context.scala +++ b/src/compiler/scala/reflect/macros/runtime/Context.scala @@ -5,24 +5,20 @@ import scala.tools.nsc.Global abstract class Context extends scala.reflect.macros.Context with Aliases - with CapturedVariables - with Infrastructure with Enclosures with Names with Reifiers with FrontEnds - with Settings + with Infrastructure with Typers with Parsers - with Exprs - with TypeTags with Evals with ExprUtils with Traces { val universe: Global - val mirror: MirrorOf[universe.type] = universe.rootMirror + val mirror: universe.Mirror = universe.rootMirror val callsiteTyper: universe.analyzer.Typer diff --git a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala index b5c988ca83..be5f2dbe83 100644 --- a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala +++ b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala @@ -19,5 +19,6 @@ trait Enclosures { val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self val enclosingMethod: Tree = site.enclMethod.tree val enclosingPosition: Position = if (enclPoses.isEmpty) NoPosition else enclPoses.head.pos - val enclosingUnit: CompilationUnit = currentRun.currentUnit + val enclosingUnit: CompilationUnit = universe.currentRun.currentUnit + val enclosingRun: Run = universe.currentRun } diff --git a/src/compiler/scala/reflect/macros/runtime/Evals.scala b/src/compiler/scala/reflect/macros/runtime/Evals.scala index acafeb5b02..1f7b5f2ff1 100644 --- a/src/compiler/scala/reflect/macros/runtime/Evals.scala +++ b/src/compiler/scala/reflect/macros/runtime/Evals.scala @@ -7,7 +7,7 @@ import scala.tools.reflect.ToolBox trait Evals { self: Context => - private lazy val evalMirror = ru.runtimeMirror(libraryClassLoader) + private lazy val evalMirror = ru.runtimeMirror(universe.analyzer.macroClassloader) private lazy val evalToolBox = evalMirror.mkToolBox() private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }] diff --git a/src/compiler/scala/reflect/macros/runtime/Exprs.scala b/src/compiler/scala/reflect/macros/runtime/Exprs.scala deleted file mode 100644 index ebf8fa2b96..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Exprs.scala +++ /dev/null @@ -1,8 +0,0 @@ -package scala.reflect.macros -package runtime - -trait Exprs { - self: Context => - - def Expr[T: WeakTypeTag](tree: Tree): Expr[T] = universe.Expr[T](mirror, universe.FixedMirrorTreeCreator(mirror, tree)) -} diff --git a/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala b/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala index 9f328eb82b..a6a198e1b4 100644 --- a/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala +++ b/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala @@ -1,28 +1,9 @@ package scala.reflect.macros package runtime -trait FrontEnds extends scala.tools.reflect.FrontEnds { +trait FrontEnds { self: Context => - import universe._ - import mirror._ - - override type Position = universe.Position - - def frontEnd: FrontEnd = wrapReporter(universe.reporter) - - def setFrontEnd(frontEnd: FrontEnd): this.type = { - universe.reporter = wrapFrontEnd(frontEnd) - this - } - - def withFrontEnd[T](frontEnd: FrontEnd)(op: => T): T = { - val old = universe.reporter - setFrontEnd(frontEnd) - try op - finally universe.reporter = old - } - def echo(pos: Position, msg: String): Unit = universe.reporter.echo(pos, msg) def info(pos: Position, msg: String, force: Boolean): Unit = universe.reporter.info(pos, msg, force) @@ -36,9 +17,4 @@ trait FrontEnds extends scala.tools.reflect.FrontEnds { def error(pos: Position, msg: String): Unit = callsiteTyper.context.error(pos, msg) def abort(pos: Position, msg: String): Nothing = throw new AbortMacroException(pos, msg) - - def interactive(): Unit = universe.reporter match { - case reporter: scala.tools.nsc.reporters.AbstractReporter => reporter.displayPrompt() - case _ => () - } } diff --git a/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala b/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala index 7157dbeaa2..7781693822 100644 --- a/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala +++ b/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala @@ -1,36 +1,16 @@ package scala.reflect.macros package runtime -import scala.tools.nsc.util.ScalaClassLoader - trait Infrastructure { self: Context => - val forJVM: Boolean = universe.forJVM - - val forMSIL: Boolean = universe.forMSIL - - val forInteractive: Boolean = universe.forInteractive - - val forScaladoc: Boolean = universe.forScaladoc - - val currentRun: Run = universe.currentRun - - val libraryClassPath: List[java.net.URL] = universe.classPath.asURLs - - lazy val libraryClassLoader: ClassLoader = universe.analyzer.macroClassloader - - type Run = universe.Run - - object Run extends RunExtractor { - def unapply(run: Run): Option[(CompilationUnit, List[CompilationUnit])] = Some((run.currentUnit, run.units.toList)) + def settings: List[String] = { + val us = universe.settings + import us._ + userSetSettings collectFirst { case x: MultiStringSetting if x.name == XmacroSettings.name => x.value } getOrElse Nil } - type CompilationUnit = universe.CompilationUnit - - object CompilationUnit extends CompilationUnitExtractor { - def unapply(compilationUnit: CompilationUnit): Option[(java.io.File, Array[Char], Tree)] = Some((compilationUnit.source.file.file, compilationUnit.source.content, compilationUnit.body)) - } + def compilerSettings: List[String] = universe.settings.recreateArgs - val currentMacro: Symbol = expandee.symbol + def classPath: List[java.net.URL] = global.classPath.asURLs } diff --git a/src/compiler/scala/reflect/macros/runtime/Parsers.scala b/src/compiler/scala/reflect/macros/runtime/Parsers.scala index 5096526fdb..ab9b94ec9f 100644 --- a/src/compiler/scala/reflect/macros/runtime/Parsers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Parsers.scala @@ -10,6 +10,7 @@ trait Parsers { def parse(code: String): Tree = // todo. provide decent implementation + // see `Typers.typedUseCase` for details try { import scala.reflect.runtime.{universe => ru} val parsed = ru.rootMirror.mkToolBox().parse(code) @@ -17,9 +18,7 @@ trait Parsers { importer.importTree(parsed) } catch { case ToolBoxError(msg, cause) => + // todo. provide a position throw new ParseError(universe.NoPosition, msg) } - - case class ParseError(val pos: Position, val msg: String) extends Throwable(msg) - object ParseError extends ParseErrorExtractor } diff --git a/src/compiler/scala/reflect/macros/runtime/Reifiers.scala b/src/compiler/scala/reflect/macros/runtime/Reifiers.scala index f15a7ad502..9e11e5e26d 100644 --- a/src/compiler/scala/reflect/macros/runtime/Reifiers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Reifiers.scala @@ -13,8 +13,6 @@ trait Reifiers { import universe._ import definitions._ - lazy val runtimeUniverse: Tree = gen.mkRuntimeUniverseRef - def reifyTree(universe: Tree, mirror: Tree, tree: Tree): Tree = { assert(ExprClass != NoSymbol) val result = scala.reflect.reify.`package`.reifyTree(self.universe)(callsiteTyper, universe, mirror, tree) diff --git a/src/compiler/scala/reflect/macros/runtime/Settings.scala b/src/compiler/scala/reflect/macros/runtime/Settings.scala deleted file mode 100644 index e9d9a17b81..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Settings.scala +++ /dev/null @@ -1,35 +0,0 @@ -package scala.reflect.macros -package runtime - -trait Settings { - self: Context => - - def settings: List[String] = { - val us = universe.settings - import us._ - userSetSettings collectFirst { case x: MultiStringSetting if x.name == XmacroSettings.name => x.value } getOrElse Nil - } - - def compilerSettings: List[String] = universe.settings.recreateArgs - - def setCompilerSettings(options: String): this.type = - // SI-5925: doesn't work with arguments that contains whitespaces - setCompilerSettings(options.split(" ").toList) - - def setCompilerSettings(options: List[String]): this.type = { - val settings = new scala.tools.nsc.Settings(_ => ()) - settings.copyInto(universe.settings) - this - } - - def withCompilerSettings[T](options: String)(op: => T): T = - // SI-5925: doesn't work with arguments that contains whitespaces - withCompilerSettings(options.split(" ").toList)(op) - - def withCompilerSettings[T](options: List[String])(op: => T): T = { - val old = options - setCompilerSettings(options) - try op - finally setCompilerSettings(old) - } -} diff --git a/src/compiler/scala/reflect/macros/runtime/TypeTags.scala b/src/compiler/scala/reflect/macros/runtime/TypeTags.scala deleted file mode 100644 index 19b60159de..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/TypeTags.scala +++ /dev/null @@ -1,9 +0,0 @@ -package scala.reflect.macros -package runtime - -trait TypeTags { - self: Context => - - def WeakTypeTag[T](tpe: Type): WeakTypeTag[T] = universe.WeakTypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) - def TypeTag[T](tpe: Type): TypeTag[T] = universe.TypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) -} diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index 2c0d41e2a9..5d3ac8cde0 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -108,7 +108,7 @@ abstract class Reifier extends States // needs to be solved some day // maybe try `resetLocalAttrs` once the dust settles var importantSymbols = Set[Symbol]( - NothingClass, AnyClass, SingletonClass, PredefModule, ScalaRunTimeModule, TypeCreatorClass, TreeCreatorClass, MirrorOfClass, + NothingClass, AnyClass, SingletonClass, PredefModule, ScalaRunTimeModule, TypeCreatorClass, TreeCreatorClass, MirrorClass, ApiUniverseClass, JavaUniverseClass, ReflectRuntimePackage, ReflectRuntimeCurrentMirror) importantSymbols ++= importantSymbols map (_.companionSymbol) importantSymbols ++= importantSymbols map (_.moduleClass) diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index 91cccaee99..b7206eda0e 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -19,7 +19,7 @@ trait Extractors { // $treecreator1.super.<init>(); // () // }; - // def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Tree = { + // def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { // val $u: U = $m$untyped.universe; // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; // $u.Apply($u.Select($u.Select($u.build.This($m.staticPackage("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2)))) @@ -32,7 +32,7 @@ trait Extractors { // $typecreator1.super.<init>(); // () // }; - // def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Type = { + // def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Type = { // val $u: U = $m$untyped.universe; // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; // $u.TypeRef($u.ThisType($m.staticPackage("scala.collection.immutable").moduleClass), $m.staticClass("scala.collection.immutable.List"), List($m.staticClass("scala.Int").toTypeConstructor)) @@ -81,7 +81,7 @@ trait Extractors { DefDef(NoMods, reifierName, List(TypeDef(Modifiers(PARAM), tparamu, List(), TypeBoundsTree(Ident(NothingClass), CompoundTypeTree(Template(List(Ident(reifierUniverse), Ident(SingletonClass)), emptyValDef, List()))))), - List(List(ValDef(Modifiers(PARAM), nme.MIRROR_UNTYPED, AppliedTypeTree(Ident(MirrorOfClass), List(Ident(tparamu))), EmptyTree))), + List(List(ValDef(Modifiers(PARAM), nme.MIRROR_UNTYPED, AppliedTypeTree(Ident(MirrorClass), List(Ident(tparamu))), EmptyTree))), reifierTpt, reifierBody)))) Block(tpec, ApplyConstructor(Ident(tpec.name), List())) } diff --git a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala index f0480e0699..000e500c69 100644 --- a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala +++ b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala @@ -75,7 +75,7 @@ trait NodePrinters { val printout = scala.collection.mutable.ListBuffer[String](); printout += universe.trim - if (mirrorIsUsed) printout += mirror.replace("MirrorOf[", "scala.reflect.api.MirrorOf[").trim + if (mirrorIsUsed) printout += mirror.replace("Mirror[", "scala.reflect.api.Mirror[").trim val imports = scala.collection.mutable.ListBuffer[String](); imports += nme.UNIVERSE_SHORT // if (buildIsUsed) imports += nme.build diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 6d3fd2e09e..5a2d5ef165 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -23,7 +23,7 @@ trait CompilationUnits { self: Global => /** One unit of compilation that has been submitted to the compiler. * It typically corresponds to a single file of source code. It includes * error-reporting hooks. */ - class CompilationUnit(val source: SourceFile) { + class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { /** the fresh name creator */ var fresh: FreshNameCreator = new FreshNameCreator.Default diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 9f7433796d..0252f9677c 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1158,7 +1158,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** A Run is a single execution of the compiler on a sets of units */ - class Run { + class Run extends RunContextApi { /** Have been running into too many init order issues with Run * during erroneous conditions. Moved all these vals up to the * top of the file so at least they're not trivially null. diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index d8dae0482b..072f4b9ef2 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1750,7 +1750,7 @@ self => in.nextToken() if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start) else atPos(start) { Bind(tpnme.WILDCARD, EmptyTree) } - case IDENTIFIER if treeInfo.isVariableName(in.name) => + case IDENTIFIER if nme.isVariableName(in.name) => atPos(start) { Bind(identForType(), EmptyTree) } case _ => typ() diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index af77d3fe3f..40e520076a 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -21,7 +21,7 @@ trait Patterns extends ast.TreeDSL { import definitions._ import CODE._ import Debug._ - import treeInfo.{ unbind, isStar, isVarPattern, isVariableName } + import treeInfo.{ unbind, isStar, isVarPattern } type PatternMatch = MatchMatrix#PatternMatch private type PatternVar = MatrixContext#PatternVar @@ -366,7 +366,7 @@ trait Patterns extends ast.TreeDSL { lazy val Select(qualifier, name) = select def pathSegments = getPathSegments(tree) def backticked: Option[String] = qualifier match { - case _: This if isVariableName(name) => Some("`%s`".format(name)) + case _: This if nme.isVariableName(name) => Some("`%s`".format(name)) case _ => None } override def covers(sym: Symbol) = newMatchesPattern(sym, tree.tpe) @@ -388,11 +388,11 @@ trait Patterns extends ast.TreeDSL { lazy val UnApply(unfn, args) = tree lazy val Apply(fn, _) = unfn lazy val MethodType(List(arg, _*), _) = fn.tpe - + // Covers if the symbol matches the unapply method's argument type, // and the return type of the unapply is Some. override def covers(sym: Symbol) = newMatchesPattern(sym, arg.tpe) - + // TODO: for alwaysCovers: // fn.tpe.finalResultType.typeSymbol == SomeClass @@ -451,7 +451,7 @@ trait Patterns extends ast.TreeDSL { (sym.tpe.baseTypeSeq exists (_ matchesPattern pattp)) } } - + def sym = tree.symbol def tpe = tree.tpe def isEmpty = tree.isEmpty @@ -496,4 +496,4 @@ trait Patterns extends ast.TreeDSL { } } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index d541b7be0a..f68cbfc141 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -185,7 +185,7 @@ abstract class UnCurry extends InfoTransform * try { * body * } catch { - * case ex: NonLocalReturnControl[_] => + * case ex: NonLocalReturnControl[T @unchecked] => * if (ex.key().eq(key)) ex.value() * else throw ex * } @@ -195,7 +195,8 @@ abstract class UnCurry extends InfoTransform localTyper typed { val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) val ex = meth.newValue(nme.ex, body.pos) setInfo extpe - val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(meth.tpe.finalResultType)) + val argType = meth.tpe.finalResultType withAnnotation (AnnotationInfo marker UncheckedClass.tpe) + val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(argType)) val rhs = ( IF ((ex DOT nme.key)() OBJ_EQ Ident(key)) THEN ((ex DOT nme.value)()) diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala new file mode 100644 index 0000000000..7e15cf91a7 --- /dev/null +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -0,0 +1,284 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package typechecker + +import scala.collection.{ mutable, immutable } +import scala.collection.mutable.ListBuffer +import scala.util.control.ControlThrowable +import symtab.Flags._ +import scala.annotation.tailrec +import Checkability._ + +/** On pattern matcher checkability: + * + * Consider a pattern match of this form: (x: X) match { case _: P => } + * + * There are four possibilities to consider: + * [P1] X will always conform to P + * [P2] x will never conform to P + * [P3] X <: P if some runtime test is true + * [P4] X cannot be checked against P + * + * The first two cases correspond to those when there is enough + * static information to say X <: P or that (x ∈ X) ⇒ (x ∉ P). + * The fourth case includes unknown abstract types or structural + * refinements appearing within a pattern. + * + * The third case is the interesting one. We designate another type, XR, + * which is essentially the intersection of X and |P|, where |P| is + * the erasure of P. If XR <: P, then no warning is emitted. + * + * Examples of how this info is put to use: + * sealed trait A[T] ; class B[T] extends A[T] + * def f(x: B[Int]) = x match { case _: A[Int] if true => } + * def g(x: A[Int]) = x match { case _: B[Int] => } + * + * `f` requires no warning because X=B[Int], P=A[Int], and B[Int] <:< A[Int]. + * `g` requires no warning because X=A[Int], P=B[Int], XR=B[Int], and B[Int] <:< B[Int]. + * XR=B[Int] because a value of type A[Int] which is tested to be a B can + * only be a B[Int], due to the definition of B (B[T] extends A[T].) + * + * This is something like asSeenFrom, only rather than asking what a type looks + * like from the point of view of one of its base classes, we ask what it looks + * like from the point of view of one of its subclasses. + */ +trait Checkable { + self: Analyzer => + + import global._ + import definitions._ + import CheckabilityChecker.{ isNeverSubType, isNeverSubClass } + + /** The applied type of class 'to' after inferring anything + * possible from the knowledge that 'to' must also be of the + * type given in 'from'. + */ + def propagateKnownTypes(from: Type, to: Symbol): Type = { + def tparams = to.typeParams + val tvars = tparams map (p => TypeVar(p)) + val tvarType = appliedType(to, tvars: _*) + val bases = from.baseClasses filter (to.baseClasses contains _) + + bases foreach { bc => + val tps1 = (from baseType bc).typeArgs + val tps2 = (tvarType baseType bc).typeArgs + (tps1, tps2).zipped foreach (_ =:= _) + // Alternate, variance respecting formulation causes + // neg/unchecked3.scala to fail (abstract types). TODO - + // figure it out. It seems there is more work to do if I + // allow for variance, because the constraints accumulate + // as bounds and "tvar.instValid" is false. + // + // foreach3(tps1, tps2, bc.typeParams)((tp1, tp2, tparam) => + // if (tparam.initialize.isCovariant) tp1 <:< tp2 + // else if (tparam.isContravariant) tp2 <:< tp1 + // else tp1 =:= tp2 + // ) + } + + val resArgs = tparams zip tvars map { + case (_, tvar) if tvar.instValid => tvar.constr.inst + case (tparam, _) => tparam.tpe + } + appliedType(to, resArgs: _*) + } + + private def isUnwarnableTypeArgSymbol(sym: Symbol) = ( + sym.isTypeParameter // dummy + || (sym.name.toTermName == nme.WILDCARD) // _ + || nme.isVariableName(sym.name) // type variable + ) + private def isUnwarnableTypeArg(arg: Type) = ( + uncheckedOk(arg) // @unchecked T + || isUnwarnableTypeArgSymbol(arg.typeSymbolDirect) // has to be direct: see pos/t1439 + ) + private def uncheckedOk(tp: Type) = tp hasAnnotation UncheckedClass + + private def typeArgsInTopLevelType(tp: Type): List[Type] = { + val tps = tp match { + case RefinedType(parents, _) => parents flatMap typeArgsInTopLevelType + case TypeRef(_, ArrayClass, arg :: Nil) => typeArgsInTopLevelType(arg) + case TypeRef(pre, sym, args) => typeArgsInTopLevelType(pre) ++ args + case ExistentialType(tparams, underlying) => tparams.map(_.tpe) ++ typeArgsInTopLevelType(underlying) + case _ => Nil + } + tps filterNot isUnwarnableTypeArg + } + + private class CheckabilityChecker(val X: Type, val P: Type) { + def Xsym = X.typeSymbol + def Psym = P.typeSymbol + def XR = propagateKnownTypes(X, Psym) + // sadly the spec says (new java.lang.Boolean(true)).isInstanceOf[scala.Boolean] + def P1 = X matchesPattern P + def P2 = !Psym.isPrimitiveValueClass && isNeverSubType(X, P) + def P3 = isNonRefinementClassType(P) && (XR matchesPattern P) + def P4 = !(P1 || P2 || P3) + + def summaryString = f""" + |Checking checkability of (x: $X) against pattern $P + |[P1] $P1%-6s X <: P // $X <: $P + |[P2] $P2%-6s x ∉ P // (x ∈ $X) ⇒ (x ∉ $P) + |[P3] $P3%-6s XR <: P // $XR <: $P + |[P4] $P4%-6s None of the above // !(P1 || P2 || P3) + """.stripMargin.trim + + val result = ( + if (X.isErroneous || P.isErroneous) CheckabilityError + else if (P1) StaticallyTrue + else if (P2) StaticallyFalse + else if (P3) RuntimeCheckable + else if (uncheckableType == NoType) { + // Avoid warning (except ourselves) if we can't pinpoint the uncheckable type + debugwarn("Checkability checker says 'Uncheckable', but uncheckable type cannot be found:\n" + summaryString) + CheckabilityError + } + else Uncheckable + ) + lazy val uncheckableType = if (Psym.isAbstractType) P else { + val possibles = typeArgsInTopLevelType(P).toSet + val opt = possibles find { targ => + // Create a derived type with every possibly uncheckable type replaced + // with a WildcardType, except for 'targ'. If !(XR <: derived) then + // 'targ' is uncheckable. + val derived = P map (tp => if (possibles(tp) && !(tp =:= targ)) WildcardType else tp) + !(XR <:< derived) + } + opt getOrElse NoType + } + + def neverSubClass = isNeverSubClass(Xsym, Psym) + def neverMatches = result == StaticallyFalse + def isUncheckable = result == Uncheckable + def uncheckableMessage = uncheckableType match { + case NoType => "something" + case tp @ RefinedType(_, _) => "refinement " + tp + case TypeRef(_, sym, _) if sym.isAbstractType => "abstract type " + sym.name + case tp => "non-variable type argument " + tp + } + } + + /** X, P, [P1], etc. are all explained at the top of the file. + */ + private object CheckabilityChecker { + /** A knowable class is one which is either effectively final + * itself, or sealed with only knowable children. + */ + def isKnowable(sym: Symbol): Boolean = /*logResult(s"isKnowable($sym)")*/( + sym.initialize.isEffectivelyFinal // pesky .initialize requirement, or we receive lies about isSealed + || sym.isSealed && (sym.children forall isKnowable) + ) + def knownSubclasses(sym: Symbol): List[Symbol] = /*logResult(s"knownSubclasses($sym)")*/(sym :: { + if (sym.isSealed) sym.children.toList flatMap knownSubclasses + else Nil + }) + def excludable(s1: Symbol, s2: Symbol) = /*logResult(s"excludable($s1, $s2)")*/( + isKnowable(s1) + && !(s2 isSubClass s1) + && knownSubclasses(s1).forall(child => !(child isSubClass s2)) + ) + + /** Given classes A and B, can it be shown that nothing which is + * an A will ever be a subclass of something which is a B? This + * entails not only showing that !(A isSubClass B) but that the + * same is true of all their subclasses. Restated for symmetry: + * the same value cannot be a member of both A and B. + * + * 1) A must not be a subclass of B, nor B of A (the trivial check) + * 2) One of A or B must be completely knowable (see isKnowable) + * 3) Assuming A is knowable, the proposition is true if + * !(A' isSubClass B) for all A', where A' is a subclass of A. + * + * Due to symmetry, the last condition applies as well in reverse. + */ + def isNeverSubClass(sym1: Symbol, sym2: Symbol) = /*logResult(s"isNeverSubClass($sym1, $sym2)")*/( + sym1.isClass + && sym2.isClass + && (excludable(sym1, sym2) || excludable(sym2, sym1)) + ) + private def isNeverSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = /*logResult(s"isNeverSubArgs($tps1, $tps2, $tparams)")*/ { + def isNeverSubArg(t1: Type, t2: Type, variance: Int) = { + if (variance > 0) isNeverSubType(t2, t1) + else if (variance < 0) isNeverSubType(t1, t2) + else isNeverSameType(t1, t2) + } + exists3(tps1, tps2, tparams map (_.variance))(isNeverSubArg) + } + private def isNeverSameType(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) => + ( isNeverSubClass(sym1, sym2) + || isNeverSubClass(sym2, sym1) + || ((sym1 == sym2) && isNeverSubArgs(args1, args2, sym1.typeParams)) + ) + case _ => + false + } + // Important to dealias at any entry point (this is the only one at this writing.) + def isNeverSubType(tp1: Type, tp2: Type): Boolean = /*logResult(s"isNeverSubType($tp1, $tp2)")*/((tp1.dealias, tp2.dealias) match { + case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) => + isNeverSubClass(sym1, sym2) || { + (sym1 isSubClass sym2) && { + val tp1seen = tp1 baseType sym2 + isNeverSubArgs(tp1seen.typeArgs, args2, sym2.typeParams) + } + } + case _ => false + }) + } + + trait InferCheckable { + self: Inferencer => + + /** TODO: much better error positions. + * Kind of stuck right now because they just pass us the one tree. + * TODO: Eliminate inPattern, canRemedy, which have no place here. + */ + def checkCheckable(tree: Tree, P0: Type, X0: Type, inPattern: Boolean, canRemedy: Boolean = false) { + if (uncheckedOk(P0)) return + def where = if (inPattern) "pattern " else "" + + // singleton types not considered here + val P = P0.widen + val X = X0.widen + + P match { + // Prohibit top-level type tests for these, but they are ok nested (e.g. case Foldable[Nothing] => ... ) + case TypeRef(_, NothingClass | NullClass | AnyValClass, _) => + InferErrorGen.TypePatternOrIsInstanceTestError(tree, P) + // If top-level abstract types can be checked using a classtag extractor, don't warn about them + case TypeRef(_, sym, _) if sym.isAbstractType && canRemedy => + ; + // Matching on types like case _: AnyRef { def bippy: Int } => doesn't work -- yet. + case RefinedType(_, decls) if !decls.isEmpty => + getContext.unit.warning(tree.pos, s"a pattern match on a refinement type is unchecked") + case _ => + val checker = new CheckabilityChecker(X, P) + log(checker.summaryString) + if (checker.neverMatches) { + val addendum = if (checker.neverSubClass) "" else " (but still might match its erasure)" + getContext.unit.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $P$addendum") + } + else if (checker.isUncheckable) { + val msg = ( + if (checker.uncheckableType =:= P) s"abstract type $where$P" + else s"${checker.uncheckableMessage} in type $where$P" + ) + getContext.unit.warning(tree.pos, s"$msg is unchecked since it is eliminated by erasure") + } + } + } + } +} + +private[typechecker] final class Checkability(val value: Int) extends AnyVal { } +private[typechecker] object Checkability { + val StaticallyTrue = new Checkability(0) + val StaticallyFalse = new Checkability(1) + val RuntimeCheckable = new Checkability(2) + val Uncheckable = new Checkability(3) + val CheckabilityError = new Checkability(4) +} diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index db16bd02ab..48abfd7a2c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -17,7 +17,7 @@ import scala.annotation.tailrec * @author Martin Odersky * @version 1.0 */ -trait Infer { +trait Infer extends Checkable { self: Analyzer => import global._ @@ -253,7 +253,7 @@ trait Infer { private val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR) /** The context-dependent inferencer part */ - class Inferencer(context: Context) extends InferencerContextErrors { + class Inferencer(context: Context) extends InferencerContextErrors with InferCheckable { import InferErrorGen._ /* -- Error Messages --------------------------------------------------- */ @@ -1361,99 +1361,6 @@ trait Infer { check(tp, Nil) } - // if top-level abstract types can be checked using a classtag extractor, don't warn about them - def checkCheckable(tree: Tree, typeToTest: Type, typeEnsured: Type, inPattern: Boolean, canRemedy: Boolean = false) = { - log(s"checkCheckable($tree, $typeToTest, $typeEnsured, inPattern = $inPattern, canRemedy = $canRemedy") - - sealed abstract class TypeConformance(check: (Type, Type) => Boolean) { - def apply(t1: Type, t2: Type): Boolean = check(t1, t2) && { - log(s"Skipping unchecked for statically verifiable condition $t1 ${this} $t2") - true - } - } - // I tried to use varianceInType to track the variance implications - // but I could not make it work. - case object =:= extends TypeConformance(_ =:= _) - case object <:< extends TypeConformance(_ <:< _) - case object >:> extends TypeConformance((t1, t2) => t2 <:< t1) - case object =!= extends TypeConformance((t1, t2) => false) - - var bound: List[Symbol] = Nil - var warningMessages: List[String] = Nil - - def isLocalBinding(sym: Symbol) = ( - sym.isAbstractType && ( - (bound contains sym) - || (sym.name == tpnme.WILDCARD) - || { - val e = context.scope.lookupEntry(sym.name) - (e ne null) && e.sym == sym && !e.sym.isTypeParameterOrSkolem && e.owner == context.scope - } - ) - ) - def check(tp0: Type, pt: Type, conformance: TypeConformance): Boolean = { - val tp = tp0.normalize - // Set the warning message to be issued when the top-level call fails. - def warn(what: String): Boolean = { - warningMessages ::= what - false - } - def checkArg(param: Symbol, arg: Type) = { - def conforms = ( - if (param.isCovariant) <:< - else if (param.isContravariant) >:> - else =:= - ) - (arg hasAnnotation UncheckedClass) || { - arg.withoutAnnotations match { - case TypeRef(_, sym, args) => - ( isLocalBinding(sym) - || arg.typeSymbol.isTypeParameterOrSkolem - || (sym.name == tpnme.WILDCARD) // avoid spurious warnings on HK types - || check(arg, param.tpeHK, conforms) - || warn("non-variable type argument " + arg) - ) - case _ => - warn("non-variable type argument " + arg) - } - } - } - - // Checking if pt (the expected type of the pattern, and the type - // we are guaranteed) conforms to tp (the type expressed in the pattern's - // type test.) If it does, then even if the type being checked for appears - // to be uncheckable, it is not a warning situation, because it is indeed - // checked: not at runtime, but statically. - conformance.apply(pt, tp) || (tp match { - case SingleType(pre, _) => check(pre, pt, =:=) - case ExistentialType(quantified, tp1) => bound :::= quantified ; check(tp1, pt, <:<) - case ThisType(_) | NoPrefix => true - case RefinedType(parents, decls) if decls.isEmpty => parents forall (p => check(p, pt, <:<)) - case RefinedType(_, _) => warn("refinement " + tp) - case TypeRef(_, ArrayClass, arg :: Nil) => check(arg, NoType, =!=) - case TypeRef(_, NonLocalReturnControlClass, _) => true // no way to suppress unchecked warnings on try/catch - // we only use the extractor for top-level type tests, type arguments remain unchecked - case TypeRef(_, sym, _) if sym.isAbstractType => isLocalBinding(sym) || canRemedy || warn("abstract type " + tp) - case TypeRef(_, _, Nil) => false // leaf node - case TypeRef(pre, sym, args) => forall2(sym.typeParams, args)(checkArg) && check(pre, pt.prefix, =:=) - case _ => warn("type " + tp) - }) - } - typeToTest match { - // Prohibit top-level type tests for these, but they are - // acceptable nested (e.g. case Foldable[Nothing] => ... ) - case TypeRef(_, NothingClass | NullClass | AnyValClass, _) => - TypePatternOrIsInstanceTestError(tree, typeToTest) - case _ => - def where = ( if (inPattern) "pattern " else "" ) + typeToTest - if (check(typeToTest, typeEnsured, =:=)) () - // Note that this is a regular warning, not an uncheckedWarning, - // which is now the province of such notifications as "pattern matcher - // exceeded its analysis budget." - else warningMessages foreach (m => - context.unit.warning(tree.pos, s"$m in type $where is unchecked since it is eliminated by erasure")) - } - } /** Type intersection of simple type tp1 with general type tp2. * The result eliminates some redundancies. diff --git a/src/compiler/scala/tools/nsc/typechecker/Modes.scala b/src/compiler/scala/tools/nsc/typechecker/Modes.scala index e9ea99faab..d942d080cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Modes.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Modes.scala @@ -86,6 +86,10 @@ trait Modes { */ final val TYPEPATmode = 0x10000 + /** RETmode is set when we are typing a return expression. + */ + final val RETmode = 0x20000 + final private val StickyModes = EXPRmode | PATTERNmode | TYPEmode | ALTmode final def onlyStickyModes(mode: Int) = @@ -133,4 +137,4 @@ trait Modes { def modeString(mode: Int): String = if (mode == 0) "NOmode" else (modeNameMap filterKeys (bit => inAllModes(mode, bit))).values mkString " " -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6e222459c9..3a443ea2c0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -253,12 +253,6 @@ trait Typers extends Modes with Adaptations with Tags { result } } - def isNonRefinementClassType(tpe: Type) = tpe match { - case SingleType(_, sym) => sym.isModuleClass - case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass - case ErrorType => true - case _ => false - } private def errorNotClass(tpt: Tree, found: Type) = { ClassTypeRequiredError(tpt, found); false } private def errorNotStable(tpt: Tree, found: Type) = { TypeNotAStablePrefixError(tpt, found); false } @@ -3772,9 +3766,13 @@ trait Typers extends Modes with Adaptations with Tags { if (fun.symbol == Predef_classOf) typedClassOf(tree, args.head, true) else { - if (!isPastTyper && fun.symbol == Any_isInstanceOf && !targs.isEmpty) - checkCheckable(tree, targs.head, AnyClass.tpe, inPattern = false) - + if (!isPastTyper && fun.symbol == Any_isInstanceOf && targs.nonEmpty) { + val scrutineeType = fun match { + case Select(qual, _) => qual.tpe + case _ => AnyClass.tpe + } + checkCheckable(tree, targs.head, scrutineeType, inPattern = false) + } val resultpe = restpe.instantiateTypeParams(tparams, targs) //@M substitution in instantiateParams needs to be careful! //@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int] @@ -3784,7 +3782,8 @@ trait Typers extends Modes with Adaptations with Tags { //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe) treeCopy.TypeApply(tree, fun, args) setType resultpe } - } else { + } + else { TypedApplyWrongNumberOfTpeParametersError(tree, fun) } case ErrorType => @@ -4181,7 +4180,7 @@ trait Typers extends Modes with Adaptations with Tags { ReturnWithoutTypeError(tree, enclMethod.owner) } else { context.enclMethod.returnsSeen = true - val expr1: Tree = typed(expr, EXPRmode | BYVALmode, restpt.tpe) + val expr1: Tree = typed(expr, EXPRmode | BYVALmode | RETmode, restpt.tpe) // Warn about returning a value if no value can be returned. if (restpt.tpe.typeSymbol == UnitClass) { // The typing in expr1 says expr is Unit (it has already been coerced if @@ -4190,7 +4189,8 @@ trait Typers extends Modes with Adaptations with Tags { if (typed(expr).tpe.typeSymbol != UnitClass) unit.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded") } - treeCopy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType NothingClass.tpe + treeCopy.Return(tree, checkDead(expr1)).setSymbol(enclMethod.owner) + .setType(adaptTypeOfReturn(expr1, restpt.tpe, NothingClass.tpe)) } } } diff --git a/src/compiler/scala/tools/reflect/FrontEnd.scala b/src/compiler/scala/tools/reflect/FrontEnd.scala new file mode 100644 index 0000000000..f0d3d5973d --- /dev/null +++ b/src/compiler/scala/tools/reflect/FrontEnd.scala @@ -0,0 +1,50 @@ +package scala.tools +package reflect + +import scala.reflect.internal.util.Position + +trait FrontEnd { + object severity extends Enumeration + class Severity(val id: Int) extends severity.Value { + var count: Int = 0 + override def toString() = this match { + case INFO => "INFO" + case WARNING => "WARNING" + case ERROR => "ERROR" + case _ => "<unknown>" + } + } + val INFO = new Severity(0) + val WARNING = new Severity(1) + val ERROR = new Severity(2) + + def hasErrors = ERROR.count > 0 + def hasWarnings = WARNING.count > 0 + + case class Info(val pos: Position, val msg: String, val severity: Severity) + val infos = new scala.collection.mutable.LinkedHashSet[Info] + + /** Handles incoming info */ + def log(pos: Position, msg: String, severity: Severity) { + infos += new Info(pos, msg, severity) + severity.count += 1 + display(infos.last) + } + + /** Displays incoming info */ + def display(info: Info): Unit + + /** Services a request to drop into interactive mode */ + def interactive(): Unit + + /** Refreshes the UI */ + def flush(): Unit = {} + + /** Resets the reporter */ + def reset(): Unit = { + INFO.count = 0 + WARNING.count = 0 + ERROR.count = 0 + infos.clear() + } +} diff --git a/src/compiler/scala/tools/reflect/FrontEnds.scala b/src/compiler/scala/tools/reflect/FrontEnds.scala deleted file mode 100644 index d0c3c1c774..0000000000 --- a/src/compiler/scala/tools/reflect/FrontEnds.scala +++ /dev/null @@ -1,88 +0,0 @@ -package scala.tools -package reflect - -import scala.tools.nsc.reporters._ -import scala.tools.nsc.Settings -import scala.reflect.ClassTag - -trait FrontEnds extends scala.reflect.api.FrontEnds { - - type Position = scala.reflect.internal.util.Position - - def mkConsoleFrontEnd(minSeverity: Int = 1): FrontEnd = { - val settings = new Settings() - if (minSeverity <= 0) settings.verbose.value = true - if (minSeverity > 1) settings.nowarn.value = true - wrapReporter(new ConsoleReporter(settings)) - } - - abstract class FrontEndToReporterProxy(val frontEnd: FrontEnd) extends AbstractReporter { - import frontEnd.{Severity => ApiSeverity} - val API_INFO = frontEnd.INFO - val API_WARNING = frontEnd.WARNING - val API_ERROR = frontEnd.ERROR - - type NscSeverity = Severity - val NSC_INFO = INFO - val NSC_WARNING = WARNING - val NSC_ERROR = ERROR - - def display(pos: Position, msg: String, nscSeverity: NscSeverity): Unit = - frontEnd.log(pos, msg, nscSeverity match { - case NSC_INFO => API_INFO - case NSC_WARNING => API_WARNING - case NSC_ERROR => API_ERROR - }) - - def displayPrompt(): Unit = - frontEnd.interactive() - - override def flush(): Unit = { - super.flush() - frontEnd.flush() - } - - override def reset(): Unit = { - super.reset() - frontEnd.reset() - } - } - - def wrapFrontEnd(frontEnd: FrontEnd): Reporter = new FrontEndToReporterProxy(frontEnd) { - val settings = new Settings() - settings.verbose.value = true - settings.nowarn.value = false - } - - class ReporterToFrontEndProxy(val reporter: Reporter) extends FrontEnd { - val API_INFO = INFO - val API_WARNING = WARNING - val API_ERROR = ERROR - - override def hasErrors = reporter.hasErrors - override def hasWarnings = reporter.hasWarnings - - def display(info: Info): Unit = info.severity match { - case API_INFO => reporter.info(info.pos, info.msg, false) - case API_WARNING => reporter.warning(info.pos, info.msg) - case API_ERROR => reporter.error(info.pos, info.msg) - } - - def interactive(): Unit = reporter match { - case reporter: AbstractReporter => reporter.displayPrompt() - case _ => // do nothing - } - - override def flush(): Unit = { - super.flush() - reporter.flush() - } - - override def reset(): Unit = { - super.reset() - reporter.reset() - } - } - - def wrapReporter(reporter: Reporter): FrontEnd = new ReporterToFrontEndProxy(reporter) -} diff --git a/src/compiler/scala/tools/reflect/StdTags.scala b/src/compiler/scala/tools/reflect/StdTags.scala index 94fd8e1fe8..a3bc9b9bd1 100644 --- a/src/compiler/scala/tools/reflect/StdTags.scala +++ b/src/compiler/scala/tools/reflect/StdTags.scala @@ -3,7 +3,7 @@ package reflect import java.lang.{Class => jClass} import scala.reflect.{ClassTag, classTag} -import scala.reflect.api.{MirrorOf, TypeCreator, Universe => ApiUniverse} +import scala.reflect.api.{Mirror, TypeCreator, Universe => ApiUniverse} // [Eugene++] Before 2.10 is released, I suggest we don't rely on automated type tag generation // sure, it's convenient, but then refactoring reflection / reification becomes a pain @@ -11,13 +11,13 @@ import scala.reflect.api.{MirrorOf, TypeCreator, Universe => ApiUniverse} trait StdTags { val u: ApiUniverse with Singleton - val m: MirrorOf[u.type] + val m: Mirror[u.type] lazy val tagOfListOfString: u.TypeTag[List[String]] = u.TypeTag[List[String]]( m, new TypeCreator { - def apply[U <: ApiUniverse with Singleton](m: MirrorOf[U]): U # Type = { + def apply[U <: ApiUniverse with Singleton](m: Mirror[U]): U # Type = { val u = m.universe val pre = u.ThisType(m.staticPackage("scala.collection.immutable").moduleClass.asInstanceOf[u.Symbol]) u.TypeRef(pre, u.definitions.ListClass, List(u.definitions.StringClass.toTypeConstructor)) @@ -28,7 +28,7 @@ trait StdTags { u.TypeTag[T]( m, new TypeCreator { - def apply[U <: ApiUniverse with Singleton](m: MirrorOf[U]): U # Type = + def apply[U <: ApiUniverse with Singleton](m: Mirror[U]): U # Type = m.staticClass(classTag[T].runtimeClass.getName).toTypeConstructor.asInstanceOf[U # Type] }) lazy val tagOfInt = u.TypeTag.Int diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index f627699597..ab814b617d 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -15,6 +15,9 @@ trait ToolBox[U <: scala.reflect.api.Universe] { * * Accumulates and displays warnings and errors, can drop to interactive mode (if supported). * The latter can be useful to study the typechecker or to debug complex macros. + * + * [[scala.tools.reflect]] provides two predefined front ends that can be created using + * [[scala.tools.reflect.mkSilentFrontEnd]] and [[scala.tools.reflect.mkConsoleFrontEnd]]. */ def frontEnd: FrontEnd diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 17d69cf94b..95135b84e0 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -334,7 +334,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR) val command = new CompilerCommand(arguments.toList, errorFn) command.settings.outputDirs setSingleOutput virtualDirectory - val instance = new ToolBoxGlobal(command.settings, new FrontEndToReporterProxy(frontEnd) { val settings = command.settings }) + val instance = new ToolBoxGlobal(command.settings, frontEndToReporter(frontEnd, command.settings)) if (frontEnd.hasErrors) { var msg = "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL msg += frontEnd.infos map (_.msg) mkString EOL diff --git a/src/compiler/scala/tools/reflect/package.scala b/src/compiler/scala/tools/reflect/package.scala index 901071d91a..8a1e3628e2 100644 --- a/src/compiler/scala/tools/reflect/package.scala +++ b/src/compiler/scala/tools/reflect/package.scala @@ -6,9 +6,12 @@ package scala.tools import scala.reflect.api.JavaUniverse +import scala.reflect.internal.util.Position import scala.language.implicitConversions +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings -package object reflect extends FrontEnds { +package object reflect { // [todo: can we generalize this? import scala.reflect.runtime.{universe => ru} implicit def ToolBox(mirror0: ru.Mirror): ToolBoxFactory[ru.type] = @@ -17,9 +20,92 @@ package object reflect extends FrontEnds { } // todo. replace this with an implicit class, once the pesky warning is gone + // we don't provide `Eval` for trees, because it's unclear where to get an evaluation mirror from implicit def Eval[T](expr: JavaUniverse # Expr[T]): Eval[T] = new Eval[T](expr) - // we don't provide `Eval` for trees, because it's unclear where to get an evaluation mirror from + /** Creates a UI-less reporter that simply accumulates all the messages + */ + def mkSilentFrontEnd(): FrontEnd = new FrontEnd { + def display(info: Info) {} + def interactive() {} + } + + /** Creates a reporter that prints messages to the console according to the settings. + * + * ``minSeverity'' determines minimum severity of the messages to be printed. + * 0 stands for INFO, 1 stands for WARNING and 2 stands for ERROR. + */ + // todo. untangle warningsAsErrors from Reporters. I don't feel like moving this flag here! + def mkConsoleFrontEnd(minSeverity: Int = 1): FrontEnd = { + val settings = new Settings() + if (minSeverity <= 0) settings.verbose.value = true + if (minSeverity > 1) settings.nowarn.value = true + reporterToFrontEnd(new ConsoleReporter(settings)) + } + + private[reflect] def reporterToFrontEnd(reporter: Reporter): FrontEnd = new FrontEnd { + val API_INFO = INFO + val API_WARNING = WARNING + val API_ERROR = ERROR + + override def hasErrors = reporter.hasErrors + override def hasWarnings = reporter.hasWarnings + + def display(info: Info): Unit = info.severity match { + case API_INFO => reporter.info(info.pos, info.msg, false) + case API_WARNING => reporter.warning(info.pos, info.msg) + case API_ERROR => reporter.error(info.pos, info.msg) + } + + def interactive(): Unit = reporter match { + case reporter: AbstractReporter => reporter.displayPrompt() + case _ => // do nothing + } + + override def flush(): Unit = { + super.flush() + reporter.flush() + } + + override def reset(): Unit = { + super.reset() + reporter.reset() + } + } + + private[reflect] def frontEndToReporter(frontEnd: FrontEnd, settings0: Settings): Reporter = new AbstractReporter { + val settings = settings0 + + import frontEnd.{Severity => ApiSeverity} + val API_INFO = frontEnd.INFO + val API_WARNING = frontEnd.WARNING + val API_ERROR = frontEnd.ERROR + + type NscSeverity = Severity + val NSC_INFO = INFO + val NSC_WARNING = WARNING + val NSC_ERROR = ERROR + + def display(pos: Position, msg: String, nscSeverity: NscSeverity): Unit = + frontEnd.log(pos, msg, nscSeverity match { + case NSC_INFO => API_INFO + case NSC_WARNING => API_WARNING + case NSC_ERROR => API_ERROR + }) + + def displayPrompt(): Unit = + frontEnd.interactive() + + override def flush(): Unit = { + super.flush() + frontEnd.flush() + } + + override def reset(): Unit = { + super.reset() + frontEnd.reset() + } + } } package reflect { diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index a20ff1667b..b373b3d0de 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -150,10 +150,8 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { if ((mode & global.analyzer.EXPRmode) != 0) { if ((annots1 corresponds annots2)(_.atp <:< _.atp)) { vprintln("already same, can't adapt further") - return false - } - - if (annots1.isEmpty && !annots2.isEmpty && ((mode & global.analyzer.BYVALmode) == 0)) { + false + } else if (annots1.isEmpty && !annots2.isEmpty && ((mode & global.analyzer.BYVALmode) == 0)) { //println("can adapt annotations? " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt) if (!hasPlusMarker(tree.tpe)) { // val base = tree.tpe <:< removeAllCPSAnnotations(pt) @@ -163,17 +161,26 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { // TBD: use same or not? //if (same) { vprintln("yes we can!! (unit)") - return true + true //} - } - } else if (!annots1.isEmpty && ((mode & global.analyzer.BYVALmode) != 0)) { - if (!hasMinusMarker(tree.tpe)) { + } else false + } else if (!hasPlusMarker(tree.tpe) && annots1.isEmpty && !annots2.isEmpty && ((mode & global.analyzer.RETmode) != 0)) { + vprintln("checking enclosing method's result type without annotations") + tree.tpe <:< pt.withoutAnnotations + } else if (!hasMinusMarker(tree.tpe) && !annots1.isEmpty && ((mode & global.analyzer.BYVALmode) != 0)) { + val optCpsTypes: Option[(Type, Type)] = cpsParamTypes(tree.tpe) + val optExpectedCpsTypes: Option[(Type, Type)] = cpsParamTypes(pt) + if (optCpsTypes.isEmpty || optExpectedCpsTypes.isEmpty) { vprintln("yes we can!! (byval)") - return true + true + } else { // check cps param types + val cpsTpes = optCpsTypes.get + val cpsPts = optExpectedCpsTypes.get + // class cpsParam[-B,+C], therefore: + cpsPts._1 <:< cpsTpes._1 && cpsTpes._2 <:< cpsPts._2 } - } - } - false + } else false + } else false } override def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = { @@ -184,6 +191,7 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { val patMode = (mode & global.analyzer.PATTERNmode) != 0 val exprMode = (mode & global.analyzer.EXPRmode) != 0 val byValMode = (mode & global.analyzer.BYVALmode) != 0 + val retMode = (mode & global.analyzer.RETmode) != 0 val annotsTree = cpsParamAnnotation(tree.tpe) val annotsExpected = cpsParamAnnotation(pt) @@ -210,9 +218,38 @@ abstract class CPSAnnotationChecker extends CPSUtils with Modes { val res = tree modifyType addMinusMarker vprintln("adapted annotations (by val) of " + tree + " to " + res.tpe) res + } else if (retMode && !hasPlusMarker(tree.tpe) && annotsTree.isEmpty && annotsExpected.nonEmpty) { + // add a marker annotation that will make tree.tpe behave as pt, subtyping wise + // tree will look like having any possible annotation + + // note 1: we are only adding a plus marker if the method's result type is a cps type + // (annotsExpected.nonEmpty == cpsParamAnnotation(pt).nonEmpty) + // note 2: we are not adding the expected cps annotations, since they will be added + // by adaptTypeOfReturn (see below). + val res = tree modifyType (_ withAnnotations List(newPlusMarker())) + vprintln("adapted annotations (return) of " + tree + " to " + res.tpe) + res } else tree } + /** Returns an adapted type for a return expression if the method's result type (pt) is a CPS type. + * Otherwise, it returns the `default` type (`typedReturn` passes `NothingClass.tpe`). + * + * A return expression in a method that has a CPS result type is an error unless the return + * is in tail position. Therefore, we are making sure that only the types of return expressions + * are adapted which will either be removed, or lead to an error. + */ + override def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = { + // only adapt if method's result type (pt) is cps type + val annots = cpsParamAnnotation(pt) + if (annots.nonEmpty) { + // return type of `tree` without plus marker, but only if it doesn't have other cps annots + if (hasPlusMarker(tree.tpe) && !hasCpsParamTypes(tree.tpe)) + tree.setType(removeAttribs(tree.tpe, MarkerCPSAdaptPlus)) + tree.tpe + } else default + } + def updateAttributesFromChildren(tpe: Type, childAnnots: List[AnnotationInfo], byName: List[Tree]): Type = { tpe match { // Would need to push annots into each alternative of overloaded type diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index 51760d2807..ba87cadfeb 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -32,6 +32,55 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with implicit val _unit = unit // allow code in CPSUtils.scala to report errors var cpsAllowed: Boolean = false // detect cps code in places we do not handle (yet) + object RemoveTailReturnsTransformer extends Transformer { + override def transform(tree: Tree): Tree = tree match { + case Block(stms, r @ Return(expr)) => + treeCopy.Block(tree, stms, expr) + + case Block(stms, expr) => + treeCopy.Block(tree, stms, transform(expr)) + + case If(cond, r1 @ Return(thenExpr), r2 @ Return(elseExpr)) => + treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr)) + + case If(cond, r1 @ Return(thenExpr), elseExpr) => + treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr)) + + case If(cond, thenExpr, r2 @ Return(elseExpr)) => + treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr)) + + case If(cond, thenExpr, elseExpr) => + treeCopy.If(tree, cond, transform(thenExpr), transform(elseExpr)) + + case Try(block, catches, finalizer) => + treeCopy.Try(tree, + transform(block), + (catches map (t => transform(t))).asInstanceOf[List[CaseDef]], + transform(finalizer)) + + case CaseDef(pat, guard, r @ Return(expr)) => + treeCopy.CaseDef(tree, pat, guard, expr) + + case CaseDef(pat, guard, body) => + treeCopy.CaseDef(tree, pat, guard, transform(body)) + + case Return(_) => + unit.error(tree.pos, "return expressions in CPS code must be in tail position") + tree + + case _ => + super.transform(tree) + } + } + + def removeTailReturns(body: Tree): Tree = { + // support body with single return expression + body match { + case Return(expr) => expr + case _ => RemoveTailReturnsTransformer.transform(body) + } + } + override def transform(tree: Tree): Tree = { if (!cpsEnabled) return tree @@ -46,11 +95,14 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with // this would cause infinite recursion. But we could remove the // ValDef case here. - case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => + case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs0) => debuglog("transforming " + dd.symbol) atOwner(dd.symbol) { - val rhs1 = transExpr(rhs, None, getExternalAnswerTypeAnn(tpt.tpe)) + val rhs = + if (cpsParamTypes(tpt.tpe).nonEmpty) removeTailReturns(rhs0) + else rhs0 + val rhs1 = transExpr(rhs, None, getExternalAnswerTypeAnn(tpt.tpe))(getExternalAnswerTypeAnn(tpt.tpe).isDefined) debuglog("result "+rhs1) debuglog("result is of type "+rhs1.tpe) @@ -75,6 +127,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val ext = getExternalAnswerTypeAnn(body.tpe) val pureBody = getAnswerTypeAnn(body.tpe).isEmpty + implicit val isParentImpure = ext.isDefined def transformPureMatch(tree: Tree, selector: Tree, cases: List[CaseDef]) = { val caseVals = cases map { case cd @ CaseDef(pat, guard, body) => @@ -154,8 +207,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } - def transExpr(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo): Tree = { - transTailValue(tree, cpsA, cpsR) match { + def transExpr(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo)(implicit isAnyParentImpure: Boolean = false): Tree = { + transTailValue(tree, cpsA, cpsR)(cpsR.isDefined || isAnyParentImpure) match { case (Nil, b) => b case (a, b) => treeCopy.Block(tree, a,b) @@ -163,7 +216,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } - def transArgList(fun: Tree, args: List[Tree], cpsA: CPSInfo): (List[List[Tree]], List[Tree], CPSInfo) = { + def transArgList(fun: Tree, args: List[Tree], cpsA: CPSInfo)(implicit isAnyParentImpure: Boolean): (List[List[Tree]], List[Tree], CPSInfo) = { val formals = fun.tpe.paramTypes val overshoot = args.length - formals.length @@ -172,7 +225,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val (stm,expr) = (for ((a,tp) <- args.zip(formals ::: List.fill(overshoot)(NoType))) yield { tp match { case TypeRef(_, ByNameParamClass, List(elemtp)) => - (Nil, transExpr(a, None, getAnswerTypeAnn(elemtp))) + // note that we're not passing just isAnyParentImpure + (Nil, transExpr(a, None, getAnswerTypeAnn(elemtp))(getAnswerTypeAnn(elemtp).isDefined || isAnyParentImpure)) case _ => val (valStm, valExpr, valSpc) = transInlineValue(a, spc) spc = valSpc @@ -184,7 +238,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } - def transValue(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo): (List[Tree], Tree, CPSInfo) = { + // precondition: cpsR.isDefined "implies" isAnyParentImpure + def transValue(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo)(implicit isAnyParentImpure: Boolean): (List[Tree], Tree, CPSInfo) = { // return value: (stms, expr, spc), where spc is CPSInfo after stms but *before* expr implicit val pos = tree.pos tree match { @@ -192,7 +247,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val (cpsA2, cpsR2) = (cpsA, linearize(cpsA, getAnswerTypeAnn(tree.tpe))) // tbd // val (cpsA2, cpsR2) = (None, getAnswerTypeAnn(tree.tpe)) - val (a, b) = transBlock(stms, expr, cpsA2, cpsR2) + val (a, b) = transBlock(stms, expr, cpsA2, cpsR2)(cpsR2.isDefined || isAnyParentImpure) val tree1 = (treeCopy.Block(tree, a, b)) // no updateSynthFlag here!!! (Nil, tree1, cpsA) @@ -206,8 +261,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val (cpsA2, cpsR2) = if (hasSynthMarker(tree.tpe)) (spc, linearize(spc, getAnswerTypeAnn(tree.tpe))) else (None, getAnswerTypeAnn(tree.tpe)) // if no cps in condition, branches must conform to tree.tpe directly - val thenVal = transExpr(thenp, cpsA2, cpsR2) - val elseVal = transExpr(elsep, cpsA2, cpsR2) + val thenVal = transExpr(thenp, cpsA2, cpsR2)(cpsR2.isDefined || isAnyParentImpure) + val elseVal = transExpr(elsep, cpsA2, cpsR2)(cpsR2.isDefined || isAnyParentImpure) // check that then and else parts agree (not necessary any more, but left as sanity check) if (cpsR.isDefined) { @@ -227,7 +282,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with else (None, getAnswerTypeAnn(tree.tpe)) val caseVals = cases map { case cd @ CaseDef(pat, guard, body) => - val bodyVal = transExpr(body, cpsA2, cpsR2) + val bodyVal = transExpr(body, cpsA2, cpsR2)(cpsR2.isDefined || isAnyParentImpure) treeCopy.CaseDef(cd, transform(pat), transform(guard), bodyVal) } @@ -245,7 +300,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with // currentOwner.newMethod(name, tree.pos, Flags.SYNTHETIC) setInfo ldef.symbol.info val sym = ldef.symbol resetFlag Flags.LABEL val rhs1 = rhs //new TreeSymSubstituter(List(ldef.symbol), List(sym)).transform(rhs) - val rhsVal = transExpr(rhs1, None, getAnswerTypeAnn(tree.tpe)) changeOwner (currentOwner -> sym) + val rhsVal = transExpr(rhs1, None, getAnswerTypeAnn(tree.tpe))(getAnswerTypeAnn(tree.tpe).isDefined || isAnyParentImpure) changeOwner (currentOwner -> sym) val stm1 = localTyper.typed(DefDef(sym, rhsVal)) // since virtpatmat does not rely on fall-through, don't call the labels it emits @@ -284,6 +339,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with (stms, updateSynthFlag(treeCopy.Assign(tree, transform(lhs), expr)), spc) case Return(expr0) => + if (isAnyParentImpure) + unit.error(tree.pos, "return expression not allowed, since method calls CPS method") val (stms, expr, spc) = transInlineValue(expr0, cpsA) (stms, updateSynthFlag(treeCopy.Return(tree, expr)), spc) @@ -321,7 +378,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } } - def transTailValue(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo): (List[Tree], Tree) = { + // precondition: cpsR.isDefined "implies" isAnyParentImpure + def transTailValue(tree: Tree, cpsA: CPSInfo, cpsR: CPSInfo)(implicit isAnyParentImpure: Boolean): (List[Tree], Tree) = { val (stms, expr, spc) = transValue(tree, cpsA, cpsR) @@ -398,7 +456,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with (stms, expr) } - def transInlineValue(tree: Tree, cpsA: CPSInfo): (List[Tree], Tree, CPSInfo) = { + def transInlineValue(tree: Tree, cpsA: CPSInfo)(implicit isAnyParentImpure: Boolean): (List[Tree], Tree, CPSInfo) = { val (stms, expr, spc) = transValue(tree, cpsA, None) // never required to be cps @@ -425,7 +483,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with - def transInlineStm(stm: Tree, cpsA: CPSInfo): (List[Tree], CPSInfo) = { + def transInlineStm(stm: Tree, cpsA: CPSInfo)(implicit isAnyParentImpure: Boolean): (List[Tree], CPSInfo) = { stm match { // TODO: what about DefDefs? @@ -455,7 +513,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } } - def transBlock(stms: List[Tree], expr: Tree, cpsA: CPSInfo, cpsR: CPSInfo): (List[Tree], Tree) = { + // precondition: cpsR.isDefined "implies" isAnyParentImpure + def transBlock(stms: List[Tree], expr: Tree, cpsA: CPSInfo, cpsR: CPSInfo)(implicit isAnyParentImpure: Boolean): (List[Tree], Tree) = { def rec(currStats: List[Tree], currAns: CPSInfo, accum: List[Tree]): (List[Tree], Tree) = currStats match { case Nil => diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 8b478f6845..e381c09398 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -8,10 +8,43 @@ package scala -/** A class to support string interpolation. - * This class supports string interpolation as outlined in Scala SIP-11. - * It needs to be fully documented once the SIP is accepted. +/** This class provides the basic mechanism to do String Interpolation. + * String Interpolation allows users + * to embed variable references directly in *processed* string literals. + * Here's an example: + * {{{ + * val name = "James" + * println(s"Hello, $name") // Hello, James + * }}} * + * Any processed string literal is rewritten as an instantiation and + * method call against this class. For example: + * {{{ + * s"Hello, $name" + * }}} + * + * is rewritten to be: + * + * {{{ + * new StringContext("Hello, ", "").s(name) + * }}} + * + * By default, this class provides the `raw`, `s` and `f` methods as + * available interpolators. + * + * To provide your own string interpolator, create an implicit class + * which adds a method to `StringContext`. Here's an example: + * {{{ + * implicit class JsonHelper(val sc: StringContext) extends AnyVal { + * def json(args: Any*): JSONObject = ... + * } + * val x: JSONObject = json"{ a: $a }" + * }}} + * + * Here the `JsonHelper` extenion class implicitly adds the `json` method to + * `StringContext` which can be used for `json` string literals. + * + * @since 2.10.0 * @param parts The parts that make up the interpolated string, * without the expressions that get inserted by interpolation. */ @@ -33,6 +66,20 @@ case class StringContext(parts: String*) { * * It inserts its arguments between corresponding parts of the string context. * It also treats standard escape sequences as defined in the Scala specification. + * Here's an example of usage: + * {{{ + * val name = "James" + * println(s"Hello, $name") // Hello, James + * }}} + * In this example, the expression $name is replaced with the `toString` of the + * variable `name`. + * The `s` interpolator can take the `toString` of any arbitrary expression within + * a `${}` block, for example: + * {{{ + * println(s"1 + 1 = ${1 + 1}") + * }}} + * will print the string `1 + 1 = 2`. + * * @param `args` The arguments to be inserted into the resulting string. * @throws An `IllegalArgumentException` * if the number of `parts` in the enclosing `StringContext` does not exceed @@ -47,6 +94,9 @@ case class StringContext(parts: String*) { * It inserts its arguments between corresponding parts of the string context. * As opposed to the simple string interpolator `s`, this one does not treat * standard escape sequences as defined in the Scala specification. + * + * For example, the raw processed string `raw"a\nb"` is equal to the scala string `"a\\nb"`. + * * @param `args` The arguments to be inserted into the resulting string. * @throws An `IllegalArgumentException` * if the number of `parts` in the enclosing `StringContext` does not exceed @@ -77,6 +127,13 @@ case class StringContext(parts: String*) { * specifier. All specifiers allowed in Java format strings are handled, and in the same * way they are treated in Java. * + * For example: + * {{{ + * val height = 1.9d + * val name = "James" + * println(f"$name%s is $height%2.2f meters tall") // James is 1.90 meters tall + * }}} + * * @param `args` The arguments to be inserted into the resulting string. * @throws An `IllegalArgumentException` * if the number of `parts` in the enclosing `StringContext` does not exceed diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 2bb0cc3c76..b0de7f8d5a 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -4,7 +4,7 @@ package api /** * This is an internal implementation class. */ -trait BuildUtils { self: Universe => +private[reflect] trait BuildUtils { self: Universe => val build: BuildApi diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala index 65b0eb9301..b86f36420d 100644 --- a/src/reflect/scala/reflect/api/Exprs.scala +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -12,14 +12,18 @@ trait Exprs { self: Universe => /** Expr wraps an expression tree and tags it with its type. */ trait Expr[+T] extends Equals with Serializable { + /** + * Underlying mirror of this expr. + */ val mirror: Mirror + /** * Migrates the expression into another mirror, jumping into a different universe if necessary. * * This means that all symbolic references to classes/objects/packages in the expression * will be re-resolved within the new mirror (typically using that mirror's classloader). */ - def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # Expr[T] + def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # Expr[T] /** * The Scala syntax tree representing the wrapped expression. @@ -91,13 +95,13 @@ trait Exprs { self: Universe => * in which case the tree first needs to be wrapped in an expr. */ object Expr { - def apply[T: WeakTypeTag](mirror: MirrorOf[self.type], treec: TreeCreator): Expr[T] = new ExprImpl[T](mirror.asInstanceOf[Mirror], treec) + def apply[T: WeakTypeTag](mirror: scala.reflect.api.Mirror[self.type], treec: TreeCreator): Expr[T] = new ExprImpl[T](mirror.asInstanceOf[Mirror], treec) def unapply[T](expr: Expr[T]): Option[Tree] = Some(expr.tree) } private class ExprImpl[+T: WeakTypeTag](val mirror: Mirror, val treec: TreeCreator) extends Expr[T] { - def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # Expr[T] = { - val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]] + def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # Expr[T] = { + val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]] val tag1 = (implicitly[WeakTypeTag[T]] in otherMirror).asInstanceOf[otherMirror.universe.WeakTypeTag[T]] otherMirror.universe.Expr[T](otherMirror1, treec)(tag1) } diff --git a/src/reflect/scala/reflect/api/FrontEnds.scala b/src/reflect/scala/reflect/api/FrontEnds.scala deleted file mode 100644 index 61ea227c47..0000000000 --- a/src/reflect/scala/reflect/api/FrontEnds.scala +++ /dev/null @@ -1,70 +0,0 @@ -package scala.reflect -package api - -trait FrontEnds { - - type Position >: Null - - trait FrontEnd { - object severity extends Enumeration - class Severity(val id: Int) extends severity.Value { - var count: Int = 0 - override def toString() = this match { - case INFO => "INFO" - case WARNING => "WARNING" - case ERROR => "ERROR" - case _ => "<unknown>" - } - } - val INFO = new Severity(0) - val WARNING = new Severity(1) - val ERROR = new Severity(2) - - def hasErrors = ERROR.count > 0 - def hasWarnings = WARNING.count > 0 - - case class Info(val pos: Position, val msg: String, val severity: Severity) - val infos = new scala.collection.mutable.LinkedHashSet[Info] - - /** Handles incoming info */ - def log(pos: Position, msg: String, severity: Severity) { - infos += new Info(pos, msg, severity) - severity.count += 1 - display(infos.last) - } - - /** Displays incoming info */ - def display(info: Info): Unit - - /** Services a request to drop into interactive mode */ - def interactive(): Unit - - /** Refreshes the UI */ - def flush(): Unit = {} - - /** Resets the reporter */ - def reset(): Unit = { - INFO.count = 0 - WARNING.count = 0 - ERROR.count = 0 - infos.clear() - } - } - - class SilentFrontEnd extends FrontEnd { - def display(info: Info) {} - def interactive() {} - } - - /** Creates a UI-less reporter that simply accumulates all the messages - */ - def mkSilentFrontEnd(): FrontEnd = new SilentFrontEnd() - - /** Creates a reporter that prints messages to the console according to the settings. - * - * ``minSeverity'' determines minimum severity of the messages to be printed. - * 0 stands for INFO, 1 stands for WARNING and 2 stands for ERROR. - */ - // todo. untangle warningsAsErrors from Reporters. I don't feel like moving this flag here! - def mkConsoleFrontEnd(minSeverity: Int = 1): FrontEnd -} diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala index ba38381561..cc703e833d 100644 --- a/src/reflect/scala/reflect/api/JavaUniverse.scala +++ b/src/reflect/scala/reflect/api/JavaUniverse.scala @@ -7,7 +7,7 @@ trait JavaUniverse extends Universe with Mirrors { self => override type Mirror >: Null <: JavaMirror - trait JavaMirror extends MirrorOf[self.type] with RuntimeMirror { + trait JavaMirror extends scala.reflect.api.Mirror[self.type] with RuntimeMirror { val classLoader: ClassLoader override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}" } @@ -23,7 +23,7 @@ trait JavaUniverse extends Universe with Mirrors { self => override def manifestToTypeTag[T](mirror0: Any, manifest: Manifest[T]): Universe # TypeTag[T] = TypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator { - def apply[U <: Universe with Singleton](mirror: MirrorOf[U]): U # Type = { + def apply[U <: Universe with Singleton](mirror: scala.reflect.api.Mirror[U]): U # Type = { mirror.universe match { case ju: JavaUniverse => val jm = mirror.asInstanceOf[ju.Mirror] diff --git a/src/reflect/scala/reflect/api/MirrorOf.scala b/src/reflect/scala/reflect/api/Mirror.scala index cd5641e692..2de0d7120e 100644 --- a/src/reflect/scala/reflect/api/MirrorOf.scala +++ b/src/reflect/scala/reflect/api/Mirror.scala @@ -8,13 +8,13 @@ package api * * This is defined outside the reflection universe cake pattern implementation * so that it can be referenced from outside. For example TypeCreator and TreeCreator - * reference MirrorOf and also need to be defined outside the cake as they are + * reference Mirror and also need to be defined outside the cake as they are * used by type tags, which can be migrated between different universes and consequently * cannot be bound to a fixed one. * * @see [[Mirrors]] */ -abstract class MirrorOf[U <: Universe with Singleton] { +abstract class Mirror[U <: Universe with Singleton] { /** The universe this mirror belongs to. */ val universe: U diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index c935533027..bff899daa4 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -11,8 +11,12 @@ package api */ trait Mirrors { self: Universe => - /** The base type of all mirrors of this universe */ - type Mirror >: Null <: MirrorOf[self.type] + /** The base type of all mirrors of this universe. + * + * This abstract type conforms the base interface for all mirrors defined in [[scala.reflect.api.Mirror]] + * and is gradually refined in specific universes (e.g. `Mirror` of a [[scala.reflect.api.JavaUniverse]] is capable of reflection). + */ + type Mirror >: Null <: scala.reflect.api.Mirror[self.type] /** The root mirror of this universe. This mirror contains standard Scala classes and types such as `Any`, `AnyRef`, `AnyVal`, * `Nothing`, `Null`, and all classes loaded from scala-library, which are shared across all mirrors within the enclosing universe. @@ -239,7 +243,7 @@ trait Mirrors { self: Universe => } /** A mirror that reflects instances and static classes */ - trait ReflectiveMirror extends MirrorOf[Mirrors.this.type] { + trait ReflectiveMirror extends scala.reflect.api.Mirror[Mirrors.this.type] { /** A reflective mirror for the given object. * diff --git a/src/reflect/scala/reflect/api/Position.scala b/src/reflect/scala/reflect/api/Position.scala new file mode 100644 index 0000000000..9c63e4becf --- /dev/null +++ b/src/reflect/scala/reflect/api/Position.scala @@ -0,0 +1,167 @@ +package scala.reflect +package api + +/** The Position class and its subclasses represent positions of ASTs and symbols. + * Except for NoPosition and FakePos, every position refers to a SourceFile + * and to an offset in the sourcefile (its `point`). For batch compilation, + * that's all. For interactive IDE's there are also RangePositions + * and TransparentPositions. A RangePosition indicates a start and an end + * in addition to its point. TransparentPositions are a subclass of RangePositions. + * Range positions that are not transparent are called opaque. + * Trees with RangePositions need to satisfy the following invariants. + * + * INV1: A tree with an offset position never contains a child + * with a range position + * INV2: If the child of a tree with a range position also has a range position, + * then the child's range is contained in the parent's range. + * INV3: Opaque range positions of children of the same node are non-overlapping + * (this means their overlap is at most a single point). + * + * The following tests are useful on positions: + * + * pos.isDefined true if position is not a NoPosition nor a FakePosition + * pos.isRange true if position is a range + * pos.isOpaqueRange true if position is an opaque range + * + * The following accessor methods are provided: + * + * pos.source The source file of the position, which must be defined + * pos.point The offset of the position's point, which must be defined + * pos.start The start of the position, which must be a range + * pos.end The end of the position, which must be a range + * + * There are also convenience methods, such as + * + * pos.startOrPoint + * pos.endOrPoint + * pos.pointOrElse(default) + * + * These are less strict about the kind of position on which they can be applied. + * + * The following conversion methods are often used: + * + * pos.focus converts a range position to an offset position, keeping its point; + * returns all other positions unchanged. + * pos.makeTransparent converts an opaque range position into a transparent one. + * returns all other positions unchanged. + */ +trait Position extends Attachments { + + type Pos >: Null <: Position + + /** Java file corresponding to the source file of this position. + * + * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. + * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined + * and exposed as a part of scala.reflect.api. + */ + def source: scala.reflect.internal.util.SourceFile + + /** Is this position neither a NoPosition nor a FakePosition? + * If isDefined is true, offset and source are both defined. + */ + def isDefined: Boolean + + /** Is this position a range position? */ + def isRange: Boolean + + /** Is this position a transparent position? */ + def isTransparent: Boolean + + /** Is this position a non-transparent range position? */ + def isOpaqueRange: Boolean + + /** if opaque range, make this position transparent */ + def makeTransparent: Pos + + /** The start of the position's range, error if not a range position */ + def start: Int + + /** The start of the position's range, or point if not a range position */ + def startOrPoint: Int + + /** The point (where the ^ is) of the position */ + def point: Int + + /** The point (where the ^ is) of the position, or else `default` if undefined */ + def pointOrElse(default: Int): Int + + /** The end of the position's range, error if not a range position */ + def end: Int + + /** The end of the position's range, or point if not a range position */ + def endOrPoint: Int + + /** The same position with a different start value (if a range) */ + def withStart(off: Int): Pos + + /** The same position with a different end value (if a range) */ + def withEnd(off: Int): Pos + + /** The same position with a different point value (if a range or offset) */ + def withPoint(off: Int): Pos + + /** If this is a range, the union with the other range, with the point of this position. + * Otherwise, this position + */ + def union(pos: Pos): Pos + + /** If this is a range position, the offset position of its point. + * Otherwise the position itself + */ + def focus: Pos + + /** If this is a range position, the offset position of its start. + * Otherwise the position itself + */ + def focusStart: Pos + + /** If this is a range position, the offset position of its end. + * Otherwise the position itself + */ + def focusEnd: Pos + + /** Does this position include the given position `pos`. + * This holds if `this` is a range position and its range [start..end] + * is the same or covers the range of the given position, which may or may not be a range position. + */ + def includes(pos: Pos): Boolean + + /** Does this position properly include the given position `pos` ("properly" meaning their + * ranges are not the same)? + */ + def properlyIncludes(pos: Pos): Boolean + + /** Does this position precede that position? + * This holds if both positions are defined and the end point of this position + * is not larger than the start point of the given position. + */ + def precedes(pos: Pos): Boolean + + /** Does this position properly precede the given position `pos` ("properly" meaning their ranges + * do not share a common point). + */ + def properlyPrecedes(pos: Pos): Boolean + + /** Does this position overlap with that position? + * This holds if both positions are ranges and there is an interval of + * non-zero length that is shared by both position ranges. + */ + def overlaps(pos: Pos): Boolean + + /** Does this position cover the same range as that position? + * Holds only if both position are ranges + */ + def sameRange(pos: Pos): Boolean + + def line: Int + + def column: Int + + /** Convert this to a position around `point` that spans a single source line */ + def toSingleLine: Pos + + def lineContent: String + + def show: String +} diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala index 0eddc88fc4..5c530e7e70 100644 --- a/src/reflect/scala/reflect/api/Positions.scala +++ b/src/reflect/scala/reflect/api/Positions.scala @@ -10,7 +10,7 @@ trait Positions { self: Universe => /** .. */ - type Position >: Null <: PositionApi { type Pos = Position } + type Position >: Null <: scala.reflect.api.Position { type Pos = Position } /** A tag that preserves the identity of the `Position` abstract type from erasure. * Can be used for pattern matching, instance tests, serialization and likes. @@ -38,168 +38,3 @@ trait Positions { */ def wrappingPos(trees: List[Tree]): Position } - -/** The Position class and its subclasses represent positions of ASTs and symbols. - * Except for NoPosition and FakePos, every position refers to a SourceFile - * and to an offset in the sourcefile (its `point`). For batch compilation, - * that's all. For interactive IDE's there are also RangePositions - * and TransparentPositions. A RangePosition indicates a start and an end - * in addition to its point. TransparentPositions are a subclass of RangePositions. - * Range positions that are not transparent are called opaque. - * Trees with RangePositions need to satisfy the following invariants. - * - * INV1: A tree with an offset position never contains a child - * with a range position - * INV2: If the child of a tree with a range position also has a range position, - * then the child's range is contained in the parent's range. - * INV3: Opaque range positions of children of the same node are non-overlapping - * (this means their overlap is at most a single point). - * - * The following tests are useful on positions: - * - * pos.isDefined true if position is not a NoPosition nor a FakePosition - * pos.isRange true if position is a range - * pos.isOpaqueRange true if position is an opaque range - * - * The following accessor methods are provided: - * - * pos.source The source file of the position, which must be defined - * pos.point The offset of the position's point, which must be defined - * pos.start The start of the position, which must be a range - * pos.end The end of the position, which must be a range - * - * There are also convenience methods, such as - * - * pos.startOrPoint - * pos.endOrPoint - * pos.pointOrElse(default) - * - * These are less strict about the kind of position on which they can be applied. - * - * The following conversion methods are often used: - * - * pos.focus converts a range position to an offset position, keeping its point; - * returns all other positions unchanged. - * pos.makeTransparent converts an opaque range position into a transparent one. - * returns all other positions unchanged. - */ -trait PositionApi extends Attachments { - - type Pos >: Null <: PositionApi - - /** Java file corresponding to the source file of this position. - */ - def fileInfo: java.io.File - - /** Content of the source file that contains this position. - */ - def fileContent: Array[Char] - - /** Is this position neither a NoPosition nor a FakePosition? - * If isDefined is true, offset and source are both defined. - */ - def isDefined: Boolean - - /** Is this position a range position? */ - def isRange: Boolean - - /** Is this position a transparent position? */ - def isTransparent: Boolean - - /** Is this position a non-transparent range position? */ - def isOpaqueRange: Boolean - - /** if opaque range, make this position transparent */ - def makeTransparent: Pos - - /** The start of the position's range, error if not a range position */ - def start: Int - - /** The start of the position's range, or point if not a range position */ - def startOrPoint: Int - - /** The point (where the ^ is) of the position */ - def point: Int - - /** The point (where the ^ is) of the position, or else `default` if undefined */ - def pointOrElse(default: Int): Int - - /** The end of the position's range, error if not a range position */ - def end: Int - - /** The end of the position's range, or point if not a range position */ - def endOrPoint: Int - - /** The same position with a different start value (if a range) */ - def withStart(off: Int): Pos - - /** The same position with a different end value (if a range) */ - def withEnd(off: Int): Pos - - /** The same position with a different point value (if a range or offset) */ - def withPoint(off: Int): Pos - - /** If this is a range, the union with the other range, with the point of this position. - * Otherwise, this position - */ - def union(pos: Pos): Pos - - /** If this is a range position, the offset position of its point. - * Otherwise the position itself - */ - def focus: Pos - - /** If this is a range position, the offset position of its start. - * Otherwise the position itself - */ - def focusStart: Pos - - /** If this is a range position, the offset position of its end. - * Otherwise the position itself - */ - def focusEnd: Pos - - /** Does this position include the given position `pos`. - * This holds if `this` is a range position and its range [start..end] - * is the same or covers the range of the given position, which may or may not be a range position. - */ - def includes(pos: Pos): Boolean - - /** Does this position properly include the given position `pos` ("properly" meaning their - * ranges are not the same)? - */ - def properlyIncludes(pos: Pos): Boolean - - /** Does this position precede that position? - * This holds if both positions are defined and the end point of this position - * is not larger than the start point of the given position. - */ - def precedes(pos: Pos): Boolean - - /** Does this position properly precede the given position `pos` ("properly" meaning their ranges - * do not share a common point). - */ - def properlyPrecedes(pos: Pos): Boolean - - /** Does this position overlap with that position? - * This holds if both positions are ranges and there is an interval of - * non-zero length that is shared by both position ranges. - */ - def overlaps(pos: Pos): Boolean - - /** Does this position cover the same range as that position? - * Holds only if both position are ranges - */ - def sameRange(pos: Pos): Boolean - - def line: Int - - def column: Int - - /** Convert this to a position around `point` that spans a single source line */ - def toSingleLine: Pos - - def lineContent: String - - def show: String -} diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index d8f955ddf3..8b24b953ae 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -86,10 +86,10 @@ trait Symbols { self: Universe => * that directly contains the current symbol's definition. * The `NoSymbol` symbol does not have an owner, and calling this method * on one causes an internal error. - * The owner of the Scala root class [[scala.reflect.api.MirrorOf.RootClass]] - * and the Scala root object [[scala.reflect.api.MirrorOf.RootPackage]] is `NoSymbol`. + * The owner of the Scala root class [[scala.reflect.api.Mirror.RootClass]] + * and the Scala root object [[scala.reflect.api.Mirror.RootPackage]] is `NoSymbol`. * Every other symbol has a chain of owners that ends in - * [[scala.reflect.api.MirrorOf.RootClass]]. + * [[scala.reflect.api.Mirror.RootClass]]. */ def owner: Symbol @@ -209,6 +209,10 @@ trait Symbols { self: Universe => /** Source file if this symbol is created during this compilation run, * or a class file if this symbol is loaded from a *.class or *.jar. + * + * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. + * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined + * and exposed as a part of scala.reflect.api. */ def associatedFile: scala.reflect.io.AbstractFile diff --git a/src/reflect/scala/reflect/api/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala index 0c8701775c..a8e8ae1b58 100644 --- a/src/reflect/scala/reflect/api/TreeCreator.scala +++ b/src/reflect/scala/reflect/api/TreeCreator.scala @@ -22,5 +22,5 @@ package api * `TreeCreator` can't have a functional type, so it's implemented as class with an apply method. */ abstract class TreeCreator { - def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Tree + def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Tree } diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala index cc6d38c548..2b3ef4320b 100644 --- a/src/reflect/scala/reflect/api/TypeCreator.scala +++ b/src/reflect/scala/reflect/api/TypeCreator.scala @@ -22,5 +22,5 @@ package api * `TypeCreator` can't have a functional type, so it's implemented as class with an apply method. */ abstract class TypeCreator { - def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Type + def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type } diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala index a7e58d2bcb..fc3f067a96 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -154,19 +154,17 @@ trait TypeTags { self: Universe => @annotation.implicitNotFound(msg = "No WeakTypeTag available for ${T}") trait WeakTypeTag[T] extends Equals with Serializable { /** - * Mirror corresponding to the universe of this WeakTypeTag. + * Underlying mirror of this type tag. */ val mirror: Mirror + /** - * Migrates type tag to another universe. - * - * Type tags are path dependent on their universe. This methods allows migration - * given the mirror corresponding to the target universe. + * Migrates the expression into another mirror, jumping into a different universe if necessary. * * Migration means that all symbolic references to classes/objects/packages in the expression * will be re-resolved within the new mirror (typically using that mirror's classloader). */ - def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # WeakTypeTag[T] + def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # WeakTypeTag[T] /** * Reflective representation of type T. @@ -201,7 +199,7 @@ trait TypeTags { self: Universe => val Null : WeakTypeTag[scala.Null] = TypeTag.Null - def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): WeakTypeTag[T] = + def apply[T](mirror1: scala.reflect.api.Mirror[self.type], tpec1: TypeCreator): WeakTypeTag[T] = tpec1(mirror1) match { case ByteTpe => WeakTypeTag.Byte.asInstanceOf[WeakTypeTag[T]] case ShortTpe => WeakTypeTag.Short.asInstanceOf[WeakTypeTag[T]] @@ -226,8 +224,8 @@ trait TypeTags { self: Universe => private class WeakTypeTagImpl[T](val mirror: Mirror, val tpec: TypeCreator) extends WeakTypeTag[T] { lazy val tpe: Type = tpec(mirror) - def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # WeakTypeTag[T] = { - val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]] + def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # WeakTypeTag[T] = { + val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]] otherMirror.universe.WeakTypeTag[T](otherMirror1, tpec) } private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = false) @@ -245,7 +243,7 @@ trait TypeTags { self: Universe => /** * @inheritdoc */ - override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T] + override def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # TypeTag[T] // case class accessories override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]] @@ -271,7 +269,7 @@ trait TypeTags { self: Universe => val Nothing: TypeTag[scala.Nothing] = new PredefTypeTag[scala.Nothing] (NothingTpe, _.TypeTag.Nothing) val Null: TypeTag[scala.Null] = new PredefTypeTag[scala.Null] (NullTpe, _.TypeTag.Null) - def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): TypeTag[T] = + def apply[T](mirror1: scala.reflect.api.Mirror[self.type], tpec1: TypeCreator): TypeTag[T] = tpec1(mirror1) match { case ByteTpe => TypeTag.Byte.asInstanceOf[TypeTag[T]] case ShortTpe => TypeTag.Short.asInstanceOf[TypeTag[T]] @@ -295,15 +293,15 @@ trait TypeTags { self: Universe => } private class TypeTagImpl[T](mirror: Mirror, tpec: TypeCreator) extends WeakTypeTagImpl[T](mirror, tpec) with TypeTag[T] { - override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T] = { - val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]] + override def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # TypeTag[T] = { + val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]] otherMirror.universe.TypeTag[T](otherMirror1, tpec) } private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true) } private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator { - def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Type = { + def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = { copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe } } diff --git a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala index 9f102c5712..05f80c8a0c 100644 --- a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala +++ b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala @@ -47,6 +47,13 @@ trait AnnotationCheckers { * before. If the implementing class cannot do the adaptiong, it * should return the tree unchanged.*/ def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree + + /** Adapt the type of a return expression. The decision of an annotation checker + * whether the type should be adapted is based on the type of the expression + * which is returned, as well as the result type of the method (pt). + * By default, this method simply returns the passed `default` type. + */ + def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = default } // Syncnote: Annotation checkers inaccessible to reflection, so no sync in var necessary. @@ -118,4 +125,23 @@ trait AnnotationCheckers { annotationCheckers.foldLeft(tree)((tree, checker) => checker.adaptAnnotations(tree, mode, pt)) } + + /** Let a registered annotation checker adapt the type of a return expression. + * Annotation checkers that cannot do the adaptation should simply return + * the `default` argument. + * + * Note that the result is undefined if more than one annotation checker + * returns an adapted type which is not a subtype of `default`. + */ + def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = { + val adaptedTypes = annotationCheckers flatMap { checker => + val adapted = checker.adaptTypeOfReturn(tree, pt, default) + if (!(adapted <:< default)) List(adapted) + else List() + } + adaptedTypes match { + case fst :: _ => fst + case List() => default + } + } } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index dc0c002ea7..abf11020fa 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -520,7 +520,7 @@ trait Definitions extends api.StandardDefinitions { def ApiUniverseReify = if (ApiUniverseClass != NoSymbol) getMemberMethod(ApiUniverseClass, nme.reify) else NoSymbol lazy val JavaUniverseClass = getClassIfDefined("scala.reflect.api.JavaUniverse") // defined in scala-reflect.jar, so we need to be careful - lazy val MirrorOfClass = getClassIfDefined("scala.reflect.api.MirrorOf") // defined in scala-reflect.jar, so we need to be careful + lazy val MirrorClass = getClassIfDefined("scala.reflect.api.Mirror") // defined in scala-reflect.jar, so we need to be careful lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 4836db5db0..019cf7f908 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -19,7 +19,7 @@ trait Mirrors extends api.Mirrors { // if there are any symbols created by that mirror trait RootSymbol extends Symbol { def mirror: Mirror } - abstract class RootsBase(rootOwner: Symbol) extends MirrorOf[Mirrors.this.type] { thisMirror => + abstract class RootsBase(rootOwner: Symbol) extends scala.reflect.api.Mirror[Mirrors.this.type] { thisMirror => protected[scala] def rootLoader: LazyType diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 4c423e0bc2..cb8dc4b197 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -580,7 +580,7 @@ trait Printers extends api.Printers { self: SymbolTable => else print(sym.name) if (printIds) print("#", sym.id) if (printKinds) print("#", sym.abbreviatedKindString) - if (printMirrors) print("%M", footnotes.put[MirrorOf[_]](mirrorThatLoaded(sym))) + if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym))) case NoType => print("NoType") case NoPrefix => @@ -609,7 +609,7 @@ trait Printers extends api.Printers { self: SymbolTable => if (depth == 0 && !printingFootnotes) { printingFootnotes = true footnotes.print[Type](this) - footnotes.print[MirrorOf[_]](this) + footnotes.print[scala.reflect.api.Mirror[_]](this) printingFootnotes = false } } diff --git a/src/reflect/scala/reflect/internal/StdCreators.scala b/src/reflect/scala/reflect/internal/StdCreators.scala index eba583d4b5..5e5e4f9043 100644 --- a/src/reflect/scala/reflect/internal/StdCreators.scala +++ b/src/reflect/scala/reflect/internal/StdCreators.scala @@ -7,14 +7,14 @@ import scala.reflect.api.{Universe => ApiUniverse} trait StdCreators { self: SymbolTable => - case class FixedMirrorTreeCreator(mirror: MirrorOf[StdCreators.this.type], tree: Tree) extends TreeCreator { - def apply[U <: ApiUniverse with Singleton](m: MirrorOf[U]): U # Tree = + case class FixedMirrorTreeCreator(mirror: scala.reflect.api.Mirror[StdCreators.this.type], tree: Tree) extends TreeCreator { + def apply[U <: ApiUniverse with Singleton](m: scala.reflect.api.Mirror[U]): U # Tree = if (m eq mirror) tree.asInstanceOf[U # Tree] else throw new IllegalArgumentException(s"Expr defined in $mirror cannot be migrated to other mirrors.") } - case class FixedMirrorTypeCreator(mirror: MirrorOf[StdCreators.this.type], tpe: Type) extends TypeCreator { - def apply[U <: ApiUniverse with Singleton](m: MirrorOf[U]): U # Type = + case class FixedMirrorTypeCreator(mirror: scala.reflect.api.Mirror[StdCreators.this.type], tpe: Type) extends TypeCreator { + def apply[U <: ApiUniverse with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = if (m eq mirror) tpe.asInstanceOf[U # Type] else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.") } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 2cdfb05e77..eacbf6a0cc 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -346,6 +346,16 @@ trait StdNames { def isSingletonName(name: Name) = name endsWith SINGLETON_SUFFIX def isModuleName(name: Name) = name endsWith MODULE_SUFFIX_NAME + /** Is name a variable name? */ + def isVariableName(name: Name): Boolean = { + val first = name.startChar + ( ((first.isLower && first.isLetter) || first == '_') + && (name != nme.false_) + && (name != nme.true_) + && (name != nme.null_) + ) + } + def isDeprecatedIdentifierName(name: Name) = name.toTermName match { case nme.`then` | nme.`macro` => true case _ => false diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 77cbbd936b..db062d138f 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -247,7 +247,7 @@ abstract class TreeInfo { /** Is tree a variable pattern? */ def isVarPattern(pat: Tree): Boolean = pat match { - case x: Ident => !x.isBackquoted && isVariableName(x.name) + case x: Ident => !x.isBackquoted && nme.isVariableName(x.name) case _ => false } def isDeprecatedIdentifier(tree: Tree): Boolean = tree match { @@ -312,14 +312,6 @@ abstract class TreeInfo { /** Is name a left-associative operator? */ def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.endChar != ':') - private val reserved = Set[Name](nme.false_, nme.true_, nme.null_) - - /** Is name a variable name? */ - def isVariableName(name: Name): Boolean = { - val first = name.startChar - ((first.isLower && first.isLetter) || first == '_') && !reserved(name) - } - /** Is tree a `this` node which belongs to `enclClass`? */ def isSelf(tree: Tree, enclClass: Symbol): Boolean = tree match { case This(_) => tree.symbol == enclClass diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index f6af515fa3..2c036b3308 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -5748,6 +5748,13 @@ trait Types extends api.Types { self: SymbolTable => case _ => false } + def isNonRefinementClassType(tpe: Type) = tpe match { + case SingleType(_, sym) => sym.isModuleClass + case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass + case ErrorType => true + case _ => false + } + // @assume tp1.isHigherKinded || tp2.isHigherKinded def isHKSubType0(tp1: Type, tp2: Type, depth: Int): Boolean = ( tp1.typeSymbol == NothingClass diff --git a/src/reflect/scala/reflect/internal/package.scala b/src/reflect/scala/reflect/internal/package.scala deleted file mode 100644 index 63568f6a6b..0000000000 --- a/src/reflect/scala/reflect/internal/package.scala +++ /dev/null @@ -1,6 +0,0 @@ -package scala.reflect - -package object internal { - - type MirrorOf[U <: scala.reflect.api.Universe with Singleton] = scala.reflect.api.MirrorOf[U] -} diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala index 14b5d3003d..201b4dfe0a 100644 --- a/src/reflect/scala/reflect/internal/util/Collections.scala +++ b/src/reflect/scala/reflect/internal/util/Collections.scala @@ -175,6 +175,20 @@ trait Collections { } false } + final def exists3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + if (f(ys1.head, ys2.head, ys3.head)) + return true + + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + false + } final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { var ys1 = xs1 var ys2 = xs2 diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 1621fb84d4..151a64daff 100644 --- a/src/reflect/scala/reflect/internal/util/Position.scala +++ b/src/reflect/scala/reflect/internal/util/Position.scala @@ -8,7 +8,6 @@ package scala.reflect.internal.util import scala.reflect.ClassTag import scala.reflect.api.Attachments -import scala.reflect.api.PositionApi object Position { val tabInc = 8 @@ -36,7 +35,7 @@ object Position { } } -abstract class Position extends PositionApi { self => +abstract class Position extends scala.reflect.api.Position { self => type Pos = Position @@ -44,16 +43,6 @@ abstract class Position extends PositionApi { self => def withPos(newPos: Position): Attachments { type Pos = self.Pos } = newPos - /** Java file corresponding to the source file of this position. - */ - // necessary for conformance with scala.reflect.api.Position - def fileInfo: java.io.File = source.file.file - - /** Contents of the source file that contains this position. - */ - // necessary for conformance with scala.reflect.api.Position - def fileContent: Array[Char] = source.content - /** An optional value containing the source file referred to by this position, or * None if not defined. */ diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala index eff7f34b02..754335d50d 100644 --- a/src/reflect/scala/reflect/macros/Aliases.scala +++ b/src/reflect/scala/reflect/macros/Aliases.scala @@ -10,17 +10,22 @@ trait Aliases { type TermName = universe.TermName type TypeName = universe.TypeName type Tree = universe.Tree - // type Position = universe.Position + type Position = universe.Position type Scope = universe.Scope type Modifiers = universe.Modifiers + type Run = universe.Run + type CompilationUnit = universe.CompilationUnit type Expr[+T] = universe.Expr[T] val Expr = universe.Expr + def Expr[T: WeakTypeTag](tree: Tree): Expr[T] type WeakTypeTag[T] = universe.WeakTypeTag[T] type TypeTag[T] = universe.TypeTag[T] val WeakTypeTag = universe.WeakTypeTag val TypeTag = universe.TypeTag + def WeakTypeTag[T](tpe: Type): WeakTypeTag[T] + def TypeTag[T](tpe: Type): TypeTag[T] def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag def typeTag[T](implicit ttag: TypeTag[T]) = ttag def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe diff --git a/src/reflect/scala/reflect/macros/CapturedVariables.scala b/src/reflect/scala/reflect/macros/CapturedVariables.scala deleted file mode 100644 index 60ed6f5e7b..0000000000 --- a/src/reflect/scala/reflect/macros/CapturedVariables.scala +++ /dev/null @@ -1,21 +0,0 @@ -package scala.reflect -package macros - -trait CapturedVariables { - self: Context => - - import mirror._ - - /** Mark a variable as captured; i.e. force boxing in a *Ref type. - */ - def captureVariable(vble: Symbol): Unit - - /** Mark given identifier as a reference to a captured variable itself - * suppressing dereferencing with the `elem` field. - */ - def referenceCapturedVariable(vble: Symbol): Tree - - /** Convert type of a captured variable to *Ref type. - */ - def capturedVariableType(vble: Symbol): Type -}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/Context.scala b/src/reflect/scala/reflect/macros/Context.scala index 37c8f9057e..7a365ed37b 100644 --- a/src/reflect/scala/reflect/macros/Context.scala +++ b/src/reflect/scala/reflect/macros/Context.scala @@ -6,17 +6,13 @@ package macros // the full context should include all traits from scala.reflect.macros (and probably reside in scala-compiler.jar) trait Context extends Aliases - with CapturedVariables with Enclosures - with Infrastructure with Names with Reifiers with FrontEnds - with Settings + with Infrastructure with Typers with Parsers - with Exprs - with TypeTags with Evals with ExprUtils { @@ -24,7 +20,7 @@ trait Context extends Aliases val universe: Universe /** The mirror of the compile-time universe */ - val mirror: MirrorOf[universe.type] + val mirror: universe.Mirror /** The type of the prefix tree from which the macro is selected */ type PrefixType diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala index a07ff85a08..218cf6ebb3 100644 --- a/src/reflect/scala/reflect/macros/Enclosures.scala +++ b/src/reflect/scala/reflect/macros/Enclosures.scala @@ -47,4 +47,8 @@ trait Enclosures { /** Compilation unit that contains this macro application. */ val enclosingUnit: CompilationUnit + + /** Compilation run that contains this macro application. + */ + val enclosingRun: Run }
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/Exprs.scala b/src/reflect/scala/reflect/macros/Exprs.scala deleted file mode 100644 index 280d5508c8..0000000000 --- a/src/reflect/scala/reflect/macros/Exprs.scala +++ /dev/null @@ -1,8 +0,0 @@ -package scala.reflect -package macros - -trait Exprs { - self: Context => - - def Expr[T: WeakTypeTag](tree: Tree): Expr[T] -} diff --git a/src/reflect/scala/reflect/macros/FrontEnds.scala b/src/reflect/scala/reflect/macros/FrontEnds.scala index d15db0725f..e6b67cfc87 100644 --- a/src/reflect/scala/reflect/macros/FrontEnds.scala +++ b/src/reflect/scala/reflect/macros/FrontEnds.scala @@ -1,18 +1,9 @@ package scala.reflect package macros -trait FrontEnds extends scala.reflect.api.FrontEnds { +trait FrontEnds { self: Context => - import mirror._ - - type Position = universe.Position - - /** Exposes means to control the compiler UI */ - def frontEnd: FrontEnd - def setFrontEnd(frontEnd: FrontEnd): this.type - def withFrontEnd[T](frontEnd: FrontEnd)(op: => T): T - /** For sending a message which should not be labeled as a warning/error, * but also shouldn't require -verbose to be visible. * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''. @@ -36,7 +27,4 @@ trait FrontEnds extends scala.reflect.api.FrontEnds { * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''. */ def abort(pos: Position, msg: String): Nothing - - /** Drops into interactive mode if supported by the compiler UI */ - def interactive(): Unit }
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala index 80153ff257..a1ef1c87a3 100644 --- a/src/reflect/scala/reflect/macros/Infrastructure.scala +++ b/src/reflect/scala/reflect/macros/Infrastructure.scala @@ -4,77 +4,16 @@ package macros trait Infrastructure { self: Context => - /** Determines whether the compiler expanding a macro targets JVM. + /** Exposes macro-specific settings as a list of strings. + * These settings are passed to the compiler via the "-Xmacro-settings:setting1,setting2...,settingN" command-line option. */ - val forJVM: Boolean + def settings: List[String] - /** Determines whether the compiler expanding a macro targets CLR. + /** Exposes current compiler settings as a list of options. + * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options. */ - val forMSIL: Boolean + def compilerSettings: List[String] - /** Determines whether the compiler expanding a macro is a presentation compiler. - */ - val forInteractive: Boolean - - /** Determines whether the compiler expanding a macro is a Scaladoc compiler. - */ - val forScaladoc: Boolean - - /** Exposes current compilation run. - */ - val currentRun: Run - - /** Exposes library classpath. - */ - val libraryClassPath: List[java.net.URL] - - /** Exposes a classloader that corresponds to the library classpath. - * - * With this classloader you can perform on-the-fly evaluation of macro arguments. - * For example, consider this code snippet: - * - * def staticEval[T](x: T) = macro staticEval[T] - * - * def staticEval[T](c: Context)(x: c.Expr[T]) = { - * import scala.reflect.runtime.{universe => ru} - * val mirror = ru.runtimeMirror(c.libraryClassLoader) - * import scala.tools.reflect.ToolBox - * val toolBox = mirror.mkToolBox() - * val importer = ru.mkImporter(c.universe).asInstanceOf[ru.Importer { val from: c.universe.type }] - * val tree = c.resetAllAttrs(x.tree.duplicate) - * val imported = importer.importTree(tree) - * val valueOfX = toolBox.eval(imported).asInstanceOf[T] - * ... - * } - */ - def libraryClassLoader: ClassLoader - - /** As seen by macro API, compilation run is an opaque type that can be deconstructed into: - * 1) Current compilation unit - * 2) List of all compilation units that comprise the run - */ - type Run - - val Run: RunExtractor - - abstract class RunExtractor { - def unapply(run: Run): Option[(CompilationUnit, List[CompilationUnit])] - } - - /** As seen by macro API, compilation unit is an opaque type that can be deconstructed into: - * 1) File that corresponds to the unit (if not applicable, null) - * 2) Content of the file (if not applicable, empty array) - * 3) Body, i.e. the AST that represents the compilation unit - */ - type CompilationUnit - - val CompilationUnit: CompilationUnitExtractor - - abstract class CompilationUnitExtractor { - def unapply(compilationUnit: CompilationUnit): Option[(java.io.File, Array[Char], Tree)] - } - - /** Returns a macro definition which triggered this macro expansion. - */ - val currentMacro: Symbol -} + /** Exposes current classpath. */ + def classPath: List[java.net.URL] +}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala index 1742d07b60..c2d4d8a3ab 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -5,14 +5,10 @@ trait Parsers { self: Context => /** .. */ - // todo. distinguish between `parse` and `parse` + // todo. distinguish between parsing an expression and parsing arbitrary code + // for example, parsing in expression mode will fail on packages def parse(code: String): Tree +} - /** Represents an error during parsing - */ - type ParseError <: Throwable - val ParseError: ParseErrorExtractor - abstract class ParseErrorExtractor { - def unapply(error: ParseError): Option[(Position, String)] - } -}
\ No newline at end of file +// should be path-dependent, otherwise exception handling becomes a mess +case class ParseError(val pos: scala.reflect.api.Position, val msg: String) extends Throwable(msg) diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala index c2a6c5be05..ed31663c68 100644 --- a/src/reflect/scala/reflect/macros/Reifiers.scala +++ b/src/reflect/scala/reflect/macros/Reifiers.scala @@ -1,21 +1,14 @@ package scala.reflect package macros -import scala.reflect.api.PositionApi - trait Reifiers { self: Context => - /** Reification prefix that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''. - * Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a full-fledged tree that can be inspected at runtime. - */ - val runtimeUniverse: Tree - /** Given a tree, generate a tree that when compiled and executed produces the original tree. * For more information and examples see the documentation for ``Universe.reify''. * * The produced tree will be bound to the specified ``universe'' and ``mirror''. - * Possible values for ``universe'' include ``runtimeUniverse''. + * Possible values for ``universe'' include ``universe.treeBuild.mkRuntimeUniverseRef''. * Possible values for ``mirror'' include ``EmptyTree'' (in that case the reifier will automatically pick an appropriate mirror). * * This function is deeply connected to ``Universe.reify'', a macro that reifies arbitrary expressions into runtime trees. @@ -83,6 +76,6 @@ trait Reifiers { // made these guys non path-dependent, otherwise exception handling quickly becomes a mess -case class ReificationError(val pos: PositionApi, val msg: String) extends Throwable(msg) +case class ReificationError(val pos: scala.reflect.api.Position, val msg: String) extends Throwable(msg) -case class UnexpectedReificationError(val pos: PositionApi, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause) +case class UnexpectedReificationError(val pos: scala.reflect.api.Position, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause) diff --git a/src/reflect/scala/reflect/macros/Settings.scala b/src/reflect/scala/reflect/macros/Settings.scala deleted file mode 100644 index a2cdb4c8e1..0000000000 --- a/src/reflect/scala/reflect/macros/Settings.scala +++ /dev/null @@ -1,36 +0,0 @@ -package scala.reflect -package macros - -trait Settings { - self: Context => - - /** Exposes macro-specific settings as a list of strings. - * These settings are passed to the compiler via the "-Xmacro-settings:setting1,setting2...,settingN" command-line option. - */ - def settings: List[String] - - /** Exposes current compiler settings as a list of options. - * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options. - */ - def compilerSettings: List[String] - - /** Updates current compiler settings with an option string. - * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options. - */ - def setCompilerSettings(options: String): this.type - - /** Updates current compiler settings with a list of options. - * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options. - */ - def setCompilerSettings(options: List[String]): this.type - - /** Temporarily sets compiler settings to a given option string and executes a given closure. - * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options. - */ - def withCompilerSettings[T](options: String)(op: => T): T - - /** Temporarily sets compiler settings to a given list of options and executes a given closure. - * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options. - */ - def withCompilerSettings[T](options: List[String])(op: => T): T -}
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/TreeBuilder.scala b/src/reflect/scala/reflect/macros/TreeBuilder.scala index ca29194859..5f18ab9ee8 100644 --- a/src/reflect/scala/reflect/macros/TreeBuilder.scala +++ b/src/reflect/scala/reflect/macros/TreeBuilder.scala @@ -53,4 +53,7 @@ abstract class TreeBuilder { def mkMethodCall(receiver: Tree, method: Symbol, targs: List[Type], args: List[Tree]): Tree def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree def mkNullaryCall(method: Symbol, targs: List[Type]): Tree + + /** A tree that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''. */ + def mkRuntimeUniverseRef: Tree } diff --git a/src/reflect/scala/reflect/macros/TypeTags.scala b/src/reflect/scala/reflect/macros/TypeTags.scala deleted file mode 100644 index 2f15e37f6a..0000000000 --- a/src/reflect/scala/reflect/macros/TypeTags.scala +++ /dev/null @@ -1,9 +0,0 @@ -package scala.reflect -package macros - -trait TypeTags { - self: Context => - - def WeakTypeTag[T](tpe: Type): WeakTypeTag[T] - def TypeTag[T](tpe: Type): TypeTag[T] -} diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index f84c11ee63..97d0a8d98a 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -109,4 +109,52 @@ abstract class Universe extends scala.reflect.api.Universe { trait IdentContextApi extends IdentApi { this: Ident => def isBackquoted: Boolean } + + /** Mark a variable as captured; i.e. force boxing in a *Ref type. + */ + def captureVariable(vble: Symbol): Unit + + /** Mark given identifier as a reference to a captured variable itself + * suppressing dereferencing with the `elem` field. + */ + def referenceCapturedVariable(vble: Symbol): Tree + + /** Convert type of a captured variable to *Ref type. + */ + def capturedVariableType(vble: Symbol): Type + + type Run <: RunContextApi + + /** Compilation run uniquely identifies current invocation of the compiler + * (e.g. can be used to implement per-run caches for macros) and provides access to units of work + * of the invocation (currently processed unit of work and the list of all units). + */ + trait RunContextApi { + /** Currently processed unit of work (a real or a virtual file). */ + def currentUnit: CompilationUnit + + /** All units of work comprising this compilation run. */ + def units: Iterator[CompilationUnit] + } + + type CompilationUnit <: CompilationUnitContextApi + + /** Compilation unit describes a unit of work of the compilation run. + * It provides such information as file name, textual representation of the unit and the underlying AST. + */ + trait CompilationUnitContextApi { + /** Source file corresponding to this compilation unit. + * + * Exposes information about the file as a part of a real or virtual file system + * along with the contents of that file. + * + * The return type is [[scala.reflect.io.AbstractFile]], which belongs to an experimental part of Scala reflection. + * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined + * and exposed as a part of scala.reflect.api. + */ + def source: scala.reflect.internal.util.SourceFile + + /** The AST that corresponds to this compilation unit. */ + def body: Tree + } }
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala deleted file mode 100644 index df93785d40..0000000000 --- a/src/reflect/scala/reflect/macros/package.scala +++ /dev/null @@ -1,6 +0,0 @@ -package scala.reflect - -package object macros { - - type MirrorOf[U <: scala.reflect.api.Universe with Singleton] = scala.reflect.api.MirrorOf[U] -} diff --git a/test/files/continuations-neg/t5314-missing-result-type.check b/test/files/continuations-neg/t5314-missing-result-type.check new file mode 100644 index 0000000000..341e580cf3 --- /dev/null +++ b/test/files/continuations-neg/t5314-missing-result-type.check @@ -0,0 +1,4 @@ +t5314-missing-result-type.scala:6: error: method bar has return statement; needs result type + def bar(x:Int) = return foo(x) + ^ +one error found diff --git a/test/files/continuations-neg/t5314-missing-result-type.scala b/test/files/continuations-neg/t5314-missing-result-type.scala new file mode 100644 index 0000000000..d7c5043a86 --- /dev/null +++ b/test/files/continuations-neg/t5314-missing-result-type.scala @@ -0,0 +1,13 @@ +import scala.util.continuations._ + +object Test extends App { + def foo(x:Int): Int @cps[Int] = x + + def bar(x:Int) = return foo(x) + + reset { + val res = bar(8) + println(res) + res + } +} diff --git a/test/files/continuations-neg/t5314-npe.check b/test/files/continuations-neg/t5314-npe.check new file mode 100644 index 0000000000..b5f024aa89 --- /dev/null +++ b/test/files/continuations-neg/t5314-npe.check @@ -0,0 +1,4 @@ +t5314-npe.scala:2: error: method bar has return statement; needs result type + def bar(x:Int) = { return x; x } // NPE + ^ +one error found diff --git a/test/files/continuations-neg/t5314-npe.scala b/test/files/continuations-neg/t5314-npe.scala new file mode 100644 index 0000000000..2b5966e07c --- /dev/null +++ b/test/files/continuations-neg/t5314-npe.scala @@ -0,0 +1,3 @@ +object Test extends App { + def bar(x:Int) = { return x; x } // NPE +} diff --git a/test/files/continuations-neg/t5314-return-reset.check b/test/files/continuations-neg/t5314-return-reset.check new file mode 100644 index 0000000000..4c817ae14d --- /dev/null +++ b/test/files/continuations-neg/t5314-return-reset.check @@ -0,0 +1,4 @@ +t5314-return-reset.scala:14: error: return expression not allowed, since method calls CPS method + if (rnd.nextInt(100) > 50) return 5 // not allowed, since method is calling `reset` + ^ +one error found diff --git a/test/files/continuations-neg/t5314-return-reset.scala b/test/files/continuations-neg/t5314-return-reset.scala new file mode 100644 index 0000000000..df9d58e4cb --- /dev/null +++ b/test/files/continuations-neg/t5314-return-reset.scala @@ -0,0 +1,21 @@ +import scala.util.continuations._ +import scala.util.Random + +object Test extends App { + val rnd = new Random + + def foo(x: Int): Int @cps[Int] = shift { k => k(x) } + + def bar(x: Int): Int @cps[Int] = return foo(x) + + def caller(): Int = { + val v: Int = reset { + val res: Int = bar(8) + if (rnd.nextInt(100) > 50) return 5 // not allowed, since method is calling `reset` + 42 + } + v + } + + caller() +} diff --git a/test/files/continuations-neg/t5314-type-error.check b/test/files/continuations-neg/t5314-type-error.check new file mode 100644 index 0000000000..1f4e46a7f2 --- /dev/null +++ b/test/files/continuations-neg/t5314-type-error.check @@ -0,0 +1,6 @@ +t5314-type-error.scala:7: error: type mismatch; + found : Int @util.continuations.cps[Int] + required: Int @util.continuations.cps[String] + def bar(x:Int): Int @cps[String] = return foo(x) + ^ +one error found diff --git a/test/files/continuations-neg/t5314-type-error.scala b/test/files/continuations-neg/t5314-type-error.scala new file mode 100644 index 0000000000..e36ce6c203 --- /dev/null +++ b/test/files/continuations-neg/t5314-type-error.scala @@ -0,0 +1,17 @@ +import scala.util.continuations._ + +object Test extends App { + def foo(x:Int): Int @cps[Int] = shift { k => k(x) } + + // should be a type error + def bar(x:Int): Int @cps[String] = return foo(x) + + def caller(): Unit = { + val v: String = reset { + val res: Int = bar(8) + "hello" + } + } + + caller() +} diff --git a/test/files/continuations-run/t5314-2.check b/test/files/continuations-run/t5314-2.check new file mode 100644 index 0000000000..35b3c93780 --- /dev/null +++ b/test/files/continuations-run/t5314-2.check @@ -0,0 +1,5 @@ +8 +hi +8 +from try +8 diff --git a/test/files/continuations-run/t5314-2.scala b/test/files/continuations-run/t5314-2.scala new file mode 100644 index 0000000000..8a896dec2c --- /dev/null +++ b/test/files/continuations-run/t5314-2.scala @@ -0,0 +1,44 @@ +import scala.util.continuations._ + +class ReturnRepro { + def s1: Int @cps[Any] = shift { k => k(5) } + def caller = reset { println(p(3)) } + def caller2 = reset { println(p2(3)) } + def caller3 = reset { println(p3(3)) } + + def p(i: Int): Int @cps[Any] = { + val v= s1 + 3 + return v + } + + def p2(i: Int): Int @cps[Any] = { + val v = s1 + 3 + if (v > 0) { + println("hi") + return v + } else { + println("hi") + return 8 + } + } + + def p3(i: Int): Int @cps[Any] = { + val v = s1 + 3 + try { + println("from try") + return v + } catch { + case e: Exception => + println("from catch") + return 7 + } + } + +} + +object Test extends App { + val repro = new ReturnRepro + repro.caller + repro.caller2 + repro.caller3 +} diff --git a/test/files/continuations-run/t5314-3.check b/test/files/continuations-run/t5314-3.check new file mode 100644 index 0000000000..71489f097c --- /dev/null +++ b/test/files/continuations-run/t5314-3.check @@ -0,0 +1,4 @@ +enter return expr +8 +hi +8 diff --git a/test/files/continuations-run/t5314-3.scala b/test/files/continuations-run/t5314-3.scala new file mode 100644 index 0000000000..62c547f5a2 --- /dev/null +++ b/test/files/continuations-run/t5314-3.scala @@ -0,0 +1,27 @@ +import scala.util.continuations._ + +class ReturnRepro { + def s1: Int @cpsParam[Any, Unit] = shift { k => k(5) } + def caller = reset { println(p(3)) } + def caller2 = reset { println(p2(3)) } + + def p(i: Int): Int @cpsParam[Unit, Any] = { + val v= s1 + 3 + return { println("enter return expr"); v } + } + + def p2(i: Int): Int @cpsParam[Unit, Any] = { + val v = s1 + 3 + if (v > 0) { + return { println("hi"); v } + } else { + return { println("hi"); 8 } + } + } +} + +object Test extends App { + val repro = new ReturnRepro + repro.caller + repro.caller2 +} diff --git a/test/files/continuations-run/t5314-with-if.check b/test/files/continuations-run/t5314-with-if.check new file mode 100644 index 0000000000..7f8f011eb7 --- /dev/null +++ b/test/files/continuations-run/t5314-with-if.check @@ -0,0 +1 @@ +7 diff --git a/test/files/continuations-run/t5314-with-if.scala b/test/files/continuations-run/t5314-with-if.scala new file mode 100644 index 0000000000..5840199a3c --- /dev/null +++ b/test/files/continuations-run/t5314-with-if.scala @@ -0,0 +1,17 @@ +import scala.util.continuations._ + +object Test extends App { + + def foo(x:Int): Int @cps[Int] = 7 + + def bar(x:Int): Int @cps[Int] = { + val v = foo(x) + if (v > 0) + return v + else + return 10 + } + + println(reset { bar(10) }) + +} diff --git a/test/files/continuations-run/t5314.check b/test/files/continuations-run/t5314.check new file mode 100644 index 0000000000..4b35d8e6d0 --- /dev/null +++ b/test/files/continuations-run/t5314.check @@ -0,0 +1,8 @@ +7 +7 +7 +8 +8 +hi +8 +8 diff --git a/test/files/continuations-run/t5314.scala b/test/files/continuations-run/t5314.scala new file mode 100644 index 0000000000..d611016ce4 --- /dev/null +++ b/test/files/continuations-run/t5314.scala @@ -0,0 +1,52 @@ +import scala.util.continuations._ + +class ReturnRepro { + def s1: Int @cpsParam[Any, Unit] = shift { k => k(5) } + def caller = reset { println(p(3)) } + def caller2 = reset { println(p2(3)) } + + def p(i: Int): Int @cpsParam[Unit, Any] = { + val v= s1 + 3 + return v + } + + def p2(i: Int): Int @cpsParam[Unit, Any] = { + val v = s1 + 3 + if (v > 0) { + println("hi") + return v + } else { + println("hi") + return 8 + } + } +} + +object Test extends App { + def foo(x:Int): Int @cps[Int] = shift { k => k(x) } + + def bar(x:Int): Int @cps[Int] = return foo(x) + + def nocps(x: Int): Int = { return x; x } + + def foo2(x:Int): Int @cps[Int] = 7 + def bar2(x:Int): Int @cps[Int] = { foo2(x); return 7 } + def bar3(x:Int): Int @cps[Int] = { foo2(x); if (x == 7) return 7 else return foo2(x) } + def bar4(x:Int): Int @cps[Int] = { foo2(x); if (x == 7) return 7 else foo2(x) } + def bar5(x:Int): Int @cps[Int] = { foo2(x); if (x == 7) return 7 else 8 } + println(reset { bar2(10) }) + println(reset { bar3(10) }) + println(reset { bar4(10) }) + println(reset { bar5(10) }) + + /* original test case */ + val repro = new ReturnRepro + repro.caller + repro.caller2 + + reset { + val res = bar(8) + println(res) + res + } +} diff --git a/test/files/neg/patmat-type-check.check b/test/files/neg/patmat-type-check.check index e045841ce1..721217c314 100644 --- a/test/files/neg/patmat-type-check.check +++ b/test/files/neg/patmat-type-check.check @@ -1,3 +1,12 @@ +patmat-type-check.scala:11: warning: fruitless type test: a value of type Test.Bop4[T] cannot also be a Seq[A] + def s3[T](x: Bop4[T]) = x match { case Seq('b', 'o', 'b') => true } + ^ +patmat-type-check.scala:15: warning: fruitless type test: a value of type Test.Bop5[_$1,T1,T2] cannot also be a Seq[A] + def s4[T1, T2](x: Bop5[_, T1, T2]) = x match { case Seq('b', 'o', 'b') => true } + ^ +patmat-type-check.scala:19: warning: fruitless type test: a value of type Test.Bop3[T] cannot also be a Seq[A] + def f4[T](x: Bop3[T]) = x match { case Seq('b', 'o', 'b') => true } + ^ patmat-type-check.scala:22: error: scrutinee is incompatible with pattern type; found : Seq[A] required: String @@ -18,4 +27,5 @@ patmat-type-check.scala:30: error: scrutinee is incompatible with pattern type; required: Test.Bop3[Char] def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail ^ +three warnings found four errors found diff --git a/test/files/neg/t1872.check b/test/files/neg/t1872.check index ef84ef79e0..c5dc2a8080 100644 --- a/test/files/neg/t1872.check +++ b/test/files/neg/t1872.check @@ -1,4 +1,8 @@ +t1872.scala:3: warning: fruitless type test: a value of type Int cannot also be a scala.util.Random + def f(x: Int) = x.isInstanceOf[util.Random] + ^ t1872.scala:3: error: isInstanceOf cannot test if value types are references. def f(x: Int) = x.isInstanceOf[util.Random] ^ +one warning found one error found diff --git a/test/files/neg/t4302.check b/test/files/neg/t4302.check index 1a59b79a3b..ea48729276 100644 --- a/test/files/neg/t4302.check +++ b/test/files/neg/t4302.check @@ -1,4 +1,4 @@ -t4302.scala:2: warning: abstract type T in type T is unchecked since it is eliminated by erasure +t4302.scala:2: warning: abstract type T is unchecked since it is eliminated by erasure def hasMatch[T](x: AnyRef) = x.isInstanceOf[T] ^ error: No warnings can be incurred under -Xfatal-warnings. diff --git a/test/files/neg/t5762.check b/test/files/neg/t5762.check new file mode 100644 index 0000000000..2a2f12144a --- /dev/null +++ b/test/files/neg/t5762.check @@ -0,0 +1,15 @@ +t5762.scala:6: warning: non-variable type argument Int in type pattern D[Int] is unchecked since it is eliminated by erasure + case _: D[Int] if bippy => 1 + ^ +t5762.scala:7: warning: non-variable type argument String in type pattern D[String] is unchecked since it is eliminated by erasure + case _: D[String] => 2 + ^ +t5762.scala:20: warning: non-variable type argument D[Int] in type pattern D[D[Int]] is unchecked since it is eliminated by erasure + case _: D[D[Int]] if bippy => 1 + ^ +t5762.scala:21: warning: non-variable type argument D[String] in type pattern D[D[String]] is unchecked since it is eliminated by erasure + case _: D[D[String]] => 2 + ^ +error: No warnings can be incurred under -Xfatal-warnings. +four warnings found +one error found diff --git a/test/files/neg/t5762.flags b/test/files/neg/t5762.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t5762.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t5762.scala b/test/files/neg/t5762.scala new file mode 100644 index 0000000000..fb73552b12 --- /dev/null +++ b/test/files/neg/t5762.scala @@ -0,0 +1,24 @@ +class D[-A] + +object Test { + var bippy: Boolean = true + def f1(x: D[Int with String]) = x match { + case _: D[Int] if bippy => 1 + case _: D[String] => 2 + } + // Correctly warns: + // + // a.scala:5: warning: non variable type-argument Int in type pattern D[Int] is unchecked since it is eliminated by erasure + // case _: D[Int] => 1 + // ^ + // a.scala:6: warning: non variable type-argument String in type pattern D[String] is unchecked since it is eliminated by erasure + // case _: D[String] => 2 + // ^ + // two warnings found + + def f2(x: D[D[Int] with D[String]]) = x match { + case _: D[D[Int]] if bippy => 1 + case _: D[D[String]] => 2 + } + // No warnings! +} diff --git a/test/files/neg/unchecked-abstract.check b/test/files/neg/unchecked-abstract.check new file mode 100644 index 0000000000..762859574b --- /dev/null +++ b/test/files/neg/unchecked-abstract.check @@ -0,0 +1,27 @@ +unchecked-abstract.scala:16: warning: abstract type H in type Con[M.this.H] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Con[H]]) + ^ +unchecked-abstract.scala:21: warning: abstract type H in type Con[M.this.H] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Con[H]]) + ^ +unchecked-abstract.scala:27: warning: abstract type T in type Inv[M.this.T] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Inv[T]]) + ^ +unchecked-abstract.scala:28: warning: abstract type L in type Inv[M.this.L] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Inv[L]]) + ^ +unchecked-abstract.scala:31: warning: abstract type H in type Inv[M.this.H] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Inv[H]]) + ^ +unchecked-abstract.scala:33: warning: abstract type L in type Inv[M.this.L] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Inv[L]]) + ^ +unchecked-abstract.scala:36: warning: abstract type H in type Inv[M.this.H] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Inv[H]]) + ^ +unchecked-abstract.scala:37: warning: abstract type T in type Inv[M.this.T] is unchecked since it is eliminated by erasure + /* warn */ println(x.isInstanceOf[Inv[T]]) + ^ +error: No warnings can be incurred under -Xfatal-warnings. +8 warnings found +one error found diff --git a/test/files/neg/unchecked-abstract.flags b/test/files/neg/unchecked-abstract.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/unchecked-abstract.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/unchecked-abstract.scala b/test/files/neg/unchecked-abstract.scala new file mode 100644 index 0000000000..5b915755f4 --- /dev/null +++ b/test/files/neg/unchecked-abstract.scala @@ -0,0 +1,93 @@ +trait Con[-X] +trait Inv[X] +trait Cov[+X] + +abstract class M { + type H + type L <: H + type T >: L <: H + + def h1(x: Con[H]) = { + /* nowarn */ println(x.isInstanceOf[Con[H]]) + /* nowarn */ println(x.isInstanceOf[Con[T]]) + /* nowarn */ println(x.isInstanceOf[Con[L]]) + } + def h2(x: Con[T]) = { + /* warn */ println(x.isInstanceOf[Con[H]]) + /* nowarn */ println(x.isInstanceOf[Con[T]]) + /* nowarn */ println(x.isInstanceOf[Con[L]]) + } + def h3(x: Con[L]) = { + /* warn */ println(x.isInstanceOf[Con[H]]) + /* warn */ println(x.isInstanceOf[Con[T]]) + /* nowarn */ println(x.isInstanceOf[Con[L]]) + } + def h4(x: Inv[H]) = { + /* nowarn */ println(x.isInstanceOf[Inv[H]]) + /* warn */ println(x.isInstanceOf[Inv[T]]) + /* warn */ println(x.isInstanceOf[Inv[L]]) + } + def h5(x: Inv[T]) = { + /* warn */ println(x.isInstanceOf[Inv[H]]) + /* nowarn */ println(x.isInstanceOf[Inv[T]]) + /* warn */ println(x.isInstanceOf[Inv[L]]) + } + def h6(x: Inv[L]) = { + /* warn */ println(x.isInstanceOf[Inv[H]]) + /* warn */ println(x.isInstanceOf[Inv[T]]) + /* nowarn */ println(x.isInstanceOf[Inv[L]]) + } + def h7(x: Cov[H]) = { + /* nowarn */ println(x.isInstanceOf[Cov[H]]) + /* warn */ println(x.isInstanceOf[Cov[T]]) + /* warn */ println(x.isInstanceOf[Cov[L]]) + } + def h8(x: Cov[T]) = { + /* nowarn */ println(x.isInstanceOf[Cov[H]]) + /* nowarn */ println(x.isInstanceOf[Cov[T]]) + /* warn */ println(x.isInstanceOf[Cov[L]]) + } + def h9(x: Cov[L]) = { + /* nowarn */ println(x.isInstanceOf[Cov[H]]) + /* nowarn */ println(x.isInstanceOf[Cov[T]]) + /* nowarn */ println(x.isInstanceOf[Cov[L]]) + } +} + +object Test extends M { + type H = Any + type T = Int + type L = Nothing + + val conh = new Con[H] { } + val cont = new Con[T] { } + val conl = new Con[L] { } + + val invh = new Inv[H] { } + val invt = new Inv[T] { } + val invl = new Inv[L] { } + + val covh = new Cov[H] { } + val covt = new Cov[T] { } + val covl = new Cov[L] { } + + def main(args: Array[String]): Unit = { + h1(conh) + h2(conh) + h2(cont) + h3(conh) + h3(cont) + h3(conl) + + h4(invh) + h5(invt) + h6(invl) + + h7(covh) + h7(covt) + h7(covl) + h8(covt) + h8(covl) + h9(covl) + } +} diff --git a/test/files/neg/unchecked-impossible.check b/test/files/neg/unchecked-impossible.check new file mode 100644 index 0000000000..75fc390fa8 --- /dev/null +++ b/test/files/neg/unchecked-impossible.check @@ -0,0 +1,6 @@ +unchecked-impossible.scala:5: warning: fruitless type test: a value of type T2[Int,Int] cannot also be a Seq[A] + case Seq(x) => + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/unchecked-impossible.flags b/test/files/neg/unchecked-impossible.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/unchecked-impossible.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/unchecked-impossible.scala b/test/files/neg/unchecked-impossible.scala new file mode 100644 index 0000000000..985a2d0b08 --- /dev/null +++ b/test/files/neg/unchecked-impossible.scala @@ -0,0 +1,16 @@ +final case class T2[+A, +B](a: A, b: B) + +class A { + def f1 = T2(1, 2) match { + case Seq(x) => + case _ => + } + def f2 = T2(1, 2) match { + case _: T2[Int, Int] => /* nowarn */ + case _ => + } + def f3 = T2(1, 2) match { + case _: T2[_, Int] => /* nowarn */ + case _ => + } +} diff --git a/test/files/neg/unchecked-knowable.check b/test/files/neg/unchecked-knowable.check new file mode 100644 index 0000000000..28e2d67920 --- /dev/null +++ b/test/files/neg/unchecked-knowable.check @@ -0,0 +1,6 @@ +unchecked-knowable.scala:17: warning: fruitless type test: a value of type Bippy cannot also be a A1 + /* warn */ (new Bippy).isInstanceOf[A1] + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/unchecked-knowable.flags b/test/files/neg/unchecked-knowable.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/unchecked-knowable.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/unchecked-knowable.scala b/test/files/neg/unchecked-knowable.scala new file mode 100644 index 0000000000..667b47f504 --- /dev/null +++ b/test/files/neg/unchecked-knowable.scala @@ -0,0 +1,20 @@ +/** Knowable - only final leaves */ +sealed abstract class A1 +sealed abstract class A2 extends A1 +final class A3 extends A1 +final class A4 extends A2 + +/** Unknowable */ +sealed abstract class B1 +sealed abstract class B2 extends B1 +final class B3 extends B1 +trait B4 extends B2 + +class Bippy +trait Dingus + +class A { + /* warn */ (new Bippy).isInstanceOf[A1] + /* nowarn */ (new Bippy).isInstanceOf[B1] + /* nowarn */ ((new Bippy): Any).isInstanceOf[A1] +} diff --git a/test/files/neg/unchecked-refinement.check b/test/files/neg/unchecked-refinement.check new file mode 100644 index 0000000000..e85a51f44d --- /dev/null +++ b/test/files/neg/unchecked-refinement.check @@ -0,0 +1,15 @@ +unchecked-refinement.scala:17: warning: abstract type U in type pattern Foo[U,U,V] is unchecked since it is eliminated by erasure + /* warn */ case _: Foo[U, U, V] if b => () + ^ +unchecked-refinement.scala:19: warning: non-variable type argument Any in type pattern Foo[Any,U,V] is unchecked since it is eliminated by erasure + /* warn */ case _: Foo[Any, U, V] if b => () + ^ +unchecked-refinement.scala:23: warning: a pattern match on a refinement type is unchecked + /* nowarn - todo */ case x: AnyRef { def bippy: Int } if b => x.bippy // this could/should do an instance check and not warn + ^ +unchecked-refinement.scala:24: warning: a pattern match on a refinement type is unchecked + /* nowarn - todo */ case x: AnyRef { def size: Int } if b => x.size // this could/should do a static conformance test and not warn + ^ +error: No warnings can be incurred under -Xfatal-warnings. +four warnings found +one error found diff --git a/test/files/neg/unchecked-refinement.flags b/test/files/neg/unchecked-refinement.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/unchecked-refinement.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/unchecked-refinement.scala b/test/files/neg/unchecked-refinement.scala new file mode 100644 index 0000000000..79ed7f13c1 --- /dev/null +++ b/test/files/neg/unchecked-refinement.scala @@ -0,0 +1,27 @@ +// a.scala +// Thu Sep 27 09:42:16 PDT 2012 + +trait Bar[-T1, T2, +T3] { } +trait Foo[-T1, T2, +T3] extends Bar[T1, T2, T3] + +class A { + var b = true + + def f1(x: Foo[Int, Int, Int]) = x match { + /* nowarn */ case _: Foo[Nothing, Int, Any] => true + } + def f2[T, U, V](x: Foo[T, U, V]) = x match { + /* nowarn */ case _: Foo[Nothing, U, Any] => true + } + def f3[T, U, V](x: Foo[T, U, V]) = x match { + /* warn */ case _: Foo[U, U, V] if b => () + /* nowarn */ case _: Foo[Nothing, U, V] if b => () + /* warn */ case _: Foo[Any, U, V] if b => () + } + + def f4(xs: List[Int]) = xs match { + /* nowarn - todo */ case x: AnyRef { def bippy: Int } if b => x.bippy // this could/should do an instance check and not warn + /* nowarn - todo */ case x: AnyRef { def size: Int } if b => x.size // this could/should do a static conformance test and not warn + /* nowarn */ case x: ((AnyRef { def size: Int }) @unchecked) if b => x.size + } +} diff --git a/test/files/neg/unchecked.check b/test/files/neg/unchecked.check index 19b8c908da..570f02f219 100644 --- a/test/files/neg/unchecked.check +++ b/test/files/neg/unchecked.check @@ -2,7 +2,7 @@ unchecked.scala:18: warning: non-variable type argument String in type pattern I case xs: Iterable[String] => xs.head // unchecked ^ unchecked.scala:22: warning: non-variable type argument Any in type pattern Set[Any] is unchecked since it is eliminated by erasure - case xs: Set[Any] => xs.head // unchecked + case xs: Set[Any] => xs.head // unchecked ^ unchecked.scala:26: warning: non-variable type argument Any in type pattern Map[Any,Any] is unchecked since it is eliminated by erasure case xs: Map[Any, Any] => xs.head // unchecked diff --git a/test/files/neg/unchecked.scala b/test/files/neg/unchecked.scala index b50cdf9d7a..e491b253ba 100644 --- a/test/files/neg/unchecked.scala +++ b/test/files/neg/unchecked.scala @@ -19,8 +19,8 @@ object Test { case _ => 0 } def f3(x: Any) = x match { - case xs: Set[Any] => xs.head // unchecked - case _ => 0 + case xs: Set[Any] => xs.head // unchecked + case _ => 0 } def f4(x: Any) = x match { case xs: Map[Any, Any] => xs.head // unchecked diff --git a/test/files/neg/unchecked2.check b/test/files/neg/unchecked2.check index 599d11c43a..a7b8391856 100644 --- a/test/files/neg/unchecked2.check +++ b/test/files/neg/unchecked2.check @@ -1,21 +1,45 @@ -unchecked2.scala:2: warning: non-variable type argument Int in type Option[Int] is unchecked since it is eliminated by erasure - Some(123).isInstanceOf[Option[Int]] - ^ -unchecked2.scala:3: warning: non-variable type argument String in type Option[String] is unchecked since it is eliminated by erasure - Some(123).isInstanceOf[Option[String]] - ^ -unchecked2.scala:4: warning: non-variable type argument List[String] in type Option[List[String]] is unchecked since it is eliminated by erasure - Some(123).isInstanceOf[Option[List[String]]] - ^ -unchecked2.scala:5: warning: non-variable type argument List[Int => String] in type Option[List[Int => String]] is unchecked since it is eliminated by erasure - Some(123).isInstanceOf[Option[List[Int => String]]] - ^ -unchecked2.scala:6: warning: non-variable type argument (String, Double) in type Option[(String, Double)] is unchecked since it is eliminated by erasure - Some(123).isInstanceOf[Option[(String, Double)]] - ^ -unchecked2.scala:7: warning: non-variable type argument String => Double in type Option[String => Double] is unchecked since it is eliminated by erasure - Some(123).isInstanceOf[Option[String => Double]] - ^ +unchecked2.scala:4: warning: fruitless type test: a value of type Some[List[Int]] cannot also be a Option[List[String]] (but still might match its erasure) + /* warn */ Some(List(1)).isInstanceOf[Option[List[String]]] + ^ +unchecked2.scala:5: warning: non-variable type argument Option[_] in type Option[Option[_]] is unchecked since it is eliminated by erasure + /* warn */ Some(123).isInstanceOf[Option[Option[_]]] + ^ +unchecked2.scala:6: warning: fruitless type test: a value of type Some[Int] cannot also be a Option[String] (but still might match its erasure) + /* warn */ Some(123).isInstanceOf[Option[String]] + ^ +unchecked2.scala:7: warning: fruitless type test: a value of type Some[Int] cannot also be a Option[List[String]] (but still might match its erasure) + /* warn */ Some(123).isInstanceOf[Option[List[String]]] + ^ +unchecked2.scala:8: warning: fruitless type test: a value of type Some[Int] cannot also be a Option[List[Int => String]] (but still might match its erasure) + /* warn */ Some(123).isInstanceOf[Option[List[Int => String]]] + ^ +unchecked2.scala:9: warning: fruitless type test: a value of type Some[Int] cannot also be a Option[(String, Double)] (but still might match its erasure) + /* warn */ Some(123).isInstanceOf[Option[(String, Double)]] + ^ +unchecked2.scala:10: warning: fruitless type test: a value of type Some[Int] cannot also be a Option[String => Double] (but still might match its erasure) + /* warn */ Some(123).isInstanceOf[Option[String => Double]] + ^ +unchecked2.scala:14: warning: non-variable type argument List[String] in type Option[List[String]] is unchecked since it is eliminated by erasure + /* warn */ (Some(List(1)): Any).isInstanceOf[Option[List[String]]] + ^ +unchecked2.scala:15: warning: non-variable type argument Int in type Option[Int] is unchecked since it is eliminated by erasure + /* warn */ (Some(123): Any).isInstanceOf[Option[Int]] + ^ +unchecked2.scala:16: warning: non-variable type argument String in type Option[String] is unchecked since it is eliminated by erasure + /* warn */ (Some(123): Any).isInstanceOf[Option[String]] + ^ +unchecked2.scala:17: warning: non-variable type argument List[String] in type Option[List[String]] is unchecked since it is eliminated by erasure + /* warn */ (Some(123): Any).isInstanceOf[Option[List[String]]] + ^ +unchecked2.scala:18: warning: non-variable type argument List[Int => String] in type Option[List[Int => String]] is unchecked since it is eliminated by erasure + /* warn */ (Some(123): Any).isInstanceOf[Option[List[Int => String]]] + ^ +unchecked2.scala:19: warning: non-variable type argument (String, Double) in type Option[(String, Double)] is unchecked since it is eliminated by erasure + /* warn */ (Some(123): Any).isInstanceOf[Option[(String, Double)]] + ^ +unchecked2.scala:20: warning: non-variable type argument String => Double in type Option[String => Double] is unchecked since it is eliminated by erasure + /* warn */ (Some(123): Any).isInstanceOf[Option[String => Double]] + ^ error: No warnings can be incurred under -Xfatal-warnings. -6 warnings found +14 warnings found one error found diff --git a/test/files/neg/unchecked2.scala b/test/files/neg/unchecked2.scala index a2e757e1dc..616b05aad8 100644 --- a/test/files/neg/unchecked2.scala +++ b/test/files/neg/unchecked2.scala @@ -1,8 +1,33 @@ object Test { - Some(123).isInstanceOf[Option[Int]] - Some(123).isInstanceOf[Option[String]] - Some(123).isInstanceOf[Option[List[String]]] - Some(123).isInstanceOf[Option[List[Int => String]]] - Some(123).isInstanceOf[Option[(String, Double)]] - Some(123).isInstanceOf[Option[String => Double]] + // These warn because it can be statically shown they won't match. + + /* warn */ Some(List(1)).isInstanceOf[Option[List[String]]] + /* warn */ Some(123).isInstanceOf[Option[Option[_]]] + /* warn */ Some(123).isInstanceOf[Option[String]] + /* warn */ Some(123).isInstanceOf[Option[List[String]]] + /* warn */ Some(123).isInstanceOf[Option[List[Int => String]]] + /* warn */ Some(123).isInstanceOf[Option[(String, Double)]] + /* warn */ Some(123).isInstanceOf[Option[String => Double]] + + // These warn because you can't check at runtime. + + /* warn */ (Some(List(1)): Any).isInstanceOf[Option[List[String]]] + /* warn */ (Some(123): Any).isInstanceOf[Option[Int]] + /* warn */ (Some(123): Any).isInstanceOf[Option[String]] + /* warn */ (Some(123): Any).isInstanceOf[Option[List[String]]] + /* warn */ (Some(123): Any).isInstanceOf[Option[List[Int => String]]] + /* warn */ (Some(123): Any).isInstanceOf[Option[(String, Double)]] + /* warn */ (Some(123): Any).isInstanceOf[Option[String => Double]] + + // These don't warn. + + /* nowarn */ Some(List(1)).isInstanceOf[Option[List[Int]]] + /* nowarn */ Some(123).isInstanceOf[Option[Int]] + /* nowarn */ Some(123).isInstanceOf[Some[Int]] + /* nowarn */ Some(123).isInstanceOf[AnyRef] + + /* nowarn */ (Some(List(1)): Any).isInstanceOf[Option[_]] + /* nowarn */ (Some(123): Any).isInstanceOf[Option[_]] + /* nowarn */ (Some(123): Any).isInstanceOf[Some[_]] + /* nowarn */ (Some(123): Any).isInstanceOf[AnyRef] } diff --git a/test/files/neg/unchecked3.check b/test/files/neg/unchecked3.check new file mode 100644 index 0000000000..a7582a8930 --- /dev/null +++ b/test/files/neg/unchecked3.check @@ -0,0 +1,42 @@ +unchecked3.scala:24: warning: non-variable type argument Double in type pattern E1[Double] is unchecked since it is eliminated by erasure + /* warn */ def peerTypes2(x: B1[Int]) = x match { case _: E1[Double] => true } + ^ +unchecked3.scala:25: warning: non-variable type argument Double in type pattern F1[Double] is unchecked since it is eliminated by erasure + /* warn */ def peerTypes3(x: B1[_]) = x match { case _: F1[Double] => true } + ^ +unchecked3.scala:28: warning: non-variable type argument Int in type pattern A2[Int] is unchecked since it is eliminated by erasure + /* warn */ def twotypes1[T](x: B2[T, Int]) = x match { case _: A2[Int] => true } + ^ +unchecked3.scala:32: warning: non-variable type argument Int in type pattern B2[_,Int] is unchecked since it is eliminated by erasure + /* warn */ def twotypes5[T](x: A2[T]) = x match { case _: B2[_, Int] => true } + ^ +unchecked3.scala:40: warning: non-variable type argument String in type pattern Array[List[String]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[List[String]] => () + ^ +unchecked3.scala:43: warning: non-variable type argument String in type pattern Array[Array[List[String]]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[Array[List[String]]] => () + ^ +unchecked3.scala:50: warning: non-variable type argument String in type pattern Array[List[String]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[List[String]] => () + ^ +unchecked3.scala:53: warning: non-variable type argument String in type pattern Array[Array[List[String]]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[Array[List[String]]] => () + ^ +unchecked3.scala:60: warning: non-variable type argument String in type pattern Array[List[String]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[List[String]] => () + ^ +unchecked3.scala:62: warning: non-variable type argument Array[String] in type pattern Array[List[Array[String]]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[List[Array[String]]] => () + ^ +unchecked3.scala:63: warning: non-variable type argument String in type pattern Array[Array[List[String]]] is unchecked since it is eliminated by erasure + /* warn */ case _: Array[Array[List[String]]] => () + ^ +unchecked3.scala:75: warning: abstract type A in type pattern Set[Q.this.A] is unchecked since it is eliminated by erasure + /* warn */ case xs: Set[A] => xs.head + ^ +unchecked3.scala:62: warning: unreachable code + /* warn */ case _: Array[List[Array[String]]] => () + ^ +error: No warnings can be incurred under -Xfatal-warnings. +13 warnings found +one error found diff --git a/test/files/neg/unchecked3.flags b/test/files/neg/unchecked3.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/unchecked3.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/unchecked3.scala b/test/files/neg/unchecked3.scala new file mode 100644 index 0000000000..7b8c13e8f8 --- /dev/null +++ b/test/files/neg/unchecked3.scala @@ -0,0 +1,83 @@ +sealed trait A2[T1] +final class B2[T1, T2] extends A2[T1] + +sealed trait A[T] +final class B[T] extends A[T] + +sealed trait A1[T] +trait B1[T] extends A1[T] +trait C1[T] extends A1[T] +trait D1[T] extends A1[Int] +trait E1[T] extends B1[Int] +trait F1[T] extends B1[T] + +object MiscUnchecked { + /* nowarn */ def knownType1(x: A[Int]) = x match { case _: B[Int] if true => 1 } + /* nowarn */ def knownType2(x: B[Int]) = x match { case _: A[Int] if true => 1 } + /* nowarn */ def tparamLeakage1(x: Any) = x match { case Array() => 1 } + /* nowarn */ def tparamLeakage2(x: Any) = x match { case List() => 1 } + + // E1[Double] implies B1[Int], but B1[Int] does not imply E1[Double], even if .isInstanceOf[E1[_]] + // F1[Int] implies B1[Int], and B1[Int] implies F1[Int] + + /* nowarn */ def peerTypes1(x: B1[Int]) = x match { case _: C1[Int] => true } + /* warn */ def peerTypes2(x: B1[Int]) = x match { case _: E1[Double] => true } + /* warn */ def peerTypes3(x: B1[_]) = x match { case _: F1[Double] => true } + /* nowarn */ def peerTypes4(x: B1[Int]) = x match { case _: F1[Int] => true } + + /* warn */ def twotypes1[T](x: B2[T, Int]) = x match { case _: A2[Int] => true } + /* nowarn */ def twotypes2[T](x: B2[Int, T]) = x match { case _: A2[Int] => true } + /* nowarn */ def twotypes3(x: A2[Int]) = x match { case _: B2[Int, _] => true } + /* nowarn */ def twotypes4[T](x: A2[T]) = x match { case _: B2[T, _] => true } + /* warn */ def twotypes5[T](x: A2[T]) = x match { case _: B2[_, Int] => true } +} + +object Arrays { + def f1(x: Any) = x match { + /* nowarn */ case _: Array[Int] => () + /* nowarn */ case _: Array[Boolean] => () + /* nowarn */ case _: Array[String] => () + /* warn */ case _: Array[List[String]] => () + /* nowarn */ case _: Array[Array[String]] => () + /* nowarn */ case _: Array[Array[Array[String]]] => () + /* warn */ case _: Array[Array[List[String]]] => () + } + + def f2(x: Array[_]) = x match { + /* nowarn */ case _: Array[Int] => () + /* nowarn */ case _: Array[Boolean] => () + /* nowarn */ case _: Array[String] => () + /* warn */ case _: Array[List[String]] => () + /* nowarn */ case _: Array[Array[String]] => () + /* nowarn */ case _: Array[Array[Array[String]]] => () + /* warn */ case _: Array[Array[List[String]]] => () + } + + def f3[T](x: Array[T]) = x match { + /* nowarn */ case _: Array[Int] => () + /* nowarn */ case _: Array[Boolean] => () + /* nowarn */ case _: Array[String] => () + /* warn */ case _: Array[List[String]] => () + /* nowarn */ case _: Array[Array[String]] => () + /* warn */ case _: Array[List[Array[String]]] => () + /* warn */ case _: Array[Array[List[String]]] => () + } +} + +object Matching { + class Q { + type A + type B <: A + + def f(xs: Traversable[B]) = xs match { + /* nowarn */ case xs: List[A] => xs.head + /* nowarn */ case xs: Seq[B] => xs.head + /* warn */ case xs: Set[A] => xs.head + } + def f2[T <: B](xs: Traversable[T]) = xs match { + /* nowarn */ case xs: List[B with T] => xs.head + /* nowarn */ case xs: Seq[A] => xs.head + /* nowarn */ case xs: Set[T] => xs.head + } + } +} diff --git a/test/files/pos/t1107/O.scala b/test/files/pos/t1107b/O.scala index aa605a6d09..aa605a6d09 100644 --- a/test/files/pos/t1107/O.scala +++ b/test/files/pos/t1107b/O.scala diff --git a/test/files/pos/t1107/T.scala b/test/files/pos/t1107b/T.scala index 1f3712d529..1f3712d529 100644 --- a/test/files/pos/t1107/T.scala +++ b/test/files/pos/t1107b/T.scala diff --git a/test/files/pos/t1203/J.java b/test/files/pos/t1203b/J.java index 7fae118e04..7fae118e04 100644 --- a/test/files/pos/t1203/J.java +++ b/test/files/pos/t1203b/J.java diff --git a/test/files/pos/t1203/S.scala b/test/files/pos/t1203b/S.scala index 68eac4bf6d..68eac4bf6d 100644 --- a/test/files/pos/t1203/S.scala +++ b/test/files/pos/t1203b/S.scala diff --git a/test/files/pos/t6275.flags b/test/files/pos/t6275.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/pos/t6275.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/pos/t6275.scala b/test/files/pos/t6275.scala new file mode 100644 index 0000000000..6b5ec7dceb --- /dev/null +++ b/test/files/pos/t6275.scala @@ -0,0 +1,11 @@ + +sealed trait A[T] +final class B[T] extends A[T] + +object ParsedAxis { + type BI = B[Int] + + def f1(a: A[Int]) = a match { case b: B[Int] => 3 } + def f2(a: A[Int]) = a match { case b: BI => 3 } + def f3(a: A[Int]) = a match { case b: B[t] => 3 } +} diff --git a/test/files/run/macro-openmacros/Impls_Macros_1.scala b/test/files/run/macro-openmacros/Impls_Macros_1.scala index 38d46c5185..b863ac048b 100644 --- a/test/files/run/macro-openmacros/Impls_Macros_1.scala +++ b/test/files/run/macro-openmacros/Impls_Macros_1.scala @@ -4,8 +4,7 @@ object Macros { def impl(c: Context): c.Expr[Unit] = { // we're macros, so we can reflect against our source path // so we don't need any partests to clean up after us! - val c.CompilationUnit(file, _, _) = c.enclosingUnit - val dir = file.getCanonicalFile.getParentFile + val dir = c.enclosingUnit.source.file.file.getCanonicalFile.getParentFile def normalizePaths(s: String) = { val base = (dir.getCanonicalPath + java.io.File.separator).replace('\\', '/') var regex = """\Q%s\E""" format base diff --git a/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala b/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala index ae2def2d3e..b4351c2c53 100644 --- a/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala @@ -23,9 +23,10 @@ case class Utils[C <: Context]( c:C ) { object QueryableMacros{ def _helper[C <: Context,S:c.WeakTypeTag]( c:C )( name:String, projection:c.Expr[_] ) = { import c.universe._ + import treeBuild._ val element_type = implicitly[c.WeakTypeTag[S]].tpe val foo = c.Expr[ru.Expr[Queryable[S]]]( - c.reifyTree( c.runtimeUniverse, EmptyTree, c.typeCheck( + c.reifyTree( mkRuntimeUniverseRef, EmptyTree, c.typeCheck( Utils[c.type](c).removeDoubleReify( Apply(Select(c.prefix.tree, newTermName( name )), List( projection.tree )) ).asInstanceOf[Tree] diff --git a/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala b/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala index ae2def2d3e..b4351c2c53 100644 --- a/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala @@ -23,9 +23,10 @@ case class Utils[C <: Context]( c:C ) { object QueryableMacros{ def _helper[C <: Context,S:c.WeakTypeTag]( c:C )( name:String, projection:c.Expr[_] ) = { import c.universe._ + import treeBuild._ val element_type = implicitly[c.WeakTypeTag[S]].tpe val foo = c.Expr[ru.Expr[Queryable[S]]]( - c.reifyTree( c.runtimeUniverse, EmptyTree, c.typeCheck( + c.reifyTree( mkRuntimeUniverseRef, EmptyTree, c.typeCheck( Utils[c.type](c).removeDoubleReify( Apply(Select(c.prefix.tree, newTermName( name )), List( projection.tree )) ).asInstanceOf[Tree] diff --git a/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala b/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala index b23a5c70e1..5330d0e32b 100644 --- a/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala @@ -4,18 +4,7 @@ object Impls { def foo(c: Ctx)(x: c.Expr[Int]) = { val x1 = c.Expr[Int](c.resetAllAttrs(x.tree)) // was: c.literal(x1.splice) - c.literal(eval(c)(x1)) - } - - private def eval[T](c: Ctx)(x: c.Expr[T]): T = { - import scala.reflect.runtime.{universe => ru} - val mirror = ru.runtimeMirror(c.libraryClassLoader) - import scala.tools.reflect.ToolBox - val toolBox = mirror.mkToolBox() - val importer = ru.mkImporter(c.universe).asInstanceOf[ru.Importer { val from: c.universe.type }] - val tree = c.resetAllAttrs(x.tree.duplicate) - val imported = importer.importTree(tree) - toolBox.eval(imported).asInstanceOf[T] + c.literal(c.eval(x1)) } } diff --git a/test/files/run/macro-reify-unreify/Macros_1.scala b/test/files/run/macro-reify-unreify/Macros_1.scala index 620a929210..9f04c13014 100644 --- a/test/files/run/macro-reify-unreify/Macros_1.scala +++ b/test/files/run/macro-reify-unreify/Macros_1.scala @@ -6,9 +6,10 @@ object Macros { object Impls { def foo(c: Ctx)(s: c.Expr[String]) = { import c.universe._ + import treeBuild._ - val world = c.reifyTree(c.runtimeUniverse, EmptyTree, s.tree) - val greeting = c.reifyTree(c.runtimeUniverse, EmptyTree, c.typeCheck(Apply(Select(Literal(Constant("hello ")), newTermName("$plus")), List(c.unreifyTree(world))))) + val world = c.reifyTree(mkRuntimeUniverseRef, EmptyTree, s.tree) + val greeting = c.reifyTree(mkRuntimeUniverseRef, EmptyTree, c.typeCheck(Apply(Select(Literal(Constant("hello ")), newTermName("$plus")), List(c.unreifyTree(world))))) val typedGreeting = c.Expr[String](greeting) c.universe.reify { diff --git a/test/files/run/macro-sip19-revised/Impls_Macros_1.scala b/test/files/run/macro-sip19-revised/Impls_Macros_1.scala index 0793696fd4..5f3f61ca3f 100644 --- a/test/files/run/macro-sip19-revised/Impls_Macros_1.scala +++ b/test/files/run/macro-sip19-revised/Impls_Macros_1.scala @@ -8,7 +8,7 @@ object Macros { val outer = c.Expr[SourceLocation](if (!inscope.isEmpty) inscope else Literal(Constant(null))) val Apply(fun, args) = c.enclosingImplicits(0)._2 - val fileName = fun.pos.fileInfo.getName + val fileName = fun.pos.source.file.file.getName val line = fun.pos.line val charOffset = fun.pos.point c.universe.reify { SourceLocation1(outer.splice, c.literal(fileName).splice, c.literal(line).splice, c.literal(charOffset).splice) } diff --git a/test/files/run/macro-sip19/Impls_Macros_1.scala b/test/files/run/macro-sip19/Impls_Macros_1.scala index f89e51f560..535ec2ccf0 100644 --- a/test/files/run/macro-sip19/Impls_Macros_1.scala +++ b/test/files/run/macro-sip19/Impls_Macros_1.scala @@ -4,7 +4,7 @@ object Macros { def impl(c: Context) = { import c.universe._ val Apply(fun, args) = c.enclosingImplicits(0)._2 - val fileName = fun.pos.fileInfo.getName + val fileName = fun.pos.source.file.file.getName val line = fun.pos.line val charOffset = fun.pos.point c.universe.reify { SourceLocation(c.literal(fileName).splice, c.literal(line).splice, c.literal(charOffset).splice) } diff --git a/test/files/run/macro-typecheck-macrosdisabled.check b/test/files/run/macro-typecheck-macrosdisabled.check index 719c6a2ef2..29a881f8b1 100644 --- a/test/files/run/macro-typecheck-macrosdisabled.check +++ b/test/files/run/macro-typecheck-macrosdisabled.check @@ -7,7 +7,7 @@ $treecreator1.super.<init>(); () }; - def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Tree = { + def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.Literal.apply($u.Constant.apply(2)) @@ -20,7 +20,7 @@ $typecreator2.super.<init>(); () }; - def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Type = { + def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Type = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.ConstantType.apply($u.Constant.apply(2)) diff --git a/test/files/run/macro-typecheck-macrosdisabled2.check b/test/files/run/macro-typecheck-macrosdisabled2.check index 1fd422083c..7bdd1d6a3a 100644 --- a/test/files/run/macro-typecheck-macrosdisabled2.check +++ b/test/files/run/macro-typecheck-macrosdisabled2.check @@ -7,7 +7,7 @@ $treecreator1.super.<init>(); () }; - def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Tree = { + def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticPackage("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) @@ -20,7 +20,7 @@ $typecreator2.super.<init>(); () }; - def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Type = { + def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Type = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.TypeRef.apply($u.ThisType.apply($m.staticPackage("scala").asModule.moduleClass), $m.staticClass("scala.Array"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asType.toTypeConstructor)) diff --git a/test/files/run/t576.scala b/test/files/run/t576.scala index dc09d8dc98..756a241572 100644 --- a/test/files/run/t576.scala +++ b/test/files/run/t576.scala @@ -12,7 +12,7 @@ object Dingus { object Test { val x1 = new A val x2 = new A - + val x3 = new { self => override def equals(other : Any) = other match { case that: self.type => true @@ -20,7 +20,7 @@ object Test { } } val x4 = new { self => - def f(x: Any) = x match { + def f(x: Any): Int = x match { case _: x1.type => 1 case _: x2.type => 2 case _: x3.type => 3 @@ -35,11 +35,11 @@ object Test { assert(x1 != x2) assert(x1 != ()) assert(x2 != x1) - + assert(x3 == x3) assert(x3 != x2) assert(x2 != x3) - + List(x1, x2, x3, x4, Dingus) map x4.f foreach println } -}
\ No newline at end of file +} diff --git a/test/files/run/toolbox_console_reporter.check b/test/files/run/toolbox_console_reporter.check index e69de29bb2..1395c68740 100644 --- a/test/files/run/toolbox_console_reporter.check +++ b/test/files/run/toolbox_console_reporter.check @@ -0,0 +1,8 @@ +hello +============compiler console============= +warning: method foo in object Utils is deprecated: test + +========================================= +============compiler messages============ +Info(NoPosition,method foo in object Utils is deprecated: test,WARNING) +========================================= diff --git a/test/files/run/toolbox_console_reporter.scala b/test/files/run/toolbox_console_reporter.scala index a57dea38a8..d672ccb9cb 100644 --- a/test/files/run/toolbox_console_reporter.scala +++ b/test/files/run/toolbox_console_reporter.scala @@ -1,16 +1,29 @@ import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{universe => ru} +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, mkConsoleFrontEnd} object Test extends App { - // todo. cannot test this unfortunately, because ConsoleFrontEnd grabs Console.out too early - // todo. and isn't affected by Console.setOut employed by partest to intercept output + val oldErr = Console.err; + val baos = new java.io.ByteArrayOutputStream(); + Console.setErr(new java.io.PrintStream(baos)); + try { + val toolbox = cm.mkToolBox(frontEnd = mkConsoleFrontEnd(), options = "-deprecation") + toolbox.eval(reify{ + object Utils { + @deprecated("test", "2.10.0") + def foo { println("hello") } + } - //val toolbox = mkToolBox(frontEnd = mkConsoleFrontEnd(), options = "-deprecation") - //toolbox.eval(reify{ - // object Utils { - // @deprecated("test", "2.10.0") - // def foo { println("hello") } - // } - // - // Utils.foo - //}) + Utils.foo + }.tree) + println("============compiler console=============") + println(baos.toString); + println("=========================================") + println("============compiler messages============") + toolbox.frontEnd.infos.foreach(println(_)) + println("=========================================") + } finally { + Console.setErr(oldErr); + } }
\ No newline at end of file diff --git a/test/files/run/toolbox_silent_reporter.scala b/test/files/run/toolbox_silent_reporter.scala index 15f559d605..03b1d6defa 100644 --- a/test/files/run/toolbox_silent_reporter.scala +++ b/test/files/run/toolbox_silent_reporter.scala @@ -1,10 +1,10 @@ import scala.reflect.runtime.universe._ import scala.reflect.runtime.{universe => ru} import scala.reflect.runtime.{currentMirror => cm} -import scala.tools.reflect.ToolBox +import scala.tools.reflect.{ToolBox, mkSilentFrontEnd} object Test extends App { - val toolbox = cm.mkToolBox(options = "-deprecation") + val toolbox = cm.mkToolBox(options = "-deprecation", frontEnd = mkSilentFrontEnd()) toolbox.eval(reify{ object Utils { @deprecated("test", "2.10.0") diff --git a/test/files/run/toolbox_typecheck_macrosdisabled.check b/test/files/run/toolbox_typecheck_macrosdisabled.check index 9e997dafed..688f37927c 100644 --- a/test/files/run/toolbox_typecheck_macrosdisabled.check +++ b/test/files/run/toolbox_typecheck_macrosdisabled.check @@ -16,7 +16,7 @@ $treecreator1.super.<init>(); () }; - def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Tree = { + def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.Literal.apply($u.Constant.apply(2)) @@ -29,7 +29,7 @@ $typecreator2.super.<init>(); () }; - def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Type = { + def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Type = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.ConstantType.apply($u.Constant.apply(2)) diff --git a/test/files/run/toolbox_typecheck_macrosdisabled2.check b/test/files/run/toolbox_typecheck_macrosdisabled2.check index 16c8d6c397..f5c9b6eeab 100644 --- a/test/files/run/toolbox_typecheck_macrosdisabled2.check +++ b/test/files/run/toolbox_typecheck_macrosdisabled2.check @@ -16,7 +16,7 @@ $treecreator1.super.<init>(); () }; - def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Tree = { + def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticPackage("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) @@ -29,7 +29,7 @@ $typecreator2.super.<init>(); () }; - def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.MirrorOf[U]): U#Type = { + def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Type = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; $u.TypeRef.apply($u.ThisType.apply($m.staticPackage("scala").asModule.moduleClass), $m.staticClass("scala.Array"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asType.toTypeConstructor)) diff --git a/test/pending/pos/exhaust_2.scala b/test/pending/pos/exhaust_2.scala new file mode 100644 index 0000000000..4f4e47c43b --- /dev/null +++ b/test/pending/pos/exhaust_2.scala @@ -0,0 +1,54 @@ +object ExhaustivityWarnBugReportMinimal { + //sealed is needed for the warning + sealed trait FoundNode[T]/*presence of parameters is irrelevant*/ + // This also causes a warning: + // sealed abstract class FoundNode[T]/*presence of parameters is irrelevant*/ + case class FoundFilter[T](/*presence of parameters is irrelevant*/) extends FoundNode[T] + case class FoundTypeCase[T](/*presence of parameters is irrelevant*/) extends FoundNode[T] + val f: Some[_] = ??? + f match { + case x: Some[t] => //no warning + } + //With these variants, no warnings: + //val v: (Some[Int], FoundNode[_]) = (???, ???) + //val v: (Some[AnyRef], FoundNode[_]) = (???, ???) + //val v: (Some[String], FoundNode[_]) = (???, ???) + + val v: (Some[_], FoundNode[_]) = (???, ???) + //Warning here: + v match { + case (x: Some[t], _: FoundNode[_]) => + } + v match { + case (x: Some[t], _) => + } + + v match { + case (x: Some[_], _) => + } + case class Foo[T]() + + val vp: (Foo[_], FoundNode[_]) = (???, ???) + vp match { + case (x: Foo[_], _) => + } + + //No warning here: + v match { + case (Some(y), _) => + } + + v match { + case (x, _) => + } + + val v2: (Some[_], Int) = (???, ???) + v2 match { + case (x: Some[t], _) => + } + + val v3: (Option[_], FoundNode[_]) = (???, ???) + v match { + case (x: Option[_], _) => + } +} |