diff options
79 files changed, 878 insertions, 279 deletions
diff --git a/src/compiler/scala/reflect/macros/contexts/Typers.scala b/src/compiler/scala/reflect/macros/contexts/Typers.scala index cd3db74016..c1ab17027f 100644 --- a/src/compiler/scala/reflect/macros/contexts/Typers.scala +++ b/src/compiler/scala/reflect/macros/contexts/Typers.scala @@ -46,9 +46,7 @@ trait Typers { universe.analyzer.inferImplicit(tree, viewTpe, true, callsiteTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw TypecheckException(pos, msg)) } - def resetAllAttrs(tree: Tree): Tree = universe.resetAllAttrs(universe.duplicateAndKeepPositions(tree)) + def resetLocalAttrs(tree: Tree): Tree = universe.resetAttrs(universe.duplicateAndKeepPositions(tree)) - def resetLocalAttrs(tree: Tree): Tree = universe.resetLocalAttrs(universe.duplicateAndKeepPositions(tree)) - - def untypecheck(tree: Tree): Tree = universe.resetLocalAttrs(universe.duplicateAndKeepPositions(tree)) + def untypecheck(tree: Tree): Tree = resetLocalAttrs(tree) } diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index ad0632f93e..6b0a0ee8d7 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -86,7 +86,7 @@ abstract class Reifier extends States throw new Error("reifee %s of type %s is not supported".format(reifee, if (reifee == null) "null" else reifee.getClass.toString)) } - // todo. why do we resetAllAttrs? + // todo. why do we reset attrs? // // typically we do some preprocessing before reification and // the code emitted/moved around during preprocessing is very hard to typecheck, so we leave it as it is @@ -109,19 +109,11 @@ abstract class Reifier extends States // // todo. this is a common problem with non-trivial macros in our current macro system // needs to be solved some day - // maybe try `resetLocalAttrs` once the dust settles - var importantSymbols = Set[Symbol]( - NothingClass, AnyClass, SingletonClass, PredefModule, ScalaRunTimeModule, TypeCreatorClass, TreeCreatorClass, MirrorClass, - ApiUniverseClass, JavaUniverseClass, ReflectRuntimePackage, runDefinitions.ReflectRuntimeCurrentMirror) - importantSymbols ++= importantSymbols map (_.companionSymbol) - importantSymbols ++= importantSymbols map (_.moduleClass) - importantSymbols ++= importantSymbols map (_.linkedClassOfClass) - def isImportantSymbol(sym: Symbol): Boolean = sym != null && sym != NoSymbol && importantSymbols(sym) - val untyped = resetAllAttrs(result, leaveAlone = { + // upd. a new hope: https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ + val untyped = resetAttrs(result, leaveAlone = { case ValDef(_, u, _, _) if u == nme.UNIVERSE_SHORT => true case ValDef(_, m, _, _) if m == nme.MIRROR_SHORT => true case tree if symtab.syms contains tree.symbol => true - case tree if isImportantSymbol(tree.symbol) => true case _ => false }) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index f6b3c42ca9..b082796757 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -140,7 +140,7 @@ trait GenTrees { if (sym == NoSymbol) { // this sometimes happens, e.g. for binds that don't have a body // or for untyped code generated during previous phases - // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?") + // (see a comment in Reifiers about the latter, starting with "why do we reset attrs?") mirrorCall(nme.Ident, reify(name)) } else if (!sym.isLocalToReifee) { diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 5492e563dd..1617db7517 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -81,6 +81,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase + def erasurePhase: Phase = if (currentRun.isDefined) currentRun.erasurePhase else NoPhase + // platform specific elements protected class GlobalPlatform extends { @@ -527,7 +529,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } with Erasure // phaseName = "posterasure" - object postErasure extends { + override object postErasure extends { val global: Global.this.type = Global.this val runsAfter = List("erasure") val runsRightAfter = Some("erasure") diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 24bce0636d..7a7d4ac0b2 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -176,13 +176,24 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => } } - /** resets symbol and tpe fields in a tree, @see ResetAttrs - */ -// def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x } -// def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x } - - def resetAllAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(false, leaveAlone).transform(x) - def resetLocalAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(true, leaveAlone).transform(x) + // Finally, noone resetAllAttrs it anymore, so I'm removing it from the compiler. + // Even though it's with great pleasure I'm doing that, I'll leave its body here to warn future generations about what happened in the past. + // + // So what actually happened in the past is that we used to have two flavors of resetAttrs: resetAllAttrs and resetLocalAttrs. + // resetAllAttrs destroyed all symbols and types in the tree in order to reset its state to something suitable for retypechecking + // and/or embedding into bigger trees / different lexical scopes. (Btw here's some background on why people would want to use + // reset attrs in the first place: https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ). + // + // However resetAllAttrs was more of a poison than of a treatment, because along with locally defined symbols that are the cause + // for almost every or maybe even every case of tree corruption, it erased external bindings that sometimes could not be restored. + // This is how we came up with resetLocalAttrs that left external bindings alone, and that was a big step forward. + // Then slowly but steadily we've evicted all usages of resetAllAttrs from our codebase in favor of resetLocalAttrs + // and have been living happily ever after. + // + // def resetAllAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(localOnly = false, leaveAlone).transform(x) + + /** @see ResetAttrs */ + def resetAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(leaveAlone).transform(x) /** A transformer which resets symbol and tpe fields of all nodes in a given tree, * with special treatment of: @@ -193,7 +204,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * * (bq:) This transformer has mutable state and should be discarded after use */ - private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null, keepLabels: Boolean = false) { + private class ResetAttrs(leaveAlone: Tree => Boolean = null) { // this used to be based on -Ydebug, but the need for logging in this code is so situational // that I've reverted to a hard-coded constant here. val debug = false @@ -277,29 +288,18 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // vetoXXX local variables declared below describe the conditions under which we cannot erase symbols. // // The first reason to not erase symbols is the threat of non-idempotency (SI-5464). - // Here we take care of labels (SI-5562) and references to package classes (SI-5705). + // Here we take care of references to package classes (SI-5705). // There are other non-idempotencies, but they are not worked around yet. // - // The second reason has to do with the fact that resetAttrs itself has limited usefulness. - // - // First of all, why do we need resetAttrs? Gor one, it's absolutely required to move trees around. - // One cannot just take a typed tree from one lexical context and transplant it somewhere else. - // Most likely symbols defined by those trees will become borked and the compiler will blow up (SI-5797). - // To work around we just erase all symbols and types and then hope that we'll be able to correctly retypecheck. - // For ones who're not affected by scalac Stockholm syndrome, this might seem to be an extremely naive fix, but well... - // - // Of course, sometimes erasing everything won't work, because if a given identifier got resolved to something - // in one lexical scope, it can get resolved to something else. - // - // What do we do in these cases? Enter the workaround for the workaround: resetLocalAttrs, which only destroys - // locally defined symbols, but doesn't touch references to stuff declared outside of a given tree. - // That's what localOnly and vetoScope are for. + // The second reason has to do with the fact that resetAttrs needs to be less destructive. + // Erasing locally-defined symbols is useful to prevent tree corruption, but erasing external bindings is not, + // therefore we want to retain those bindings, especially given that restoring them can be impossible + // if we move these trees into lexical contexts different from their original locations. if (dupl.hasSymbol) { val sym = dupl.symbol - val vetoScope = localOnly && !(locals contains sym) - val vetoLabel = keepLabels && sym.isLabel + val vetoScope = !(locals contains sym) val vetoThis = dupl.isInstanceOf[This] && sym.isPackageClass - if (!(vetoScope || vetoLabel || vetoThis)) dupl.symbol = NoSymbol + if (!(vetoScope || vetoThis)) dupl.symbol = NoSymbol } dupl.clearType() } @@ -308,10 +308,9 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => } def transform(x: Tree): Tree = { - if (localOnly) new MarkLocals().traverse(x) - if (localOnly && debug) { + if (debug) { assert(locals.size == orderedLocals.size) val msg = orderedLocals.toList filter {_ != NoSymbol} map {" " + _} mkString EOL trace("locals (%d total): %n".format(orderedLocals.size))(msg) diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala index cc78e27282..32987fed8c 100644 --- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala @@ -8,7 +8,7 @@ package transform /** This phase maps ErasedValueTypes to the underlying unboxed representation and * performs peephole optimizations. */ -trait PostErasure extends InfoTransform with TypingTransformers { +trait PostErasure extends InfoTransform with TypingTransformers with scala.reflect.internal.transform.PostErasure { val global: Global import global._ @@ -19,16 +19,6 @@ trait PostErasure extends InfoTransform with TypingTransformers { def newTransformer(unit: CompilationUnit): Transformer = new PostErasureTransformer(unit) override def changesBaseClasses = false - object elimErasedValueType extends TypeMap { - def apply(tp: Type) = tp match { - case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) - case ErasedValueType(_, underlying) => underlying - case _ => mapOver(tp) - } - } - - def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp) - class PostErasureTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { override def transform(tree: Tree) = { def finish(res: Tree) = logResult(s"Posterasure reduction\n Old: $tree\n New")(res) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index e5907e1a0f..5b7956a757 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -457,7 +457,9 @@ trait Contexts { self: Analyzer => c.prefix = prefixInChild c.enclClass = if (isTemplateOrPackage) c else enclClass c(ConstructorSuffix) = !isTemplateOrPackage && c(ConstructorSuffix) - c.enclMethod = if (isDefDef) c else enclMethod + + // SI-8245 `isLazy` need to skip lazy getters to ensure `return` binds to the right place + c.enclMethod = if (isDefDef && !owner.isLazy) c else enclMethod registerContext(c.asInstanceOf[analyzer.Context]) debuglog("[context] ++ " + c.unit + " / " + tree.summaryString) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 645f267a21..886dbed6d6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1205,7 +1205,7 @@ trait Namers extends MethodSynthesis { * flag. */ private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overriddenSymbol: => Symbol) { - val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetLocalAttrs(ddef.duplicate) + val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(ddef.duplicate) // having defs here is important to make sure that there's no sneaky tree sharing // in methods with multiple default parameters def rtparams = rtparams0.map(_.duplicate) @@ -1292,7 +1292,7 @@ trait Namers extends MethodSynthesis { return // fix #3649 (prevent crash in erroneous source code) } } - val ClassDef(_, _, rtparams, _) = resetLocalAttrs(cdef.duplicate) + val ClassDef(_, _, rtparams, _) = resetAttrs(cdef.duplicate) defTparams = rtparams.map(rt => copyTypeDef(rt)(mods = rt.mods &~ (COVARIANT | CONTRAVARIANT))) nmr } @@ -1408,8 +1408,14 @@ trait Namers extends MethodSynthesis { if (expr1.isErrorTyped) ErrorType else { - if (!treeInfo.isStableIdentifierPattern(expr1)) - typer.TyperErrorGen.UnstableTreeError(expr1) + expr1 match { + case This(_) => + // SI-8207 okay, typedIdent expands Ident(self) to C.this which doesn't satisfy the next case + // TODO should we change `typedIdent` not to expand to the `Ident` to a `This`? + case _ if treeInfo.isStableIdentifierPattern(expr1) => + case _ => + typer.TyperErrorGen.UnstableTreeError(expr1) + } val newImport = treeCopy.Import(imp, expr1, selectors).asInstanceOf[Import] checkSelectors(newImport) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 46ff98875f..6a4df415ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -173,7 +173,7 @@ trait NamesDefaults { self: Analyzer => // setSymbol below is important because the 'selected' function might be overloaded. by // assigning the correct method symbol, typedSelect will just assign the type. the reason // to still call 'typed' is to correctly infer singleton types, SI-5259. - val selectPos = + val selectPos = if(qual.pos.isRange && baseFun.pos.isRange) qual.pos.union(baseFun.pos).withStart(Math.min(qual.pos.end, baseFun.pos.end)) else baseFun.pos val f = blockTyper.typedOperator(Select(newQual, selected).setSymbol(baseFun1.symbol).setPos(selectPos)) @@ -287,7 +287,7 @@ trait NamesDefaults { self: Analyzer => } else { // TODO In 83c9c764b, we tried to a stable type here to fix SI-7234. But the resulting TypeTree over a - // singleton type without an original TypeTree fails to retypecheck after a resetLocalAttrs (SI-7516), + // singleton type without an original TypeTree fails to retypecheck after a resetAttrs (SI-7516), // which is important for (at least) macros. arg.tpe } @@ -310,7 +310,7 @@ trait NamesDefaults { self: Analyzer => new ChangeOwnerTraverser(context.owner, sym) traverse arg // fixes #4502 if (repeated) arg match { case WildcardStarArg(expr) => expr - case _ => blockTyper typed gen.mkSeqApply(resetLocalAttrs(arg)) + case _ => blockTyper typed gen.mkSeqApply(resetAttrs(arg)) } else arg } Some(atPos(body.pos)(ValDef(sym, body).setType(NoType))) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index f7684b93af..2125e281f0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1414,7 +1414,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case TypeRef(pre, sym, args) => tree match { case tt: TypeTree if tt.original == null => // SI-7783 don't warn about inferred types - // FIXME: reconcile this check with one in resetAllAttrs + // FIXME: reconcile this check with one in resetAttrs case _ => checkUndesiredProperties(sym, tree.pos) } if(sym.isJavaDefined) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 101e1526fe..10fe530445 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -832,7 +832,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper else tpr.typed(withImplicitArgs, mode, pt) } orElse { _ => - val resetTree = resetLocalAttrs(original) + val resetTree = resetAttrs(original) debuglog(s"fallback on implicits: ${tree}/$resetTree") val tree1 = typed(resetTree, mode) // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that @@ -2307,7 +2307,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper context.scope.unlink(ldef.symbol) val sym2 = namer.enterInScope( context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), restpe)) - val rhs2 = typed(resetAllAttrs(ldef.rhs), restpe) + val LabelDef(_, _, rhs1) = resetAttrs(ldef) + val rhs2 = typed(rhs1, restpe) ldef.params foreach (param => param setType param.symbol.tpe) deriveLabelDef(ldef)(_ => rhs2) setSymbol sym2 setType restpe } @@ -2589,7 +2590,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // // Well behaved trees satisfy the property: // - // typed(tree) == typed(resetLocalAttrs(typed(tree)) + // typed(tree) == typed(resetAttrs(typed(tree)) // // Trees constructed without low-level symbol manipulation get this for free; // references to local symbols are cleared by `ResetAttrs`, but bind to the diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index ffac29b4b8..cc2d9141ce 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -52,13 +52,13 @@ trait Unapplies extends ast.TreeDSL { } private def constrParamss(cdef: ClassDef): List[List[ValDef]] = { - val ClassDef(_, _, _, Template(_, _, body)) = resetLocalAttrs(cdef.duplicate) + val ClassDef(_, _, _, Template(_, _, body)) = resetAttrs(cdef.duplicate) val DefDef(_, _, _, vparamss, _, _) = treeInfo firstConstructor body vparamss } private def constrTparamsInvariant(cdef: ClassDef): List[TypeDef] = { - val ClassDef(_, _, tparams, _) = resetLocalAttrs(cdef.duplicate) + val ClassDef(_, _, tparams, _) = resetAttrs(cdef.duplicate) val tparamsInvariant = tparams.map(tparam => copyTypeDef(tparam)(mods = tparam.mods &~ (COVARIANT | CONTRAVARIANT))) tparamsInvariant } diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index 4237f36ade..bd95fdbb50 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -7,7 +7,7 @@ package scala package tools package nsc -import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter } +import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter, Reader } package object util { // forwarder for old code that builds against 2.9 and 2.10 @@ -46,6 +46,17 @@ package object util { (result, ts2 filterNot (ts1 contains _)) } + def stringFromReader(reader: Reader) = { + val writer = new StringWriter() + var c = reader.read() + while(c != -1) { + writer.write(c) + c = reader.read() + } + reader.close() + writer.toString() + } + /** Generate a string using a routine that wants to write on a stream. */ def stringFromWriter(writer: PrintWriter => Unit): String = { val stringWriter = new StringWriter() diff --git a/src/compiler/scala/tools/reflect/ReflectGlobal.scala b/src/compiler/scala/tools/reflect/ReflectGlobal.scala index f8ded56ec6..6f369212ad 100644 --- a/src/compiler/scala/tools/reflect/ReflectGlobal.scala +++ b/src/compiler/scala/tools/reflect/ReflectGlobal.scala @@ -12,9 +12,10 @@ class ReflectGlobal(currentSettings: Settings, reporter: Reporter, override val extends Global(currentSettings, reporter) with scala.tools.reflect.ReflectSetup with scala.reflect.runtime.SymbolTable { override def transformedType(sym: Symbol) = - erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info))) + postErasure.transformInfo(sym, + erasure.transformInfo(sym, + uncurry.transformInfo(sym, + refChecks.transformInfo(sym, sym.info)))) override def isCompilerUniverse = true diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 4c1bc794bc..4a3db09909 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -71,12 +71,6 @@ trait ToolBox[U <: scala.reflect.api.Universe] { */ def inferImplicitView(tree: u.Tree, from: u.Type, to: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree - /** Recursively resets symbols and types in a given tree. - * WARNING: Don't use this API, go for [[untypecheck]] instead. - */ - @deprecated("Use `tb.untypecheck` instead", "2.11.0") - def resetAllAttrs(tree: u.Tree): u.Tree - /** Recursively resets locally defined symbols and types in a given tree. * WARNING: Don't use this API, go for [[untypecheck]] instead. */ @@ -102,6 +96,15 @@ trait ToolBox[U <: scala.reflect.api.Universe] { */ def compile(tree: u.Tree): () => Any + /** Defines a top-level class, trait or module in this ToolBox, + * putting it into a uniquely-named package and returning a symbol that references the defined entity. + * For a ClassDef, a ClassSymbol is returned, and for a ModuleDef, a ModuleSymbol is returned (not a module class, but a module itself). + * + * This method can be used to generate definitions that will later be re-used by subsequent calls to + * `compile`, `define` or `eval`. To refer to the generated definition in a tree, use q"$sym". + */ + def define(tree: u.ImplDef): u.Symbol + /** Compiles and runs a tree using this ToolBox. * Is equivalent to `compile(tree)()`. */ diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 4a8c91bd1b..7bae3203c2 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -193,6 +193,19 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg)) }) + private def wrapInPackageAndCompile(packageName: TermName, tree: ImplDef): Symbol = { + val pdef = PackageDef(Ident(packageName), List(tree)) + val unit = new CompilationUnit(NoSourceFile) + unit.body = pdef + + val run = new Run + reporter.reset() + run.compileUnits(List(unit), run.namerPhase) + throwIfErrors() + + tree.symbol + } + def compile(expr0: Tree): () => Any = { val expr = wrapIntoTerm(expr0) @@ -200,7 +213,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) - def wrap(expr0: Tree): ModuleDef = { + def wrapInModule(expr0: Tree): ModuleDef = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) val (obj, _) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( @@ -236,22 +249,15 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => NoPosition)) trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value)) - val cleanedUp = resetLocalAttrs(moduledef) + val cleanedUp = resetAttrs(moduledef) trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value)) cleanedUp.asInstanceOf[ModuleDef] } - val mdef = wrap(expr) - val pdef = PackageDef(Ident(mdef.name), List(mdef)) - val unit = new CompilationUnit(NoSourceFile) - unit.body = pdef + val mdef = wrapInModule(expr) + val msym = wrapInPackageAndCompile(mdef.name, mdef) - val run = new Run - reporter.reset() - run.compileUnits(List(unit), run.namerPhase) - throwIfErrors() - - val className = mdef.symbol.fullName + val className = msym.fullName if (settings.debug) println("generated: "+className) def moduleFileName(className: String) = className + "$" val jclazz = jClass.forName(moduleFileName(className), true, classLoader) @@ -278,6 +284,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } } + def define(tree: ImplDef): Symbol = { + val freeTerms = tree.freeTerms + if (freeTerms.nonEmpty) throw ToolBoxError(s"reflective toolbox has failed: cannot have free terms in a top-level definition") + verify(tree) + wrapInPackageAndCompile(nextWrapperModuleName(), tree) + } + def parse(code: String): Tree = { reporter.reset() val tree = gen.mkTreeOrBlock(newUnitParser(code, "<toolbox>").parseStatsOrPackages()) @@ -385,18 +398,10 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => uitree } - def resetAllAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi => - import compilerApi._ - val ctree: compiler.Tree = importer.importTree(tree) - val ttree: compiler.Tree = compiler.resetAllAttrs(ctree) - val uttree = exporter.importTree(ttree) - uttree - } - def resetLocalAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi => import compilerApi._ val ctree: compiler.Tree = importer.importTree(tree) - val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree) + val ttree: compiler.Tree = compiler.resetAttrs(ctree) val uttree = exporter.importTree(ttree) uttree } @@ -421,6 +426,18 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => compiler.compile(ctree) } + def define(tree: u.ImplDef): u.Symbol = withCompilerApi { compilerApi => + import compilerApi._ + + if (compiler.settings.verbose) println("importing "+tree) + val ctree: compiler.ImplDef = importer.importTree(tree).asInstanceOf[compiler.ImplDef] + + if (compiler.settings.verbose) println("defining "+ctree) + val csym: compiler.Symbol = compiler.define(ctree) + val usym = exporter.importSymbol(csym) + usym + } + def eval(tree: u.Tree): Any = compile(tree)() } } diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index 29c92a111c..47fb66744e 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -22,9 +22,9 @@ import generic.CanBuildFrom * on a map that will no longer have elements removed but will be * used heavily may save both time and storage space. * - * This map is not indended to contain more than 2^29 entries (approximately - * 500 million). The maximum capacity is 2^30, but performance will degrade - * rapidly as 2^30 is approached. + * This map is not intended to contain more than 2^29^ entries (approximately + * 500 million). The maximum capacity is 2^30^, but performance will degrade + * rapidly as 2^30^ is approached. * */ final class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean) @@ -291,24 +291,21 @@ extends AbstractMap[K, V] private[this] val vz = _values private[this] var index = 0 - private[this] var found = false - def hasNext = found || (index<hz.length && { + def hasNext: Boolean = index<hz.length && { var h = hz(index) - if (h+h != 0) found = true - else { + while (h+h == 0) { index += 1 - while (index < hz.length && { h = hz(index); h+h == 0 }) index += 1 - found = (index < hz.length) + if (index >= hz.length) return false + h = hz(index) } - found - }) + true + } - def next = { - if (found || hasNext) { - val ans = (_keys(index).asInstanceOf[K], _values(index).asInstanceOf[V]) + def next: (K, V) = { + if (hasNext) { + val ans = (kz(index).asInstanceOf[K], vz(index).asInstanceOf[V]) index += 1 - found = false ans } else throw new NoSuchElementException("next") diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index b70426a145..6743b9e42a 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -647,9 +647,10 @@ object Regex { /** A class to step through a sequence of regex matches. * * All methods inherited from [[scala.util.matching.Regex.MatchData]] will throw - * an [[java.lang.IllegalStateException]] until the matcher is initialized by - * calling `hasNext` or `next()` or causing these methods to be called, such as - * by invoking `toString` or iterating through the iterator's elements. + * a [[java.lang.IllegalStateException]] until the matcher is initialized. The + * matcher can be initialized by calling `hasNext` or `next()` or causing these + * methods to be called, such as by invoking `toString` or iterating through + * the iterator's elements. * * @see [[java.util.regex.Matcher]] */ diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala index 5667d93e29..6539137cee 100644 --- a/src/reflect/scala/reflect/api/Importers.scala +++ b/src/reflect/scala/reflect/api/Importers.scala @@ -52,7 +52,7 @@ package api * val imported = importer.importTree(tree) * * // after the tree is imported, it can be evaluated as usual - * val tree = toolBox.resetAllAttrs(imported.duplicate) + * val tree = toolBox.untypecheck(imported.duplicate) * val valueOfX = toolBox.eval(imported).asInstanceOf[T] * ... * } diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 83da5141b9..60e00ca5fd 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -1066,7 +1066,7 @@ trait Trees { self: Universe => * UnApply( * // a dummy node that carries the type of unapplication to patmat * // the <unapply-selector> here doesn't have an underlying symbol - * // it only has a type assigned, therefore after `resetAllAttrs` this tree is no longer typeable + * // it only has a type assigned, therefore after `untypecheck` this tree is no longer typeable * Apply(Select(Ident(Foo), newTermName("unapply")), List(Ident(newTermName("<unapply-selector>")))), * // arguments of the unapply => nothing synthetic here * List(Bind(newTermName("x"), Ident(nme.WILDCARD)))), diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala index 7457910226..be76758224 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -134,7 +134,7 @@ import scala.language.implicitConversions * reflection APIs provided by Java (for classes) and Scala (for types).</li> * * <li>'''Certain manifest operations(i.e., <:<, >:> and typeArguments) are not - * supported.''' <br/>Instead, one culd use the reflection APIs provided by Java (for + * supported.''' <br/>Instead, one could use the reflection APIs provided by Java (for * classes) and Scala (for types).</li> *</ul> * diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala index 14db252a16..009bc39d4c 100644 --- a/src/reflect/scala/reflect/internal/Required.scala +++ b/src/reflect/scala/reflect/internal/Required.scala @@ -6,6 +6,9 @@ import settings.MutableSettings trait Required { self: SymbolTable => def picklerPhase: Phase + + def erasurePhase: Phase + def settings: MutableSettings @deprecated("Interactive is implemented with a custom Global; this flag is ignored", "2.11.0") def forInteractive = false diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 74b2208278..4fbac235f4 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -899,7 +899,7 @@ trait Types -1 } - /** If this is a poly- or methodtype, a copy with cloned type / value parameters + /** If this is a ExistentialType, PolyType or MethodType, a copy with cloned type / value parameters * owned by `owner`. Identity for all other types. */ def cloneInfo(owner: Symbol) = this @@ -2683,8 +2683,55 @@ trait Types override def baseTypeSeq = underlying.baseTypeSeq map maybeRewrap override def isHigherKinded = false - override def skolemizeExistential(owner: Symbol, origin: AnyRef) = + /** [SI-6169, SI-8197 -- companion to SI-1786] + * + * Approximation to improve the bounds of a Java-defined existential type, + * based on the bounds of the type parameters of the quantified type + * In Scala syntax, given a java-defined class C[T <: String], the existential type C[_] + * is improved to C[_ <: String] before skolemization, which captures (get it?) what Java does: + * enter the type paramers' bounds into the context when checking subtyping/type equality of existential types + * + * (Also tried doing this once during class file parsing or when creating the existential type, + * but that causes cyclic errors because it happens too early.) + */ + private def sharpenQuantifierBounds(): Unit = { + /* Check that we're looking at rawToExistential's handiwork + * (`existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))`). + * We can't do this sharpening there because we'll run into cycles. + */ + def rawToExistentialCreatedMe = (quantified corresponds underlying.typeArgs){ (q, a) => q.tpe =:= a } + + if (underlying.typeSymbol.isJavaDefined && rawToExistentialCreatedMe) { + val tpars = underlying.typeSymbol.initialize.typeParams // TODO: is initialize needed? + debuglog(s"sharpen bounds: $this | ${underlying.typeArgs.map(_.typeSymbol)} <-- ${tpars.map(_.info)}") + + foreach2(quantified, tpars) { (quant, tparam) => + // TODO: check `tparam.info.substSym(tpars, quantified) <:< quant.info` instead (for some weird reason not working for test/t6169/ExistF) + // for now, crude approximation for the common case + if (quant.info.bounds.isEmptyBounds && !tparam.info.bounds.isEmptyBounds) { + // avoid creating cycles [pos/t2940] that consist of an existential quantifier's + // bounded by an existential type that unhygienically has that quantifier as its own quantifier + // (TODO: clone latter existential with fresh quantifiers -- not covering this case for now) + if ((existentialsInType(tparam.info) intersect quantified).isEmpty) + quant setInfo tparam.info.substSym(tpars, quantified) + } + } + } + + _sharpenQuantifierBounds = false + } + private[this] var _sharpenQuantifierBounds = true + + override def skolemizeExistential(owner: Symbol, origin: AnyRef) = { + // do this here because it's quite close to what Java does: + // when checking subtyping/type equality, enter constraints + // derived from the existentially quantified type into the typing environment + // (aka \Gamma, which tracks types for variables and constraints/kinds for types) + // as a nice bonus, delaying this until we need it avoids cyclic errors + if (_sharpenQuantifierBounds) sharpenQuantifierBounds + deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying) + } private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map { case TypeRef(_, sym, _) if (qset contains sym) => @@ -2905,6 +2952,8 @@ trait Types override def params: List[Symbol] = zippedArgs map (_._1) override def typeArgs: List[Type] = zippedArgs map (_._2) + + override def safeToString: String = super.safeToString + typeArgs.map(_.safeToString).mkString("[", ", ", "]") } trait UntouchableTypeVar extends TypeVar { @@ -3025,15 +3074,19 @@ trait Types def addLoBound(tp: Type, isNumericBound: Boolean = false) { assert(tp != this, tp) // implies there is a cycle somewhere (?) //println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG - undoLog record this - constr.addLoBound(tp, isNumericBound) + if (!sharesConstraints(tp)) { + undoLog record this + constr.addLoBound(tp, isNumericBound) + } } def addHiBound(tp: Type, isNumericBound: Boolean = false) { // assert(tp != this) //println("addHiBound: "+(safeToString, debugString(tp))) //DEBUG - undoLog record this - constr.addHiBound(tp, isNumericBound) + if (!sharesConstraints(tp)) { + undoLog record this + constr.addHiBound(tp, isNumericBound) + } } // </region> @@ -3045,6 +3098,16 @@ trait Types case ConstantTrue => true case tv: TypeVar => tv.suspended } + + /** `AppliedTypeVar`s share the same `TypeConstraint` with the `HKTypeVar` that it was spawned from. + * A type inference session can also have more than one ATV. + * If we don't detect that, we end up with "cyclic constraint" when we try to instantiate type parameters + * after solving in, pos/t8237 + */ + protected final def sharesConstraints(other: Type): Boolean = other match { + case other: TypeVar => constr == other.constr // SI-8237 avoid cycles. Details in pos/t8237.scala + case _ => false + } private[Types] def suspended_=(b: Boolean): Unit = _suspended = if (b) ConstantTrue else ConstantFalse // SI-7785 Link the suspended attribute of a TypeVar created in, say, a TypeMap (e.g. AsSeenFrom) to its originator private[Types] def linkSuspended(origin: TypeVar): Unit = _suspended = origin diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index e2159d30f5..564cbb1ce3 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -257,6 +257,12 @@ private[internal] trait TypeConstraints { // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) foreach3(tvars, tparams, variances)(solveOne) - tvars forall (tv => tv.instWithinBounds || util.andFalse(log(s"Inferred type for ${tv.originString} does not conform to bounds: ${tv.constr}"))) + + def logBounds(tv: TypeVar) = log { + val what = if (!tv.instValid) "is invalid" else s"does not conform to bounds: ${tv.constr}" + s"Inferred type for ${tv.originString} (${tv.inst}) $what" + } + + tvars forall (tv => tv.instWithinBounds || util.andFalse(logBounds(tv))) } } diff --git a/src/reflect/scala/reflect/internal/transform/PostErasure.scala b/src/reflect/scala/reflect/internal/transform/PostErasure.scala new file mode 100644 index 0000000000..f0c7d0f050 --- /dev/null +++ b/src/reflect/scala/reflect/internal/transform/PostErasure.scala @@ -0,0 +1,19 @@ +package scala.reflect +package internal +package transform + +trait PostErasure { + val global: SymbolTable + import global._ + import definitions._ + + object elimErasedValueType extends TypeMap { + def apply(tp: Type) = tp match { + case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) + case ErasedValueType(_, underlying) => underlying + case _ => mapOver(tp) + } + } + + def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp) +} diff --git a/src/reflect/scala/reflect/internal/transform/Transforms.scala b/src/reflect/scala/reflect/internal/transform/Transforms.scala index fa185db22f..296ccde443 100644 --- a/src/reflect/scala/reflect/internal/transform/Transforms.scala +++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala @@ -26,17 +26,20 @@ trait Transforms { self: SymbolTable => private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks) private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry) private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure) + private val postErasureLazy = new Lazy(new { val global: Transforms.this.type = self } with PostErasure) def refChecks = refChecksLazy.force def uncurry = uncurryLazy.force def erasure = erasureLazy.force + def postErasure = postErasureLazy.force def transformedType(sym: Symbol) = - erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info))) + postErasure.transformInfo(sym, + erasure.transformInfo(sym, + uncurry.transformInfo(sym, + refChecks.transformInfo(sym, sym.info)))) def transformedType(tpe: Type) = - erasure.scalaErasure(uncurry.uncurry(tpe)) + postErasure.elimErasedValueType(erasure.scalaErasure(uncurry.uncurry(tpe))) } diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala index 222ae43d79..68e07dd319 100644 --- a/src/reflect/scala/reflect/macros/Evals.scala +++ b/src/reflect/scala/reflect/macros/Evals.scala @@ -17,13 +17,13 @@ trait Evals { * permitted by the shape of the arguments. * * Known issues: because of [[https://issues.scala-lang.org/browse/SI-5748 https://issues.scala-lang.org/browse/SI-5748]] - * trees being evaluated first need to undergo `resetAllAttrs`. Resetting symbols and types + * trees being evaluated first need to undergo `untypecheck`. Resetting symbols and types * mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first. * * {{{ * scala> def impl(c: Context)(x: c.Expr[String]) = { - * | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate)) - * | println(s"compile-time value is: \${c.eval(x1)}") + * | val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate)) + * | println(s"compile-time value is: ${c.eval(x1)}") * | x * | } * impl: (c: Context)(x: c.Expr[String])c.Expr[String] diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala index 87de442921..6c077de1d2 100644 --- a/src/reflect/scala/reflect/macros/Typers.scala +++ b/src/reflect/scala/reflect/macros/Typers.scala @@ -68,12 +68,6 @@ trait Typers { */ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree - /** Recursively resets symbols and types in a given tree. - * WARNING: Don't use this API, go for [[untypecheck]] instead. - */ - @deprecated("Use `c.untypecheck` instead", "2.11.0") - def resetAllAttrs(tree: Tree): Tree - /** Recursively resets locally defined symbols and types in a given tree. * WARNING: Don't use this API, go for [[untypecheck]] instead. */ diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index d84e6aa737..bc5c8b2840 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -122,7 +122,7 @@ abstract class Universe extends scala.reflect.api.Universe { def setType(tp: Type): Tree /** Like `setType`, but if this is a previously empty TypeTree that - * fact is remembered so that resetAllAttrs will snap back. + * fact is remembered so that `untypecheck` will snap back. * * \@PP: Attempting to elaborate on the above, I find: If defineType * is called on a TypeTree whose type field is null or NoType, @@ -130,7 +130,8 @@ abstract class Universe extends scala.reflect.api.Universe { * ResetAttrsTraverser, which nulls out the type field of TypeTrees * for which wasEmpty is true, leaving the others alone. * - * resetAllAttrs is used in situations where some speculative + * `untypecheck` (or `resetAttrs` in compiler parlance) is used + * in situations where some speculative * typing of a tree takes place, fails, and the tree needs to be * returned to its former state to try again. So according to me: * using `defineType` instead of `setType` is how you communicate diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 68c67bb1f8..bc95b839b7 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -16,7 +16,7 @@ import java.io.IOException import scala.reflect.internal.{ MissingRequirementError, JavaAccFlags, JMethodOrConstructor } import internal.pickling.ByteCodecs import internal.pickling.UnPickler -import scala.collection.mutable.{ HashMap, ListBuffer } +import scala.collection.mutable.{ HashMap, ListBuffer, ArrayBuffer } import internal.Flags._ import ReflectionUtils._ import scala.language.existentials @@ -118,15 +118,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def abort(msg: String) = throw new ScalaReflectionException(msg) - private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror") - private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") - private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") - private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") - private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") - private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym") - private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym") - private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") - private def ErrorNonExistentField(sym: Symbol) = abort( + private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror") + private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") + private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") + private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") + private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") + private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym") + private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym") + private def ErrorArrayConstructor(sym: Symbol, owner: Symbol) = abort(s"Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead") + private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") + private def ErrorNonExistentField(sym: Symbol) = abort( sm"""Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method |note that private parameters of class constructors don't get mapped onto fields and/or accessors, |unless they are used outside of their declaring constructors.""") @@ -221,6 +222,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def checkConstructorOf(sym: Symbol, owner: ClassSymbol) { if (!sym.isClassConstructor) ErrorNotConstructor(sym, owner) + if (owner == ArrayClass) ErrorArrayConstructor(sym, owner) ensuringNotFree(sym) { if (!owner.info.decls.toList.contains(sym)) ErrorNotConstructor(sym, owner) } @@ -247,7 +249,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } def reflectMethod(method: MethodSymbol): MethodMirror = { checkMemberOf(method, symbol) - mkJavaMethodMirror(instance, method) + mkMethodMirror(instance, method) } def reflectClass(cls: ClassSymbol): ClassMirror = { if (cls.isStatic) ErrorStaticClass(cls) @@ -262,16 +264,35 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def toString = s"instance mirror for $instance" } - private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol) + // caches value class metadata, so that we minimize the work that needs to be done during Mirror.apply + private class DerivedValueClassMetadata(info: Type) { + val symbol = info.typeSymbol + val isDerivedValueClass = symbol.isDerivedValueClass + lazy val boxer = runtimeClass(symbol.toType).getDeclaredConstructors().head + lazy val unboxer = { + val fields @ (field :: _) = symbol.toType.declarations.collect{ case ts: TermSymbol if ts.isParamAccessor && ts.isMethod => ts }.toList + assert(fields.length == 1, s"$symbol: $fields") + runtimeClass(symbol.asClass).getDeclaredMethod(field.name.toString) + } + } + + private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol, metadata: DerivedValueClassMetadata) extends FieldMirror { + def this(receiver: Any, symbol: TermSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.info)) + def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol, metadata) + import metadata._ + lazy val jfield = ensureAccessible(fieldToJava(symbol)) - def get = jfield get receiver + def get = { + val value = jfield get receiver + if (isDerivedValueClass) boxer.newInstance(value) else value + } def set(value: Any) = { // it appears useful to be able to set values of vals, therefore I'm disabling this check // if (!symbol.isMutable) ErrorSetImmutableField(symbol) - jfield.set(receiver, value) + jfield.set(receiver, if (isDerivedValueClass) unboxer.invoke(value) else value) } - def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol) + override def toString = s"field mirror for ${symbol.fullName} (bound to $receiver)" } @@ -312,13 +333,17 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni bytecodelessMethodOwners(meth.owner) && !bytecodefulObjectMethods(meth) } + private def isByNameParam(p: Type) = isByNameParamType(p) + private def isValueClassParam(p: Type) = p.typeSymbol.isDerivedValueClass + // unlike other mirrors, method mirrors are created by a factory // that's because we want to have decent performance // therefore we move special cases into separate subclasses // rather than have them on a hot path them in a unified implementation of the `apply` method - private def mkJavaMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): JavaMethodMirror = { - if (isBytecodelessMethod(symbol)) new JavaBytecodelessMethodMirror(receiver, symbol) - else if (symbol.paramss.flatten exists (p => isByNameParamType(p.info))) new JavaByNameMethodMirror(receiver, symbol) + private def mkMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): MethodMirror = { + def existsParam(pred: Type => Boolean) = symbol.paramss.flatten.map(_.info).exists(pred) + if (isBytecodelessMethod(symbol)) new BytecodelessMethodMirror(receiver, symbol) + else if (existsParam(isByNameParam) || existsParam(isValueClassParam)) new JavaTransformingMethodMirror(receiver, symbol) else { symbol.paramss.flatten.length match { case 0 => new JavaVanillaMethodMirror0(receiver, symbol) @@ -330,68 +355,123 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } } } - private abstract class JavaMethodMirror(val symbol: MethodSymbol) extends MethodMirror { + + private abstract class JavaMethodMirror(val symbol: MethodSymbol, protected val ret: DerivedValueClassMetadata) extends MethodMirror { lazy val jmeth = ensureAccessible(methodToJava(symbol)) - def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) + lazy val jconstr = ensureAccessible(constructorToJava(symbol)) - def jinvoke(jmeth: jMethod, receiver: Any, args: Seq[Any]): Any = { - val result = jinvokeraw(jmeth, receiver, args) - if (jmeth.getReturnType == java.lang.Void.TYPE) () + def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) + else if (receiver == null) jconstr.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*) + else jconstr.newInstance((receiver +: args).asInstanceOf[Seq[AnyRef]]: _*) + def jinvoke(args: Seq[Any]): Any = { + val result = jinvokeraw(args) + if (!symbol.isConstructor && jmeth.getReturnType == java.lang.Void.TYPE) () + else if (!symbol.isConstructor && ret.isDerivedValueClass) ret.boxer.newInstance(result.asInstanceOf[AnyRef]) else result } - override def toString = s"method mirror for ${showMethodSig(symbol)} (bound to $receiver)" - } - - private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol) - extends JavaMethodMirror(symbol) { - def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol) - def apply(args: Any*): Any = jinvoke(jmeth, receiver, args) - } - - private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver) - } - - private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef]) - } - - private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) - } - - private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + override def toString = { + val what = if (symbol.isConstructor) "constructor mirror" else "method mirror" + s"$what for ${showMethodSig(symbol)} (bound to $receiver)" + } } - private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) - } + private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaMethodMirror(symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol, ret) + def apply(args: Any*): Any = jinvoke(args) + } + + private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver) + else if (receiver == null) jconstr.newInstance() + else jconstr.newInstance(receiver.asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) + } + + // caches MethodSymbol metadata, so that we minimize the work that needs to be done during Mirror.apply + // TODO: vararg is only supported in the last parameter list (SI-6182), so we don't need to worry about the rest for now + private class MethodMetadata(symbol: MethodSymbol) { + private val params = symbol.paramss.flatten.toArray + private val vcMetadata = params.map(p => new DerivedValueClassMetadata(p.info)) + val isByName = params.map(p => isByNameParam(p.info)) + def isDerivedValueClass(i: Int) = vcMetadata(i).isDerivedValueClass + def paramUnboxers(i: Int) = vcMetadata(i).unboxer + val paramCount = params.length + val ret = new DerivedValueClassMetadata(symbol.returnType) + } + + private class JavaTransformingMethodMirror(val receiver: Any, symbol: MethodSymbol, metadata: MethodMetadata) + extends JavaMethodMirror(symbol, metadata.ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new MethodMetadata(symbol)) + override def bind(newReceiver: Any) = new JavaTransformingMethodMirror(newReceiver, symbol, metadata) + import metadata._ - private class JavaByNameMethodMirror(val receiver: Any, symbol: MethodSymbol) - extends JavaMethodMirror(symbol) { - def bind(newReceiver: Any) = new JavaByNameMethodMirror(newReceiver, symbol) def apply(args: Any*): Any = { - val transformed = map2(args.toList, symbol.paramss.flatten)((arg, param) => if (isByNameParamType(param.info)) () => arg else arg) - jinvoke(jmeth, receiver, transformed) + val args1 = new Array[Any](args.length) + var i = 0 + while (i < args1.length) { + val arg = args(i) + if (i >= paramCount) args1(i) = arg // don't transform varargs + else if (isByName(i)) args1(i) = () => arg // don't transform by-name value class params + else if (isDerivedValueClass(i)) args1(i) = paramUnboxers(i).invoke(arg) + i += 1 + } + jinvoke(args1) } } - private class JavaBytecodelessMethodMirror[T: ClassTag](val receiver: T, symbol: MethodSymbol) - extends JavaMethodMirror(symbol) { - def bind(newReceiver: Any) = new JavaBytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol) - def apply(args: Any*): Any = { + private class BytecodelessMethodMirror[T: ClassTag](val receiver: T, val symbol: MethodSymbol) + extends MethodMirror { + def bind(newReceiver: Any) = new BytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol) + override def toString = s"bytecodeless method mirror for ${showMethodSig(symbol)} (bound to $receiver)" + + def apply(args: Any*): Any = { // checking type conformance is too much of a hassle, so we don't do it here // actually it's not even necessary, because we manually dispatch arguments below val params = symbol.paramss.flatten @@ -414,7 +494,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def invokePrimitiveMethod = { val jmeths = classOf[BoxesRunTime].getDeclaredMethods.filter(_.getName == nme.primitiveMethodName(symbol.name).toString) assert(jmeths.length == 1, jmeths.toList) - jinvoke(jmeths.head, null, objReceiver +: objArgs) + val jmeth = jmeths.head + val result = jmeth.invoke(null, (objReceiver +: objArgs).asInstanceOf[Seq[AnyRef]]: _*) + if (jmeth.getReturnType == java.lang.Void.TYPE) () + else result } symbol match { @@ -445,23 +528,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } } - private class JavaConstructorMirror(val outer: AnyRef, val symbol: MethodSymbol) - extends MethodMirror { - def bind(newReceiver: Any) = new JavaConstructorMirror(newReceiver.asInstanceOf[AnyRef], symbol) - override val receiver = outer - lazy val jconstr = ensureAccessible(constructorToJava(symbol)) - def apply(args: Any*): Any = { - if (symbol.owner == ArrayClass) - abort("Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead") - - val effectiveArgs = - if (outer == null) args.asInstanceOf[Seq[AnyRef]] - else outer +: args.asInstanceOf[Seq[AnyRef]] - jconstr.newInstance(effectiveArgs: _*) - } - override def toString = s"constructor mirror for ${showMethodSig(symbol)} (bound to $outer)" - } - private abstract class JavaTemplateMirror extends TemplateMirror { def outer: AnyRef @@ -474,7 +540,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def isStatic = false def reflectConstructor(constructor: MethodSymbol) = { checkConstructorOf(constructor, symbol) - new JavaConstructorMirror(outer, constructor) + mkMethodMirror(outer, constructor) } override def toString = s"class mirror for ${symbol.fullName} (bound to $outer)" } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index cfd66744ff..f6556a442d 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -12,6 +12,8 @@ class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with Refl override def inform(msg: String): Unit = log(msg) def picklerPhase = internal.SomePhase + def erasurePhase = internal.SomePhase + lazy val settings = new Settings private val isLogging = sys.props contains "scala.debug.reflect" diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index 813c0e1386..d642b25127 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -12,7 +12,7 @@ import scala.reflect.internal.util.AbstractFileClassLoader /** A few java-reflection oriented utility functions useful during reflection bootstrapping. */ -private[scala] object ReflectionUtils { +object ReflectionUtils { // Unwraps some chained exceptions which arise during reflective calls. def unwrapThrowable(x: Throwable): Throwable = x match { case _: InvocationTargetException | // thrown by reflectively invoked method or constructor diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 8fba1e538e..d261fc5be9 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -18,7 +18,7 @@ import scala.reflect.internal.util.{ BatchSourceFile, SourceFile } import scala.tools.util.PathResolver import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings } -import scala.tools.nsc.util.{ ScalaClassLoader, stringFromWriter, StackTraceOps } +import scala.tools.nsc.util.{ ScalaClassLoader, stringFromReader, stringFromWriter, StackTraceOps } import scala.tools.nsc.util.Exceptional.unwrap import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, CompiledScript, Compilable} @@ -534,8 +534,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set var code = "" var bound = false - @throws[ScriptException] - def compile(script: String): CompiledScript = { + def compiled(script: String): CompiledScript = { if (!bound) { quietBind("engine" -> this.asInstanceOf[ScriptEngine]) bound = true @@ -562,18 +561,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } } - @throws[ScriptException] - def compile(reader: java.io.Reader): CompiledScript = { - val writer = new java.io.StringWriter() - var c = reader.read() - while(c != -1) { - writer.write(c) - c = reader.read() - } - reader.close() - compile(writer.toString()) - } - private class WrappedRequest(val req: Request) extends CompiledScript { var recorded = false @@ -1014,10 +1001,16 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } @throws[ScriptException] - def eval(script: String, context: ScriptContext): Object = compile(script).eval(context) + def compile(script: String): CompiledScript = eval("new javax.script.CompiledScript { def eval(context: javax.script.ScriptContext): Object = { " + script + " }.asInstanceOf[Object]; def getEngine: javax.script.ScriptEngine = engine }").asInstanceOf[CompiledScript] + + @throws[ScriptException] + def compile(reader: java.io.Reader): CompiledScript = compile(stringFromReader(reader)) + + @throws[ScriptException] + def eval(script: String, context: ScriptContext): Object = compiled(script).eval(context) @throws[ScriptException] - def eval(reader: java.io.Reader, context: ScriptContext): Object = compile(reader).eval(context) + def eval(reader: java.io.Reader, context: ScriptContext): Object = eval(stringFromReader(reader), context) override def finalize = close diff --git a/test/disabled/run/t7843-jsr223-service.scala b/test/disabled/run/t7843-jsr223-service.scala deleted file mode 100644 index e2ea850698..0000000000 --- a/test/disabled/run/t7843-jsr223-service.scala +++ /dev/null @@ -1,18 +0,0 @@ -/*DISABLED: - For Paul, it steals focus when it runs. - - For me, it fails with some platform specific extra output: - - -ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngin - n: Object = 10 - 12345678910 -*/ -import javax.script._ -import scala.tools.nsc.interpreter.IMain - -object Test extends App { - val engine = new ScriptEngineManager getEngineByName "scala" - engine.asInstanceOf[IMain].settings.usejavacp.value = true - engine put ("n", 10) - engine eval "1 to n.asInstanceOf[Int] foreach print" -} diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 880ddc4327..20ddd55f1f 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -88,7 +88,7 @@ names-defaults-neg.scala:76: error: no type parameters for method test4: (x: T[T --- because --- argument expression's type is not compatible with formal parameter type; found : List[Int] - required: ?T + required: ?T[?T[List[?T[X forSome { type X }]]]] Error occurred in an application involving default arguments. test4() ^ diff --git a/test/files/neg/t8207.check b/test/files/neg/t8207.check new file mode 100644 index 0000000000..59facd897a --- /dev/null +++ b/test/files/neg/t8207.check @@ -0,0 +1,7 @@ +t8207.scala:1: error: '.' expected but '}' found. +class C { import C.this.toString } + ^ +t8207.scala:3: error: '.' expected but '}' found. +class D { import D.this.toString } + ^ +two errors found diff --git a/test/files/neg/t8207.scala b/test/files/neg/t8207.scala new file mode 100644 index 0000000000..738ce381f4 --- /dev/null +++ b/test/files/neg/t8207.scala @@ -0,0 +1,3 @@ +class C { import C.this.toString } + +class D { import D.this.toString } diff --git a/test/files/neg/t8237-default.check b/test/files/neg/t8237-default.check new file mode 100644 index 0000000000..59fe21ed03 --- /dev/null +++ b/test/files/neg/t8237-default.check @@ -0,0 +1,13 @@ +t8237-default.scala:5: error: no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])Nothing exist so that it can be applied to arguments (List[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : List[Int] + required: ?T[?T[List[?T[X forSome { type X }]]]] + test4(test4$default$1) + ^ +t8237-default.scala:5: error: type mismatch; + found : List[Int] + required: T[T[List[T[X forSome { type X }]]]] + test4(test4$default$1) + ^ +two errors found diff --git a/test/files/neg/t8237-default.scala b/test/files/neg/t8237-default.scala new file mode 100644 index 0000000000..f695aa523f --- /dev/null +++ b/test/files/neg/t8237-default.scala @@ -0,0 +1,29 @@ +// This test case was extracte from `names-defaults-neg.scala` +// It pinpoints an improvement an error message that results from +// a type inference failure +object Test extends App { + test4(test4$default$1) + + def test4[T[P]](x: T[T[List[T[X forSome { type X }]]]]) = ??? + def test4$default$1[T[P]]: List[Int] = ??? +} + +/* +OLD: + no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])Nothing exist so that it can be applied to arguments (List[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : List[Int] + required: ?T + test4(test4$default$1) + ^ + +NEW: + +no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])Nothing exist so that it can be applied to arguments (List[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : List[Int] + required: ?T[?T[List[?T[X forSome { type X }]]] + test4(test4$default$1) +*/ diff --git a/test/files/pos/annotated-original/M_1.scala b/test/files/pos/annotated-original/M_1.scala index e312f9abbf..84a01bcce5 100644 --- a/test/files/pos/annotated-original/M_1.scala +++ b/test/files/pos/annotated-original/M_1.scala @@ -2,6 +2,6 @@ import language.experimental.macros import scala.reflect.macros.blackbox.Context object M { - def impl(c: Context)(a: c.Expr[Any]) = c.Expr[Any](c.resetLocalAttrs(a.tree)) + def impl(c: Context)(a: c.Expr[Any]) = c.Expr[Any](c.untypecheck(a.tree)) def m(a: Any) = macro impl } diff --git a/test/files/pos/annotated-treecopy/Impls_Macros_1.scala b/test/files/pos/annotated-treecopy/Impls_Macros_1.scala index b02864b994..fdf9c72c31 100644 --- a/test/files/pos/annotated-treecopy/Impls_Macros_1.scala +++ b/test/files/pos/annotated-treecopy/Impls_Macros_1.scala @@ -44,7 +44,7 @@ object Macros { val typeOut = c.Expr[String](q"${ttag.tpe.toString}").splice def apply(_arg: T): U = c.Expr[U](b1)(ttag.asInstanceOf[c.WeakTypeTag[U]]).splice }) - val untyped = c.resetLocalAttrs(template.tree) + val untyped = c.untypecheck(template.tree) c.Expr[T => U](untyped) case _ => sys.error("Bad function type") diff --git a/test/files/pos/t6169/Exist.java b/test/files/pos/t6169/Exist.java new file mode 100644 index 0000000000..dfc6b36b33 --- /dev/null +++ b/test/files/pos/t6169/Exist.java @@ -0,0 +1,4 @@ +public class Exist<T extends String> { + // java helpfully re-interprets Exist<?> as Exist<? extends String> + public Exist<?> foo() { throw new RuntimeException(); } +}
\ No newline at end of file diff --git a/test/files/pos/t6169/ExistF.java b/test/files/pos/t6169/ExistF.java new file mode 100644 index 0000000000..70fabd74cf --- /dev/null +++ b/test/files/pos/t6169/ExistF.java @@ -0,0 +1,4 @@ +public class ExistF<T extends ExistF<T>> { + // java helpfully re-interprets ExistF<?> as ExistF<?0 extends ExistF<?0>> + public ExistF<?> foo() { throw new RuntimeException(); } +}
\ No newline at end of file diff --git a/test/files/pos/t6169/ExistIndir.java b/test/files/pos/t6169/ExistIndir.java new file mode 100644 index 0000000000..e66d1698c4 --- /dev/null +++ b/test/files/pos/t6169/ExistIndir.java @@ -0,0 +1,4 @@ +public class ExistIndir<T extends String, U extends T> { + // java helpfully re-interprets ExistIndir<?> as ExistIndir<? extends String> + public ExistIndir<?, ?> foo() { throw new RuntimeException(); } +} diff --git a/test/files/pos/t6169/OP.java b/test/files/pos/t6169/OP.java new file mode 100644 index 0000000000..15e4c5640f --- /dev/null +++ b/test/files/pos/t6169/OP.java @@ -0,0 +1 @@ +public abstract class OP<T> { } diff --git a/test/files/pos/t6169/Skin.java b/test/files/pos/t6169/Skin.java new file mode 100644 index 0000000000..780de1ee09 --- /dev/null +++ b/test/files/pos/t6169/Skin.java @@ -0,0 +1 @@ +public interface Skin<C extends Skinnable> { } diff --git a/test/files/pos/t6169/Skinnable.java b/test/files/pos/t6169/Skinnable.java new file mode 100644 index 0000000000..f91eaa30d8 --- /dev/null +++ b/test/files/pos/t6169/Skinnable.java @@ -0,0 +1,3 @@ +public interface Skinnable { + OP<Skin<?>> skinProperty(); +} diff --git a/test/files/pos/t6169/skinnable.scala b/test/files/pos/t6169/skinnable.scala new file mode 100644 index 0000000000..3ba2734526 --- /dev/null +++ b/test/files/pos/t6169/skinnable.scala @@ -0,0 +1,14 @@ +object ObjectProperty { + implicit def jfxObjectProperty2sfx[T](p: OP[T]) = new ObjectProperty[T](p) +} + +class ObjectProperty[T](val delegate: OP[T]) + +trait TestWildcardBoundInference { + def delegate: Skinnable + def skin: ObjectProperty[Skin[_ /* inferred: <: Skinnable */]] = ObjectProperty.jfxObjectProperty2sfx(delegate.skinProperty) + skin: ObjectProperty[Skin[_ <: Skinnable]] + + def skinCheckInference = delegate.skinProperty + skinCheckInference: ObjectProperty[Skin[_ <: Skinnable]] +}
\ No newline at end of file diff --git a/test/files/pos/t6169/t6169.scala b/test/files/pos/t6169/t6169.scala new file mode 100644 index 0000000000..37f42619ca --- /dev/null +++ b/test/files/pos/t6169/t6169.scala @@ -0,0 +1,7 @@ +class Test { + class MyExist extends ExistF[MyExist] + // SI-8197, SI-6169: java infers the bounds of existentials, so we have to as well now that SI-1786 is fixed... + def stringy: Exist[_ <: String] = (new Exist[String]).foo + def fbounded: (ExistF[t] forSome {type t <: ExistF[t] }) = (new MyExist).foo + def indir: ExistIndir[_ <: String, _ <: String] = (new ExistIndir[String, String]).foo +}
\ No newline at end of file diff --git a/test/files/pos/t7377/Macro_1.scala b/test/files/pos/t7377/Macro_1.scala index 9f51248095..b38687c8b3 100644 --- a/test/files/pos/t7377/Macro_1.scala +++ b/test/files/pos/t7377/Macro_1.scala @@ -2,6 +2,6 @@ import language.experimental._ import scala.reflect.macros.blackbox.Context object M { - def noopImpl[A](c: Context)(expr: c.Expr[A]): c.Expr[A] = c.Expr(c.typecheck(c.resetLocalAttrs(expr.tree))) + def noopImpl[A](c: Context)(expr: c.Expr[A]): c.Expr[A] = c.Expr(c.typecheck(c.untypecheck(expr.tree))) def noop[A](expr: A): A = macro noopImpl[A] } diff --git a/test/files/pos/t7516/A_1.scala b/test/files/pos/t7516/A_1.scala index 3bba19966d..3bd477dcda 100644 --- a/test/files/pos/t7516/A_1.scala +++ b/test/files/pos/t7516/A_1.scala @@ -3,7 +3,7 @@ import scala.reflect._,macros._, scala.language.experimental.macros object A { def impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[List[T]] = { val r = c.universe.reify { List(t.splice) } - c.Expr[List[T]]( c.resetLocalAttrs(r.tree) ) + c.Expr[List[T]]( c.untypecheck(r.tree) ) } def demo[T](t: T): List[T] = macro impl[T] } diff --git a/test/files/pos/t8064/Macro_1.scala b/test/files/pos/t8064/Macro_1.scala index dd42950b34..9f1e6955b4 100644 --- a/test/files/pos/t8064/Macro_1.scala +++ b/test/files/pos/t8064/Macro_1.scala @@ -5,6 +5,6 @@ object Macro { def apply(a: Any): Any = macro impl def impl(c: Context)(a: c.Tree): c.Tree = { - c.resetLocalAttrs(a) + c.untypecheck(a) } } diff --git a/test/files/pos/t8207.scala b/test/files/pos/t8207.scala new file mode 100644 index 0000000000..680b40f379 --- /dev/null +++ b/test/files/pos/t8207.scala @@ -0,0 +1,6 @@ +class C { me => + import me.{toString => ts} + locally(this: me.type) + trait T + type X = me.T +} diff --git a/test/files/pos/t8237.scala b/test/files/pos/t8237.scala new file mode 100644 index 0000000000..005089079e --- /dev/null +++ b/test/files/pos/t8237.scala @@ -0,0 +1,29 @@ +import scala.language.higherKinds + +object TestExplicit { + trait TC[A] + def fTt[A,E[X] <: List[X]](a: A)(implicit tt: TC[E[A]]) = a + implicit def tc[T]: TC[T] = ??? + + // Typechecking results in SOE in TypeVar.isGround + fTt(1)(tc) + // fun = TestExplicit.this.fTt[Int, E](1) + // args = TestExplicit.this.tc[E[Int]] + // argTpes.head.instantiateTypeParams = TC[?E#1[Int]] + // formals.head.instantiateTypeParams = TC[?E#2[Int]] + // (where ?E#1 and ?E#2 as distinct AppliedTypeVars that resulted + // from separate applications of type args to the same HKTypeVar, ?E) + // + // As we check if the argument conforms to the formal, we would have + // AppliedTypeVars sharing the same TypeConstraints on the LHS and RHS, + // which leads to a cyclic constraint. +} + +object TestImplicit { + trait TC[A] + def fTt[A,E[X] <: List[X]](a: A)(implicit tt: TC[E[A]]) = a + implicit def tc[T]: TC[T] = ??? + + // Oddly enough, this one works. + fTt(1) +} diff --git a/test/files/pos/t8237b.scala b/test/files/pos/t8237b.scala new file mode 100644 index 0000000000..52bb310e8b --- /dev/null +++ b/test/files/pos/t8237b.scala @@ -0,0 +1,10 @@ +import scala.language.higherKinds +import scala.reflect.runtime.universe._ +object Test { + + def fTt[A,E[X]<:List[X]](a: A)(implicit tt: TypeTag[E[A]]) = a + + trait TC[A] + implicit def TCListInt[A]: TC[A] = ??? + fTt(1) +} 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 624479480d..f038d8714f 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 @@ -3,7 +3,7 @@ import scala.reflect.macros.blackbox.Context object Impls { def foo(c: Context)(x: c.Expr[Int]) = { import c.universe._ - val x1 = c.Expr[Int](c.resetAllAttrs(x.tree)) + val x1 = c.Expr[Int](c.untypecheck(x.tree)) c.Expr[Int](Literal(Constant(c.eval(x1)))) } } diff --git a/test/files/run/reflection-magicsymbols-invoke.check b/test/files/run/reflection-magicsymbols-invoke.check index 352aefaf25..43116858de 100644 --- a/test/files/run/reflection-magicsymbols-invoke.check +++ b/test/files/run/reflection-magicsymbols-invoke.check @@ -28,7 +28,7 @@ it's important to print the list of AnyVal's members if some of them change (possibly, adding and/or removing magic symbols), we must update this test constructor AnyVal: ()AnyVal method getClass: ()Class[_ <: AnyVal] -testing AnyVal.<init>: class java.lang.InstantiationException: null +testing AnyVal.<init>: class scala.ScalaReflectionException: unsupported symbol constructor AnyVal when invoking bytecodeless method mirror for scala.AnyVal.<init>(): AnyVal (bound to null) testing AnyVal.getClass: class scala.ScalaReflectionException: expected a member of class Integer, you provided method scala.AnyVal.getClass ============ AnyRef diff --git a/test/files/run/t6411a.check b/test/files/run/t6411a.check new file mode 100644 index 0000000000..9226146195 --- /dev/null +++ b/test/files/run/t6411a.check @@ -0,0 +1,96 @@ +meth = method yg_1 +as seen by Scala reflection: def yg_1[T](y: Y[T]): T +as seen by Java reflection: public java.lang.Object a$.yg_1(java.lang.Object) +result = 1 +meth = method yg_1 +as seen by Scala reflection: def yg_1[T](y: Y[T]): T +as seen by Java reflection: public java.lang.Object a$.yg_1(java.lang.Object) +result = 1 +meth = method yi_2 +as seen by Scala reflection: def yi_2(y: Y[Int]): Int +as seen by Java reflection: public int a$.yi_2(java.lang.Integer) +result = 2 +meth = method yi_2 +as seen by Scala reflection: def yi_2(y: Y[Int]): Int +as seen by Java reflection: public int a$.yi_2(java.lang.Integer) +result = class java.lang.IllegalArgumentException: argument type mismatch +meth = method ys_3 +as seen by Scala reflection: def ys_3(y: Y[String]): String +as seen by Java reflection: public java.lang.String a$.ys_3(java.lang.String) +result = class java.lang.IllegalArgumentException: argument type mismatch +meth = method ys_3 +as seen by Scala reflection: def ys_3(y: Y[String]): String +as seen by Java reflection: public java.lang.String a$.ys_3(java.lang.String) +result = 3 +meth = method ya_4 +as seen by Scala reflection: def ya_4(ys: Array[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.ya_4(Y[]) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method ya_4 +as seen by Scala reflection: def ya_4(ys: Array[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.ya_4(Y[]) +result = List(4) +meth = method yl_5 +as seen by Scala reflection: def yl_5(ys: List[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.yl_5(scala.collection.immutable.List) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method yl_5 +as seen by Scala reflection: def yl_5(ys: List[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.yl_5(scala.collection.immutable.List) +result = List(5) +meth = method yni_7 +as seen by Scala reflection: def yni_7(y: => Y[Int]): Int +as seen by Java reflection: public int a$.yni_7(scala.Function0) +result = 7 +meth = method yns_8 +as seen by Scala reflection: def yns_8(y: => Y[String]): String +as seen by Java reflection: public java.lang.String a$.yns_8(scala.Function0) +result = 8 +meth = method zg_1 +as seen by Scala reflection: def zg_1[T](z: Z[T]): T +as seen by Java reflection: public java.lang.Object a$.zg_1(Z) +result = 1 +meth = method zg_1 +as seen by Scala reflection: def zg_1[T](z: Z[T]): T +as seen by Java reflection: public java.lang.Object a$.zg_1(Z) +result = 1 +meth = method zi_2 +as seen by Scala reflection: def zi_2(z: Z[Int]): Int +as seen by Java reflection: public int a$.zi_2(Z) +result = 2 +meth = method zi_2 +as seen by Scala reflection: def zi_2(z: Z[Int]): Int +as seen by Java reflection: public int a$.zi_2(Z) +result = class java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer +meth = method zs_3 +as seen by Scala reflection: def zs_3(z: Z[String]): String +as seen by Java reflection: public java.lang.String a$.zs_3(Z) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method zs_3 +as seen by Scala reflection: def zs_3(z: Z[String]): String +as seen by Java reflection: public java.lang.String a$.zs_3(Z) +result = 3 +meth = method za_4 +as seen by Scala reflection: def za_4(zs: Array[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.za_4(Z[]) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method za_4 +as seen by Scala reflection: def za_4(zs: Array[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.za_4(Z[]) +result = List(4) +meth = method zl_5 +as seen by Scala reflection: def zl_5(zs: List[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.zl_5(scala.collection.immutable.List) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method zl_5 +as seen by Scala reflection: def zl_5(zs: List[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.zl_5(scala.collection.immutable.List) +result = List(5) +meth = method zni_7 +as seen by Scala reflection: def zni_7(z: => Z[Int]): Int +as seen by Java reflection: public int a$.zni_7(scala.Function0) +result = 7 +meth = method zns_8 +as seen by Scala reflection: def zns_8(z: => Z[String]): String +as seen by Java reflection: public java.lang.String a$.zns_8(scala.Function0) +result = 8 diff --git a/test/files/run/t6411a.scala b/test/files/run/t6411a.scala new file mode 100644 index 0000000000..3bfeac2890 --- /dev/null +++ b/test/files/run/t6411a.scala @@ -0,0 +1,81 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.language.reflectiveCalls + +class Y[T](val i: T) extends AnyVal { + override def toString = s"Y($i)" +} +class Z[T](val i: T) extends AnyRef { + override def toString = s"Z($i)" +} + +object a { + def yg_1[T](y: Y[T]) = y.i + def yi_2(y: Y[Int]) = y.i + def ys_3(y: Y[String]) = y.i + def ya_4(ys: Array[Y[String]]) = ys.toList.map(_.i) + def yl_5(ys: List[Y[String]]) = ys.map(_.i) + def yv_6(ys: Y[String]*) = ys.toList.map(_.i) + def yni_7(y: => Y[Int]) = y.i + def yns_8(y: => Y[String]) = y.i + + def zg_1[T](z: Z[T]) = z.i + def zi_2(z: Z[Int]) = z.i + def zs_3(z: Z[String]) = z.i + def za_4(zs: Array[Z[String]]) = zs.toList.map(_.i) + def zl_5(zs: List[Z[String]]) = zs.map(_.i) + def zv_6(zs: Z[String]*) = zs.toList.map(_.i) + def zni_7(z: => Z[Int]) = z.i + def zns_8(z: => Z[String]) = z.i +} + +object Test extends App { + def test(methName: String, arg: Any) = { + val moduleA = cm.reflect(a) + val msym = moduleA.symbol.typeSignature.declaration(TermName(methName)).asMethod + println(s"meth = $msym") + val mmirror = moduleA.reflectMethod(msym) + val mresult = + try { mmirror(arg) } + catch { + case ex: Exception => + val ex1 = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex) + s"${ex1.getClass}: ${ex1.getMessage}" + } + println(s"as seen by Scala reflection: ${msym.asInstanceOf[scala.reflect.internal.Symbols#Symbol].defString}") + println(s"as seen by Java reflection: ${mmirror.asInstanceOf[{val jmeth: java.lang.reflect.Method}].jmeth}") + println(s"result = $mresult") + } + + test("yg_1", new Y(1)) + test("yg_1", new Y("1")) + test("yi_2", new Y(2)) + test("yi_2", new Y("2")) + test("ys_3", new Y(3)) + test("ys_3", new Y("3")) + test("ya_4", Array(new Y(4))) + test("ya_4", Array(new Y("4"))) + test("yl_5", List(new Y(5))) + test("yl_5", List(new Y("5"))) + // FIXME: disabled because of SI-7056 + // test("yv_6", new Y(6)) + // test("yv_6", new Y("6")) + test("yni_7", new Y(7)) + test("yns_8", new Y("8")) + + test("zg_1", new Z(1)) + test("zg_1", new Z("1")) + test("zi_2", new Z(2)) + test("zi_2", new Z("2")) + test("zs_3", new Z(3)) + test("zs_3", new Z("3")) + test("za_4", Array(new Z(4))) + test("za_4", Array(new Z("4"))) + test("zl_5", List(new Z(5))) + test("zl_5", List(new Z("5"))) + // FIXME: disabled because of SI-7056 + // test("zv_6", new Z(6)) + // test("zv_6", new Z("6")) + test("zni_7", new Z(7)) + test("zns_8", new Z("8")) +}
\ No newline at end of file diff --git a/test/files/run/t6411b.check b/test/files/run/t6411b.check new file mode 100644 index 0000000000..e20bed6d8d --- /dev/null +++ b/test/files/run/t6411b.check @@ -0,0 +1 @@ +Bar(Foo(3)) diff --git a/test/files/run/t6411b.scala b/test/files/run/t6411b.scala new file mode 100644 index 0000000000..af30108826 --- /dev/null +++ b/test/files/run/t6411b.scala @@ -0,0 +1,12 @@ +import scala.reflect.runtime.universe._ + +case class Foo(n: Int) extends AnyVal +case class Bar(foo: Foo) + +object Test extends App { + val mirror = runtimeMirror(getClass.getClassLoader) + val cm = mirror.reflectClass(typeOf[Bar].typeSymbol.asClass) + val ctor = typeOf[Bar].declaration(nme.CONSTRUCTOR).asMethod + val ctorm = cm.reflectConstructor(ctor) + println(ctorm(Foo(3))) +}
\ No newline at end of file diff --git a/test/files/run/t7240/Macros_1.scala b/test/files/run/t7240/Macros_1.scala index 019ddf7cd6..c6e976038d 100644 --- a/test/files/run/t7240/Macros_1.scala +++ b/test/files/run/t7240/Macros_1.scala @@ -41,7 +41,7 @@ object Bakery { def constructor = Apply(Select(New(Ident(newTypeName("eval"))), nme.CONSTRUCTOR), List()) c.eval(c.Expr[Any]( - c.resetAllAttrs(Block(composeDSL(Literal(Constant(1))), constructor)))) + c.untypecheck(Block(composeDSL(Literal(Constant(1))), constructor)))) c.Expr[Any](Literal(Constant(1))) } diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check index d03ee3a6cf..b7443aa0c4 100644 --- a/test/files/run/t7319.check +++ b/test/files/run/t7319.check @@ -21,7 +21,7 @@ scala> convert(Some[Int](0)) --- because --- argument expression's type is not compatible with formal parameter type; found : Some[Int] - required: ?F forSome { type _$1 <: ?F forSome { type _$2 } } + required: ?F[_$1] forSome { type _$1 <: ?F[_$2] forSome { type _$2 } } convert(Some[Int](0)) ^ <console>:12: error: type mismatch; diff --git a/test/files/run/t7328.check b/test/files/run/t7328.check new file mode 100644 index 0000000000..e386fe70d9 --- /dev/null +++ b/test/files/run/t7328.check @@ -0,0 +1,4 @@ +Foo +Foo(3) +Foo(3) +Foo(5) diff --git a/test/files/run/t7328.scala b/test/files/run/t7328.scala new file mode 100644 index 0000000000..8816fa2347 --- /dev/null +++ b/test/files/run/t7328.scala @@ -0,0 +1,18 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} + +case class Foo(x: Int) extends AnyVal +case class Bar(foo: Foo) + +object Test extends App { + val foo = typeOf[Bar].declaration(TermName("foo")).asMethod + println(foo.returnType) // Foo + + val bar = Bar(Foo(3)) + println(bar.foo) // Foo(3) + + val im = cm.reflect(bar) + println(im.reflectField(foo).get) // incorrectly gives java.lang.Integer(3) not Foo(3) + im.reflectField(foo).set(Foo(5)) // java.lang.IllegalArgumentException: Can not set int field Bar.foo to Foo + println(im.reflectMethod(foo)()) // incorrectly gives java.lang.Integer(3) not Foo(3) +}
\ No newline at end of file diff --git a/test/files/run/t7570a.check b/test/files/run/t7570a.check new file mode 100644 index 0000000000..3cc58df837 --- /dev/null +++ b/test/files/run/t7570a.check @@ -0,0 +1 @@ +C diff --git a/test/files/run/t7570a.scala b/test/files/run/t7570a.scala new file mode 100644 index 0000000000..b8b4ddeaf2 --- /dev/null +++ b/test/files/run/t7570a.scala @@ -0,0 +1,11 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox +import definitions._ +import Flag._ + +object Test extends App { + val tb = cm.mkToolBox() + val csym = tb.define(q"""class C { override def toString = "C" }""") + println(tb.eval(q"new $csym")) +}
\ No newline at end of file diff --git a/test/files/run/t7570b.check b/test/files/run/t7570b.check new file mode 100644 index 0000000000..0c28247025 --- /dev/null +++ b/test/files/run/t7570b.check @@ -0,0 +1 @@ +compilation failed: reflective toolbox has failed: cannot have free terms in a top-level definition diff --git a/test/files/run/t7570b.scala b/test/files/run/t7570b.scala new file mode 100644 index 0000000000..f1db193186 --- /dev/null +++ b/test/files/run/t7570b.scala @@ -0,0 +1,17 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, ToolBoxError} +import definitions._ +import Flag._ + +object Test extends App { + val tb = cm.mkToolBox() + val msg = build.newFreeTerm("msg", "C") + build.setTypeSignature(msg, typeOf[String]) + try { + val csym = tb.define(q"""class C { override def toString = $msg }""") + println(tb.eval(q"new $csym")) + } catch { + case ToolBoxError(message, _) => println(s"compilation failed: $message") + } +}
\ No newline at end of file diff --git a/test/files/run/t7570c.check b/test/files/run/t7570c.check new file mode 100644 index 0000000000..61e659d9e0 --- /dev/null +++ b/test/files/run/t7570c.check @@ -0,0 +1,2 @@ +(class C,true,false,false) +(object D,false,true,false) diff --git a/test/files/run/t7570c.scala b/test/files/run/t7570c.scala new file mode 100644 index 0000000000..a5bdbffe18 --- /dev/null +++ b/test/files/run/t7570c.scala @@ -0,0 +1,13 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, ToolBoxError} +import definitions._ +import Flag._ + +object Test extends App { + val tb = cm.mkToolBox() + val csym = tb.define(q"""class C { override def toString = "C" }""") + println((csym, csym.isClass, csym.isModule, csym.isModuleClass)) + val dsym = tb.define(q"""object D { override def toString = "D" }""".asInstanceOf[ModuleDef]) + println((dsym, dsym.isClass, dsym.isModule, dsym.isModuleClass)) +}
\ No newline at end of file diff --git a/test/disabled/run/t7843-jsr223-service.check b/test/files/run/t7843-jsr223-service.check index a668df3567..a668df3567 100644 --- a/test/disabled/run/t7843-jsr223-service.check +++ b/test/files/run/t7843-jsr223-service.check diff --git a/test/files/run/t7843-jsr223-service.scala b/test/files/run/t7843-jsr223-service.scala new file mode 100644 index 0000000000..31112212ea --- /dev/null +++ b/test/files/run/t7843-jsr223-service.scala @@ -0,0 +1,8 @@ +import scala.tools.nsc.interpreter.IMain + +object Test extends App { + val engine = new IMain.Factory getScriptEngine() + engine.asInstanceOf[IMain].settings.usejavacp.value = true + engine put ("n", 10) + engine eval "1 to n.asInstanceOf[Int] foreach print" +} diff --git a/test/files/run/t7933.check b/test/files/run/t7933.check new file mode 100644 index 0000000000..317e9677c3 --- /dev/null +++ b/test/files/run/t7933.check @@ -0,0 +1,2 @@ +hello +hello diff --git a/test/files/run/t7933.scala b/test/files/run/t7933.scala new file mode 100644 index 0000000000..b06dffcd80 --- /dev/null +++ b/test/files/run/t7933.scala @@ -0,0 +1,11 @@ +import scala.tools.nsc.interpreter.IMain + +object Test extends App { + val engine = new IMain.Factory getScriptEngine() + engine.asInstanceOf[IMain].settings.usejavacp.value = true + val res2 = engine.asInstanceOf[javax.script.Compilable] + res2 compile "8" eval() + val res5 = res2 compile """println("hello") ; 8""" + res5 eval() + res5 eval() +} diff --git a/test/files/run/t8245.scala b/test/files/run/t8245.scala new file mode 100644 index 0000000000..d44defbb9e --- /dev/null +++ b/test/files/run/t8245.scala @@ -0,0 +1,14 @@ +object Test { + def foo(o: Option[Int]): Int = { + lazy val i: Int = { + def local: Int = {if ("".isEmpty) return 42; -42} + assert(local == 42) + o.getOrElse(return -1) + } + i + 1 + } + + def main(args: Array[String]) { + assert(foo(None) == -1) + } +} diff --git a/test/junit/scala/collection/SetMapConsistencyTest.scala b/test/junit/scala/collection/SetMapConsistencyTest.scala index 7bb8ca958b..0d6f43db06 100644 --- a/test/junit/scala/collection/SetMapConsistencyTest.scala +++ b/test/junit/scala/collection/SetMapConsistencyTest.scala @@ -478,7 +478,7 @@ class SetMapConsistencyTest { } @Test - def si8213() { + def testSI8213() { val am = new scala.collection.mutable.AnyRefMap[String, Int] for (i <- 0 until 1024) am += i.toString -> i am.getOrElseUpdate("1024", { am.clear; -1 }) @@ -488,4 +488,23 @@ class SetMapConsistencyTest { lm.getOrElseUpdate(1024, { lm.clear; -1 }) assert(lm == scala.collection.mutable.LongMap(1024L -> -1)) } + + // Mutating when an iterator is in the wild shouldn't produce random junk in the iterator + // Todo: test all sets/maps this way + @Test + def testSI8154() { + def f() = { + val xs = scala.collection.mutable.AnyRefMap[String, Int]("a" -> 1) + val it = xs.iterator + it.hasNext + xs.clear() + + if (it.hasNext) Some(it.next) + else None + } + assert(f() match { + case Some((a,b)) if (a==null || b==null) => false + case _ => true + }) + } } diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index a3699a4eeb..b42e9a07cb 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -69,6 +69,7 @@ class SymbolTableForUnitTesting extends SymbolTable { // Members declared in scala.reflect.internal.Required def picklerPhase: scala.reflect.internal.Phase = SomePhase + def erasurePhase: scala.reflect.internal.Phase = SomePhase // Members declared in scala.reflect.internal.SymbolTable def currentRunId: Int = 1 diff --git a/test/pending/run/idempotency-partial-functions.scala b/test/pending/run/idempotency-partial-functions.scala index e673da5a29..b26c442599 100644 --- a/test/pending/run/idempotency-partial-functions.scala +++ b/test/pending/run/idempotency-partial-functions.scala @@ -22,7 +22,7 @@ object Test extends App { val tb = cm.mkToolBox() val tpartials = tb.typecheck(partials.tree) println(tpartials) - val rtpartials = tb.resetAllAttrs(tpartials) + val rtpartials = tb.untypecheck(tpartials) println(tb.eval(rtpartials)) } Test.main(null)
\ No newline at end of file |