diff options
Diffstat (limited to 'src')
61 files changed, 937 insertions, 436 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index ff0b3d7d10..f60089c935 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -45,7 +45,9 @@ trait GenTrees { case global.EmptyTree => reifyMirrorObject(EmptyTree) case global.emptyValDef => - mirrorBuildSelect(nme.emptyValDef) + mirrorSelect(nme.emptyValDef) + case global.pendingSuperCall => + mirrorSelect(nme.pendingSuperCall) case FreeDef(_, _, _, _, _) => reifyNestedFreeDef(tree) case FreeRef(_, _) => @@ -101,7 +103,8 @@ trait GenTrees { case ReifiedTree(_, _, inlinedSymtab, rtree, _, _, _) => if (reifyDebug) println("inlining the splicee") // all free vars local to the enclosing reifee should've already been inlined by ``Metalevels'' - inlinedSymtab.syms foreach (sym => if (sym.isLocalToReifee) assert(false, inlinedSymtab.symDef(sym))) + for (sym <- inlinedSymtab.syms if sym.isLocalToReifee) + abort("local free var, should have already been inlined by Metalevels: " + inlinedSymtab.symDef(sym)) state.symtab ++= inlinedSymtab rtree case tree => diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala index c684f16325..e0570d61f2 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala @@ -33,9 +33,6 @@ trait GenUtils { def mirrorSelect(name: String): Tree = termPath(nme.UNIVERSE_PREFIX + name) def mirrorSelect(name: TermName): Tree = mirrorSelect(name.toString) - def mirrorBuildSelect(name: TermName): Tree = - termPath("" + nme.UNIVERSE_BUILD_PREFIX + name) - def mirrorMirrorSelect(name: TermName): Tree = termPath("" + nme.MIRROR_PREFIX + name) diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 663fbeceb0..a2108b8ced 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -23,7 +23,7 @@ trait CompilationUnits { self: Global => /** One unit of compilation that has been submitted to the compiler. * It typically corresponds to a single file of source code. It includes * error-reporting hooks. */ - class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { + class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { self => /** the fresh name creator */ val fresh: FreshNameCreator = new FreshNameCreator.Default @@ -47,7 +47,23 @@ trait CompilationUnits { self: Global => /** Synthetic definitions generated by namer, eliminated by typer. */ - val synthetics = mutable.HashMap[Symbol, Tree]() + object synthetics { + private val map = mutable.HashMap[Symbol, Tree]() + def update(sym: Symbol, tree: Tree) { + debuglog(s"adding synthetic ($sym, $tree) to $self") + map.update(sym, tree) + } + def -=(sym: Symbol) { + debuglog(s"removing synthetic $sym from $self") + map -= sym + } + def get(sym: Symbol): Option[Tree] = logResultIf[Option[Tree]](s"found synthetic for $sym in $self", _.isDefined) { + map get sym + } + def keys: Iterable[Symbol] = map.keys + def clear(): Unit = map.clear() + override def toString = map.toString + } /** things to check at end of compilation unit */ val toCheck = new ListBuffer[() => Unit] diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala index 77acbba056..e7bd5da9dd 100644 --- a/src/compiler/scala/tools/nsc/ast/Positions.scala +++ b/src/compiler/scala/tools/nsc/ast/Positions.scala @@ -20,7 +20,7 @@ trait Positions extends scala.reflect.internal.Positions { // When we prune due to encountering a position, traverse the // pruned children so we can warn about those lacking positions. t.children foreach { c => - if ((c eq EmptyTree) || (c eq emptyValDef)) () + if (!c.canHaveAttrs) () else if (c.pos == NoPosition) { reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase) inform("parent: " + treeSymStatus(t)) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 9e98e9b0e8..bec6de46d0 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -60,7 +60,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) { // This can't be "Annotated(New(UncheckedClass), expr)" because annotations // are very picky about things and it crashes the compiler with "unexpected new". - Annotated(New(scalaDot(UncheckedClass.name), ListOfNil), expr) + Annotated(New(scalaDot(UncheckedClass.name), Nil), expr) } // Builds a tree of the form "{ lhs = rhs ; lhs }" diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index e796258967..c22f103f8b 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -65,6 +65,13 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // --- factory methods ---------------------------------------------------------- + /** Factory method for a primary constructor super call `super.<init>(args_1)...(args_n)` + */ + def PrimarySuperCall(argss: List[List[Tree]]): Tree = argss match { + case Nil => Apply(gen.mkSuperInitCall, Nil) + case xs :: rest => rest.foldLeft(Apply(gen.mkSuperInitCall, xs): Tree)(Apply.apply) + } + /** Generates a template with constructor corresponding to * * constrmods (vparams1_) ... (vparams_n) preSuper { presupers } @@ -82,7 +89,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * body * } */ - def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): Template = { + def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): Template = { /* Add constructor to template */ // create parameters for <init> as synthetic trees. @@ -117,9 +124,16 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit) vparamss1 = List() :: vparamss1; val superRef: Tree = atPos(superPos)(gen.mkSuperInitCall) - val superCall = (superRef /: argss) (Apply.apply) + val superCall = pendingSuperCall // we can't know in advance which of the parents will end up as a superclass + // this requires knowing which of the parents is a type macro and which is not + // and that's something that cannot be found out before typer + // (the type macros aren't in the trunk yet, but there is a plan for them to land there soon) + // this means that we don't know what will be the arguments of the super call + // therefore here we emit a dummy which gets populated when the template is named and typechecked List( - atPos(wrappingPos(superPos, lvdefs ::: argss.flatten)) ( + // TODO: previously this was `wrappingPos(superPos, lvdefs ::: argss.flatten)` + // is it going to be a problem that we can no longer include the `argss`? + atPos(wrappingPos(superPos, lvdefs)) ( DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant()))))) } } @@ -137,11 +151,10 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * @param constrMods the modifiers for the class constructor, i.e. as in `class C private (...)` * @param vparamss the value parameters -- if they have symbols they * should be owned by `sym` - * @param argss the supercall arguments * @param body the template statements without primary constructor * and value parameter fields. */ - def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): ClassDef = { + def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): ClassDef = { // "if they have symbols they should be owned by `sym`" assert( mforall(vparamss)(p => (p.symbol eq NoSymbol) || (p.symbol.owner == sym)), @@ -151,7 +164,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => ClassDef(sym, Template(sym.info.parents map TypeTree, if (sym.thisSym == sym || phase.erasedTypes) emptyValDef else ValDef(sym.thisSym), - constrMods, vparamss, argss, body, superPos)) + constrMods, vparamss, body, superPos)) } // --- subcomponents -------------------------------------------------- @@ -324,6 +337,8 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => else super.transform { tree match { + case tree if !tree.canHaveAttrs => + tree case tpt: TypeTree => if (tpt.original != null) transform(tpt.original) @@ -337,8 +352,6 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => transform(fn) case This(_) if tree.symbol != null && tree.symbol.isPackageClass => tree - case EmptyTree => - tree case _ => val dupl = tree.duplicate if (tree.hasSymbolField && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 679ef1a0c9..76d7af7cc6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1528,9 +1528,9 @@ self => val nstart = in.skipToken() val npos = r2p(nstart, nstart, in.lastOffset) val tstart = in.offset - val (parents, argss, self, stats) = template(isTrait = false) + val (parents, self, stats) = template() val cpos = r2p(tstart, tstart, in.lastOffset max tstart) - makeNew(parents, self, stats, argss, npos, cpos) + makeNew(parents, self, stats, npos, cpos) case _ => syntaxErrorOrIncomplete("illegal start of simple expression", true) errorTermTree @@ -2070,7 +2070,7 @@ self => def annotationExpr(): Tree = atPos(in.offset) { val t = exprSimpleType() if (in.token == LPAREN) New(t, multipleArgumentExprs()) - else New(t, ListOfNil) + else New(t, Nil) } /* -------- PARAMETERS ------------------------------------------- */ @@ -2705,20 +2705,17 @@ self => * TraitParents ::= AnnotType {with AnnotType} * }}} */ - def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = { - val parents = new ListBuffer[Tree] += startAnnotType() - val argss = ( - // TODO: the insertion of ListOfNil here is where "new Foo" becomes - // indistinguishable from "new Foo()". - if (in.token == LPAREN && !isTrait) multipleArgumentExprs() - else ListOfNil - ) - - while (in.token == WITH) { - in.nextToken() - parents += startAnnotType() + def templateParents(): List[Tree] = { + val parents = new ListBuffer[Tree] + def readAppliedParent() = { + val start = in.offset + val parent = startAnnotType() + val argss = if (in.token == LPAREN) multipleArgumentExprs() else Nil + parents += atPos(start)((parent /: argss)(Apply.apply)) } - (parents.toList, argss) + readAppliedParent() + while (in.token == WITH) { in.nextToken(); readAppliedParent() } + parents.toList } /** {{{ @@ -2728,12 +2725,12 @@ self => * EarlyDef ::= Annotations Modifiers PatDef * }}} */ - def template(isTrait: Boolean): (List[Tree], List[List[Tree]], ValDef, List[Tree]) = { + def template(): (List[Tree], ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { // @S: pre template body cannot stub like post body can! val (self, body) = templateBody(isPre = true) - if (in.token == WITH && self.isEmpty) { + if (in.token == WITH && (self eq emptyValDef)) { val earlyDefs: List[Tree] = body flatMap { case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => List(copyValDef(vdef)(mods = mods | Flags.PRESUPER)) @@ -2745,16 +2742,16 @@ self => case _ => List() } in.nextToken() - val (parents, argss) = templateParents(isTrait = isTrait) - val (self1, body1) = templateBodyOpt(traitParentSeen = isTrait) - (parents, argss, self1, earlyDefs ::: body1) + val parents = templateParents() + val (self1, body1) = templateBodyOpt(parenMeansSyntaxError = false) + (parents, self1, earlyDefs ::: body1) } else { - (List(), ListOfNil, self, body) + (List(), self, body) } } else { - val (parents, argss) = templateParents(isTrait = isTrait) - val (self, body) = templateBodyOpt(traitParentSeen = isTrait) - (parents, argss, self, body) + val parents = templateParents() + val (self, body) = templateBodyOpt(parenMeansSyntaxError = false) + (parents, self, body) } } @@ -2768,15 +2765,15 @@ self => * }}} */ def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = { - val (parents0, argss, self, body) = ( + val (parents0, self, body) = ( if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) { in.nextToken() - template(isTrait = mods.isTrait) + template() } else { newLineOptWhenFollowedBy(LBRACE) - val (self, body) = templateBodyOpt(traitParentSeen = false) - (List(), ListOfNil, self, body) + val (self, body) = templateBodyOpt(parenMeansSyntaxError = mods.isTrait || name.isTermName) + (List(), self, body) } ) def anyrefParents() = { @@ -2798,7 +2795,7 @@ self => if (inScalaRootPackage && ScalaValueClassNames.contains(name)) Template(parents0, self, anyvalConstructor :: body) else - Template(anyrefParents, self, constrMods, vparamss, argss, body, o2p(tstart)) + Template(anyrefParents, self, constrMods, vparamss, body, o2p(tstart)) } } @@ -2813,14 +2810,15 @@ self => case (self, Nil) => (self, EmptyTree.asList) case result => result } - def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = { + def templateBodyOpt(parenMeansSyntaxError: Boolean): (ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { templateBody(isPre = false) } else { - if (in.token == LPAREN) - syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ - " may not have parameters", true) + if (in.token == LPAREN) { + if (parenMeansSyntaxError) syntaxError(s"traits or objects may not have parameters", true) + else abort("unexpected opening parenthesis") + } (emptyValDef, List()) } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index d6c499d838..39270719fb 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -201,20 +201,26 @@ abstract class TreeBuilder { */ def makeAnonymousNew(stats: List[Tree]): Tree = { val stats1 = if (stats.isEmpty) List(Literal(Constant(()))) else stats - makeNew(Nil, emptyValDef, stats1, ListOfNil, NoPosition, NoPosition) + makeNew(Nil, emptyValDef, stats1, NoPosition, NoPosition) } /** Create positioned tree representing an object creation <new parents { stats } * @param npos the position of the new * @param cpos the position of the anonymous class starting with parents */ - def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree], argss: List[List[Tree]], + def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree], npos: Position, cpos: Position): Tree = if (parents.isEmpty) - makeNew(List(scalaAnyRefConstr), self, stats, argss, npos, cpos) - else if (parents.tail.isEmpty && stats.isEmpty) - atPos(npos union cpos) { New(parents.head, argss) } - else { + makeNew(List(scalaAnyRefConstr), self, stats, npos, cpos) + else if (parents.tail.isEmpty && stats.isEmpty) { + // `Parsers.template` no longer differentiates tpts and their argss + // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil) + // instead of parents = Ident(C), argss = Nil as before + // this change works great for things that are actually templates + // but in this degenerate case we need to perform postprocessing + val app = treeInfo.dissectApplied(parents.head) + atPos(npos union cpos) { New(app.callee, app.argss) } + } else { val x = tpnme.ANON_CLASS_NAME atPos(npos union cpos) { Block( @@ -222,12 +228,12 @@ abstract class TreeBuilder { atPos(cpos) { ClassDef( Modifiers(FINAL), x, Nil, - Template(parents, self, NoMods, ListOfNil, argss, stats, cpos.focus)) + Template(parents, self, NoMods, ListOfNil, stats, cpos.focus)) }), atPos(npos) { New( Ident(x) setPos npos.focus, - ListOfNil) + Nil) } ) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 4e973c86ea..cc3562079e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -612,7 +612,8 @@ abstract class GenICode extends SubComponent { } else ctx1.bb.emit(CONSTANT(Constant(false))) } else if (r.isValueType && cast) { - assert(false, tree) /* Erasure should have added an unboxing operation to prevent that. */ + /* Erasure should have added an unboxing operation to prevent that. */ + abort("should have been unboxed by erasure: " + tree) } else if (r.isValueType) { ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.typeSymbol)))) } else { @@ -1073,8 +1074,7 @@ abstract class GenICode extends SubComponent { val sym = ( if (!tree.symbol.isPackageClass) tree.symbol else tree.symbol.info.member(nme.PACKAGE) match { - case NoSymbol => - abort("Cannot use package as value: " + tree) + case NoSymbol => abort("Cannot use package as value: " + tree) case s => devWarning(s"Found ${tree.symbol} where a package object is required. Converting to ${s.moduleClass}") s.moduleClass diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index ad53acd519..92d732ed04 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -18,7 +18,7 @@ import asm.Label * * Documentation at http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2012Q2/GenASM.pdf */ -abstract class GenASM extends SubComponent with BytecodeWriters { +abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { import global._ import icodes._ import icodes.opcodes._ @@ -50,61 +50,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // cause cycles before Global has finished initialization. lazy val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo") - def isJavaEntryPoint(icls: IClass) = { - val sym = icls.symbol - def fail(msg: String, pos: Position = sym.pos) = { - icls.cunit.warning(sym.pos, - sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + - " Reason: " + msg - // TODO: make this next claim true, if possible - // by generating valid main methods as static in module classes - // not sure what the jvm allows here - // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead." - ) - false - } - def failNoForwarder(msg: String) = { - fail(msg + ", which means no static forwarder can be generated.\n") - } - val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil - val hasApproximate = possibles exists { m => - m.info match { - case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass - case _ => false - } - } - // At this point it's a module with a main-looking method, so either succeed or warn that it isn't. - hasApproximate && { - // Before erasure so we can identify generic mains. - enteringErasure { - val companion = sym.linkedClassOfClass - - if (hasJavaMainMethod(companion)) - failNoForwarder("companion contains its own main method") - else if (companion.tpe.member(nme.main) != NoSymbol) - // this is only because forwarders aren't smart enough yet - failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") - else if (companion.isTrait) - failNoForwarder("companion is a trait") - // Now either succeeed, or issue some additional warnings for things which look like - // attempts to be java main methods. - else possibles exists { m => - m.info match { - case PolyType(_, _) => - fail("main methods cannot be generic.") - case MethodType(params, res) => - if (res.typeSymbol :: params exists (_.isAbstractType)) - fail("main methods cannot refer to type parameters or abstract types.", m.pos) - else - isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) - case tp => - fail("don't know what this is: " + tp, m.pos) - } - } - } - } - } - private def initBytecodeWriter(entryPoints: List[IClass]): BytecodeWriter = { settings.outputDirs.getSingleOutput match { case Some(f) if f hasExtension "jar" => @@ -159,7 +104,14 @@ abstract class GenASM extends SubComponent with BytecodeWriters { } // For predictably ordered error messages. - var sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName) + var sortedClasses = classes.values.toList sortBy (_.symbol.fullName) + + // Warn when classes will overwrite one another on case-insensitive systems. + for ((_, v1 :: v2 :: _) <- sortedClasses groupBy (_.symbol.javaClassName.toString.toLowerCase)) { + v1.cunit.warning(v1.symbol.pos, + s"Class ${v1.symbol.javaClassName} differs only in case from ${v2.symbol.javaClassName}. " + + "Such classes will overwrite one another on case-insensitive filesystems.") + } debuglog("Created new bytecode generator for " + classes.size + " classes.") val bytecodeWriter = initBytecodeWriter(sortedClasses filter isJavaEntryPoint) @@ -1093,12 +1045,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // a plain class lacking companion module, for details see `isCandidateForForwarders`). // ----------------------------------------------------------------------------------------- - val ExcludedForwarderFlags = { - import Flags._ - // Should include DEFERRED but this breaks findMember. - ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags ) - } - /** Add a forwarder for method m. Used only from addForwarders(). */ private def addForwarder(isRemoteClass: Boolean, jclass: asm.ClassVisitor, module: Symbol, m: Symbol) { val moduleName = javaName(module) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala new file mode 100644 index 0000000000..f0f91e7d1a --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala @@ -0,0 +1,97 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Jason Zaugg + */ + +package scala.tools.nsc +package backend.jvm +import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.symtab._ + +/** Code shared between the legagy backend [[scala.tools.nsc.backend.jvm.GenJVM]] + * and the new backend [[scala.tools.nsc.backend.jvm.GenASM]]. There should be + * more here, but for now I'm starting with the refactorings that are either + * straightforward to review or necessary for maintenance. + */ +trait GenJVMASM { + val global: Global + import global._ + import icodes._ + import definitions._ + + protected def outputDirectory(sym: Symbol): AbstractFile = + settings.outputDirs outputDirFor enteringFlatten(sym.sourceFile) + + protected def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { + var dir = base + val pathParts = clsName.split("[./]").toList + for (part <- pathParts.init) { + dir = dir.subdirectoryNamed(part) + } + dir.fileNamed(pathParts.last + suffix) + } + protected def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = + getFile(outputDirectory(sym), clsName, suffix) + + protected val ExcludedForwarderFlags = { + import Flags._ + // Should include DEFERRED but this breaks findMember. + ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO ) + } + + protected def isJavaEntryPoint(icls: IClass) = { + val sym = icls.symbol + def fail(msg: String, pos: Position = sym.pos) = { + icls.cunit.warning(sym.pos, + sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + + " Reason: " + msg + // TODO: make this next claim true, if possible + // by generating valid main methods as static in module classes + // not sure what the jvm allows here + // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead." + ) + false + } + def failNoForwarder(msg: String) = { + fail(msg + ", which means no static forwarder can be generated.\n") + } + val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil + val hasApproximate = possibles exists { m => + m.info match { + case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass + case _ => false + } + } + // At this point it's a module with a main-looking method, so either succeed or warn that it isn't. + hasApproximate && { + // Before erasure so we can identify generic mains. + enteringErasure { + val companion = sym.linkedClassOfClass + val companionMain = companion.tpe.member(nme.main) + + if (hasJavaMainMethod(companion)) + failNoForwarder("companion contains its own main method") + else if (companion.tpe.member(nme.main) != NoSymbol) + // this is only because forwarders aren't smart enough yet + failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") + else if (companion.isTrait) + failNoForwarder("companion is a trait") + // Now either succeeed, or issue some additional warnings for things which look like + // attempts to be java main methods. + else possibles exists { m => + m.info match { + case PolyType(_, _) => + fail("main methods cannot be generic.") + case MethodType(params, res) => + if (res.typeSymbol :: params exists (_.isAbstractType)) + fail("main methods cannot refer to type parameters or abstract types.", m.pos) + else + isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) + case tp => + fail("don't know what this is: " + tp, m.pos) + } + } + } + } + } +} diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index 650775b259..5dd20a6919 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -146,18 +146,18 @@ abstract class ClosureElimination extends SubComponent { case _ => } - case UNBOX(_) => + case UNBOX(boxType) => info.stack match { case Deref(LocalVar(loc1)) :: _ if info.bindings isDefinedAt LocalVar(loc1) => val value = info.getBinding(loc1) value match { - case Boxed(LocalVar(loc2)) => + case Boxed(LocalVar(loc2)) if loc2.kind == boxType => bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil) debuglog("replaced " + i + " with " + info.getBinding(loc2)) case _ => () } - case Boxed(LocalVar(loc1)) :: _ => + case Boxed(LocalVar(loc1)) :: _ if loc1.kind == boxType => val loc2 = info.getAlias(loc1) bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil) debuglog("replaced " + i + " with " + LocalVar(loc2)) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index acdc3e6797..4dac5b7d90 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -895,7 +895,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // units.filter should return only one element (currentRun.units filter (_.source.file == aSym.sourceFile)).toList match { case List(unit) => - (unit.body find (_.symbol == aSym)) match { + // SI-4922 `sym == aSym` is insufficent if `aSym` is a clone of symbol + // of the parameter in the tree, as can happen with type parametric methods. + def isCorrespondingParam(sym: Symbol) = ( + sym != null && + sym != NoSymbol && + sym.owner == aSym.owner && + sym.name == aSym.name && + sym.isParamWithDefault + ) + (unit.body find (t => isCorrespondingParam(t.symbol))) match { case Some(ValDef(_,_,_,rhs)) => makeTree(rhs) case _ => None } diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala index ecaa793da7..5a1a4cbdeb 100644 --- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala +++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala @@ -143,7 +143,7 @@ self: scala.tools.nsc.Global => */ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try { for (tree <- trees) { - if (!tree.isEmpty && tree.pos == NoPosition) { + if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) { val children = tree.children if (children.isEmpty) { tree setPos pos.focus @@ -164,7 +164,7 @@ self: scala.tools.nsc.Global => */ override def atPos[T <: Tree](pos: Position)(tree: T): T = { if (pos.isOpaqueRange) { - if (!tree.isEmpty && tree.pos == NoPosition) { + if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) { tree.setPos(pos) val children = tree.children if (children.nonEmpty) { @@ -202,7 +202,7 @@ self: scala.tools.nsc.Global => def validate(tree: Tree, encltree: Tree): Unit = { - if (!tree.isEmpty) { + if (!tree.isEmpty && tree.canHaveAttrs) { if (settings.Yposdebug.value && (settings.verbose.value || settings.Yrangepos.value)) println("[%10s] %s".format("validate", treeStatus(tree, encltree))) diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index a48c2a4b67..cb091ac9a7 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -116,7 +116,7 @@ trait MemberHandlers { if (replProps.vids) s"""" + " @ " + "%%8x".format(System.identityHashCode($path)) + " """.trim else "" - """ + "%s%s: %s = " + %s""".format(prettyName, vidString, string2code(req typeOf name), resultString) + """ + "%s%s: %s = " + %s""".format(string2code(prettyName), vidString, string2code(req typeOf name), resultString) } } } @@ -143,8 +143,7 @@ trait MemberHandlers { override def resultExtractionCode(req: Request) = { val lhsType = string2code(req lookupTypeOf name) val res = string2code(req fullPath name) - - """ + "%s: %s = " + %s + "\n" """.format(lhs, lhsType, res) + "\n" + """ + "%s: %s = " + %s + "\n" """.format(string2code(lhs.toString), lhsType, res) + "\n" } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index f4c8cf991d..bb82cfb827 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -506,7 +506,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (parentToken == AT && in.token == DEFAULT) { val annot = atPos(pos) { - New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), ListOfNil) + New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil) } mods1 = mods1 withAnnotations List(annot) skipTo(SEMI) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 42ea7e61f0..caa45ea6db 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -206,7 +206,7 @@ abstract class Pickler extends SubComponent { case RefinedType(parents, decls) => val rclazz = tp.typeSymbol for (m <- decls.iterator) - if (m.owner != rclazz) assert(false, "bad refinement member "+m+" of "+tp+", owner = "+m.owner) + if (m.owner != rclazz) abort("bad refinement member "+m+" of "+tp+", owner = "+m.owner) putSymbol(rclazz); putTypes(parents); putSymbols(decls.toList) case ClassInfoType(parents, decls, clazz) => putSymbol(clazz); putTypes(parents); putSymbols(decls.toList) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 534a140684..e99b42a402 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -68,7 +68,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { def matchesName(param: Symbol) = param.name == name || param.name.startsWith(name + nme.NAME_JOIN_STRING) (constrParams filter matchesName) match { - case Nil => assert(false, name + " not in " + constrParams) ; null + case Nil => abort(name + " not in " + constrParams) case p :: _ => p } } @@ -511,7 +511,6 @@ abstract class Constructors extends Transform with ast.TreeDSL { sym = closureClass, constrMods = Modifiers(0), vparamss = List(List(outerFieldDef)), - argss = ListOfNil, body = List(applyMethodDef), superPos = impl.pos) } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 6953647513..39b894fbef 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -266,7 +266,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { /** Mix in members of implementation class mixinClass into class clazz */ def mixinImplClassMembers(mixinClass: Symbol, mixinInterface: Symbol) { - assert(mixinClass.isImplClass, "Not an impl class:" + + if (!mixinClass.isImplClass) debugwarn ("Impl class flag is not set " + ((mixinClass.debugLocationString, mixinInterface.debugLocationString))) for (member <- mixinClass.info.decls ; if isForwarded(member)) { @@ -357,7 +357,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // first complete the superclass with mixed in members addMixedinMembers(clazz.superClass, unit) - //Console.println("adding members of " + clazz.info.baseClasses.tail.takeWhile(superclazz !=) + " to " + clazz);//DEBUG for (mc <- clazz.mixinClasses ; if mc hasFlag lateINTERFACE) { // @SEAN: adding trait tracking so we don't have to recompile transitive closures unit.depends += mc @@ -868,8 +867,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val cond = Apply(Select(moduleVarRef, Object_eq), List(NULL)) mkFastPathBody(clazz, moduleSym, cond, List(assign), List(NULL), returnTree, attrThis, args) case _ => - assert(false, "Invalid getter " + rhs + " for module in class " + clazz) - EmptyTree + abort("Invalid getter " + rhs + " for module in class " + clazz) } def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position, fieldSym: Symbol): Tree = { diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 7cad2b3986..c375bc4362 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -325,8 +325,16 @@ abstract class TailCalls extends Transform { transformTrees(cases).asInstanceOf[List[CaseDef]] ) + case Try(block, catches, finalizer @ EmptyTree) => + // SI-1672 Catches are in tail position when there is no finalizer + treeCopy.Try(tree, + noTailTransform(block), + transformTrees(catches).asInstanceOf[List[CaseDef]], + EmptyTree + ) + case Try(block, catches, finalizer) => - // no calls inside a try are in tail position, but keep recursing for nested functions + // no calls inside a try are in tail position if there is a finalizer, but keep recursing for nested functions treeCopy.Try(tree, noTailTransform(block), noTailTransforms(catches).asInstanceOf[List[CaseDef]], diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 19b9c188b0..90ea93d7b2 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -250,7 +250,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyMethodDef), fun.pos)), + List(ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } @@ -376,7 +376,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)), + List(ClassDef(anonClass, NoMods, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index b176782b1f..30c12a4286 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -182,14 +182,18 @@ trait ContextErrors { } def ParentTypesError(templ: Template, ex: TypeError) = { - templ.tpe = null - issueNormalTypeError(templ, ex.getMessage()) + templ.tpe = null + issueNormalTypeError(templ, ex.getMessage()) + setError(templ) } // additional parentTypes errors - def ConstrArgsInTraitParentTpeError(arg: Tree, parent: Symbol) = + def ConstrArgsInParentWhichIsTraitError(arg: Tree, parent: Symbol) = issueNormalTypeError(arg, parent + " is a trait; does not take constructor arguments") + def ConstrArgsInParentOfTraitError(arg: Tree, parent: Symbol) = + issueNormalTypeError(arg, "parents of traits may not have parameters") + def MissingTypeArgumentsParentTpeError(supertpt: Tree) = issueNormalTypeError(supertpt, "missing type arguments") @@ -1040,9 +1044,6 @@ trait ContextErrors { def MaxParametersCaseClassError(tree: Tree) = issueNormalTypeError(tree, "Implementation restriction: case classes cannot have more than " + definitions.MaxFunctionArity + " parameters.") - def InheritsItselfError(tree: Tree) = - issueNormalTypeError(tree, tree.tpe.typeSymbol+" inherits itself") - def MissingParameterOrValTypeError(vparam: Tree) = issueNormalTypeError(vparam, "missing parameter type") @@ -1276,7 +1277,10 @@ trait ContextErrors { fail() } - private def implRefError(message: String) = genericError(methPart(macroDdef.rhs), message) + private def implRefError(message: String) = { + val treeInfo.Applied(implRef, _, _) = macroDdef.rhs + genericError(implRef, message) + } private def compatibilityError(message: String) = implRefError( diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 739e28bf0c..bf5aa95f22 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -149,9 +149,20 @@ trait Implicits { class SearchResult(val tree: Tree, val subst: TreeTypeSubstituter) { override def toString = "SearchResult(%s, %s)".format(tree, if (subst.isEmpty) "" else subst) + + def isFailure = false + def isAmbiguousFailure = false + final def isSuccess = !isFailure + } + + lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + override def isFailure = true } - lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) + lazy val AmbiguousSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + override def isFailure = true + override def isAmbiguousFailure = true + } /** A class that records an available implicit * @param name The name of the implicit @@ -823,7 +834,7 @@ trait Implicits { catch divergenceHandler tryImplicitInfo(i) match { - case SearchFailure => + case sr if sr.isFailure => // We don't want errors that occur during checking implicit info // to influence the check of further infos. context.condBufferFlush(_.kind != ErrorKinds.Divergent) @@ -863,14 +874,14 @@ trait Implicits { rest find (alt => !improves(chosen, alt)) match { case Some(competing) => AmbiguousImplicitError(chosen, competing, "both", "and", "")(isView, pt, tree)(context) - return SearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala + return AmbiguousSearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala case _ => if (isView) chosen.useCountView += 1 else chosen.useCountArg += 1 } } - if (best == SearchFailure) { + if (best.isFailure) { /** If there is no winner, and we witnessed and caught divergence, * now we can throw it for the error message. */ @@ -1369,24 +1380,25 @@ trait Implicits { var result = searchImplicit(context.implicitss, true) - if (result == SearchFailure) { + if (result.isFailure) { if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart) } else { if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart) if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits) } - if (result == SearchFailure) { + if (result.isFailure) { val previousErrs = context.flushAndReturnBuffer() val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null + val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits result = materializeImplicit(pt) // `materializeImplicit` does some preprocessing for `pt` // is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`? - if (result == SearchFailure) result = searchImplicit(implicitsOfExpectedType, false) + if (result.isFailure && !wasAmbigious) result = searchImplicit(implicitsOfExpectedType, false) - if (result == SearchFailure) { + if (result.isFailure) { context.updateBuffer(previousErrs) if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart) } else { @@ -1395,7 +1407,7 @@ trait Implicits { } } - if (result == SearchFailure && settings.debug.value) + if (result.isFailure && settings.debug.value) log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType) result diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index be3c027259..6cc536ad9b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -220,7 +220,7 @@ trait Infer extends Checkable { // such as T <: T gets completed. See #360 tvar.constr.inst = ErrorType else - assert(false, tvar.origin+" at "+tvar.origin.typeSymbol.owner) + abort(tvar.origin+" at "+tvar.origin.typeSymbol.owner) } tvars map instantiate } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 538e2d1d76..9a32747c3a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -874,13 +874,8 @@ trait Namers extends MethodSynthesis { private def templateSig(templ: Template): Type = { val clazz = context.owner def checkParent(tpt: Tree): Type = { - val tp = tpt.tpe - val inheritsSelf = tp.typeSymbol == owner - if (inheritsSelf) - InheritsItselfError(tpt) - - if (inheritsSelf || tp.isError) AnyRefClass.tpe - else tp + if (tpt.tpe.isError) AnyRefClass.tpe + else tpt.tpe } val parents = typer.parentTypes(templ) map checkParent @@ -1285,8 +1280,12 @@ trait Namers extends MethodSynthesis { if (!annotated.isInitialized) tree match { case defn: MemberDef => val ainfos = defn.mods.annotations filterNot (_ eq null) map { ann => - // need to be lazy, #1782. enteringTyper to allow inferView in annotation args, SI-5892. - AnnotationInfo lazily enteringTyper(typer typedAnnotation ann) + // need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892. + AnnotationInfo lazily { + val context1 = typer.context.make(ann) + context1.setReportErrors() + enteringTyper(newTyper(context1) typedAnnotation ann) + } } if (ainfos.nonEmpty) { annotated setAnnotations ainfos diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 16680c3f13..b2334faa71 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1266,13 +1266,15 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans val cdef = ClassDef(mods | MODULE, name.toTypeName, Nil, impl) setSymbol classSym setType NoType def findOrCreateModuleVar() = localTyper.typedPos(tree.pos) { - lazy val createModuleVar = gen.mkModuleVarDef(sym) - sym.enclClass.info.decl(nme.moduleVarName(sym.name.toTermName)) match { - // In case we are dealing with local symbol then we already have - // to correct error with forward reference - case NoSymbol => createModuleVar - case vsym => ValDef(vsym) - } + // See SI-5012, SI-6712. + val vsym = ( + if (sym.owner.isTerm) NoSymbol + else sym.enclClass.info.decl(nme.moduleVarName(sym.name.toTermName)) + ) + // In case we are dealing with local symbol then we already have + // to correct error with forward reference + if (vsym == NoSymbol) gen.mkModuleVarDef(sym) + else ValDef(vsym) } def createStaticModuleAccessor() = exitingRefchecks { val method = ( @@ -1679,7 +1681,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkAnyValSubclass(currentOwner) if (bridges.nonEmpty) deriveTemplate(tree)(_ ::: bridges) else tree - case dc@TypeTreeWithDeferredRefCheck() => assert(false, "adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc"); dc + case dc@TypeTreeWithDeferredRefCheck() => abort("adapt should have turned dc: TypeTreeWithDeferredRefCheck into tpt: TypeTree, with tpt.original == dc") case tpt@TypeTree() => if(tpt.original != null) { tpt.original foreach { diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 64c5b41638..0a1d3bfa7a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -4,7 +4,31 @@ package typechecker trait StdAttachments { self: Analyzer => + import global._ + + /** Carries information necessary to expand the host tree. + * At times we need to store this info, because macro expansion can be delayed until its targs are inferred. + * After a macro application has been successfully expanded, this attachment is destroyed. + */ type UnaffiliatedMacroContext = scala.reflect.macros.runtime.Context type MacroContext = UnaffiliatedMacroContext { val universe: self.global.type } case class MacroRuntimeAttachment(delayed: Boolean, typerContext: Context, macroContext: Option[MacroContext]) + + /** After being synthesized by the parser, primary constructors aren't fully baked yet. + * A call to super in such constructors is just a fill-me-in-later dummy resolved later + * by `parentTypes`. This attachment coordinates `parentTypes` and `typedTemplate` and + * allows them to complete the synthesis. + */ + case class SuperCallArgsAttachment(argss: List[List[Tree]]) + + /** Convenience method for `SuperCallArgsAttachment`. + * Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern, + * so it really benefits from a dedicated extractor. + */ + def superCallArgs(tree: Tree): Option[List[List[Tree]]] = + tree.attachments.get[SuperCallArgsAttachment] collect { case SuperCallArgsAttachment(argss) => argss } + + /** Determines whether the given tree has an associated SuperCallArgsAttachment. + */ + def hasSuperArgs(tree: Tree): Boolean = superCallArgs(tree).nonEmpty }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 8d606a8fd5..fd6acc25cc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -52,8 +52,10 @@ trait Typers extends Modes with Adaptations with Tags { object UnTyper extends Traverser { override def traverse(tree: Tree) = { - if (tree != EmptyTree) tree.tpe = null - if (tree.hasSymbolField) tree.symbol = NoSymbol + if (tree.canHaveAttrs) { + tree.tpe = null + if (tree.hasSymbolField) tree.symbol = NoSymbol + } super.traverse(tree) } } @@ -135,7 +137,7 @@ trait Typers extends Modes with Adaptations with Tags { val res = if (paramFailed || (paramTp.isError && {paramFailed = true; true})) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context) argResultsBuff += res - if (res != SearchFailure) { + if (res.isSuccess) { argBuff += mkArg(res.tree, param.name) } else { mkArg = mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args @@ -711,7 +713,7 @@ trait Typers extends Modes with Adaptations with Tags { featureTrait.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse val featureName = (nestedOwners map (_.name + ".")).mkString + featureTrait.name def action(): Boolean = { - def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context) != SearchFailure + def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context).isSuccess def hasOption = settings.language.value exists (s => s == featureName || s == "_") val OK = hasImport || hasOption if (!OK) { @@ -1320,13 +1322,6 @@ trait Typers extends Modes with Adaptations with Tags { if (member(qual, name) != NoSymbol) qual else adaptToMember(qual, HasMember(name)) - private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { - // XXX: see about using the class's symbol.... - enclTparams foreach (sym => context.scope.enter(sym)) - namer.enterValueParams(vparamss) - typed(cbody) - } - private def validateNoCaseAncestor(clazz: Symbol) = { if (!phase.erasedTypes) { for (ancestor <- clazz.ancestors find (_.isCase)) { @@ -1428,114 +1423,242 @@ trait Typers extends Modes with Adaptations with Tags { unit.error(tparam.pos, "type parameter of value class may not be specialized") } - def parentTypes(templ: Template): List[Tree] = - if (templ.parents.isEmpty) List(atPos(templ.pos)(TypeTree(AnyRefClass.tpe))) - else try { - val clazz = context.owner - // Normalize supertype and mixins so that supertype is always a class, not a trait. - var supertpt = typedTypeConstructor(templ.parents.head) - val firstParent = supertpt.tpe.typeSymbol - var mixins = templ.parents.tail map typedType - // If first parent is a trait, make it first mixin and add its superclass as first parent - while ((supertpt.tpe.typeSymbol ne null) && supertpt.tpe.typeSymbol.initialize.isTrait) { - val supertpt1 = typedType(supertpt) - if (!supertpt1.isErrorTyped) { - mixins = supertpt1 :: mixins - supertpt = TypeTree(supertpt1.tpe.firstParent) setPos supertpt.pos.focus - } + /** Typechecks a parent type reference. + * + * This typecheck is harder than it might look, because it should honor early + * definitions and also perform type argument inference with the help of super call + * arguments provided in `encodedtpt`. + * + * The method is called in batches (batch = 1 time per each parent type referenced), + * two batches per definition: once from namer, when entering a ClassDef or a ModuleDef + * and once from typer, when typechecking the definition. + * + * ***Arguments*** + * + * `encodedtpt` represents the parent type reference wrapped in an `Apply` node + * which indicates value arguments (i.e. type macro arguments or super constructor call arguments) + * If no value arguments are provided by the user, the `Apply` node is still + * there, but its `args` will be set to `Nil`. + * This argument is synthesized by `tools.nsc.ast.Parsers.templateParents`. + * + * `templ` is an enclosing template, which contains a primary constructor synthesized by the parser. + * Such a constructor is a DefDef which contains early initializers and maybe a super constructor call + * (I wrote "maybe" because trait constructors don't call super constructors). + * This argument is synthesized by `tools.nsc.ast.Trees.Template`. + * + * `inMixinPosition` indicates whether the reference is not the first in the + * list of parents (and therefore cannot be a class) or the opposite. + * + * ***Return value and side effects*** + * + * Returns a `TypeTree` representing a resolved parent type. + * If the typechecked parent reference implies non-nullary and non-empty argument list, + * this argument list is attached to the returned value in SuperCallArgsAttachment. + * The attachment is necessary for the subsequent typecheck to fixup a super constructor call + * in the body of the primary constructor (see `typedTemplate` for details). + * + * This method might invoke `typedPrimaryConstrBody`, hence it might cause the side effects + * described in the docs of that method. It might also attribute the Super(_, _) reference + * (if present) inside the primary constructor of `templ`. + * + * ***Example*** + * + * For the following definition: + * + * class D extends { + * val x = 2 + * val y = 4 + * } with B(x)(3) with C(y) with T + * + * this method will be called six times: + * + * (3 times from the namer) + * typedParentType(Apply(Apply(Ident(B), List(Ident(x))), List(3)), templ, inMixinPosition = false) + * typedParentType(Apply(Ident(C), List(Ident(y))), templ, inMixinPosition = true) + * typedParentType(Apply(Ident(T), List()), templ, inMixinPosition = true) + * + * (3 times from the typer) + * <the same three calls> + */ + private def typedParentType(encodedtpt: Tree, templ: Template, inMixinPosition: Boolean): Tree = { + val app = treeInfo.dissectApplied(encodedtpt) + val (treeInfo.Applied(core, targs, argss), decodedtpt) = (app, app.callee) + val argssAreTrivial = argss == Nil || argss == ListOfNil + + // we cannot avoid cyclic references with `initialize` here, because when type macros arrive, + // we'll have to check the probe for isTypeMacro anyways. + // therefore I think it's reasonable to trade a more specific "inherits itself" error + // for a generic, yet understandable "cyclic reference" error + var probe = typedTypeConstructor(core.duplicate).tpe.typeSymbol + if (probe == null) probe = NoSymbol + probe.initialize + + if (probe.isTrait || inMixinPosition) { + if (!argssAreTrivial) { + if (probe.isTrait) ConstrArgsInParentWhichIsTraitError(encodedtpt, probe) + else () // a class in a mixin position - this warrants an error in `validateParentClasses` + // therefore here we do nothing, e.g. don't check that the # of ctor arguments + // matches the # of ctor parameters or stuff like that } - if (supertpt.tpe.typeSymbol == AnyClass && firstParent.isTrait) - supertpt.tpe = AnyRefClass.tpe - - // Determine - // - supertparams: Missing type parameters from supertype - // - supertpe: Given supertype, polymorphic in supertparams - val supertparams = if (supertpt.hasSymbolField) supertpt.symbol.typeParams else List() - var supertpe = supertpt.tpe - if (!supertparams.isEmpty) - supertpe = PolyType(supertparams, appliedType(supertpe.typeConstructor, supertparams map (_.tpeHK))) - - // A method to replace a super reference by a New in a supercall - def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { - case Apply(fn, args) => - treeCopy.Apply(scall, transformSuperCall(fn), args map (_.duplicate)) - case Select(Super(_, _), nme.CONSTRUCTOR) => - treeCopy.Select( - scall, - atPos(supertpt.pos.focus)(New(TypeTree(supertpe)) setType supertpe), - nme.CONSTRUCTOR) + typedType(decodedtpt) + } else { + var supertpt = typedTypeConstructor(decodedtpt) + val supertparams = if (supertpt.hasSymbolField) supertpt.symbol.typeParams else Nil + if (supertparams.nonEmpty) { + typedPrimaryConstrBody(templ) { + val supertpe = PolyType(supertparams, appliedType(supertpt.tpe, supertparams map (_.tpeHK))) + val supercall = New(supertpe, mmap(argss)(_.duplicate)) + val treeInfo.Applied(Select(ctor, nme.CONSTRUCTOR), _, _) = supercall + ctor setType supertpe // this is an essential hack, otherwise it will occasionally fail to typecheck + atPos(supertpt.pos.focus)(supercall) + } match { + case EmptyTree => MissingTypeArgumentsParentTpeError(supertpt) + case tpt => supertpt = TypeTree(tpt.tpe) setPos supertpt.pos.focus + } } + // this is the place where we tell the typer what argss should be used for the super call + // if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`) + // the super call dummy is already good enough, so we don't need to do anything + if (argssAreTrivial) supertpt else supertpt updateAttachment SuperCallArgsAttachment(argss) + } + } - treeInfo.firstConstructor(templ.body) match { - case constr @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => - // Convert constructor body to block in environment and typecheck it - val (preSuperStats, superCall) = { - val (stats, rest) = cstats span (x => !treeInfo.isSuperConstrCall(x)) - (stats map (_.duplicate), if (rest.isEmpty) EmptyTree else rest.head.duplicate) - } - val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall match { - case Apply(_, _) if supertparams.nonEmpty => transformSuperCall(superCall) - case _ => cunit.duplicate - }) - val outercontext = context.outer - - assert(clazz != NoSymbol, templ) - val cscope = outercontext.makeNewScope(constr, outercontext.owner) - val cbody2 = newTyper(cscope) // called both during completion AND typing. - .typePrimaryConstrBody(clazz, - cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) - - superCall match { - case Apply(_, _) => - val sarg = treeInfo.firstArgument(superCall) - if (sarg != EmptyTree && supertpe.typeSymbol != firstParent) - ConstrArgsInTraitParentTpeError(sarg, firstParent) - if (!supertparams.isEmpty) - supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus - case _ => - if (!supertparams.isEmpty) - MissingTypeArgumentsParentTpeError(supertpt) - } + /** Typechecks the mishmash of trees that happen to be stuffed into the primary constructor of a given template. + * Before commencing the typecheck, replaces the `pendingSuperCall` dummy with the result of `actualSuperCall`. + * `actualSuperCall` can return `EmptyTree`, in which case the dummy is replaced with a literal unit. + * + * ***Return value and side effects*** + * + * If a super call is present in the primary constructor and is not erased by the transform, returns it typechecked. + * Otherwise (e.g. if the primary constructor is missing or the super call isn't there) returns `EmptyTree`. + * + * As a side effect, this method attributes the underlying fields of early vals. + * Early vals aren't typechecked anywhere else, so it's essential to call `typedPrimaryConstrBody` + * at least once per definition. It'd be great to disentangle this logic at some point. + * + * ***Example*** + * + * For the following definition: + * + * class D extends { + * val x = 2 + * val y = 4 + * } with B(x)(3) with C(y) with T + * + * the primary constructor of `templ` will be: + * + * Block(List( + * ValDef(NoMods, x, TypeTree(), 2) + * ValDef(NoMods, y, TypeTree(), 4) + * global.pendingSuperCall, + * Literal(Constant(()))) + * + * Note the `pendingSuperCall` part. This is the representation of a fill-me-in-later supercall dummy, + * which encodes the fact that supercall argss are unknown during parsing and need to be transplanted + * from one of the parent types. Read more about why the argss are unknown in `tools.nsc.ast.Trees.Template`. + */ + private def typedPrimaryConstrBody(templ: Template)(actualSuperCall: => Tree): Tree = + treeInfo.firstConstructor(templ.body) match { + case ctor @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => + val (preSuperStats, superCall) = { + val (stats, rest) = cstats span (x => !treeInfo.isSuperConstrCall(x)) + (stats map (_.duplicate), if (rest.isEmpty) EmptyTree else rest.head.duplicate) + } + val superCall1 = (superCall match { + case global.pendingSuperCall => actualSuperCall + case EmptyTree => EmptyTree + }) orElse cunit + val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall1) + val clazz = context.owner + assert(clazz != NoSymbol, templ) + val cscope = context.outer.makeNewScope(ctor, context.outer.owner) + val cbody2 = { // called both during completion AND typing. + val typer1 = newTyper(cscope) + // XXX: see about using the class's symbol.... + clazz.unsafeTypeParams foreach (sym => typer1.context.scope.enter(sym)) + typer1.namer.enterValueParams(vparamss map (_.map(_.duplicate))) + typer1.typed(cbody1) + } - val preSuperVals = treeInfo.preSuperFields(templ.body) - if (preSuperVals.isEmpty && preSuperStats.nonEmpty) - devWarning("Wanted to zip empty presuper val list with " + preSuperStats) - else - map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) + val preSuperVals = treeInfo.preSuperFields(templ.body) + if (preSuperVals.isEmpty && preSuperStats.nonEmpty) + devWarning("Wanted to zip empty presuper val list with " + preSuperStats) + else + map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) - case _ => - if (!supertparams.isEmpty) - MissingTypeArgumentsParentTpeError(supertpt) - } + if (superCall1 == cunit) EmptyTree else cbody2 + case _ => + EmptyTree + } - // Certain parents are added in the parser before it is known whether - // that class also declared them as parents. For instance, this is an - // error unless we take corrective action here: - // - // case class Foo() extends Serializable - // - // So we strip the duplicates before typer. - def fixDuplicates(remaining: List[Tree]): List[Tree] = remaining match { - case Nil => Nil - case x :: xs => - val sym = x.symbol - x :: fixDuplicates( - if (isPossibleSyntheticParent(sym)) xs filterNot (_.symbol == sym) - else xs - ) + /** Makes sure that the first type tree in the list of parent types is always a class. + * If the first parent is a trait, prepend its supertype to the list until it's a class. + */ + private def normalizeFirstParent(parents: List[Tree]): List[Tree] = parents match { + case first :: rest if treeInfo.isTraitRef(first) => + def explode(supertpt: Tree, acc: List[Tree]): List[Tree] = { + if (treeInfo.isTraitRef(supertpt)) { + val supertpt1 = typedType(supertpt) + if (!supertpt1.isErrorTyped) { + val supersupertpt = TypeTree(supertpt1.tpe.firstParent) setPos supertpt.pos.focus + return explode(supersupertpt, supertpt1 :: acc) + } + } + if (supertpt.tpe.typeSymbol == AnyClass) supertpt.tpe = AnyRefClass.tpe + supertpt :: acc } + explode(first, Nil) ++ rest + case _ => parents + } - fixDuplicates(supertpt :: mixins) mapConserve (tpt => checkNoEscaping.privates(clazz, tpt)) - } - catch { - case ex: TypeError => - // fallback in case of cyclic errors - // @H none of the tests enter here but I couldn't rule it out - log("Type error calculating parents in template " + templ) - log("Error: " + ex) - ParentTypesError(templ, ex) - List(TypeTree(AnyRefClass.tpe)) - } + /** Certain parents are added in the parser before it is known whether + * that class also declared them as parents. For instance, this is an + * error unless we take corrective action here: + * + * case class Foo() extends Serializable + * + * So we strip the duplicates before typer. + */ + private def fixDuplicateSyntheticParents(parents: List[Tree]): List[Tree] = parents match { + case Nil => Nil + case x :: xs => + val sym = x.symbol + x :: fixDuplicateSyntheticParents( + if (isPossibleSyntheticParent(sym)) xs filterNot (_.symbol == sym) + else xs + ) + } + + def parentTypes(templ: Template): List[Tree] = templ.parents match { + case Nil => List(atPos(templ.pos)(TypeTree(AnyRefClass.tpe))) + case first :: rest => + try { + val supertpts = fixDuplicateSyntheticParents(normalizeFirstParent( + typedParentType(first, templ, inMixinPosition = false) +: + (rest map (typedParentType(_, templ, inMixinPosition = true))))) + + // if that is required to infer the targs of a super call + // typedParentType calls typedPrimaryConstrBody to do the inferring typecheck + // as a side effect, that typecheck also assigns types to the fields underlying early vals + // however if inference is not required, the typecheck doesn't happen + // and therefore early fields have their type trees not assigned + // here we detect this situation and take preventive measures + if (treeInfo.hasUntypedPreSuperFields(templ.body)) + typedPrimaryConstrBody(templ)(EmptyTree) + + supertpts mapConserve (tpt => checkNoEscaping.privates(context.owner, tpt)) + } catch { + case ex: TypeError => + // fallback in case of cyclic errors + // @H none of the tests enter here but I couldn't rule it out + // upd. @E when a definitions inherits itself, we end up here + // because `typedParentType` triggers `initialize` for parent types symbols + log("Type error calculating parents in template " + templ) + log("Error: " + ex) + ParentTypesError(templ, ex) + List(TypeTree(AnyRefClass.tpe)) + } + } /** <p>Check that</p> * <ul> @@ -1750,9 +1873,12 @@ trait Typers extends Modes with Adaptations with Tags { // the following is necessary for templates generated later assert(clazz.info.decls != EmptyScope, clazz) enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body) - validateParentClasses(parents1, selfType) + if (!templ.isErrorTyped) // if `parentTypes` has invalidated the template, don't validate it anymore + validateParentClasses(parents1, selfType) if (clazz.isCase) validateNoCaseAncestor(clazz) + if (clazz.isTrait && hasSuperArgs(parents1.head)) + ConstrArgsInParentOfTraitError(parents1.head, clazz) if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.owner.isPackageClass) unit.error(clazz.pos, "inner classes cannot be classfile annotations") @@ -1760,9 +1886,21 @@ trait Typers extends Modes with Adaptations with Tags { if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) - val body = - if (isPastTyper || reporter.hasErrors) templ.body - else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _)) + val body = { + val body = + if (isPastTyper || reporter.hasErrors) templ.body + else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _)) + val primaryCtor = treeInfo.firstConstructor(body) + val primaryCtor1 = primaryCtor match { + case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) => + val argss = superCallArgs(parents1.head) getOrElse Nil + val pos = wrappingPos(parents1.head.pos, argss.flatten) + val superCall = atPos(pos)(PrimarySuperCall(argss)) + deriveDefDef(primaryCtor)(block => Block(earlyVals :+ superCall, unit) setPos pos) setPos pos + case _ => primaryCtor + } + body mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat } + } val body1 = typedStats(body, templ.symbol) @@ -2473,7 +2611,7 @@ trait Typers extends Modes with Adaptations with Tags { if (members.head eq EmptyTree) setError(tree) else { val typedBlock = typedPos(tree.pos, mode, pt) { - Block(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) + Block(ClassDef(anonClass, NoMods, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) } // Don't leak implementation details into the type, see SI-6575 if (isPartial && !typedBlock.isErrorTyped) @@ -2676,7 +2814,11 @@ trait Typers extends Modes with Adaptations with Tags { var moreToAdd = true while (moreToAdd) { val initElems = scope.elems - for (sym <- scope) + // SI-5877 The decls of a package include decls of the package object. But we don't want to add + // the corresponding synthetics to the package class, only to the package object class. + def shouldAdd(sym: Symbol) = + inBlock || !context.isInPackageObject(sym, context.owner) + for (sym <- scope if shouldAdd(sym)) for (tree <- context.unit.synthetics get sym) { newStats += typedStat(tree) // might add even more synthetics to the scope context.unit.synthetics -= sym @@ -3701,7 +3843,7 @@ trait Typers extends Modes with Adaptations with Tags { case DynamicApplicationNamed(qual, _) if acceptsApplyDynamic(qual.tpe.widen) => true case _ => false // look deeper? - // val methPart = treeInfo.methPart(fun) + // val treeInfo.Applied(methPart, _, _) = fun // println("methPart of "+ fun +" is "+ methPart) // if (methPart ne fun) isApplyDynamicNamed(methPart) // else false @@ -3737,7 +3879,7 @@ trait Typers extends Modes with Adaptations with Tags { */ def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { log(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") - val treeSelection = treeInfo.methPart(tree) + val treeInfo.Applied(treeSelection, _, _) = tree def isDesugaredApply = treeSelection match { case Select(`qual`, nme.apply) => true case _ => false @@ -3750,7 +3892,7 @@ trait Typers extends Modes with Adaptations with Tags { // not supported: foo.bar(a1,..., an: _*) def hasStar(args: List[Tree]) = treeInfo.isWildcardStarArgList(args) def applyOp(args: List[Tree]) = if (hasNamed(args)) nme.applyDynamicNamed else nme.applyDynamic - def matches(t: Tree) = isDesugaredApply || treeInfo.methPart(t) == treeSelection + def matches(t: Tree) = isDesugaredApply || treeInfo.dissectApplied(t).core == treeSelection /** Note that the trees which arrive here are potentially some distance from * the trees of direct interest. `cxTree` is some enclosing expression which @@ -3768,9 +3910,8 @@ trait Typers extends Modes with Adaptations with Tags { case _ => t.children flatMap findSelection headOption } findSelection(cxTree) match { - case Some((opName, tapply)) => - val targs = treeInfo.typeArguments(tapply) - val fun = gen.mkTypeApply(Select(qual, opName), targs) + case Some((opName, treeInfo.Applied(_, targs, _))) => + val fun = gen.mkTypeApply(Select(qual, opName), targs) atPos(qual.pos)(Apply(fun, Literal(Constant(name.decode)) :: Nil)) case _ => setError(tree) @@ -3965,8 +4106,8 @@ trait Typers extends Modes with Adaptations with Tags { return fail() if (treeInfo.mayBeVarGetter(varsym)) { - treeInfo.methPart(lhs1) match { - case Select(qual, name) => + lhs1 match { + case treeInfo.Applied(Select(qual, name), _, _) => val sel = Select(qual, nme.getterToSetter(name.toTermName)) setPos lhs.pos val app = Apply(sel, List(rhs)) setPos tree.pos return typed(app, mode, pt) @@ -4347,9 +4488,9 @@ trait Typers extends Modes with Adaptations with Tags { } case Apply(fn, indices) => - treeInfo.methPart(fn) match { - case Select(table, nme.apply) => mkUpdate(table, indices) - case _ => UnexpectedTreeAssignmentConversionError(qual) + fn match { + case treeInfo.Applied(Select(table, nme.apply), _, _) => mkUpdate(table, indices) + case _ => UnexpectedTreeAssignmentConversionError(qual) } } typed1(tree1, mode, pt) @@ -5182,21 +5323,21 @@ trait Typers extends Modes with Adaptations with Tags { // enough to see those. See #3938 ConstructorPrefixError(tree, restpe) } else { - //@M fix for #2208 - // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef - if (result.tpe.typeArgs.isEmpty) { - // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) { - // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not - // designed to deal with the cycles in the scala package (ScalaObject extends - // AnyRef, but the AnyRef type alias is entered after the scala package is - // loaded and completed, so that ScalaObject is unpickled while AnyRef is not - // yet defined ) - // !!! TODO - revisit now that ScalaObject is gone. - result setType(restpe) - } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208 - // during uncurry (after refchecks), all types are normalized - result - } + //@M fix for #2208 + // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef + if (result.tpe.typeArgs.isEmpty) { + // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) { + // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not + // designed to deal with the cycles in the scala package (ScalaObject extends + // AnyRef, but the AnyRef type alias is entered after the scala package is + // loaded and completed, so that ScalaObject is unpickled while AnyRef is not + // yet defined ) + // !!! TODO - revisit now that ScalaObject is gone. + result setType(restpe) + } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208 + // during uncurry (after refchecks), all types are normalized + result + } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 061c6679da..3e76da4fdc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -114,7 +114,7 @@ trait Unapplies extends ast.TreeDSL ModuleDef( Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin), cdef.name.toTermName, - Template(parents, emptyValDef, NoMods, Nil, ListOfNil, body, cdef.impl.pos.focus)) + Template(parents, emptyValDef, NoMods, Nil, body, cdef.impl.pos.focus)) } private val caseMods = Modifiers(SYNTHETIC | CASE) diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 42cdfcdd49..834f5436dc 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -227,7 +227,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => emptyValDef, NoMods, List(), - List(List()), List(methdef), NoPosition)) trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value)) diff --git a/src/eclipse/continuations-library/.classpath b/src/eclipse/continuations-library/.classpath new file mode 100644 index 0000000000..b3ca4eeb48 --- /dev/null +++ b/src/eclipse/continuations-library/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="library"/> + <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/> + <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="output" path="build-quick-continuations-library"/> +</classpath> diff --git a/src/eclipse/continuations-library/.project b/src/eclipse/continuations-library/.project new file mode 100644 index 0000000000..f3a53a3d97 --- /dev/null +++ b/src/eclipse/continuations-library/.project @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>continuations-library</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.scala-ide.sdt.core.scalabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.scala-ide.sdt.core.scalanature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> + <linkedResources> + <link> + <name>build-quick-continuations-library</name> + <type>2</type> + <locationURI>SCALA_BASEDIR/build/quick/classes/continuations/library</locationURI> + </link> + <link> + <name>library</name> + <type>2</type> + <locationURI>SCALA_BASEDIR/src/continuations/library</locationURI> + </link> + </linkedResources> +</projectDescription> diff --git a/src/eclipse/continuations-library/.settings/org.scala-ide.sdt.core.prefs b/src/eclipse/continuations-library/.settings/org.scala-ide.sdt.core.prefs new file mode 100644 index 0000000000..63e1df247f --- /dev/null +++ b/src/eclipse/continuations-library/.settings/org.scala-ide.sdt.core.prefs @@ -0,0 +1,2 @@ +P=continuations\:enable +scala.compiler.useProjectSettings=true diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath index 39a2c67f7c..75a9fae19a 100644 --- a/src/eclipse/partest/.classpath +++ b/src/eclipse/partest/.classpath @@ -9,5 +9,6 @@ <classpathentry kind="lib" path="lib/ant/ant.jar"/> <classpathentry kind="lib" path="lib/jline.jar"/> <classpathentry combineaccessrules="false" kind="src" path="/asm"/> + <classpathentry combineaccessrules="false" kind="src" path="/continuations-library"/> <classpathentry kind="output" path="build-quick-partest"/> </classpath> diff --git a/src/eclipse/reflect/.classpath b/src/eclipse/reflect/.classpath index 57a3928dc3..36e6b6adf1 100644 --- a/src/eclipse/reflect/.classpath +++ b/src/eclipse/reflect/.classpath @@ -3,5 +3,6 @@ <classpathentry kind="src" path="reflect"/> <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry combineaccessrules="false" kind="src" path="/continuations-library"/> <classpathentry kind="output" path="build-quick-reflect"/> </classpath> diff --git a/src/eclipse/scala-compiler/.classpath b/src/eclipse/scala-compiler/.classpath index 3d851de53a..0488a0dc39 100644 --- a/src/eclipse/scala-compiler/.classpath +++ b/src/eclipse/scala-compiler/.classpath @@ -7,5 +7,6 @@ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="lib" path="lib/ant/ant.jar"/> <classpathentry kind="lib" path="lib/jline.jar"/> + <classpathentry combineaccessrules="false" kind="src" path="/continuations-library"/> <classpathentry kind="output" path="build-quick-compiler"/> </classpath> diff --git a/src/eclipse/scalap/.classpath b/src/eclipse/scalap/.classpath index 3863097a65..0a55745702 100644 --- a/src/eclipse/scalap/.classpath +++ b/src/eclipse/scalap/.classpath @@ -7,5 +7,6 @@ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="lib" path="lib/ant/ant.jar"/> <classpathentry kind="lib" path="lib/jline.jar"/> + <classpathentry combineaccessrules="false" kind="src" path="/continuations-library"/> <classpathentry kind="output" path="build-quick-scalap"/> </classpath> diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 8be0cb1619..1b5fd6c8d3 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -100,8 +100,8 @@ case class StringContext(parts: String*) { * ''Note:'' Even when using the raw interpolator, Scala will preprocess unicode escapes. * For example: * {{{ - * scala> raw"\u0123" - * res0: String = ģ + * scala> raw"\u005cu0025" + * res0: String = # * }}} * * @param `args` The arguments to be inserted into the resulting string. @@ -191,7 +191,7 @@ object StringContext { var cur = 0 var idx = 0 def output(ch: Char) = { - bldr append str.substring (start, cur) + bldr.append(str, start, cur) bldr append ch start = idx } @@ -199,14 +199,15 @@ object StringContext { cur = idx if (str(idx) == '\\') { idx += 1 + if (idx >= len) throw new InvalidEscapeException(str, cur) if ('0' <= str(idx) && str(idx) <= '7') { val leadch = str(idx) var oct = leadch - '0' idx += 1 - if ('0' <= str(idx) && str(idx) <= '7') { + if (idx < len && '0' <= str(idx) && str(idx) <= '7') { oct = oct * 8 + str(idx) - '0' idx += 1 - if (leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') { + if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') { oct = oct * 8 + str(idx) - '0' idx += 1 } @@ -234,6 +235,6 @@ object StringContext { } } if (start == 0) str - else (bldr append str.substring(start, idx)).toString + else bldr.append(str, start, idx).toString } } diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 603e0b6497..955ebce6bd 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -22,7 +22,7 @@ import scala.math.{ min, max, Ordering } * Sequences are special cases of iterable collections of class `Iterable`. * Unlike iterables, sequences always have a defined order of elements. * Sequences provide a method `apply` for indexing. Indices range from `0` up to the `length` of - * a sequence. Sequences support a number to find occurrences of elements or subsequences, including + * a sequence. Sequences support a number of methods to find occurrences of elements or subsequences, including * `segmentLength`, `prefixLength`, `indexWhere`, `indexOf`, `lastIndexWhere`, `lastIndexOf`, * `startsWith`, `endsWith`, `indexOfSlice`. * diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 9115b9e5fb..5e6126a7cf 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -10,10 +10,11 @@ package scala.collection package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } -import Wrappers._ import scala.language.implicitConversions trait WrapAsJava { + import Wrappers._ + /** * Implicitly converts a Scala Iterator to a Java Iterator. * The returned Java Iterator is backed by the provided Scala diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index 5a5d204ece..ffcca62291 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -10,11 +10,13 @@ package scala.collection package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } -import Wrappers._ import scala.language.implicitConversions trait LowPriorityWrapAsScala { this: WrapAsScala => + + import Wrappers._ + /** * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap. * The returned Scala ConcurrentMap is backed by the provided Java @@ -34,6 +36,7 @@ trait LowPriorityWrapAsScala { } trait WrapAsScala extends LowPriorityWrapAsScala { + import Wrappers._ /** * Implicitly converts a Java `Iterator` to a Scala `Iterator`. * diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index e1aba20fdb..02c10700b1 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -33,7 +33,6 @@ import scala.collection.parallel.immutable.ParRange * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#ranges "Scala's Collection Library overview"]] * section on `Ranges` for more information. * - * @define Coll Range * @define coll range * @define mayNotTerminateInf * @define willNotTerminateInf diff --git a/src/library/scala/collection/mutable/MutableList.scala b/src/library/scala/collection/mutable/MutableList.scala index 183de5b727..fd92d2e555 100644 --- a/src/library/scala/collection/mutable/MutableList.scala +++ b/src/library/scala/collection/mutable/MutableList.scala @@ -56,12 +56,16 @@ extends AbstractSeq[A] /** Returns the rest of this list */ override def tail: MutableList[A] = { - require(nonEmpty, "tail of empty list") val tl = new MutableList[A] + tailImpl(tl) + tl + } + + protected final def tailImpl(tl: MutableList[A]) { + require(nonEmpty, "tail of empty list") tl.first0 = first0.tail - tl.last0 = last0 tl.len = len - 1 - tl + tl.last0 = if (tl.len == 0) tl.first0 else last0 } /** Prepends a single element to this list. This operation takes constant diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index 5ea012eb9f..b947fa3cca 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -66,7 +66,7 @@ extends MutableList[A] else { val res = first0.elem first0 = first0.next - len -= 1 + decrementLength() res } @@ -82,11 +82,11 @@ extends MutableList[A] else if (p(first0.elem)) { val res: Option[A] = Some(first0.elem) first0 = first0.next - len -= 1 + decrementLength() res } else { val optElem = removeFromList(p) - if (optElem != None) len -= 1 + if (optElem != None) decrementLength() optElem } @@ -119,7 +119,7 @@ extends MutableList[A] while ((first0.nonEmpty) && p(first0.elem)) { res += first0.elem first0 = first0.next - len -= 1 + decrementLength() } if (first0.isEmpty) res else removeAllFromList(p, res) @@ -130,10 +130,10 @@ extends MutableList[A] var leftlst = first0 while (leftlst.next.nonEmpty) { if (p(leftlst.next.elem)) { - res += leftlst.next.elem - if (leftlst.next eq last0) last0 = leftlst - leftlst.next = leftlst.next.next - len -= 1 + res += leftlst.next.elem + if (leftlst.next eq last0) last0 = leftlst + leftlst.next = leftlst.next.next + decrementLength() } else leftlst = leftlst.next } res @@ -154,7 +154,7 @@ extends MutableList[A] else { val res: Option[LinkedList[A]] = Some(cell.next) cell.next = cell.next.next - len -= 1 + decrementLength() res } } @@ -170,11 +170,8 @@ extends MutableList[A] // TODO - Don't override this just for new to create appropriate type.... override def tail: Queue[A] = { - require(nonEmpty, "tail of empty list") val tl = new Queue[A] - tl.first0 = first0.tail - tl.last0 = last0 - tl.len = len - 1 + tailImpl(tl) tl } @@ -183,6 +180,11 @@ extends MutableList[A] bf ++= seq bf.result } + + private[this] def decrementLength() { + len -= 1 + if (len == 0) last0 = first0 + } } diff --git a/src/library/scala/util/Random.scala b/src/library/scala/util/Random.scala index 24c4cd7a32..2b11594f66 100644 --- a/src/library/scala/util/Random.scala +++ b/src/library/scala/util/Random.scala @@ -17,7 +17,7 @@ import scala.language.{implicitConversions, higherKinds} * @author Stephane Micheloud * */ -class Random(val self: java.util.Random) { +class Random(val self: java.util.Random) extends AnyRef with Serializable { /** Creates a new random number generator using a single long seed. */ def this(seed: Long) = this(new java.util.Random(seed)) diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 0c8e81a220..8f256aa1f5 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -59,8 +59,6 @@ private[reflect] trait BuildUtils { self: Universe => def flagsFromBits(bits: Long): FlagSet - def emptyValDef: ValDef - def This(sym: Symbol): Tree def Select(qualifier: Tree, sym: Symbol): Select diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index c98107f9b5..cfa6315797 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -75,11 +75,26 @@ trait Trees { self: Universe => def isDef: Boolean /** Is this tree one of the empty trees? + * * Empty trees are: the `EmptyTree` null object, `TypeTree` instances that don't carry a type * and the special `emptyValDef` singleton. + * + * In the compiler the `isEmpty` check and the derived `orElse` method are mostly used + * as a check for a tree being a null object (`EmptyTree` for term trees and empty TypeTree for type trees). + * + * Unfortunately `emptyValDef` is also considered to be `isEmpty`, but this is deemed to be + * a conceptual mistake pending a fix in https://issues.scala-lang.org/browse/SI-6762. + * + * @see `canHaveAttrs` */ def isEmpty: Boolean + /** Can this tree carry attributes (i.e. symbols, types or positions)? + * Typically the answer is yes, except for the `EmptyTree` null object and + * two special singletons: `emptyValDef` and `pendingSuperCall`. + */ + def canHaveAttrs: Boolean + /** The canonical way to test if a Tree represents a term. */ def isTerm: Boolean @@ -1611,14 +1626,23 @@ trait Trees { self: Universe => * This node always occurs in the following context: * * (`new` tpt).<init>[targs](args) + * + * For example, an AST representation of: + * + * new Example[Int](2)(3) + * + * is the following code: + * + * Apply( + * Apply( + * TypeApply( + * Select(New(TypeTree(typeOf[Example])), nme.CONSTRUCTOR) + * TypeTree(typeOf[Int])), + * List(Literal(Constant(2)))), + * List(Literal(Constant(3)))) * @group Extractors */ abstract class NewExtractor { - /** A user level `new`. - * One should always use this factory method to build a user level `new`. - * - * @param tpt a class type - */ def apply(tpt: Tree): New def unapply(new_ : New): Option[Tree] } @@ -1720,6 +1744,16 @@ trait Trees { self: Universe => * This AST node corresponds to the following Scala code: * * fun[args] + * + * Should only be used with `fun` nodes which are terms, i.e. which have `isTerm` returning `true`. + * Otherwise `AppliedTypeTree` should be used instead. + * + * def foo[T] = ??? + * foo[Int] // represented as TypeApply(Ident(<foo>), List(TypeTree(<Int>))) + * + * List[Int] as in `val x: List[Int] = ???` + * // represented as AppliedTypeTree(Ident(<List>), List(TypeTree(<Int>))) + * * @group Extractors */ abstract class TypeApplyExtractor { @@ -1890,6 +1924,12 @@ trait Trees { self: Universe => * This AST node corresponds to the following Scala code: * * qualifier.selector + * + * Should only be used with `qualifier` nodes which are terms, i.e. which have `isTerm` returning `true`. + * Otherwise `SelectFromTypeTree` should be used instead. + * + * foo.Bar // represented as Select(Ident(<foo>), <Bar>) + * Foo#Bar // represented as SelectFromTypeTree(Ident(<Foo>), <Bar>) * @group Extractors */ abstract class SelectExtractor { @@ -2122,7 +2162,6 @@ trait Trees { self: Universe => * @group Trees * @template */ - // [Eugene++] don't see why we need it, when we have Select type SelectFromTypeTree >: Null <: TypTree with RefTree with SelectFromTypeTreeApi /** A tag that preserves the identity of the `SelectFromTypeTree` abstract type from erasure. @@ -2142,6 +2181,12 @@ trait Trees { self: Universe => * qualifier # selector * * Note: a path-dependent type p.T is expressed as p.type # T + * + * Should only be used with `qualifier` nodes which are types, i.e. which have `isType` returning `true`. + * Otherwise `Select` should be used instead. + * + * Foo#Bar // represented as SelectFromTypeTree(Ident(<Foo>), <Bar>) + * foo.Bar // represented as Select(Ident(<foo>), <Bar>) * @group Extractors */ abstract class SelectFromTypeTreeExtractor { @@ -2217,6 +2262,15 @@ trait Trees { self: Universe => * This AST node corresponds to the following Scala code: * * tpt[args] + * + * Should only be used with `tpt` nodes which are types, i.e. which have `isType` returning `true`. + * Otherwise `TypeApply` should be used instead. + * + * List[Int] as in `val x: List[Int] = ???` + * // represented as AppliedTypeTree(Ident(<List>), List(TypeTree(<Int>))) + * + * def foo[T] = ??? + * foo[Int] // represented as TypeApply(Ident(<foo>), List(TypeTree(<Int>))) * @group Extractors */ abstract class AppliedTypeTreeExtractor { @@ -2366,123 +2420,155 @@ trait Trees { self: Universe => */ val emptyValDef: ValDef + /** An empty superclass constructor call corresponding to: + * super.<init>() + * This is used as a placeholder in the primary constructor body in class templates + * to denote the insertion point of a call to superclass constructor after the typechecker + * figures out the superclass of a given template. + * @group Trees + */ + val pendingSuperCall: Apply + // ---------------------- factories ---------------------------------------------- /** A factory method for `ClassDef` nodes. * @group Factories */ + @deprecated("Use the canonical ClassDef constructor to create a class and then initialize its position and symbol manually", "2.10.1") def ClassDef(sym: Symbol, impl: Template): ClassDef /** A factory method for `ModuleDef` nodes. * @group Factories */ + @deprecated("Use the canonical ModuleDef constructor to create an object and then initialize its position and symbol manually", "2.10.1") def ModuleDef(sym: Symbol, impl: Template): ModuleDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical ValDef constructor to create a val and then initialize its position and symbol manually", "2.10.1") def ValDef(sym: Symbol, rhs: Tree): ValDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical ValDef constructor to create a val with an empty right-hand side and then initialize its position and symbol manually", "2.10.1") def ValDef(sym: Symbol): ValDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1") def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1") def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1") def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1") def DefDef(sym: Symbol, rhs: Tree): DefDef /** A factory method for `ValDef` nodes. * @group Factories */ + @deprecated("Use the canonical DefDef constructor to create a method and then initialize its position and symbol manually", "2.10.1") def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef /** A factory method for `TypeDef` nodes. * @group Factories */ + @deprecated("Use the canonical TypeDef constructor to create a type alias and then initialize its position and symbol manually", "2.10.1") def TypeDef(sym: Symbol, rhs: Tree): TypeDef /** A factory method for `TypeDef` nodes. * @group Factories */ + @deprecated("Use the canonical TypeDef constructor to create an abstract type or type parameter and then initialize its position and symbol manually", "2.10.1") def TypeDef(sym: Symbol): TypeDef /** A factory method for `LabelDef` nodes. * @group Factories */ + @deprecated("Use the canonical LabelDef constructor to create a label and then initialize its position and symbol manually", "2.10.1") def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef /** A factory method for `Block` nodes. * Flattens directly nested blocks. * @group Factories */ + @deprecated("Use the canonical Block constructor, explicitly specifying its expression if necessary. Flatten directly nested blocks manually if needed", "2.10.1") def Block(stats: Tree*): Block /** A factory method for `CaseDef` nodes. * @group Factories */ + @deprecated("Use the canonical CaseDef constructor passing EmptyTree for guard", "2.10.1") def CaseDef(pat: Tree, body: Tree): CaseDef /** A factory method for `Bind` nodes. * @group Factories */ + @deprecated("Use the canonical Bind constructor to create a bind and then initialize its symbol manually", "2.10.1") def Bind(sym: Symbol, body: Tree): Bind /** A factory method for `Try` nodes. * @group Factories */ + @deprecated("Use canonical CaseDef constructors to to create exception catching expressions and then wrap them in Try", "2.10.1") def Try(body: Tree, cases: (Tree, Tree)*): Try /** A factory method for `Throw` nodes. * @group Factories */ + @deprecated("Use the canonical New constructor to create an object instantiation expression and then wrap it in Throw", "2.10.1") def Throw(tpe: Type, args: Tree*): Throw /** Factory method for object creation `new tpt(args_1)...(args_n)` * A `New(t, as)` is expanded to: `(new t).<init>(as)` * @group Factories */ + @deprecated("Use Apply(...Apply(Select(New(tpt), nme.CONSTRUCTOR), args1)...argsN) instead", "2.10.1") def New(tpt: Tree, argss: List[List[Tree]]): Tree /** 0-1 argument list new, based on a type. * @group Factories */ + @deprecated("Use New(TypeTree(tpe), args.toList) instead", "2.10.1") def New(tpe: Type, args: Tree*): Tree /** 0-1 argument list new, based on a symbol. * @group Factories */ + @deprecated("Use New(sym.toType, args) instead", "2.10.1") def New(sym: Symbol, args: Tree*): Tree /** A factory method for `Apply` nodes. * @group Factories */ + @deprecated("Use Apply(Ident(sym), args.toList) instead", "2.10.1") def Apply(sym: Symbol, args: Tree*): Tree /** 0-1 argument list new, based on a type tree. * @group Factories */ + @deprecated("Use Apply(Select(New(tpt), nme.CONSTRUCTOR), args) instead", "2.10.1") def ApplyConstructor(tpt: Tree, args: List[Tree]): Tree /** A factory method for `Super` nodes. * @group Factories */ + @deprecated("Use Super(This(sym), mix) instead", "2.10.1") def Super(sym: Symbol, mix: TypeName): Tree /** A factory method for `This` nodes. @@ -2494,6 +2580,7 @@ trait Trees { self: Universe => * The string `name` argument is assumed to represent a [[scala.reflect.api.Names#TermName `TermName`]]. * @group Factories */ + @deprecated("Use Select(tree, newTermName(name)) instead", "2.10.1") def Select(qualifier: Tree, name: String): Select /** A factory method for `Select` nodes. @@ -2504,6 +2591,7 @@ trait Trees { self: Universe => /** A factory method for `Ident` nodes. * @group Factories */ + @deprecated("Use Ident(newTermName(name)) instead", "2.10.1") def Ident(name: String): Ident /** A factory method for `Ident` nodes. @@ -2843,7 +2931,8 @@ trait Trees { self: Universe => trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef]) /** Transforms a `ValDef`. */ def transformValDef(tree: ValDef): ValDef = - if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef] + if (tree eq emptyValDef) tree + else transform(tree).asInstanceOf[ValDef] /** Transforms a list of `ValDef` nodes. */ def transformValDefs(trees: List[ValDef]): List[ValDef] = trees mapConserve (transformValDef(_)) diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 6bf12f06de..eba10e8ffb 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -60,7 +60,7 @@ trait BaseTypeSeqs { elems(i) match { case rtp @ RefinedType(variants, decls) => // can't assert decls.isEmpty; see t0764 - //if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j)) + //if (!decls.isEmpty) abort("computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j)) //Console.println("compute closure of "+this+" => glb("+variants+")") pending += i try { diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 9da6ad652a..175943d264 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -45,8 +45,6 @@ trait BuildUtils { self: SymbolTable => def flagsFromBits(bits: Long): FlagSet = bits - def emptyValDef: ValDef = self.emptyValDef - def This(sym: Symbol): Tree = self.This(sym) def Select(qualifier: Tree, sym: Symbol): Select = self.Select(qualifier, sym) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 6ad9a63822..29f1c7e1ca 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -333,6 +333,8 @@ trait Importers extends api.Importers { self: SymbolTable => new ModuleDef(importModifiers(mods), importName(name).toTermName, importTemplate(impl)) case from.emptyValDef => emptyValDef + case from.pendingSuperCall => + pendingSuperCall case from.ValDef(mods, name, tpt, rhs) => new ValDef(importModifiers(mods), importName(name).toTermName, importTree(tpt), importTree(rhs)) case from.DefDef(mods, name, tparams, vparamss, tpt, rhs) => diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index faa161d6b1..f8c670827a 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -38,7 +38,7 @@ trait Positions extends api.Positions { self: SymbolTable => protected class DefaultPosAssigner extends PosAssigner { var pos: Position = _ override def traverse(t: Tree) { - if (t eq EmptyTree) () + if (!t.canHaveAttrs) () else if (t.pos == NoPosition) { t.setPos(pos) super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if? diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index c36724e388..2a3525206f 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -435,7 +435,7 @@ trait Printers extends api.Printers { self: SymbolTable => case tree => xprintTree(this, tree) } - if (printTypes && tree.isTerm && !tree.isEmpty) { + if (printTypes && tree.isTerm && tree.canHaveAttrs) { print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}") } } @@ -540,8 +540,10 @@ trait Printers extends api.Printers { self: SymbolTable => print(")") case EmptyTree => print("EmptyTree") - case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef => + case self.emptyValDef => print("emptyValDef") + case self.pendingSuperCall => + print("pendingSuperCall") case tree: Tree => val hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol val isError = hasSymbolField && tree.symbol.name.toString == nme.ERROR.toString diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index f7b4b87570..c5521ae650 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -645,6 +645,7 @@ trait StdNames { val notifyAll_ : NameType = "notifyAll" val notify_ : NameType = "notify" val null_ : NameType = "null" + val pendingSuperCall: NameType = "pendingSuperCall" val prefix : NameType = "prefix" val productArity: NameType = "productArity" val productElement: NameType = "productElement" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 5af4c616ff..1f8658cc86 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -3051,7 +3051,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => class RefinementClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position) extends ClassSymbol(owner0, pos0, tpnme.REFINE_CLASS_NAME) { override def name_=(name: Name) { - assert(false, "Cannot set name of RefinementClassSymbol to " + name) + abort("Cannot set name of RefinementClassSymbol to " + name) super.name_=(name) } override def isRefinementClass = true diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 4f60d9cabc..13b761086c 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -184,29 +184,26 @@ abstract class TreeInfo { def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name.toTermName)) != NoSymbol tree match { - case Ident(_) => isVar - case Select(_, _) => isVar || isGetter - case _ => - methPart(tree) match { - case Select(qual, nme.apply) => qual.tpe.member(nme.update) != NoSymbol - case _ => false - } + case Ident(_) => isVar + case Select(_, _) => isVar || isGetter + case Applied(Select(qual, nme.apply), _, _) => qual.tpe.member(nme.update) != NoSymbol + case _ => false } } /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the * same object? */ - def isSelfConstrCall(tree: Tree): Boolean = methPart(tree) match { - case Ident(nme.CONSTRUCTOR) - | Select(This(_), nme.CONSTRUCTOR) => true + def isSelfConstrCall(tree: Tree): Boolean = tree match { + case Applied(Ident(nme.CONSTRUCTOR), _, _) => true + case Applied(Select(This(_), nme.CONSTRUCTOR), _, _) => true case _ => false } /** Is tree a super constructor call? */ - def isSuperConstrCall(tree: Tree): Boolean = methPart(tree) match { - case Select(Super(_, _), nme.CONSTRUCTOR) => true + def isSuperConstrCall(tree: Tree): Boolean = tree match { + case Applied(Select(Super(_, _), nme.CONSTRUCTOR), _, _) => true case _ => false } @@ -332,6 +329,9 @@ abstract class TreeInfo { def preSuperFields(stats: List[Tree]): List[ValDef] = stats collect { case vd: ValDef if isEarlyValDef(vd) => vd } + def hasUntypedPreSuperFields(stats: List[Tree]): Boolean = + preSuperFields(stats) exists (_.tpt.isEmpty) + def isEarlyDef(tree: Tree) = tree match { case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER case ValDef(mods, _, _, _) => mods hasFlag PRESUPER @@ -392,22 +392,6 @@ abstract class TreeInfo { case _ => false } - /** If this tree represents a type application (after unwrapping - * any applies) the first type argument. Otherwise, EmptyTree. - */ - def firstTypeArg(tree: Tree): Tree = tree match { - case Apply(fn, _) => firstTypeArg(fn) - case TypeApply(_, targ :: _) => targ - case _ => EmptyTree - } - - /** If this tree represents a type application the type arguments. Otherwise Nil. - */ - def typeArguments(tree: Tree): List[Tree] = tree match { - case TypeApply(_, targs) => targs - case _ => Nil - } - /** If this tree has type parameters, those. Otherwise Nil. */ def typeParameters(tree: Tree): List[TypeDef] = tree match { @@ -522,31 +506,126 @@ abstract class TreeInfo { def isSynthCaseSymbol(sym: Symbol) = sym hasAllFlags SYNTH_CASE_FLAGS def hasSynthCaseSymbol(t: Tree) = t.symbol != null && isSynthCaseSymbol(t.symbol) + def isTraitRef(tree: Tree): Boolean = { + val sym = if (tree.tpe != null) tree.tpe.typeSymbol else null + ((sym ne null) && sym.initialize.isTrait) + } - /** The method part of an application node + /** Applications in Scala can have one of the following shapes: + * + * 1) naked core: Ident(_) or Select(_, _) or basically anything else + * 2) naked core with targs: TypeApply(core, targs) or AppliedTypeTree(core, targs) + * 3) apply or several applies wrapping a core: Apply(core, _), or Apply(Apply(core, _), _), etc + * + * This class provides different ways to decompose applications and simplifies their analysis. + * + * ***Examples*** + * (TypeApply in the examples can be replaced with AppliedTypeTree) + * + * Ident(foo): + * * callee = Ident(foo) + * * core = Ident(foo) + * * targs = Nil + * * argss = Nil + * + * TypeApply(foo, List(targ1, targ2...)) + * * callee = TypeApply(foo, List(targ1, targ2...)) + * * core = foo + * * targs = List(targ1, targ2...) + * * argss = Nil + * + * Apply(foo, List(arg1, arg2...)) + * * callee = foo + * * core = foo + * * targs = Nil + * * argss = List(List(arg1, arg2...)) + * + * Apply(Apply(foo, List(arg21, arg22, ...)), List(arg11, arg12...)) + * * callee = foo + * * core = foo + * * targs = Nil + * * argss = List(List(arg11, arg12...), List(arg21, arg22, ...)) + * + * Apply(Apply(TypeApply(foo, List(targs1, targs2, ...)), List(arg21, arg22, ...)), List(arg11, arg12...)) + * * callee = TypeApply(foo, List(targs1, targs2, ...)) + * * core = foo + * * targs = Nil + * * argss = List(List(arg11, arg12...), List(arg21, arg22, ...)) */ - def methPart(tree: Tree): Tree = tree match { - case Apply(fn, _) => methPart(fn) - case TypeApply(fn, _) => methPart(fn) - case AppliedTypeTree(fn, _) => methPart(fn) - case _ => tree + class Applied(val tree: Tree) { + /** The tree stripped of the possibly nested applications. + * The original tree if it's not an application. + */ + def callee: Tree = { + def loop(tree: Tree): Tree = tree match { + case Apply(fn, _) => loop(fn) + case tree => tree + } + loop(tree) + } + + /** The `callee` unwrapped from type applications. + * The original `callee` if it's not a type application. + */ + def core: Tree = callee match { + case TypeApply(fn, _) => fn + case AppliedTypeTree(fn, _) => fn + case tree => tree + } + + /** The type arguments of the `callee`. + * `Nil` if the `callee` is not a type application. + */ + def targs: List[Tree] = callee match { + case TypeApply(_, args) => args + case AppliedTypeTree(_, args) => args + case _ => Nil + } + + /** (Possibly multiple lists of) value arguments of an application. + * `Nil` if the `callee` is not an application. + */ + def argss: List[List[Tree]] = { + def loop(tree: Tree): List[List[Tree]] = tree match { + case Apply(fn, args) => loop(fn) :+ args + case _ => Nil + } + loop(tree) + } + + /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _) + * has depth 3. Continues through type applications (without counting them.) + */ + def applyDepth: Int = { + def loop(tree: Tree): Int = tree match { + case Apply(fn, _) => 1 + loop(fn) + case TypeApply(fn, _) => loop(fn) + case AppliedTypeTree(fn, _) => loop(fn) + case _ => 0 + } + loop(tree) + } } - /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _) - * has depth 3. Continues through type applications (without counting them.) + /** Returns a wrapper that knows how to destructure and analyze applications. */ - def applyDepth(tree: Tree): Int = tree match { - case Apply(fn, _) => 1 + applyDepth(fn) - case TypeApply(fn, _) => applyDepth(fn) - case AppliedTypeTree(fn, _) => applyDepth(fn) - case _ => 0 - } - def firstArgument(tree: Tree): Tree = tree match { - case Apply(fn, args) => - val f = firstArgument(fn) - if (f == EmptyTree && !args.isEmpty) args.head else f - case _ => - EmptyTree + def dissectApplied(tree: Tree) = new Applied(tree) + + /** Destructures applications into important subparts described in `Applied` class, + * namely into: core, targs and argss (in the specified order). + * + * Trees which are not applications are also accepted. Their callee and core will + * be equal to the input, while targs and argss will be Nil. + * + * The provided extractors don't expose all the API of the `Applied` class. + * For advanced use, call `dissectApplied` explicitly and use its methods instead of pattern matching. + */ + object Applied { + def unapply(applied: Applied): Option[(Tree, List[Tree], List[List[Tree]])] = + Some((applied.core, applied.targs, applied.argss)) + + def unapply(tree: Tree): Option[(Tree, List[Tree], List[List[Tree]])] = + unapply(dissectApplied(tree)) } /** Does list of trees start with a definition of @@ -643,7 +722,7 @@ abstract class TreeInfo { } def unapply(tree: Tree) = refPart(tree) match { - case ref: RefTree => Some((ref.qualifier.symbol, ref.symbol, typeArguments(tree))) + case ref: RefTree => Some((ref.qualifier.symbol, ref.symbol, dissectApplied(tree).targs)) case _ => None } } diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 5c1d109662..6dc1ff157c 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -37,6 +37,7 @@ trait Trees extends api.Trees { self: SymbolTable => def isDef = false def isEmpty = false + def canHaveAttrs = true /** The canonical way to test if a Tree represents a term. */ @@ -229,14 +230,6 @@ trait Trees extends api.Trees { self: SymbolTable => override def isDef = true } - case object EmptyTree extends TermTree { - val asList = List(this) - super.tpe_=(NoType) - override def tpe_=(t: Type) = - if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>") - override def isEmpty = true - } - abstract class MemberDef extends DefTree with MemberDefApi { def mods: Modifiers def keyword: String = this match { @@ -610,6 +603,7 @@ trait Trees extends api.Trees { self: SymbolTable => case _: ApplyToImplicitArgs => new ApplyToImplicitArgs(fun, args) case _: ApplyImplicitView => new ApplyImplicitView(fun, args) // TODO: ApplyConstructor ??? + case self.pendingSuperCall => self.pendingSuperCall case _ => new Apply(fun, args) }).copyAttrs(tree) def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = @@ -971,12 +965,23 @@ trait Trees extends api.Trees { self: SymbolTable => def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) - object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) { - override def isEmpty = true + trait CannotHaveAttrs extends Tree { + override def canHaveAttrs = false + + private def unsupported(what: String, args: Any*) = + throw new UnsupportedOperationException(s"$what($args) inapplicable for "+self.toString) + super.setPos(NoPosition) - override def setPos(pos: Position) = { assert(false); this } + override def setPos(pos: Position) = unsupported("setPos", pos) + + super.setType(NoType) + override def tpe_=(t: Type) = if (t != NoType) unsupported("tpe_=", t) } + case object EmptyTree extends TermTree with CannotHaveAttrs { override def isEmpty = true; val asList = List(this) } + object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) with CannotHaveAttrs + object pendingSuperCall extends Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()) with CannotHaveAttrs + def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef = atPos(sym.pos) { assert(sym != NoSymbol) @@ -1044,6 +1049,9 @@ trait Trees extends api.Trees { self: SymbolTable => def New(tpe: Type, args: Tree*): Tree = ApplyConstructor(TypeTree(tpe), args.toList) + def New(tpe: Type, argss: List[List[Tree]]): Tree = + New(TypeTree(tpe), argss) + def New(sym: Symbol, args: Tree*): Tree = New(sym.tpe, args: _*) @@ -1124,7 +1132,7 @@ trait Trees extends api.Trees { self: SymbolTable => traverse(annot); traverse(arg) case Template(parents, self, body) => traverseTrees(parents) - if (!self.isEmpty) traverse(self) + if (self ne emptyValDef) traverse(self) traverseStats(body, tree.symbol) case Block(stats, expr) => traverseTrees(stats); traverse(expr) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 09fc534d8a..58dd7f3a03 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1337,7 +1337,7 @@ trait Types extends api.Types { self: SymbolTable => if (!sym.isClass) { // SI-6640 allow StubSymbols to reveal what's missing from the classpath before we trip the assertion. sym.failIfStub() - assert(false, sym) + abort(s"ThisType($sym) for sym which is not a class") } override def isTrivial: Boolean = sym.isPackageClass @@ -6797,7 +6797,7 @@ trait Types extends api.Types { self: SymbolTable => case ExistentialType(tparams, quantified) :: rest => mergePrefixAndArgs(quantified :: rest, variance, depth) map (existentialAbstraction(tparams, _)) case _ => - assert(false, tps); None + abort(s"mergePrefixAndArgs($tps, $variance, $depth): unsupported tps") } def addMember(thistp: Type, tp: Type, sym: Symbol): Unit = addMember(thistp, tp, sym, AnyDepth) diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 5a0454a569..5b01b5ffa5 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -308,7 +308,7 @@ abstract class UnPickler { if (isModuleRoot) moduleRoot setFlag pflags else owner.newLinkedModule(clazz, pflags) case VALsym => - if (isModuleRoot) { assert(false); NoSymbol } + if (isModuleRoot) { abort(s"VALsym at module root: owner = $owner, name = $name") } else owner.newTermSymbol(name.toTermName, NoPosition, pflags) case _ => diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala index 0c1640ceb9..6dc6a0f7b8 100644 --- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala +++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala @@ -19,8 +19,7 @@ trait UnCurry { case MethodType(params, MethodType(params1, restpe)) => apply(MethodType(params ::: params1, restpe)) case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) => - assert(false, "unexpected curried method types with intervening existential") - tp0 + abort("unexpected curried method types with intervening existential") case MethodType(h :: t, restpe) if h.isImplicit => apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe)) case NullaryMethodType(restpe) => diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index bbc95feaab..1c29cabe24 100644 --- a/src/reflect/scala/reflect/internal/util/Position.scala +++ b/src/reflect/scala/reflect/internal/util/Position.scala @@ -7,6 +7,7 @@ package scala.reflect.internal.util import scala.reflect.ClassTag +import scala.reflect.internal.FatalError import scala.reflect.macros.Attachments object Position { @@ -269,7 +270,7 @@ class OffsetPosition(override val source: SourceFile, override val point: Int) e /** new for position ranges */ class RangePosition(source: SourceFile, override val start: Int, point: Int, override val end: Int) extends OffsetPosition(source, point) { - if (start > end) assert(false, "bad position: "+show) + if (start > end) sys.error("bad position: "+show) override def isRange: Boolean = true override def isOpaqueRange: Boolean = true override def startOrPoint: Int = start diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 556db08baa..f6ce19e1d7 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -413,7 +413,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni case sym if sym.owner.isPrimitiveValueClass => invokePrimitiveMethod case sym if sym == Predef_classOf => fail("Predef.classOf is a compile-time function") case sym if sym.isTermMacro => fail(s"${symbol.fullName} is a macro, i.e. a compile-time function") - case _ => assert(false, this) + case _ => abort(s"unsupported symbol $symbol when invoking $this") } } } |