diff options
Diffstat (limited to 'src/compiler')
13 files changed, 264 insertions, 155 deletions
diff --git a/src/compiler/scala/reflect/internal/AnnotationInfos.scala b/src/compiler/scala/reflect/internal/AnnotationInfos.scala index 085537fc9f..5bdd04e544 100644 --- a/src/compiler/scala/reflect/internal/AnnotationInfos.scala +++ b/src/compiler/scala/reflect/internal/AnnotationInfos.scala @@ -18,8 +18,6 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable => // the Symbol's field directly. For Type, a new AnnotatedType is // created which wraps the original type. trait Annotatable[Self] { - self: Self => - /** The annotations on this type. */ def annotations: List[AnnotationInfo] // Annotations on this type. def setAnnotations(annots: List[AnnotationInfo]): Self // Replace annotations with argument list. diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 724e5bf628..240dedc658 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -3054,7 +3054,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def originalEnclosingMethod = this override def owner: Symbol = - abort("no-symbol does not have an owner (this is a bug: scala " + scala.util.Properties.versionString + ")") + abort("no-symbol does not have an owner") override def typeConstructor: Type = abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)") } diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 81582db5f2..808198598b 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -3068,7 +3068,8 @@ trait Types extends api.Types { self: SymbolTable => } def registerTypeEquality(tp: Type, typeVarLHS: Boolean): Boolean = { - //println("regTypeEq: "+(safeToString, debugString(tp), typeVarLHS)) //@MDEBUG +// println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (constr.instValid) "IV" else "")) //@MDEBUG +// println("constr: "+ constr) def checkIsSameType(tp: Type) = if(typeVarLHS) constr.inst =:= tp else tp =:= constr.inst @@ -3127,7 +3128,7 @@ trait Types extends api.Types { self: SymbolTable => } def originName = { val name = origin.typeSymbolDirect.decodedName - if (name contains "_$") origin.typeSymbolDirect.decodedName else name + if (name contains "_$") origin.typeSymbolDirect.decodedName else name // wait, what? - what? } def originLocation = { val sym = origin.typeSymbolDirect @@ -3146,7 +3147,7 @@ trait Types extends api.Types { self: SymbolTable => protected def typeVarString = originName override def safeToString = ( if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" - else if (constr.inst ne NoType) "" + constr.inst + else if (constr.inst ne NoType) "=?" + constr.inst else (if(untouchable) "!?" else "?") + levelString + originName ) override def kind = "TypeVar" @@ -4925,7 +4926,23 @@ trait Types extends api.Types { self: SymbolTable => override def hashCode = tp1.hashCode * 41 + tp2.hashCode override def equals(other: Any) = other match { case stp: SubTypePair => - (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) + // suspend TypeVars in types compared by =:=, + // since we don't want to mutate them simply to check whether a subtype test is pending + // in addition to making subtyping "more correct" for type vars, + // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) + // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) + @inline def suspend(tp: Type) = + if (tp.isGround) null else suspendTypeVarsInType(tp) + @inline def revive(suspension: List[TypeVar]) = + if (suspension ne null) suspension foreach (_.suspended = false) + + val suspensions = Array(tp1, stp.tp1, tp2, stp.tp2) map suspend + + val sameTypes = (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) + + suspensions foreach revive + + sameTypes case _ => false } diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl index 599936f6f8..85bb5f2056 100644 --- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl @@ -9,10 +9,19 @@ ############################################################################## findScalaHome () { - # see #2092 + # see SI-2092 local SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done - ( cd -P "$( dirname "$SOURCE" )"/.. && pwd ) + local bindir="$( dirname "$SOURCE" )" + if [[ -d "$bindir"/.. ]]; then + ( cd -P "$bindir"/.. && pwd ) + else + # See SI-5792 + local dir=$(dirname "${BASH_SOURCE[0]}") + local link=$(dirname "$(readlink "${BASH_SOURCE[0]}")") + local path="$dir/$link/.." + ( cd "$path" && pwd ) + fi } execCommand () { [[ -n $SCALA_RUNNER_DEBUG ]] && echo "" && for arg in "$@@"; do echo "$arg"; done && echo ""; diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index aa8f469513..225afaf0fb 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -274,8 +274,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // we can exclude lateFINAL. Such symbols are eligible for inlining, but to
// avoid breaking proxy software which depends on subclassing, we do not
// emit ACC_FINAL.
+ // Nested objects won't receive ACC_FINAL in order to allow for their overloading.
+
val finalFlag = (
- ((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0)
+ (sym.hasFlag(Flags.FINAL) || isTopLevelModule(sym))
&& !sym.enclClass.isInterface
&& !sym.isClassConstructor
&& !sym.isMutable // lazy vals and vars both
@@ -649,8 +651,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val INNER_CLASSES_FLAGS =
(asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_PRIVATE | asm.Opcodes.ACC_PROTECTED |
- asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL |
- asm.Opcodes.ACC_INTERFACE | asm.Opcodes.ACC_ABSTRACT)
+ asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_INTERFACE | asm.Opcodes.ACC_ABSTRACT)
val PublicStatic = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC
val PublicStaticFinal = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 7d3249a7d3..b5ce7588f6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -191,7 +191,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val MIN_SWITCH_DENSITY = 0.7 val INNER_CLASSES_FLAGS = - (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT) + (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_INTERFACE | ACC_ABSTRACT) val PublicStatic = ACC_PUBLIC | ACC_STATIC val PublicStaticFinal = ACC_PUBLIC | ACC_STATIC | ACC_FINAL @@ -1976,8 +1976,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // we can exclude lateFINAL. Such symbols are eligible for inlining, but to // avoid breaking proxy software which depends on subclassing, we do not // emit ACC_FINAL. + // Nested objects won't receive ACC_FINAL in order to allow for their overloading. + val finalFlag = ( - ((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0) + (sym.hasFlag(Flags.FINAL) || isTopLevelModule(sym)) && !sym.enclClass.isInterface && !sym.isClassConstructor && !sym.isMutable // lazy vals and vars both diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 2b26f1590d..e8387c80f5 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -75,7 +75,8 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD val stats1 = stats.flatMap(_ match { case Block(List(d1@DefDef(_, n1, _, _, _, _)), d2@DefDef(_, n2, _, _, _, _)) if (nme.newLazyValSlowComputeName(n2) == n1) => List(d1, d2) - case stat => List(stat) + case stat => + List(stat) }) treeCopy.Block(block1, stats1, expr) @@ -138,7 +139,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD case ValDef(_, _, _, _) if !sym.owner.isModule && !sym.owner.isClass => deriveValDef(tree) { rhs0 => - val rhs = super.transform(rhs0) + val rhs = transform(rhs0) if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 4ce5985af8..79b9317f20 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -903,14 +903,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { if (sym.isLazy && !isEmpty && !clazz.isImplClass) { assert(fieldOffset contains sym, sym) - deriveDefDef(stat)(rhs => - if (isUnit) - mkLazyDef(clazz, sym, List(rhs), UNIT, fieldOffset(sym)) - else { - val Block(stats, res) = rhs + deriveDefDef(stat) { + case t if isUnit => mkLazyDef(clazz, sym, List(t), UNIT, fieldOffset(sym)) + + case Block(stats, res) => mkLazyDef(clazz, sym, stats, Select(This(clazz), res.symbol), fieldOffset(sym)) - } - ) + + case t => t // pass specialized lazy vals through + } } else if (needsInitFlag(sym) && !isEmpty && !clazz.hasFlag(IMPLCLASS | TRAIT)) { assert(fieldOffset contains sym, sym) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 7e780304e7..07a10ecb1f 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -666,16 +666,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // log("other concrete " + m) forwardToOverload(m) - } else if (m.isValue && !m.isMethod) { // concrete value definition + } else if (m.isMethod && m.hasFlag(LAZY)) { + forwardToOverload(m) + + } else if (m.isValue && !m.isMethod && !m.hasFlag(LAZY)) { // concrete value definition def mkAccessor(field: Symbol, name: Name) = { - val newFlags = (SPECIALIZED | m.getter(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR | LAZY) + val newFlags = (SPECIALIZED | m.getter(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR) // we rely on the super class to initialize param accessors val sym = sClass.newMethod(name, field.pos, newFlags) info(sym) = SpecializedAccessor(field) sym } def overrideIn(clazz: Symbol, sym: Symbol) = { - val newFlags = (sym.flags | OVERRIDE | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | PARAMACCESSOR | LAZY) + val newFlags = (sym.flags | OVERRIDE | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | PARAMACCESSOR) val sym1 = sym.cloneSymbol(clazz, newFlags) sym1 modifyInfo (_ asSeenFrom (clazz.tpe, sym1.owner)) } @@ -881,7 +884,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the specialized overload of `m`, in the given environment. */ private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { - val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | ACCESSOR | LAZY) + val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR) // this method properly duplicates the symbol's info ( sym.cloneSymbol(owner, newFlags, specializedName(sym, env)) modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 722440349a..793b85da18 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1133,16 +1133,27 @@ trait Implicits { * An EmptyTree is returned if materialization fails. */ private def tagOfType(pre: Type, tp: Type, tagClass: Symbol): SearchResult = { - def success(arg: Tree) = + def success(arg: Tree) = { + def isMacroException(msg: String): Boolean = + // [Eugene] very unreliable, ask Hubert about a better way + msg contains "exception during macro expansion" + + def processMacroExpansionError(pos: Position, msg: String): SearchResult = { + // giving up and reporting all macro exceptions regardless of their source + // this might lead to an avalanche of errors if one of your implicit macros misbehaves + if (isMacroException(msg)) context.error(pos, msg) + failure(arg, "failed to typecheck the materialized tag: %n%s".format(msg), pos) + } + try { val tree1 = typed(atPos(pos.focus)(arg)) - def isErroneous = tree exists (_.isErroneous) - if (context.hasErrors) failure(tp, "failed to typecheck the materialized typetag: %n%s".format(context.errBuffer.head.errMsg), context.errBuffer.head.errPos) + if (context.hasErrors) processMacroExpansionError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg) else new SearchResult(tree1, EmptyTreeTypeSubstituter) } catch { case ex: TypeError => - failure(arg, "failed to typecheck the materialized typetag: %n%s".format(ex.msg), ex.pos) + processMacroExpansionError(ex.pos, ex.msg) } + } val prefix = ( // ClassTags only exist for scala.reflect.mirror, so their materializer diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 353514c397..c10901cdce 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -641,143 +641,181 @@ trait Macros extends Traces { */ private type MacroRuntime = List[Any] => Any private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, Option[MacroRuntime]] - private def macroRuntime(macroDef: Symbol): Option[MacroRuntime] = - macroRuntimesCache.getOrElseUpdate(macroDef, { - val runtime = { - macroTraceVerbose("looking for macro implementation: ")(macroDef) - macroTraceVerbose("macroDef is annotated with: ")(macroDef.annotations) - - val ann = macroDef.getAnnotation(MacroImplAnnotation) - if (ann == None) { - macroTraceVerbose("@macroImpl annotation is missing (this means that macro definition failed to typecheck)")(macroDef) - return None - } + private lazy val fastTrack: Map[Symbol, MacroRuntime] = { + import scala.reflect.api.Universe + import scala.reflect.makro.internal._ + Map( // challenge: how can we factor out the common code? Does not seem to be easy. + MacroInternal_materializeArrayTag -> (args => { + assert(args.length == 3, args) + val c = args(0).asInstanceOf[MacroContext] + materializeArrayTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]]) + }), + MacroInternal_materializeErasureTag -> (args => { + assert(args.length == 3, args) + val c = args(0).asInstanceOf[MacroContext] + materializeErasureTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]]) + }), + MacroInternal_materializeClassTag -> (args => { + assert(args.length == 3, args) + val c = args(0).asInstanceOf[MacroContext] + materializeClassTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]]) + }), + MacroInternal_materializeTypeTag -> (args => { + assert(args.length == 3, args) + val c = args(0).asInstanceOf[MacroContext] + materializeTypeTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]]) + }), + MacroInternal_materializeConcreteTypeTag -> (args => { + assert(args.length == 3, args) + val c = args(0).asInstanceOf[MacroContext] + materializeConcreteTypeTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]]) + }) + ) + } + private def macroRuntime(macroDef: Symbol): Option[MacroRuntime] = { + macroTraceVerbose("looking for macro implementation: ")(macroDef) + if (fastTrack contains macroDef) { + macroLogVerbose("macro expansion serviced by a fast track") + Some(fastTrack(macroDef)) + } else { + macroRuntimesCache.getOrElseUpdate(macroDef, { + val runtime = { + macroTraceVerbose("looking for macro implementation: ")(macroDef) + macroTraceVerbose("macroDef is annotated with: ")(macroDef.annotations) - val macroImpl = ann.get.args(0).symbol - if (macroImpl == NoSymbol) { - macroTraceVerbose("@macroImpl annotation is malformed (this means that macro definition failed to typecheck)")(macroDef) - return None - } + val ann = macroDef.getAnnotation(MacroImplAnnotation) + if (ann == None) { + macroTraceVerbose("@macroImpl annotation is missing (this means that macro definition failed to typecheck)")(macroDef) + return None + } - macroLogVerbose("resolved implementation %s at %s".format(macroImpl, macroImpl.pos)) - if (macroImpl.isErroneous) { - macroTraceVerbose("macro implementation is erroneous (this means that either macro body or macro implementation signature failed to typecheck)")(macroDef) - return None - } + val macroImpl = ann.get.args(0).symbol + if (macroImpl == NoSymbol) { + macroTraceVerbose("@macroImpl annotation is malformed (this means that macro definition failed to typecheck)")(macroDef) + return None + } - def loadMacroImpl(macroMirror: Mirror): Option[(Object, macroMirror.Symbol)] = { - try { - // this logic relies on the assumptions that were valid for the old macro prototype - // namely that macro implementations can only be defined in top-level classes and modules - // with the new prototype that materialized in a SIP, macros need to be statically accessible, which is different - // for example, a macro def could be defined in a trait that is implemented by an object - // there are some more clever cases when seemingly non-static method ends up being statically accessible - // however, the code below doesn't account for these guys, because it'd take a look of time to get it right - // for now I leave it as a todo and move along to more the important stuff - - macroTraceVerbose("loading implementation class from %s: ".format(macroMirror))(macroImpl.owner.fullName) - macroTraceVerbose("classloader is: ")("%s of type %s".format(macroMirror.classLoader, if (macroMirror.classLoader != null) macroMirror.classLoader.getClass.toString else "primordial classloader")) - def inferClasspath(cl: ClassLoader) = cl match { - case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]" - case null => "[" + scala.tools.util.PathResolver.Environment.javaBootClassPath + "]" - case _ => "<unknown>" - } - macroTraceVerbose("classpath is: ")(inferClasspath(macroMirror.classLoader)) - - // [Eugene] relies on the fact that macro implementations can only be defined in static classes - // [Martin to Eugene] There's similar logic buried in Symbol#flatname. Maybe we can refactor? - def classfile(sym: Symbol): String = { - def recur(sym: Symbol): String = sym match { - case sym if sym.owner.isPackageClass => - val suffix = if (sym.isModuleClass) "$" else "" - sym.fullName + suffix - case sym => - val separator = if (sym.owner.isModuleClass) "" else "$" - recur(sym.owner) + separator + sym.javaSimpleName.toString + macroLogVerbose("resolved implementation %s at %s".format(macroImpl, macroImpl.pos)) + if (macroImpl.isErroneous) { + macroTraceVerbose("macro implementation is erroneous (this means that either macro body or macro implementation signature failed to typecheck)")(macroDef) + return None + } + + def loadMacroImpl(macroMirror: Mirror): Option[(Object, macroMirror.Symbol)] = { + try { + // this logic relies on the assumptions that were valid for the old macro prototype + // namely that macro implementations can only be defined in top-level classes and modules + // with the new prototype that materialized in a SIP, macros need to be statically accessible, which is different + // for example, a macro def could be defined in a trait that is implemented by an object + // there are some more clever cases when seemingly non-static method ends up being statically accessible + // however, the code below doesn't account for these guys, because it'd take a look of time to get it right + // for now I leave it as a todo and move along to more the important stuff + + macroTraceVerbose("loading implementation class from %s: ".format(macroMirror))(macroImpl.owner.fullName) + macroTraceVerbose("classloader is: ")("%s of type %s".format(macroMirror.classLoader, if (macroMirror.classLoader != null) macroMirror.classLoader.getClass.toString else "primordial classloader")) + def inferClasspath(cl: ClassLoader) = cl match { + case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]" + case null => "[" + scala.tools.util.PathResolver.Environment.javaBootClassPath + "]" + case _ => "<unknown>" } + macroTraceVerbose("classpath is: ")(inferClasspath(macroMirror.classLoader)) + + // [Eugene] relies on the fact that macro implementations can only be defined in static classes + // [Martin to Eugene] There's similar logic buried in Symbol#flatname. Maybe we can refactor? + def classfile(sym: Symbol): String = { + def recur(sym: Symbol): String = sym match { + case sym if sym.owner.isPackageClass => + val suffix = if (sym.isModuleClass) "$" else "" + sym.fullName + suffix + case sym => + val separator = if (sym.owner.isModuleClass) "" else "$" + recur(sym.owner) + separator + sym.javaSimpleName.toString + } - if (sym.isClass || sym.isModule) recur(sym) - else recur(sym.enclClass) - } + if (sym.isClass || sym.isModule) recur(sym) + else recur(sym.enclClass) + } - // [Eugene] this doesn't work for inner classes - // neither does macroImpl.owner.javaClassName, so I had to roll my own implementation - //val receiverName = macroImpl.owner.fullName - val implClassName = classfile(macroImpl.owner) - val implClassSymbol: macroMirror.Symbol = macroMirror.symbolForName(implClassName) + // [Eugene] this doesn't work for inner classes + // neither does macroImpl.owner.javaClassName, so I had to roll my own implementation + //val receiverName = macroImpl.owner.fullName + val implClassName = classfile(macroImpl.owner) + val implClassSymbol: macroMirror.Symbol = macroMirror.symbolForName(implClassName) - if (macroDebugVerbose) { - println("implClassSymbol is: " + implClassSymbol.fullNameString) + if (macroDebugVerbose) { + println("implClassSymbol is: " + implClassSymbol.fullNameString) - if (implClassSymbol != macroMirror.NoSymbol) { - val implClass = macroMirror.classToJava(implClassSymbol) - val implSource = implClass.getProtectionDomain.getCodeSource - println("implClass is %s from %s".format(implClass, implSource)) - println("implClassLoader is %s with classpath %s".format(implClass.getClassLoader, inferClasspath(implClass.getClassLoader))) + if (implClassSymbol != macroMirror.NoSymbol) { + val implClass = macroMirror.classToJava(implClassSymbol) + val implSource = implClass.getProtectionDomain.getCodeSource + println("implClass is %s from %s".format(implClass, implSource)) + println("implClassLoader is %s with classpath %s".format(implClass.getClassLoader, inferClasspath(implClass.getClassLoader))) + } } - } - val implObjSymbol = implClassSymbol.companionModule - macroTraceVerbose("implObjSymbol is: ")(implObjSymbol.fullNameString) + val implObjSymbol = implClassSymbol.companionModule + macroTraceVerbose("implObjSymbol is: ")(implObjSymbol.fullNameString) - if (implObjSymbol == macroMirror.NoSymbol) None - else { - // yet another reflection method that doesn't work for inner classes - //val receiver = macroMirror.companionInstance(receiverClass) - val implObj = try { - val implObjClass = java.lang.Class.forName(implClassName, true, macroMirror.classLoader) - implObjClass getField "MODULE$" get null - } catch { - case ex: NoSuchFieldException => macroTraceVerbose("exception when loading implObj: ")(ex); null - case ex: NoClassDefFoundError => macroTraceVerbose("exception when loading implObj: ")(ex); null - case ex: ClassNotFoundException => macroTraceVerbose("exception when loading implObj: ")(ex); null - } - - if (implObj == null) None + if (implObjSymbol == macroMirror.NoSymbol) None else { - val implMethSymbol = implObjSymbol.info.member(macroMirror.newTermName(macroImpl.name.toString)) - macroLogVerbose("implMethSymbol is: " + implMethSymbol.fullNameString) - macroLogVerbose("jimplMethSymbol is: " + macroMirror.methodToJava(implMethSymbol)) + // yet another reflection method that doesn't work for inner classes + //val receiver = macroMirror.companionInstance(receiverClass) + val implObj = try { + val implObjClass = java.lang.Class.forName(implClassName, true, macroMirror.classLoader) + implObjClass getField "MODULE$" get null + } catch { + case ex: NoSuchFieldException => macroTraceVerbose("exception when loading implObj: ")(ex); null + case ex: NoClassDefFoundError => macroTraceVerbose("exception when loading implObj: ")(ex); null + case ex: ClassNotFoundException => macroTraceVerbose("exception when loading implObj: ")(ex); null + } - if (implMethSymbol == macroMirror.NoSymbol) None + if (implObj == null) None else { - macroLogVerbose("successfully loaded macro impl as (%s, %s)".format(implObj, implMethSymbol)) - Some((implObj, implMethSymbol)) + val implMethSymbol = implObjSymbol.info.member(macroMirror.newTermName(macroImpl.name.toString)) + macroLogVerbose("implMethSymbol is: " + implMethSymbol.fullNameString) + macroLogVerbose("jimplMethSymbol is: " + macroMirror.methodToJava(implMethSymbol)) + + if (implMethSymbol == macroMirror.NoSymbol) None + else { + macroLogVerbose("successfully loaded macro impl as (%s, %s)".format(implObj, implMethSymbol)) + Some((implObj, implMethSymbol)) + } } } + } catch { + case ex: ClassNotFoundException => + macroTraceVerbose("implementation class failed to load: ")(ex.toString) + None } - } catch { - case ex: ClassNotFoundException => - macroTraceVerbose("implementation class failed to load: ")(ex.toString) - None } - } - val primary = loadMacroImpl(primaryMirror) - primary match { - case Some((implObj, implMethSymbol)) => - def runtime(args: List[Any]) = primaryMirror.invoke(implObj, implMethSymbol)(args: _*).asInstanceOf[Any] - Some(runtime _) - case None => - if (settings.XmacroFallbackClasspath.value != "") { - macroLogVerbose("trying to load macro implementation from the fallback mirror: %s".format(settings.XmacroFallbackClasspath.value)) - val fallback = loadMacroImpl(fallbackMirror) - fallback match { - case Some((implObj, implMethSymbol)) => - def runtime(args: List[Any]) = fallbackMirror.invoke(implObj, implMethSymbol)(args: _*).asInstanceOf[Any] - Some(runtime _) - case None => - None + val primary = loadMacroImpl(primaryMirror) + primary match { + case Some((implObj, implMethSymbol)) => + def runtime(args: List[Any]) = primaryMirror.invoke(implObj, implMethSymbol)(args: _*).asInstanceOf[Any] + Some(runtime _) + case None => + if (settings.XmacroFallbackClasspath.value != "") { + macroLogVerbose("trying to load macro implementation from the fallback mirror: %s".format(settings.XmacroFallbackClasspath.value)) + val fallback = loadMacroImpl(fallbackMirror) + fallback match { + case Some((implObj, implMethSymbol)) => + def runtime(args: List[Any]) = fallbackMirror.invoke(implObj, implMethSymbol)(args: _*).asInstanceOf[Any] + Some(runtime _) + case None => + None + } + } else { + None } - } else { - None - } + } } - } - if (runtime == None) macroDef setFlag IS_ERROR - runtime - }) + if (runtime == None) macroDef setFlag IS_ERROR + runtime + }) + } + } /** Should become private again once we're done with migrating typetag generation from implicits */ def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext { val mirror: global.type } = @@ -1203,8 +1241,10 @@ trait Macros extends Traces { if (relevancyThreshold == -1) None else { var relevantElements = realex.getStackTrace().take(relevancyThreshold + 1) - var framesTillReflectiveInvocationOfMacroImpl = relevantElements.reverse.indexWhere(_.isNativeMethod) + 1 - relevantElements = relevantElements dropRight framesTillReflectiveInvocationOfMacroImpl + def isMacroInvoker(este: StackTraceElement) = este.isNativeMethod || (este.getClassName != null && (este.getClassName contains "fastTrack")) + var threshold = relevantElements.reverse.indexWhere(isMacroInvoker) + 1 + while (threshold != relevantElements.length && isMacroInvoker(relevantElements(relevantElements.length - threshold - 1))) threshold += 1 + relevantElements = relevantElements dropRight threshold realex.setStackTrace(relevantElements) val message = new java.io.StringWriter() diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index b878ce3a53..4e578e3f0d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1488,8 +1488,23 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R private def transformCaseApply(tree: Tree, ifNot: => Unit) = { val sym = tree.symbol - - if (sym.isSourceMethod && sym.isCase && sym.name == nme.apply) + + def isClassTypeAccessible(tree: Tree): Boolean = tree match { + case TypeApply(fun, targs) => + isClassTypeAccessible(fun) + case Select(module, apply) => + // Fixes SI-5626. Classes in refinement types cannot be constructed with `new`. In this case, + // the companion class is actually not a ClassSymbol, but a reference to an abstract type. + module.symbol.companionClass.isClass + } + + val doTransform = + sym.isSourceMethod && + sym.isCase && + sym.name == nme.apply && + isClassTypeAccessible(tree) + + if (doTransform) toConstructor(tree.pos, tree.tpe) else { ifNot diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 1ebcea4a07..3d9453d8cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -210,13 +210,25 @@ trait Unapplies extends ast.TreeDSL // and re-added in ``finishWith'' in the namer. def paramWithDefault(vd: ValDef) = treeCopy.ValDef(vd, vd.mods | DEFAULTPARAM, vd.name, atPos(vd.pos.focus)(TypeTree() setOriginal vd.tpt), toIdent(vd)) - - val paramss = mmap(cparamss)(paramWithDefault) - val classTpe = classType(cdef, tparams) + + val (copyParamss, funParamss) = cparamss match { + case Nil => (Nil, Nil) + case ps :: pss => + (List(ps.map(paramWithDefault)), mmap(pss)(p => copyUntyped[ValDef](p).copy(rhs = EmptyTree))) + } + + val classTpe = classType(cdef, tparams) + val bodyTpe = funParamss.foldRight(classTpe)((params, restp) => gen.scalaFunctionConstr(params.map(_.tpt), restp)) + + val argss = copyParamss match { + case Nil => Nil + case ps :: Nil => mmap(ps :: funParamss)(toIdent) + } + val body = funParamss.foldRight(New(classTpe, argss): Tree)(Function) Some(atPos(cdef.pos.focus)( - DefDef(Modifiers(SYNTHETIC), nme.copy, tparams, paramss, classTpe, - New(classTpe, mmap(paramss)(toIdent))) + DefDef(Modifiers(SYNTHETIC), nme.copy, tparams, copyParamss, bodyTpe, + body) )) } } |