diff options
33 files changed, 462 insertions, 187 deletions
diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1 index 5a541f8cf3..736086a8c3 100644 --- a/lib/scala-compiler.jar.desired.sha1 +++ b/lib/scala-compiler.jar.desired.sha1 @@ -1 +1 @@ -c020eccb8cf37963725985f36b44d070915cf4d2 ?scala-compiler.jar +5b3f50d124f84dcda869e17fb0cfd605ed40f385 ?scala-compiler.jar diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1 index d059e861f0..4c15c663dd 100644 --- a/lib/scala-library.jar.desired.sha1 +++ b/lib/scala-library.jar.desired.sha1 @@ -1 +1 @@ -31c7188cef85c28b84b9ce35bc6780996e5dd139 ?scala-library.jar +8f19876a8908e7d7d2a140a8434805cfec2c1346 ?scala-library.jar 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 09e7303b90..81582db5f2 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -2663,6 +2663,10 @@ trait Types extends api.Types { self: SymbolTable => override def kind = "OverloadedType" } + def overloadedType(pre: Type, alternatives: List[Symbol]): Type = + if (alternatives.tail.isEmpty) pre memberType alternatives.head + else OverloadedType(pre, alternatives) + /** A class remembering a type instantiation for some a set of overloaded * polymorphic symbols. * Not used after phase `typer`. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 042e739abe..7d3249a7d3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -1159,6 +1159,27 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with */ def generateMirrorClass(clasz: Symbol, sourceFile: SourceFile) { import JAccessFlags._ + /* We need to save inner classes buffer and create a new one to make sure + * that we do confuse inner classes of the class we mirror with inner + * classes of the class we are mirroring. These two sets can be different + * as seen in this case: + * + * class A { + * class B + * def b: B = new B + * } + * object C extends A + * + * Here mirror class of C has a static forwarder for (inherited) method `b` + * therefore it refers to class `B` and needs InnerClasses entry. However, + * the real class for `C` (named `C$`) is empty and does not refer to `B` + * thus does not need InnerClasses entry it. + * + * NOTE: This logic has been refactored in GenASM and everything is + * implemented in a much cleaner way by having two separate buffers. + */ + val savedInnerClasses = innerClassBuffer + innerClassBuffer = mutable.LinkedHashSet[Symbol]() val moduleName = javaName(clasz) // + "$" val mirrorName = moduleName.substring(0, moduleName.length() - 1) val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL, @@ -1172,6 +1193,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val ssa = scalaSignatureAddingMarker(mirrorClass, clasz.companionSymbol) addAnnotations(mirrorClass, clasz.annotations ++ ssa) emitClass(mirrorClass, clasz) + innerClassBuffer = savedInnerClasses } var linearization: List[BasicBlock] = Nil diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 3625b19dd4..3de287e58c 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -480,16 +480,22 @@ abstract class Erasure extends AddInterfaces // TODO: should we do this for user-defined unapplies as well? // does the first argument list have exactly one argument -- for user-defined unapplies we can't be sure def maybeWrap(bridgingCall: Tree): Tree = { - val canReturnNone = ( // can't statically know which member is going to be selected, so don't let this depend on member.isSynthetic + val guardExtractor = ( // can't statically know which member is going to be selected, so don't let this depend on member.isSynthetic (member.name == nme.unapply || member.name == nme.unapplySeq) && !afterErasure((member.tpe <:< other.tpe))) // no static guarantees (TODO: is the subtype test ever true?) - if (canReturnNone) { - import CODE._ + import CODE._ + val _false = FALSE_typed + val pt = member.tpe.resultType + lazy val zero = + if (_false.tpe <:< pt) _false + else if (NoneModule.tpe <:< pt) REF(NoneModule) + else EmptyTree + + if (guardExtractor && (zero ne EmptyTree)) { val typeTest = gen.mkIsInstanceOf(REF(bridge.firstParam), member.tpe.params.head.tpe) - IF (typeTest) THEN bridgingCall ELSE REF(NoneModule) - } - else bridgingCall + IF (typeTest) THEN bridgingCall ELSE zero + } else bridgingCall } val rhs = member.tpe match { case MethodType(Nil, ConstantType(c)) => Literal(c) 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/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 34e1aaedfd..b5e58efaff 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -958,9 +958,14 @@ trait Typers extends Modes with Adaptations with Taggings { * see test/files/../t5189*.scala */ def adaptConstrPattern(): Tree = { // (5) - val extractor = tree.symbol.filter(sym => reallyExists(unapplyMember(sym.tpe))) + def isExtractor(sym: Symbol) = reallyExists(unapplyMember(sym.tpe)) + val extractor = tree.symbol filter isExtractor if (extractor != NoSymbol) { tree setSymbol extractor + tree.tpe match { + case OverloadedType(pre, alts) => tree.tpe = overloadedType(pre, alts filter isExtractor) + case _ => + } val unapply = unapplyMember(extractor.tpe) val clazz = unapplyParameterType(unapply) 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) )) } } diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala index a3d985733e..c3c329121c 100644 --- a/src/library/scala/concurrent/ConcurrentPackageObject.scala +++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala @@ -11,7 +11,6 @@ package scala.concurrent import java.util.concurrent.{ Executors, ExecutorService, ThreadFactory } import scala.concurrent.forkjoin.{ ForkJoinPool, ForkJoinWorkerThread } import scala.concurrent.util.Duration -import ConcurrentPackageObject._ import language.implicitConversions @@ -36,19 +35,6 @@ abstract class ConcurrentPackageObject { case _ => true } - private[concurrent] def resolveEither[T](source: Either[Throwable, T]): Either[Throwable, T] = source match { - case Left(t) => resolver(t) - case _ => source - } - - private[concurrent] def resolver[T](throwable: Throwable): Either[Throwable, T] = throwable match { - case t: scala.runtime.NonLocalReturnControl[_] => Right(t.value.asInstanceOf[T]) - case t: scala.util.control.ControlThrowable => Left(new ExecutionException("Boxed ControlThrowable", t)) - case t: InterruptedException => Left(new ExecutionException("Boxed InterruptedException", t)) - case e: Error => Left(new ExecutionException("Boxed Error", e)) - case t => Left(t) - } - /* concurrency constructs */ /** Starts an asynchronous computation and returns a `Future` object with the result of that computation. @@ -102,18 +88,3 @@ abstract class ConcurrentPackageObject { @inline implicit final def int2durationops(x: Int): DurationOps = new DurationOps(x) } - -private[concurrent] object ConcurrentPackageObject { - // TODO, docs, return type - // Note that having this in the package object led to failures when - // compiling a subset of sources; it seems that the wildcard is not - // properly handled, and you get messages like "type _$1 defined twice". - // This is consistent with other package object breakdowns. - // private val resolverFunction: PartialFunction[Throwable, Either[Throwable, _]] = { - // case t: scala.runtime.NonLocalReturnControl[_] => Right(t.value) - // case t: scala.util.control.ControlThrowable => Left(new ExecutionException("Boxed ControlThrowable", t)) - // case t: InterruptedException => Left(new ExecutionException("Boxed InterruptedException", t)) - // case e: Error => Left(new ExecutionException("Boxed Error", e)) - // case t => Left(t) - // } -} diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index 4666674b5b..d2a2d5e8a8 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -54,8 +54,7 @@ object ExecutionContext { def fromExecutor(e: Executor, reporter: Throwable => Unit = defaultReporter): ExecutionContext with Executor = new impl.ExecutionContextImpl(e, reporter) def defaultReporter: Throwable => Unit = { - // `Error`s are currently wrapped by `resolver`. - // Also, re-throwing `Error`s here causes an exception handling test to fail. + // re-throwing `Error`s here causes an exception handling test to fail. //case e: Error => throw e case t => t.printStackTrace() } diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 70b3c3dbbb..496e4698d4 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -201,7 +201,7 @@ trait Future[+T] extends Awaitable[T] { case Right(v) => try p success f(v) catch { - case NonFatal(t) => p complete resolver(t) + case NonFatal(t) => p failure t } } @@ -227,7 +227,7 @@ trait Future[+T] extends Awaitable[T] { case Right(v) => p success v } } catch { - case NonFatal(t) => p complete resolver(t) + case NonFatal(t) => p failure t } } @@ -260,7 +260,7 @@ trait Future[+T] extends Awaitable[T] { if (pred(v)) p success v else p failure new NoSuchElementException("Future.filter predicate is not satisfied by: " + v) } catch { - case NonFatal(t) => p complete resolver(t) + case NonFatal(t) => p failure t } } @@ -309,7 +309,7 @@ trait Future[+T] extends Awaitable[T] { if (pf.isDefinedAt(v)) p success pf(v) else p failure new NoSuchElementException("Future.collect partial function is not defined at: " + v) } catch { - case NonFatal(t) => p complete resolver(t) + case NonFatal(t) => p failure t } } @@ -334,7 +334,9 @@ trait Future[+T] extends Awaitable[T] { onComplete { case Left(t) if pf isDefinedAt t => try { p success pf(t) } - catch { case NonFatal(t) => p complete resolver(t) } + catch { + case NonFatal(t) => p failure t + } case otherwise => p complete otherwise } @@ -362,7 +364,7 @@ trait Future[+T] extends Awaitable[T] { try { p completeWith pf(t) } catch { - case NonFatal(t) => p complete resolver(t) + case NonFatal(t) => p failure t } case otherwise => p complete otherwise } diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 7dc3ed2988..3ed960c7ab 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -10,10 +10,10 @@ package scala.concurrent.impl -import java.util.concurrent.{Callable, Executor, ExecutorService, Executors, ThreadFactory} +import java.util.concurrent.{ Callable, Executor, ExecutorService, Executors, ThreadFactory } import scala.concurrent.forkjoin._ -import scala.concurrent.{ExecutionContext, resolver, Awaitable} -import scala.concurrent.util.{ Duration } +import scala.concurrent.{ ExecutionContext, Awaitable } +import scala.concurrent.util.Duration diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 20d4122e8f..bf136b6195 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -57,7 +57,7 @@ private[concurrent] object Future { case NonFatal(e) => // Commenting out reporting for now, since it produces too much output in the tests //executor.reportFailure(e) - scala.concurrent.resolver(e) + Left(e) } } }) diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index da70b3dea5..5a5b893f16 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -11,7 +11,7 @@ package scala.concurrent.impl import java.util.concurrent.TimeUnit.{ NANOSECONDS, MILLISECONDS } -import scala.concurrent.{Awaitable, ExecutionContext, resolveEither, resolver, blocking, CanAwait, TimeoutException} +import scala.concurrent.{ Awaitable, ExecutionContext, blocking, CanAwait, TimeoutException, ExecutionException } //import scala.util.continuations._ import scala.concurrent.util.Duration import scala.util @@ -26,6 +26,20 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Fu object Promise { + + private def resolveEither[T](source: Either[Throwable, T]): Either[Throwable, T] = source match { + case Left(t) => resolver(t) + case _ => source + } + + private def resolver[T](throwable: Throwable): Either[Throwable, T] = throwable match { + case t: scala.runtime.NonLocalReturnControl[_] => Right(t.value.asInstanceOf[T]) + case t: scala.util.control.ControlThrowable => Left(new ExecutionException("Boxed ControlThrowable", t)) + case t: InterruptedException => Left(new ExecutionException("Boxed InterruptedException", t)) + case e: Error => Left(new ExecutionException("Boxed Error", e)) + case t => Left(t) + } + /** Default promise implementation. */ class DefaultPromise[T](implicit val executor: ExecutionContext) extends AbstractPromise with Promise[T] { self => diff --git a/test/files/pos/overloaded_extractor_and_regular_def.scala b/test/files/pos/overloaded_extractor_and_regular_def.scala new file mode 100644 index 0000000000..c8e7da5cad --- /dev/null +++ b/test/files/pos/overloaded_extractor_and_regular_def.scala @@ -0,0 +1,32 @@ +trait TreesBase { + type Tree + + type Apply <: Tree + + val Apply: ApplyExtractor + + abstract class ApplyExtractor { + def apply(x: Int): Apply + def unapply(apply: Apply): Option[Int] + } +} + +trait TreesApi extends TreesBase { + def Apply(x: String) +} + +class Universe extends TreesApi { + abstract class Tree + case class Apply(x: Int) extends Tree + object Apply extends ApplyExtractor + def Apply(x: String) = Apply(x.toInt) +} + +object Test extends App { + def foo(tapi: TreesApi) { + import tapi._ + def bar(tree: Tree) { + val Apply(x) = tree + } + } +}
\ No newline at end of file diff --git a/test/files/pos/t1133.scala b/test/files/pos/t1133.scala new file mode 100644 index 0000000000..4538de5f5f --- /dev/null +++ b/test/files/pos/t1133.scala @@ -0,0 +1,32 @@ +object Match +{ + def main(args: Array[String]) = { + args(0) match { + case Extractor1(Extractor2(Extractor3("dog", "dog", "dog"), x2, x3), b, c, Extractor3("b", "b", f), e) => println(e) + case Extractor3(Extractor2(Extractor1("a", "aa", "aaa", "aa", "a"), Extractor2("a", "aa", "aaa"), e), y, z) => println(e) + case Extractor2(Extractor3("a", "a", x), Extractor3("b", "b", y), Extractor3("c", "c", z)) => println(z) + case _ => println("fail") + } + } + + object Extractor1 { + def unapply(x: Any) = x match { + case x: String => Some(x, x+x, x+x+x, x+x, x) + case _ => None + } + } + + object Extractor2 { + def unapply(x: Any) = x match { + case x: String => Some(x, x+x, x+x+x) + case _ => None + } + } + + object Extractor3 { + def unapply(x: Any) = x match { + case x: String => Some(x, x, x) + case _ => None + } + } +} diff --git a/test/files/pos/t5626.scala b/test/files/pos/t5626.scala new file mode 100644 index 0000000000..c501dfbe60 --- /dev/null +++ b/test/files/pos/t5626.scala @@ -0,0 +1,12 @@ +class C { + val blob = { + new { case class Foo() } + } + val blub = { + class Inner { case class Foo() } + new Inner + } + + val foo = blob.Foo() + val bar = blub.Foo() +} diff --git a/test/files/pos/t5720-ownerous.scala b/test/files/pos/t5720-ownerous.scala index 3a12499612..ad4d4c171d 100644 --- a/test/files/pos/t5720-ownerous.scala +++ b/test/files/pos/t5720-ownerous.scala @@ -28,10 +28,10 @@ class C { //def model = Option(M("foo")()).getOrElse(M("bar")()).copy(currentUser = "")() // the bug - def model = Option(m).getOrElse(M("bar")()).copy("baz")() + def model = Option(m).getOrElse(M("bar")()).copy("baz")("empty") // style points for this version - def modish = ((null: Option[M]) getOrElse new M()()).copy()() + def modish = ((null: Option[M]) getOrElse new M()()).copy()("empty") // various simplifications are too simple case class N(currentUser: String = "anon") diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check index 5656d1a276..f253de71d6 100644 --- a/test/files/run/names-defaults.check +++ b/test/files/run/names-defaults.check @@ -92,7 +92,7 @@ test5 test5 5 10: 2 -slkdfj1 +slkdfj2 1 lskfdjlk 11 diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala index e1bc7cbf59..220414f02a 100644 --- a/test/files/run/names-defaults.scala +++ b/test/files/run/names-defaults.scala @@ -176,7 +176,7 @@ object Test extends App { println(Fact2()("jyp")) println(Fact2(x = 1)()) - println(Fact2(10)().copy(y = "blabla")()) + println(Fact2(10)().copy(y = "blabla")(3)) // assignment to var <-> named argument @@ -195,7 +195,7 @@ object Test extends App { // dependent types and copy method val a11 = new A2 val b11 = a11.B2(new a11.C2)(1) - println(b11.copy()()) + println(b11.copy()(2)) diff --git a/test/files/run/patmat_unapp_abstype-new.check b/test/files/run/patmat_unapp_abstype-new.check index 72239d16cd..42c54631d2 100644 --- a/test/files/run/patmat_unapp_abstype-new.check +++ b/test/files/run/patmat_unapp_abstype-new.check @@ -1,4 +1,4 @@ TypeRef -none of the above +MethodType Bar Foo diff --git a/test/files/run/patmat_unapp_abstype-new.flags b/test/files/run/patmat_unapp_abstype-new.flags deleted file mode 100644 index ba80cad69b..0000000000 --- a/test/files/run/patmat_unapp_abstype-new.flags +++ /dev/null @@ -1 +0,0 @@ --Xoldpatmat diff --git a/test/files/run/t4025.check b/test/files/run/t4025.check new file mode 100644 index 0000000000..6715003cb6 --- /dev/null +++ b/test/files/run/t4025.check @@ -0,0 +1,19 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> class Color(val red: Int) +defined class Color + +scala> + +scala> case class Red(r:Int) extends Color(r) +defined class Red + +scala> + +scala> def f(c: Any) = c match { case Red(_) => () } +f: (c: Any)Unit + +scala> diff --git a/test/files/run/t4025.scala b/test/files/run/t4025.scala new file mode 100644 index 0000000000..5db0093970 --- /dev/null +++ b/test/files/run/t4025.scala @@ -0,0 +1,12 @@ +import scala.tools.nsc.Settings +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ +class Color(val red: Int) + +case class Red(r:Int) extends Color(r) + +def f(c: Any) = c match { case Red(_) => () } +""" +} diff --git a/test/files/run/t4124.check b/test/files/run/t4124.check new file mode 100644 index 0000000000..66a0092d93 --- /dev/null +++ b/test/files/run/t4124.check @@ -0,0 +1,4 @@ +hi +hi +bye +bye diff --git a/test/files/run/t4124.scala b/test/files/run/t4124.scala new file mode 100644 index 0000000000..9f35b57ce3 --- /dev/null +++ b/test/files/run/t4124.scala @@ -0,0 +1,24 @@ +import xml.Node + +object Test extends App { + val body: Node = <elem>hi</elem> + println ((body: AnyRef, "foo") match { + case (node: Node, "bar") => "bye" + case (ser: Serializable, "foo") => "hi" + }) + + println ((body, "foo") match { + case (node: Node, "bar") => "bye" + case (ser: Serializable, "foo") => "hi" + }) + + println ((body: AnyRef, "foo") match { + case (node: Node, "foo") => "bye" + case (ser: Serializable, "foo") => "hi" + }) + + println ((body: AnyRef, "foo") match { + case (node: Node, "foo") => "bye" + case (ser: Serializable, "foo") => "hi" + }) +} diff --git a/test/files/run/t5009.check b/test/files/run/t5009.check new file mode 100644 index 0000000000..cc9df54b34 --- /dev/null +++ b/test/files/run/t5009.check @@ -0,0 +1,4 @@ +C(1,true) +10 +C(7283,20) +100 diff --git a/test/files/run/t5009.scala b/test/files/run/t5009.scala new file mode 100644 index 0000000000..b4fe1bc894 --- /dev/null +++ b/test/files/run/t5009.scala @@ -0,0 +1,17 @@ +object Test extends App { + + case class C[T, U <: String, O >: Object](x: Int, y: T)(z: U, b: Boolean)(s: O, val l: Int) + + val c = C(1, true)("dlkfj", true)("dlkfjlk", 10) + println(c) + println(c.l) + + val f1a = c.copy(y = 20, x = 7283) + + val f1b = c.copy[Int, String, Object](y = 20, x = 7283) + val f2b = f1b("lkdjen", false) + val res = f2b(new Object, 100) + println(res) + println(res.l) + +} diff --git a/test/files/run/t5407.check b/test/files/run/t5407.check new file mode 100644 index 0000000000..51993f072d --- /dev/null +++ b/test/files/run/t5407.check @@ -0,0 +1,2 @@ +2 +2 diff --git a/test/files/run/t5407.scala b/test/files/run/t5407.scala new file mode 100644 index 0000000000..35a8ec6a45 --- /dev/null +++ b/test/files/run/t5407.scala @@ -0,0 +1,17 @@ +case class Foo(private val x: Int, y: Option[Int], z: Boolean) + +object Test extends App { + def foo(x: Foo) = x match { + case Foo(x, Some(y), z) => y + case Foo(x, y, z) => 0 + } + val x = Foo(1, Some(2), false) + println(foo(x)) + + + def bar(x: Foo) = x match { + case Foo(x, Some(y), z) => y + case Foo(x, None, z) => 0 + } + println(bar(x)) +}
\ No newline at end of file |