diff options
88 files changed, 838 insertions, 750 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 31974b5b76..949f7f1799 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -45,9 +45,7 @@ trait GenTrees { case global.EmptyTree => reifyMirrorObject(EmptyTree) case global.emptyValDef => - mirrorSelect(nme.emptyValDef) - case global.pendingSuperCall => - mirrorSelect(nme.pendingSuperCall) + mirrorBuildSelect(nme.emptyValDef) case FreeDef(_, _, _, _, _) => reifyNestedFreeDef(tree) case FreeRef(_, _) => diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index 7aa87dc2f8..bb7e1f9b56 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -69,8 +69,7 @@ trait GenTypes { def reificationIsConcrete: Boolean = state.reificationIsConcrete def spliceType(tpe: Type): Tree = { - val quantified = currentQuantified - if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) { + if (tpe.isSpliceable && !(boundSymbolsInCallstack contains tpe.typeSymbol)) { if (reifyDebug) println("splicing " + tpe) val tagFlavor = if (concrete) tpnme.TypeTag.toString else tpnme.WeakTypeTag.toString diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala index 21db93d8f5..49877b4286 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala @@ -34,6 +34,9 @@ trait GenUtils { def mirrorSelect(name: String): Tree = termPath(nme.UNIVERSE_PREFIX + name) + def mirrorBuildSelect(name: String): Tree = + termPath(nme.UNIVERSE_BUILD_PREFIX + name) + def mirrorMirrorSelect(name: String): Tree = termPath(nme.MIRROR_PREFIX + name) diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala index dc0028be38..8e13a45cdb 100644 --- a/src/compiler/scala/reflect/reify/phases/Reify.scala +++ b/src/compiler/scala/reflect/reify/phases/Reify.scala @@ -28,7 +28,10 @@ trait Reify extends GenSymbols finally currents = currents.tail } } - def currentQuantified = flatCollect(reifyStack.currents)({ case ExistentialType(quantified, _) => quantified }) + def boundSymbolsInCallstack = flatCollect(reifyStack.currents) { + case ExistentialType(quantified, _) => quantified + case PolyType(typeParams, _) => typeParams + } def current = reifyStack.currents.head def currents = reifyStack.currents diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala index 49569f5e05..d8fb632f73 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.canHaveAttrs) () + if ((c eq EmptyTree) || (c eq emptyValDef)) () 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 96146b7343..99b82d9746 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -58,7 +58,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), Nil), expr) + Annotated(New(scalaDot(UncheckedClass.name), ListOfNil), expr) } // if it's a Match, mark the selector unchecked; otherwise nothing. def mkUncheckedMatch(tree: Tree) = tree match { diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index def1198dae..2ad762fd55 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -65,13 +65,6 @@ 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.mkSuperSelect, Nil) - case xs :: rest => rest.foldLeft(Apply(gen.mkSuperSelect, xs): Tree)(Apply.apply) - } - /** Generates a template with constructor corresponding to * * constrmods (vparams1_) ... (vparams_n) preSuper { presupers } @@ -89,7 +82,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * body * } */ - def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): Template = { + def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): Template = { /* Add constructor to template */ // create parameters for <init> as synthetic trees. @@ -124,16 +117,9 @@ 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.mkSuperSelect) - 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 + val superCall = (superRef /: argss) (Apply.apply) List( - // 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)) ( + atPos(wrappingPos(superPos, lvdefs ::: argss.flatten)) ( DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant()))))) } } @@ -151,10 +137,11 @@ 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]], body: List[Tree], superPos: Position): ClassDef = { + def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], 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)), @@ -164,7 +151,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, body, superPos)) + constrMods, vparamss, argss, body, superPos)) } // --- subcomponents -------------------------------------------------- @@ -337,8 +324,6 @@ 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) @@ -352,6 +337,8 @@ 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.hasSymbol && (!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 c508e14343..6f79f639b9 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1559,9 +1559,9 @@ self => val nstart = in.skipToken() val npos = r2p(nstart, nstart, in.lastOffset) val tstart = in.offset - val (parents, self, stats) = template() + val (parents, argss, self, stats) = template(isTrait = false) val cpos = r2p(tstart, tstart, in.lastOffset max tstart) - makeNew(parents, self, stats, npos, cpos) + makeNew(parents, self, stats, argss, npos, cpos) case _ => syntaxErrorOrIncomplete("illegal start of simple expression", true) errorTermTree @@ -2103,7 +2103,7 @@ self => def annotationExpr(): Tree = atPos(in.offset) { val t = exprSimpleType() if (in.token == LPAREN) New(t, multipleArgumentExprs()) - else New(t, Nil) + else New(t, ListOfNil) } /* -------- PARAMETERS ------------------------------------------- */ @@ -2739,17 +2739,20 @@ self => * TraitParents ::= AnnotType {with AnnotType} * }}} */ - 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)) + 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() } - readAppliedParent() - while (in.token == WITH) { in.nextToken(); readAppliedParent() } - parents.toList + (parents.toList, argss) } /** {{{ @@ -2759,12 +2762,12 @@ self => * EarlyDef ::= Annotations Modifiers PatDef * }}} */ - def template(): (List[Tree], ValDef, List[Tree]) = { + def template(isTrait: Boolean): (List[Tree], List[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 eq emptyValDef)) { + if (in.token == WITH && self.isEmpty) { val earlyDefs: List[Tree] = body flatMap { case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => List(copyValDef(vdef)(mods = mods | Flags.PRESUPER)) @@ -2776,16 +2779,16 @@ self => case _ => List() } in.nextToken() - val parents = templateParents() - val (self1, body1) = templateBodyOpt(parenMeansSyntaxError = false) - (parents, self1, earlyDefs ::: body1) + val (parents, argss) = templateParents(isTrait = isTrait) + val (self1, body1) = templateBodyOpt(traitParentSeen = isTrait) + (parents, argss, self1, earlyDefs ::: body1) } else { - (List(), self, body) + (List(), ListOfNil, self, body) } } else { - val parents = templateParents() - val (self, body) = templateBodyOpt(parenMeansSyntaxError = false) - (parents, self, body) + val (parents, argss) = templateParents(isTrait = isTrait) + val (self, body) = templateBodyOpt(traitParentSeen = isTrait) + (parents, argss, self, body) } } @@ -2799,15 +2802,15 @@ self => * }}} */ def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = { - val (parents0, self, body) = ( + val (parents0, argss, self, body) = ( if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) { in.nextToken() - template() + template(isTrait = mods.isTrait) } else { newLineOptWhenFollowedBy(LBRACE) - val (self, body) = templateBodyOpt(parenMeansSyntaxError = mods.isTrait || name.isTermName) - (List(), self, body) + val (self, body) = templateBodyOpt(traitParentSeen = false) + (List(), ListOfNil, self, body) } ) def anyrefParents() = { @@ -2829,7 +2832,7 @@ self => if (inScalaRootPackage && ScalaValueClassNames.contains(name)) Template(parents0, self, anyvalConstructor :: body) else - Template(anyrefParents, self, constrMods, vparamss, body, o2p(tstart)) + Template(anyrefParents, self, constrMods, vparamss, argss, body, o2p(tstart)) } } @@ -2844,15 +2847,14 @@ self => case (self, Nil) => (self, EmptyTree.asList) case result => result } - def templateBodyOpt(parenMeansSyntaxError: Boolean): (ValDef, List[Tree]) = { + def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { templateBody(isPre = false) } else { - if (in.token == LPAREN) { - if (parenMeansSyntaxError) syntaxError(s"traits or objects may not have parameters", true) - else abort("unexpected opening parenthesis") - } + if (in.token == LPAREN) + syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ + " may not have parameters", true) (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 ac8ab493e0..7969bb9c20 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -205,26 +205,20 @@ abstract class TreeBuilder { */ def makeAnonymousNew(stats: List[Tree]): Tree = { val stats1 = if (stats.isEmpty) List(Literal(Constant(()))) else stats - makeNew(Nil, emptyValDef, stats1, NoPosition, NoPosition) + makeNew(Nil, emptyValDef, stats1, ListOfNil, 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], + def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree], argss: List[List[Tree]], npos: Position, cpos: Position): Tree = if (parents.isEmpty) - 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 { + makeNew(List(scalaAnyRefConstr), self, stats, argss, npos, cpos) + else if (parents.tail.isEmpty && stats.isEmpty) + atPos(npos union cpos) { New(parents.head, argss) } + else { val x = tpnme.ANON_CLASS_NAME atPos(npos union cpos) { Block( @@ -232,12 +226,12 @@ abstract class TreeBuilder { atPos(cpos) { ClassDef( Modifiers(FINAL), x, Nil, - Template(parents, self, NoMods, ListOfNil, stats, cpos.focus)) + Template(parents, self, NoMods, ListOfNil, argss, stats, cpos.focus)) }), atPos(npos) { New( Ident(x) setPos npos.focus, - Nil) + ListOfNil) } ) } diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index d4a6d18c60..1beed3f420 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -20,7 +20,7 @@ abstract class DeadCodeElimination extends SubComponent { /** The block and index where an instruction is located */ type InstrLoc = (BasicBlock, Int) - + val phaseName = "dce" /** Create a new phase */ @@ -68,10 +68,10 @@ abstract class DeadCodeElimination extends SubComponent { /** what local variables have been accessed at least once? */ var accessedLocals: List[Local] = Nil - + /** Map from a local and a basic block to the instructions that store to that local in that basic block */ val localStores = mutable.Map[(Local, BasicBlock), mutable.BitSet]() withDefault {_ => mutable.BitSet()} - + /** Stores that clobber previous stores to array or ref locals. See SI-5313 */ val clobbers = mutable.Set[InstrLoc]() @@ -91,7 +91,7 @@ abstract class DeadCodeElimination extends SubComponent { accessedLocals = m.params.reverse m.code.blocks ++= linearizer.linearize(m) collectRDef(m) - mark + mark() sweep(m) accessedLocals = accessedLocals.distinct val diff = m.locals diff accessedLocals @@ -113,10 +113,25 @@ abstract class DeadCodeElimination extends SubComponent { useful(bb) = new mutable.BitSet(bb.size) var rd = rdef.in(bb); for (Pair(i, idx) <- bb.toList.zipWithIndex) { + + // utility for adding to worklist + def moveToWorkList() = moveToWorkListIf(true) + + // utility for (conditionally) adding to worklist + def moveToWorkListIf(cond: Boolean) = + if (cond) { + debuglog("in worklist: " + i) + worklist += ((bb, idx)) + } else { + debuglog("not in worklist: " + i) + } + + // instruction-specific logic i match { case LOAD_LOCAL(_) => defs = defs + Pair(((bb, idx)), rd.vars) + moveToWorkListIf(false) case STORE_LOCAL(l) => /* SI-4935 Check whether a module is stack top, if so mark the instruction that loaded it @@ -135,7 +150,8 @@ abstract class DeadCodeElimination extends SubComponent { case _ => false } } - if (necessary) worklist += ((bb, idx)) + moveToWorkListIf(necessary) + // add it to the localStores map val key = (l, bb) val set = localStores(key) @@ -144,10 +160,15 @@ abstract class DeadCodeElimination extends SubComponent { case RETURN(_) | JUMP(_) | CJUMP(_, _, _, _) | CZJUMP(_, _, _, _) | STORE_FIELD(_, _) | THROW(_) | LOAD_ARRAY_ITEM(_) | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | STORE_THIS(_) | - LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() => worklist += ((bb, idx)) - case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)); debuglog("marking " + m1) + LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() => + moveToWorkList() + + case CALL_METHOD(m1, _) if isSideEffecting(m1) => + moveToWorkList() + case CALL_METHOD(m1, SuperCall(_)) => - worklist += ((bb, idx)) // super calls to constructor + moveToWorkList() // super calls to constructor + case DROP(_) => val necessary = rdef.findDefs(bb, idx, 1) exists { p => val (bb1, idx1) = p @@ -156,12 +177,13 @@ abstract class DeadCodeElimination extends SubComponent { case LOAD_EXCEPTION(_) | DUP(_) | LOAD_MODULE(_) => true case _ => dropOf((bb1, idx1)) = (bb,idx) :: dropOf.getOrElse((bb1, idx1), Nil) -// println("DROP is innessential: " + i + " because of: " + bb1(idx1) + " at " + bb1 + ":" + idx1) + debuglog("DROP is innessential: " + i + " because of: " + bb1(idx1) + " at " + bb1 + ":" + idx1) false } } - if (necessary) worklist += ((bb, idx)) + moveToWorkListIf(necessary) case _ => () + moveToWorkListIf(false) } rd = rdef.interpret(bb, idx, rd) } @@ -183,19 +205,30 @@ abstract class DeadCodeElimination extends SubComponent { debuglog("Marking instr: \tBB_" + bb + ": " + idx + " " + bb(idx)) val instr = bb(idx) - // adds the instrutions that define the stack values about to be consumed to the work list to + // adds the instrutions that define the stack values about to be consumed to the work list to // be marked useful def addDefs() = for ((bb1, idx1) <- rdef.findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) { debuglog(s"\t${bb1(idx1)} is consumed by $instr") worklist += ((bb1, idx1)) } + // DROP logic -- if an instruction is useful, its drops are also useful + // and we don't mark the DROPs as useful directly but add them to the + // worklist so we also mark their reaching defs as useful - see SI-7060 if (!useful(bb)(idx)) { useful(bb) += idx dropOf.get(bb, idx) foreach { - for ((bb1, idx1) <- _) - useful(bb1) += idx1 + for ((bb1, idx1) <- _) { + /* + * SI-7060: A drop that we now mark as useful can be reached via several paths, + * so we should follow by marking all its reaching definition as useful too: + */ + debuglog("\tAdding: " + bb1(idx1) + " to the worklist, as a useful DROP.") + worklist += ((bb1, idx1)) + } } + + // per-instruction logic instr match { case LOAD_LOCAL(l1) => for ((l2, bb1, idx1) <- defs((bb, idx)) if l1 == l2; if !useful(bb1)(idx1)) { @@ -203,7 +236,7 @@ abstract class DeadCodeElimination extends SubComponent { worklist += ((bb1, idx1)) } - case STORE_LOCAL(l1) if l1.kind.isRefOrArrayType => + case STORE_LOCAL(l1) if l1.kind.isRefOrArrayType => addDefs() // see SI-5313 // search for clobbers of this store if we aren't doing l1 = null @@ -211,7 +244,7 @@ abstract class DeadCodeElimination extends SubComponent { // a lot of null stores very cheaply if (idx == 0 || bb(idx - 1) != CONSTANT(Constant(null))) findClobbers(l1, bb, idx + 1) - + case nw @ NEW(REFERENCE(sym)) => assert(nw.init ne null, "null new.init at: " + bb + ": " + idx + "(" + instr + ")") worklist += findInstruction(bb, nw.init) @@ -236,15 +269,15 @@ abstract class DeadCodeElimination extends SubComponent { } } } - + /** * Finds and marks all clobbers of the given local starting in the given * basic block at the given index - * + * * Storing to local variables of reference or array type may be indirectly - * observable because it may remove a reference to an object which may allow the object - * to be gc'd. See SI-5313. In this code I call the LOCAL_STORE(s) that immediately follow a - * LOCAL_STORE and that store to the same local "clobbers." If a LOCAL_STORE is marked + * observable because it may remove a reference to an object which may allow the object + * to be gc'd. See SI-5313. In this code I call the LOCAL_STORE(s) that immediately follow a + * LOCAL_STORE and that store to the same local "clobbers." If a LOCAL_STORE is marked * useful then its clobbers must go into the set of clobbers, which will be * compensated for later */ @@ -253,20 +286,20 @@ abstract class DeadCodeElimination extends SubComponent { val inspected = mutable.Set[BasicBlock]() // our worklist of blocks that still need to be checked val blocksToBeInspected = mutable.Set[BasicBlock]() - - // Tries to find the next clobber of l1 in bb1 starting at idx1. + + // Tries to find the next clobber of l1 in bb1 starting at idx1. // if it finds one it adds the clobber to clobbers set for later - // handling. If not it adds the direct successor blocks to + // handling. If not it adds the direct successor blocks to // the uninspectedBlocks to try to find clobbers there. Either way // it adds the exception successor blocks for further search - def findClobberInBlock(idx1: Int, bb1: BasicBlock) { + def findClobberInBlock(idx1: Int, bb1: BasicBlock) { val key = ((l, bb1)) val foundClobber = (localStores contains key) && { def minIdx(s : mutable.BitSet) = if(s.isEmpty) -1 else s.min // find the smallest index greater than or equal to idx1 val clobberIdx = minIdx(localStores(key) dropWhile (_ < idx1)) - if (clobberIdx == -1) + if (clobberIdx == -1) false else { debuglog(s"\t${bb1(clobberIdx)} is a clobber of ${bb(idx)}") @@ -275,7 +308,7 @@ abstract class DeadCodeElimination extends SubComponent { } } - // always need to look into the exception successors for additional clobbers + // always need to look into the exception successors for additional clobbers // because we don't know when flow might enter an exception handler blocksToBeInspected ++= (bb1.exceptionSuccessors filterNot inspected) // If we didn't find a clobber here then we need to look at successor blocks. @@ -284,7 +317,7 @@ abstract class DeadCodeElimination extends SubComponent { blocksToBeInspected ++= (bb1.directSuccessors filterNot inspected) } } - + // first search starting at the current index // note we don't put bb in the inspected list yet because a loop may later force // us back around to search from the beginning of bb @@ -301,14 +334,16 @@ abstract class DeadCodeElimination extends SubComponent { def sweep(m: IMethod) { val compensations = computeCompensations(m) + debuglog("Sweeping: " + m) + m foreachBlock { bb => -// Console.println("** Sweeping block " + bb + " **") + debuglog(bb + ":") val oldInstr = bb.toList bb.open bb.clear for (Pair(i, idx) <- oldInstr.zipWithIndex) { if (useful(bb)(idx)) { -// log(" " + i + " is useful") + debuglog(" * " + i + " is useful") bb.emit(i, i.pos) compensations.get(bb, idx) match { case Some(is) => is foreach bb.emit @@ -328,13 +363,13 @@ abstract class DeadCodeElimination extends SubComponent { log(s"Eliminated instantation of $sym inside $m") case STORE_LOCAL(l) if clobbers contains ((bb, idx)) => // if an unused instruction was a clobber of a used store to a reference or array type - // then we'll replace it with the store of a null to make sure the reference is + // then we'll replace it with the store of a null to make sure the reference is // eliminated. See SI-5313 bb emit CONSTANT(Constant(null)) bb emit STORE_LOCAL(l) case _ => () } - debuglog("Skipped: bb_" + bb + ": " + idx + "( " + i + ")") + debuglog(" " + i + " [swept]") } } @@ -355,6 +390,7 @@ abstract class DeadCodeElimination extends SubComponent { val defs = rdef.findDefs(bb, idx, 1, depth) for (d <- defs) { val (bb, idx) = d + debuglog("rdef: "+ bb(idx)) bb(idx) match { case DUP(_) if idx > 0 => bb(idx - 1) match { diff --git a/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala b/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala index f60d56d9bb..f509c63ba0 100755 --- a/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala +++ b/src/compiler/scala/tools/nsc/doc/base/CommentFactoryBase.scala @@ -100,26 +100,26 @@ trait CommentFactoryBase { this: MemberLookupBase => } - protected val endOfText = '\u0003' - protected val endOfLine = '\u000A' + private val endOfText = '\u0003' + private val endOfLine = '\u000A' /** Something that should not have happened, happened, and Scaladoc should exit. */ - protected def oops(msg: String): Nothing = + private def oops(msg: String): Nothing = throw FatalError("program logic: " + msg) /** The body of a line, dropping the (optional) start star-marker, * one leading whitespace and all trailing whitespace. */ - protected val CleanCommentLine = + private val CleanCommentLine = new Regex("""(?:\s*\*\s?)?(.*)""") /** Dangerous HTML tags that should be replaced by something safer, * such as wiki syntax, or that should be dropped. */ - protected val DangerousTags = + private val DangerousTags = new Regex("""<(/?(div|ol|ul|li|h[1-6]|p))( [^>]*)?/?>|<!--.*-->""") /** Maps a dangerous HTML tag to a safe wiki replacement, or an empty string * if it cannot be salvaged. */ - protected def htmlReplacement(mtch: Regex.Match): String = mtch.group(1) match { + private def htmlReplacement(mtch: Regex.Match): String = mtch.group(1) match { case "p" | "div" => "\n\n" case "h1" => "\n= " case "/h1" => " =\n" @@ -135,11 +135,11 @@ trait CommentFactoryBase { this: MemberLookupBase => /** Javadoc tags that should be replaced by something useful, such as wiki * syntax, or that should be dropped. */ - protected val JavadocTags = + private val JavadocTags = new Regex("""\{\@(code|docRoot|inheritDoc|link|linkplain|literal|value)([^}]*)\}""") /** Maps a javadoc tag to a useful wiki replacement, or an empty string if it cannot be salvaged. */ - protected def javadocReplacement(mtch: Regex.Match): String = mtch.group(1) match { + private def javadocReplacement(mtch: Regex.Match): String = mtch.group(1) match { case "code" => "`" + mtch.group(2) + "`" case "docRoot" => "" case "inheritDoc" => "" @@ -151,41 +151,41 @@ trait CommentFactoryBase { this: MemberLookupBase => } /** Safe HTML tags that can be kept. */ - protected val SafeTags = + private val SafeTags = new Regex("""((&\w+;)|(&#\d+;)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|code|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""") - protected val safeTagMarker = '\u000E' + private val safeTagMarker = '\u000E' /** A Scaladoc tag not linked to a symbol and not followed by text */ - protected val SingleTag = + private val SingleTagRegex = new Regex("""\s*@(\S+)\s*""") /** A Scaladoc tag not linked to a symbol. Returns the name of the tag, and the rest of the line. */ - protected val SimpleTag = + private val SimpleTagRegex = new Regex("""\s*@(\S+)\s+(.*)""") /** A Scaladoc tag linked to a symbol. Returns the name of the tag, the name * of the symbol, and the rest of the line. */ - protected val SymbolTag = + private val SymbolTagRegex = new Regex("""\s*@(param|tparam|throws|groupdesc|groupname|groupprio)\s+(\S*)\s*(.*)""") /** The start of a scaladoc code block */ - protected val CodeBlockStart = + private val CodeBlockStartRegex = new Regex("""(.*?)((?:\{\{\{)|(?:\u000E<pre(?: [^>]*)?>\u000E))(.*)""") /** The end of a scaladoc code block */ - protected val CodeBlockEnd = + private val CodeBlockEndRegex = new Regex("""(.*?)((?:\}\}\})|(?:\u000E</pre>\u000E))(.*)""") /** A key used for a tag map. The key is built from the name of the tag and * from the linked symbol if the tag has one. * Equality on tag keys is structural. */ - protected sealed abstract class TagKey { + private sealed abstract class TagKey { def name: String } - protected final case class SimpleTagKey(name: String) extends TagKey - protected final case class SymbolTagKey(name: String, symbol: String) extends TagKey + private final case class SimpleTagKey(name: String) extends TagKey + private final case class SymbolTagKey(name: String, symbol: String) extends TagKey /** Parses a raw comment string into a `Comment` object. * @param comment The expanded comment string (including start and end markers) to be parsed. @@ -231,7 +231,7 @@ trait CommentFactoryBase { this: MemberLookupBase => inCodeBlock: Boolean ): Comment = remaining match { - case CodeBlockStart(before, marker, after) :: ls if (!inCodeBlock) => + case CodeBlockStartRegex(before, marker, after) :: ls if (!inCodeBlock) => if (!before.trim.isEmpty && !after.trim.isEmpty) parse0(docBody, tags, lastTagKey, before :: marker :: after :: ls, false) else if (!before.trim.isEmpty) @@ -250,7 +250,7 @@ trait CommentFactoryBase { this: MemberLookupBase => parse0(docBody append endOfLine append marker, tags, lastTagKey, ls, true) } - case CodeBlockEnd(before, marker, after) :: ls => + case CodeBlockEndRegex(before, marker, after) :: ls => if (!before.trim.isEmpty && !after.trim.isEmpty) parse0(docBody, tags, lastTagKey, before :: marker :: after :: ls, true) if (!before.trim.isEmpty) @@ -269,17 +269,17 @@ trait CommentFactoryBase { this: MemberLookupBase => parse0(docBody append endOfLine append marker, tags, lastTagKey, ls, false) } - case SymbolTag(name, sym, body) :: ls if (!inCodeBlock) => + case SymbolTagRegex(name, sym, body) :: ls if (!inCodeBlock) => val key = SymbolTagKey(name, sym) val value = body :: tags.getOrElse(key, Nil) parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) - case SimpleTag(name, body) :: ls if (!inCodeBlock) => + case SimpleTagRegex(name, body) :: ls if (!inCodeBlock) => val key = SimpleTagKey(name) val value = body :: tags.getOrElse(key, Nil) parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) - case SingleTag(name) :: ls if (!inCodeBlock) => + case SingleTagRegex(name) :: ls if (!inCodeBlock) => val key = SimpleTagKey(name) val value = "" :: tags.getOrElse(key, Nil) parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 7dc0b786a7..73738ebd21 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -162,6 +162,20 @@ trait CompilerControl { self: Global => def askLinkPos(sym: Symbol, source: SourceFile, response: Response[Position]) = postWorkItem(new AskLinkPosItem(sym, source, response)) + /** Sets sync var `response` to doc comment information for a given symbol. + * + * @param sym The symbol whose doc comment should be retrieved (might come from a classfile) + * @param site The place where sym is observed. + * @param source The source file that's supposed to contain the definition + * @param response A response that will be set to the following: + * If `source` contains a definition of a given symbol that has a doc comment, + * the (expanded, raw, position) triplet for a comment, otherwise ("", "", NoPosition). + * Note: This operation does not automatically load `source`. If `source` + * is unloaded, it stays that way. + */ + def askDocComment(sym: Symbol, site: Symbol, source: SourceFile, response: Response[(String, String, Position)]) = + postWorkItem(new AskDocCommentItem(sym, site, source, response)) + /** Sets sync var `response` to list of members that are visible * as members of the tree enclosing `pos`, possibly reachable by an implicit. * @pre source is loaded @@ -245,15 +259,12 @@ trait CompilerControl { self: Global => } /** Returns parse tree for source `source`. No symbols are entered. Syntax errors are reported. - * Can be called asynchronously from presentation compiler. + * + * This method is thread-safe and as such can safely run outside of the presentation + * compiler thread. */ - def parseTree(source: SourceFile): Tree = ask { () => - getUnit(source) match { - case Some(unit) if unit.status >= JustParsed => - unit.body - case _ => - new UnitParser(new CompilationUnit(source)).parse() - } + def parseTree(source: SourceFile): Tree = { + new UnitParser(new CompilationUnit(source)).parse() } /** Asks for a computation to be done quickly on the presentation compiler thread */ @@ -379,6 +390,14 @@ trait CompilerControl { self: Global => response raise new MissingResponse } + case class AskDocCommentItem(val sym: Symbol, val site: Symbol, val source: SourceFile, response: Response[(String, String, Position)]) extends WorkItem { + def apply() = self.getDocComment(sym, site, source, response) + override def toString = "doc comment "+sym+" in "+source + + def raiseMissing() = + response raise new MissingResponse + } + case class AskLoadedTypedItem(val source: SourceFile, response: Response[Tree]) extends WorkItem { def apply() = self.waitLoadedTyped(source, response, this.onCompilerThread) override def toString = "wait loaded & typed "+source diff --git a/src/compiler/scala/tools/nsc/interactive/Doc.scala b/src/compiler/scala/tools/nsc/interactive/Doc.scala deleted file mode 100755 index ad28a28105..0000000000 --- a/src/compiler/scala/tools/nsc/interactive/Doc.scala +++ /dev/null @@ -1,59 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2007-2012 LAMP/EPFL - * @author Eugene Vigdorchik - */ - -package scala.tools.nsc -package interactive - -import doc.base._ -import comment._ -import scala.xml.NodeSeq - -sealed trait DocResult -final case class UrlResult(url: String) extends DocResult -final case class HtmlResult(comment: Comment) extends DocResult - -abstract class Doc(val settings: doc.Settings) extends MemberLookupBase with CommentFactoryBase { - - override val global: interactive.Global - import global._ - - def chooseLink(links: List[LinkTo]): LinkTo - - override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] = - ask { () => - if (sym.isClass || sym.isModule) - Some(LinkToTpl(sym)) - else - if ((site.isClass || site.isModule) && site.info.members.toList.contains(sym)) - Some(LinkToMember(sym, site)) - else - None - } - - override def toString(link: LinkTo) = ask { () => - link match { - case LinkToMember(mbr: Symbol, site: Symbol) => - mbr.signatureString + " in " + site.toString - case LinkToTpl(sym: Symbol) => sym.toString - case _ => link.toString - } - } - - def retrieve(sym: Symbol, site: Symbol): Option[DocResult] = { - val sig = ask { () => externalSignature(sym) } - findExternalLink(sym, sig) map { link => UrlResult(link.url) } orElse { - val resp = new Response[Tree] - // Ensure docComment tree is type-checked. - val pos = ask { () => docCommentPos(sym) } - askTypeAt(pos, resp) - resp.get.left.toOption flatMap { _ => - ask { () => - val comment = parseAtSymbol(expandedDocComment(sym), rawDocComment(sym), pos, Some(site)) - Some(HtmlResult(comment)) - } - } - } - } -} diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 4ab7b98b3d..105b0e4833 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -225,7 +225,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") /** Called from parser, which signals hereby that a method definition has been parsed. */ override def signalParseProgress(pos: Position) { - checkForMoreWork(pos) + // We only want to be interruptible when running on the PC thread. + if(onCompilerThread) { + checkForMoreWork(pos) + } } /** Called from typechecker, which signals hereby that a node has been completely typechecked. @@ -447,7 +450,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") */ @elidable(elidable.WARNING) override def assertCorrectThread() { - assert(initializing || (Thread.currentThread() eq compileRunner), + assert(initializing || onCompilerThread, "Race condition detected: You are running a presentation compiler method outside the PC thread.[phase: %s]".format(globalPhase) + " Please file a ticket with the current stack trace at https://www.assembla.com/spaces/scala-ide/support/tickets") } @@ -462,6 +465,9 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") compileRunner } + private def ensureUpToDate(unit: RichCompilationUnit) = + if (!unit.isUpToDate && unit.status != JustParsed) reset(unit) // reparse previously typechecked units. + /** Compile all loaded source files in the order given by `allSources`. */ private[interactive] final def backgroundCompile() { @@ -474,7 +480,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") // ensure all loaded units are parsed for (s <- allSources; unit <- getUnit(s)) { // checkForMoreWork(NoPosition) // disabled, as any work done here would be in an inconsistent state - if (!unit.isUpToDate && unit.status != JustParsed) reset(unit) // reparse previously typechecked units. + ensureUpToDate(unit) parseAndEnter(unit) serviceParsedEntered() } @@ -727,7 +733,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") try { debugLog("starting targeted type check") typeCheck(unit) - println("tree not found at "+pos) +// println("tree not found at "+pos) EmptyTree } catch { case ex: TyperResult => new Locator(pos) locateIn ex.tree @@ -758,64 +764,69 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") respond(response)(typedTree(source, forceReload)) } - /** Implements CompilerControl.askLinkPos */ - private[interactive] def getLinkPos(sym: Symbol, source: SourceFile, response: Response[Position]) { + private def withTempUnit[T](source: SourceFile)(f: RichCompilationUnit => T): T = + getUnit(source) match { + case None => + reloadSources(List(source)) + try f(getUnit(source).get) + finally afterRunRemoveUnitOf(source) + case Some(unit) => + f(unit) + } - /** Find position of symbol `sym` in unit `unit`. Pre: `unit is loaded. */ - def findLinkPos(unit: RichCompilationUnit): Position = { - val originalTypeParams = sym.owner.typeParams - parseAndEnter(unit) - val pre = adaptToNewRunMap(ThisType(sym.owner)) - val rawsym = pre.typeSymbol.info.decl(sym.name) - val newsym = rawsym filter { alt => - sym.isType || { - try { - val tp1 = pre.memberType(alt) onTypeError NoType - val tp2 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, sym.owner.typeParams) - matchesType(tp1, tp2, false) || { - debugLog(s"getLinkPos matchesType($tp1, $tp2) failed") - val tp3 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, alt.owner.typeParams) - matchesType(tp1, tp3, false) || { - debugLog(s"getLinkPos fallback matchesType($tp1, $tp3) failed") - false - } - } - } - catch { - case ex: ControlThrowable => throw ex - case ex: Throwable => - println("error in hyperlinking: " + ex) - ex.printStackTrace() + /** Find a 'mirror' of symbol `sym` in unit `unit`. Pre: `unit is loaded. */ + private def findMirrorSymbol(sym: Symbol, unit: RichCompilationUnit): Symbol = { + val originalTypeParams = sym.owner.typeParams + ensureUpToDate(unit) + parseAndEnter(unit) + val pre = adaptToNewRunMap(ThisType(sym.owner)) + val rawsym = pre.typeSymbol.info.decl(sym.name) + val newsym = rawsym filter { alt => + sym.isType || { + try { + val tp1 = pre.memberType(alt) onTypeError NoType + val tp2 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, sym.owner.typeParams) + matchesType(tp1, tp2, false) || { + debugLog(s"findMirrorSymbol matchesType($tp1, $tp2) failed") + val tp3 = adaptToNewRunMap(sym.tpe) substSym (originalTypeParams, alt.owner.typeParams) + matchesType(tp1, tp3, false) || { + debugLog(s"findMirrorSymbol fallback matchesType($tp1, $tp3) failed") false + } } } - } - if (newsym == NoSymbol) { - if (rawsym.exists && !rawsym.isOverloaded) rawsym.pos - else { - debugLog("link not found " + sym + " " + source + " " + pre) - NoPosition + catch { + case ex: ControlThrowable => throw ex + case ex: Throwable => + debugLog("error in findMirrorSymbol: " + ex) + ex.printStackTrace() + false } - } else if (newsym.isOverloaded) { - settings.uniqid.value = true - debugLog("link ambiguous " + sym + " " + source + " " + pre + " " + newsym.alternatives) - NoPosition - } else { - debugLog("link found for " + newsym + ": " + newsym.pos) - newsym.pos } } + if (newsym == NoSymbol) { + if (rawsym.exists && !rawsym.isOverloaded) rawsym + else { + debugLog("mirror not found " + sym + " " + unit.source + " " + pre) + NoSymbol + } + } else if (newsym.isOverloaded) { + settings.uniqid.value = true + debugLog("mirror ambiguous " + sym + " " + unit.source + " " + pre + " " + newsym.alternatives) + NoSymbol + } else { + debugLog("mirror found for " + newsym + ": " + newsym.pos) + newsym + } + } + /** Implements CompilerControl.askLinkPos */ + private[interactive] def getLinkPos(sym: Symbol, source: SourceFile, response: Response[Position]) { informIDE("getLinkPos "+sym+" "+source) respond(response) { if (sym.owner.isClass) { - getUnit(source) match { - case None => - reloadSources(List(source)) - try findLinkPos(getUnit(source).get) - finally afterRunRemoveUnitOf(source) - case Some(unit) => - findLinkPos(unit) + withTempUnit(source){ u => + findMirrorSymbol(sym, u).pos } } else { debugLog("link not in class "+sym+" "+source+" "+sym.owner) @@ -824,6 +835,50 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } } + /** Implements CompilerControl.askDocComment */ + private[interactive] def getDocComment(sym: Symbol, site: Symbol, source: SourceFile, response: Response[(String, String, Position)]) { + informIDE("getDocComment "+sym+" "+source) + respond(response) { + withTempUnit(source){ u => + val mirror = findMirrorSymbol(sym, u) + if (mirror eq NoSymbol) + ("", "", NoPosition) + else { + forceDocComment(mirror, u) + (expandedDocComment(mirror), rawDocComment(mirror), docCommentPos(mirror)) + } + } + } + } + + private def forceDocComment(sym: Symbol, unit: RichCompilationUnit) { + // Either typer has been run and we don't find DocDef, + // or we force the targeted typecheck here. + // In both cases doc comment maps should be filled for the subject symbol. + val docTree = + unit.body find { + case DocDef(_, defn) if defn.symbol eq sym => true + case _ => false + } + + for (t <- docTree) { + debugLog("Found DocDef tree for "+sym) + // Cannot get a typed tree at position since DocDef range is transparent. + val prevPos = unit.targetPos + val prevInterruptsEnabled = interruptsEnabled + try { + unit.targetPos = t.pos + interruptsEnabled = true + typeCheck(unit) + } catch { + case _: TyperResult => // ignore since we are after the side effect. + } finally { + unit.targetPos = prevPos + interruptsEnabled = prevInterruptsEnabled + } + } + } + def stabilizedType(tree: Tree): Type = tree match { case Ident(_) if tree.symbol.isStable => singleType(NoPrefix, tree.symbol) diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala index ffad19fbaa..84cb03c140 100644 --- a/src/compiler/scala/tools/nsc/interactive/Picklers.scala +++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala @@ -165,6 +165,11 @@ trait Picklers { self: Global => .wrapped { case sym ~ source => new AskLinkPosItem(sym, source, new Response) } { item => item.sym ~ item.source } .asClass (classOf[AskLinkPosItem]) + implicit def askDocCommentItem: CondPickler[AskDocCommentItem] = + (pkl[Symbol] ~ pkl[Symbol] ~ pkl[SourceFile]) + .wrapped { case sym ~ site ~ source => new AskDocCommentItem(sym, site, source, new Response) } { item => item.sym ~ item.site ~ item.source } + .asClass (classOf[AskDocCommentItem]) + implicit def askLoadedTypedItem: CondPickler[AskLoadedTypedItem] = pkl[SourceFile] .wrapped { source => new AskLoadedTypedItem(source, new Response) } { _.source } @@ -182,5 +187,5 @@ trait Picklers { self: Global => implicit def action: Pickler[() => Unit] = reloadItem | askTypeAtItem | askTypeItem | askTypeCompletionItem | askScopeCompletionItem | - askToDoFirstItem | askLinkPosItem | askLoadedTypedItem | askParsedEnteredItem | emptyAction + askToDoFirstItem | askLinkPosItem | askDocCommentItem | askLoadedTypedItem | askParsedEnteredItem | emptyAction } diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala index 64117bd8ee..b95f1fa7ca 100644 --- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala +++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala @@ -144,7 +144,7 @@ self: scala.tools.nsc.Global => */ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try { for (tree <- trees) { - if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) { + if (!tree.isEmpty && tree.pos == NoPosition) { val children = tree.children if (children.isEmpty) { tree setPos pos.focus @@ -165,7 +165,7 @@ self: scala.tools.nsc.Global => */ override def atPos[T <: Tree](pos: Position)(tree: T): T = { if (pos.isOpaqueRange) { - if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) { + if (!tree.isEmpty && tree.pos == NoPosition) { tree.setPos(pos) val children = tree.children if (children.nonEmpty) { @@ -203,7 +203,7 @@ self: scala.tools.nsc.Global => def validate(tree: Tree, encltree: Tree): Unit = { - if (!tree.isEmpty && tree.canHaveAttrs) { + if (!tree.isEmpty) { 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/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala index ea2333a65b..7bb2b7b7c8 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala @@ -8,7 +8,8 @@ import scala.reflect.internal.util.Position /** Trait encapsulating the creation of a presentation compiler's instance.*/ private[tests] trait PresentationCompilerInstance extends TestSettings { protected val settings = new Settings - protected def docSettings: doc.Settings = new doc.Settings(_ => ()) + protected val docSettings = new doc.Settings(_ => ()) + protected val compilerReporter: CompilerReporter = new InteractiveReporter { override def compiler = PresentationCompilerInstance.this.compiler } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 050f7a8f95..43a8402fc7 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -551,7 +551,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), Nil) + New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), ListOfNil) } mods1 = mods1 withAnnotations List(annot) skipTo(SEMI) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 0a98d45cac..3df6334ec1 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -175,7 +175,6 @@ trait ScalaSettings extends AbsScalaSettings val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") val Yinvalidate = StringSetting ("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "") val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") - val companionsInPkgObjs = BooleanSetting("-Ycompanions-in-pkg-objs", "Allow companion objects and case classes in package objects. See issue SI-5954.") val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index ec0797acb5..4891ef2fd1 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -511,6 +511,7 @@ 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/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 965063a724..e9f403aea0 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -277,7 +277,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)), + List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyMethodDef), fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } @@ -403,7 +403,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)), + List(ClassDef(anonClass, NoMods, ListOfNil, 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 fbf23968f0..4bf7f78167 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -184,18 +184,14 @@ trait ContextErrors { } def ParentTypesError(templ: Template, ex: TypeError) = { - templ.tpe = null - issueNormalTypeError(templ, ex.getMessage()) - setError(templ) + templ.tpe = null + issueNormalTypeError(templ, ex.getMessage()) } // additional parentTypes errors - def ConstrArgsInParentWhichIsTraitError(arg: Tree, parent: Symbol) = + def ConstrArgsInTraitParentTpeError(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") @@ -1048,6 +1044,9 @@ 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") diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 0b46582cbf..f6142a81be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -388,7 +388,7 @@ abstract class Duplicators extends Analyzer { cases } - super.typedPos(tree.pos, mode, pt)(Match(scrut, cases1)) + super.typed(atPos(tree.pos)(Match(scrut, cases1)), mode, pt) case EmptyTree => // no need to do anything, in particular, don't set the type to null, EmptyTree.tpe_= asserts diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index c728185d4e..ab338447c9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -857,8 +857,13 @@ trait Namers extends MethodSynthesis { private def templateSig(templ: Template): Type = { val clazz = context.owner def checkParent(tpt: Tree): Type = { - if (tpt.tpe.isError) AnyRefClass.tpe - else tpt.tpe + val tp = tpt.tpe + val inheritsSelf = tp.typeSymbol == owner + if (inheritsSelf) + InheritsItselfError(tpt) + + if (inheritsSelf || tp.isError) AnyRefClass.tpe + else tp } val parents = typer.parentTypes(templ) map checkParent diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 20db479463..64c5b41638 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -4,31 +4,7 @@ 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 SuperArgsAttachment(argss: List[List[Tree]]) - - /** Convenience method for `SuperArgsAttachment`. - * Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern, - * so it really benefits from a dedicated extractor. - */ - def superArgs(tree: Tree): Option[List[List[Tree]]] = - tree.attachments.get[SuperArgsAttachment] collect { case SuperArgsAttachment(argss) => argss } - - /** Determines whether the given tree has an associated SuperArgsAttachment. - */ - def hasSuperArgs(tree: Tree): Boolean = superArgs(tree).nonEmpty }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 39f6f764e7..242eb9c9fe 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -50,6 +50,10 @@ trait SyntheticMethods extends ast.TreeDSL { else if (clazz.isDerivedValueClass) valueSymbols else Nil } + private lazy val renamedCaseAccessors = perRunCaches.newMap[Symbol, mutable.Map[TermName, TermName]]() + /** Does not force the info of `caseclazz` */ + final def caseAccessorName(caseclazz: Symbol, paramName: TermName) = + (renamedCaseAccessors get caseclazz).fold(paramName)(_(paramName)) /** Add the synthetic methods to case classes. */ @@ -384,6 +388,8 @@ trait SyntheticMethods extends ast.TreeDSL { // TODO: shouldn't the next line be: `original resetFlag CASEACCESSOR`? ddef.symbol resetFlag CASEACCESSOR lb += logResult("case accessor new")(newAcc) + val renamedInClassMap = renamedCaseAccessors.getOrElseUpdate(clazz, mutable.Map() withDefault(x => x)) + renamedInClassMap(original.name.toTermName) = newAcc.symbol.name.toTermName } (lb ++= templ.body ++= synthesize()).toList diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 026c130a87..2103f669c3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -53,10 +53,8 @@ trait Typers extends Modes with Adaptations with Tags { object UnTyper extends Traverser { override def traverse(tree: Tree) = { - if (tree.canHaveAttrs) { - tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol - } + if (tree != EmptyTree) tree.tpe = null + if (tree.hasSymbol) tree.symbol = NoSymbol super.traverse(tree) } } @@ -1401,6 +1399,13 @@ 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)) { @@ -1502,243 +1507,126 @@ trait Typers extends Modes with Adaptations with Tags { unit.error(tparam.pos, "type parameter of value class may not be specialized") } - /** 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 SuperArgsAttachment. - * 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 - } - typedType(decodedtpt) - } else { - var supertpt = typedTypeConstructor(decodedtpt) - val supertparams = if (supertpt.hasSymbol) 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 + 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 } } - // 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 SuperArgsAttachment(argss) - } - } - - /** 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) - } + 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.hasSymbol) supertpt.symbol.typeParams else List() + var supertpe = supertpt.tpe + if (!supertparams.isEmpty) + supertpe = PolyType(supertparams, appliedType(supertpe, 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) + } - val preSuperVals = treeInfo.preSuperFields(templ.body) - if (preSuperVals.isEmpty && preSuperStats.nonEmpty) - debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) - else - map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) + 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 cstats1 = if (superCall == EmptyTree) preSuperStats else preSuperStats :+ superCall + 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 treeInfo.Applied(_, _, argss) = superCall + val sarg = argss.flatten.headOption.getOrElse(EmptyTree) + 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) + } - if (superCall1 == cunit) EmptyTree else cbody2 - case _ => - EmptyTree - } + val preSuperVals = treeInfo.preSuperFields(templ.body) + if (preSuperVals.isEmpty && preSuperStats.nonEmpty) + debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) + else + map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) - /** 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 + case _ => + if (!supertparams.isEmpty) + MissingTypeArgumentsParentTpeError(supertpt) } - explode(first, Nil) ++ rest - case _ => parents - } +/* experimental: early types as type arguments + val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef) + val earlyMap = new EarlyMap(clazz) + List.mapConserve(supertpt :: mixins){ tpt => + val tpt1 = checkNoEscaping.privates(clazz, tpt) + if (hasEarlyTypes) tpt1 else tpt1 setType earlyMap(tpt1.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 - ) - } + //Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG - 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)) + // 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 + ) } - } + + 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)) + } /** <p>Check that</p> * <ul> @@ -1914,29 +1802,29 @@ trait Typers extends Modes with Adaptations with Tags { // SI-5954. On second compile of a companion class contained in a package object we end up // with some confusion of names which leads to having two symbols with the same name in the - // same owner. Until that can be straightened out we can't allow companion objects in package + // same owner. Until that can be straightened out we will warn on companion objects in package // objects. But this code also tries to be friendly by distinguishing between case classes and // user written companion pairs - def restrictPackageObjectMembers(mdef : ModuleDef) = for (m <- mdef.symbol.info.members) { + def warnPackageObjectMembers(mdef : ModuleDef) = for (m <- mdef.symbol.info.members) { // ignore synthetic objects, because the "companion" object to a case class is synthetic and // we only want one error per case class if (!m.isSynthetic) { // can't handle case classes in package objects - if (m.isCaseClass) pkgObjectRestriction(m, mdef, "case") + if (m.isCaseClass) pkgObjectWarning(m, mdef, "case") // can't handle companion class/object pairs in package objects else if ((m.isClass && m.companionModule != NoSymbol && !m.companionModule.isSynthetic) || (m.isModule && m.companionClass != NoSymbol && !m.companionClass.isSynthetic)) - pkgObjectRestriction(m, mdef, "companion") + pkgObjectWarning(m, mdef, "companion") } - def pkgObjectRestriction(m : Symbol, mdef : ModuleDef, restricted : String) = { + def pkgObjectWarning(m : Symbol, mdef : ModuleDef, restricted : String) = { val pkgName = mdef.symbol.ownerChain find (_.isPackage) map (_.decodedName) getOrElse mdef.symbol.toString - context.error(if (m.pos.isDefined) m.pos else mdef.pos, s"implementation restriction: package object ${pkgName} cannot contain ${restricted} ${m}. Instead, ${m} should be placed directly in package ${pkgName}.") + context.warning(if (m.pos.isDefined) m.pos else mdef.pos, s"${m} should be placed directly in package ${pkgName} instead of package object ${pkgName}. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954.") } } - if (!settings.companionsInPkgObjs.value && mdef.symbol.isPackageObject) - restrictPackageObjectMembers(mdef) + if (mdef.symbol.isPackageObject) + warnPackageObjectMembers(mdef) treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType } @@ -2003,12 +1891,9 @@ 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) - if (!templ.isErrorTyped) // if `parentTypes` has invalidated the template, don't validate it anymore - validateParentClasses(parents1, selfType) + 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") @@ -2016,21 +1901,9 @@ 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 = { - 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 = superArgs(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 body = + if (isPastTyper || reporter.hasErrors) templ.body + else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _)) val body1 = typedStats(body, templ.symbol) @@ -2820,7 +2693,7 @@ trait Typers extends Modes with Adaptations with Tags { members foreach (m => anonClass.info.decls enter m.symbol) val typedBlock = typedPos(tree.pos, mode, pt) { - Block(ClassDef(anonClass, NoMods, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) + Block(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) } if (typedBlock.isErrorTyped) typedBlock diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 577aa087ea..b51dc0ccd5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -94,12 +94,33 @@ trait Unapplies extends ast.TreeDSL * @param param The name of the parameter of the unapply method, assumed to be of type C[Ts] * @param caseclazz The case class C[Ts] */ - private def caseClassUnapplyReturnValue(param: Name, caseclazz: Symbol) = { - def caseFieldAccessorValue(selector: Symbol): Tree = Ident(param) DOT selector + private def caseClassUnapplyReturnValue(param: Name, caseclazz: ClassDef) = { + def caseFieldAccessorValue(selector: ValDef): Tree = { + val accessorName = selector.name + val privateLocalParamAccessor = caseclazz.impl.body.collectFirst { + case dd: ValOrDefDef if dd.name == accessorName && dd.mods.isPrivateLocal => dd.symbol + } + privateLocalParamAccessor match { + case None => + // Selecting by name seems to be the most straight forward way here to + // avoid forcing the symbol of the case class in order to list the accessors. + val maybeRenamedAccessorName = caseAccessorName(caseclazz.symbol, accessorName) + Ident(param) DOT maybeRenamedAccessorName + case Some(sym) => + // But, that gives a misleading error message in neg/t1422.scala, where a case + // class has an illegal private[this] parameter. We can detect this by checking + // the modifiers on the param accessors. + // + // We just generate a call to that param accessor here, which gives us an inaccessible + // symbol error, as before. + Ident(param) DOT sym + } + } - caseclazz.caseFieldAccessors match { - case Nil => TRUE - case xs => SOME(xs map caseFieldAccessorValue: _*) + // Working with trees, rather than symbols, to avoid cycles like SI-5082 + constrParamss(caseclazz).take(1).flatten match { + case Nil => TRUE + case xs => SOME(xs map caseFieldAccessorValue: _*) } } @@ -127,7 +148,7 @@ trait Unapplies extends ast.TreeDSL ModuleDef( Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin), cdef.name.toTermName, - Template(parents, emptyValDef, NoMods, Nil, body, cdef.impl.pos.focus)) + Template(parents, emptyValDef, NoMods, Nil, ListOfNil, body, cdef.impl.pos.focus)) } private val caseMods = Modifiers(SYNTHETIC | CASE) @@ -158,7 +179,7 @@ trait Unapplies extends ast.TreeDSL } val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree)) val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule) - val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef.symbol) }, ifNull)(Ident(unapplyParamName)) + val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef) }, ifNull)(Ident(unapplyParamName)) atPos(cdef.pos.focus)( DefDef(caseMods, method, tparams, List(cparams), TypeTree(), body) diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 0125f1b189..95135b84e0 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -230,6 +230,7 @@ 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/library/scala/collection/IndexedSeq.scala b/src/library/scala/collection/IndexedSeq.scala index 63e5adf428..2de0043c96 100644 --- a/src/library/scala/collection/IndexedSeq.scala +++ b/src/library/scala/collection/IndexedSeq.scala @@ -28,10 +28,10 @@ trait IndexedSeq[+A] extends Seq[A] * @define coll indexed sequence * @define Coll `IndexedSeq` */ -object IndexedSeq extends IndexedSeqFactory[IndexedSeq] { +object IndexedSeq extends SeqFactory[IndexedSeq] { // A single CBF which can be checked against to identify // an indexed collection type. - override val ReusableCBF: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] { + override lazy val ReusableCBF: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] { override def apply() = newBuilder[Nothing] } def newBuilder[A]: Builder[A, IndexedSeq[A]] = immutable.IndexedSeq.newBuilder[A] diff --git a/src/library/scala/collection/generic/GenTraversableFactory.scala b/src/library/scala/collection/generic/GenTraversableFactory.scala index a43862abaf..2d3f7e609b 100644 --- a/src/library/scala/collection/generic/GenTraversableFactory.scala +++ b/src/library/scala/collection/generic/GenTraversableFactory.scala @@ -38,10 +38,12 @@ import scala.language.higherKinds abstract class GenTraversableFactory[CC[X] <: GenTraversable[X] with GenericTraversableTemplate[X, CC]] extends GenericCompanion[CC] { - private[this] val ReusableCBFInstance: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] { + // A default implementation of GenericCanBuildFrom which can be cast + // to whatever is desired. + private class ReusableCBF extends GenericCanBuildFrom[Nothing] { override def apply() = newBuilder[Nothing] } - def ReusableCBF: GenericCanBuildFrom[Nothing] = ReusableCBFInstance + lazy val ReusableCBF: GenericCanBuildFrom[Nothing] = new ReusableCBF /** A generic implementation of the `CanBuildFrom` trait, which forwards * all calls to `apply(from)` to the `genericBuilder` method of diff --git a/src/library/scala/collection/generic/IndexedSeqFactory.scala b/src/library/scala/collection/generic/IndexedSeqFactory.scala deleted file mode 100644 index 200d033c2d..0000000000 --- a/src/library/scala/collection/generic/IndexedSeqFactory.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.collection -package generic - -import language.higherKinds - -/** A template for companion objects of IndexedSeq and subclasses thereof. - * - * @since 2.10 - */ -abstract class IndexedSeqFactory[CC[X] <: IndexedSeq[X] with GenericTraversableTemplate[X, CC]] extends SeqFactory[CC] { - override def ReusableCBF: GenericCanBuildFrom[Nothing] = - scala.collection.IndexedSeq.ReusableCBF.asInstanceOf[GenericCanBuildFrom[Nothing]] -} diff --git a/src/library/scala/collection/immutable/IndexedSeq.scala b/src/library/scala/collection/immutable/IndexedSeq.scala index bf4ba3a381..96414c07ef 100644 --- a/src/library/scala/collection/immutable/IndexedSeq.scala +++ b/src/library/scala/collection/immutable/IndexedSeq.scala @@ -31,7 +31,9 @@ trait IndexedSeq[+A] extends Seq[A] * @define coll indexed sequence * @define Coll `IndexedSeq` */ -object IndexedSeq extends IndexedSeqFactory[IndexedSeq] { +object IndexedSeq extends SeqFactory[IndexedSeq] { + override lazy val ReusableCBF = + scala.collection.IndexedSeq.ReusableCBF.asInstanceOf[GenericCanBuildFrom[Nothing]] class Impl[A](buf: ArrayBuffer[A]) extends AbstractSeq[A] with IndexedSeq[A] with Serializable { def length = buf.length def apply(idx: Int) = buf.apply(idx) diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index f083e80175..bcce4a99bd 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -18,7 +18,16 @@ import scala.collection.parallel.immutable.ParVector /** Companion object to the Vector class */ -object Vector extends IndexedSeqFactory[Vector] { +object Vector extends SeqFactory[Vector] { + // left lying around for binary compatibility check + private[collection] class VectorReusableCBF extends GenericCanBuildFrom[Nothing] { + override def apply() = newBuilder[Nothing] + } + // left lying around for binary compatibility check + private val VectorReusableCBF: GenericCanBuildFrom[Nothing] = new VectorReusableCBF + + override lazy val ReusableCBF = + scala.collection.IndexedSeq.ReusableCBF.asInstanceOf[GenericCanBuildFrom[Nothing]] def newBuilder[A]: Builder[A, Vector[A]] = new VectorBuilder[A] implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Vector[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 6b778b26f5..bb938a7aeb 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -52,20 +52,6 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza super.toArray[U] } - def :+[B >: T: scala.reflect.ClassTag](elem: B): Array[B] = { - val result = Array.ofDim[B](repr.length + 1) - Array.copy(repr, 0, result, 0, repr.length) - result(repr.length) = elem - result - } - - def +:[B >: T: scala.reflect.ClassTag](elem: B): Array[B] = { - val result = Array.ofDim[B](repr.length + 1) - result(0) = elem - Array.copy(repr, 0, result, 1, repr.length) - result - } - override def par = ParArray.handoff(repr) /** Flattens a two-dimensional array by concatenating all its rows diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 8f256aa1f5..0c8e81a220 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -59,6 +59,8 @@ 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 cfa6315797..0937a93738 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -75,26 +75,11 @@ 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 @@ -2420,15 +2405,6 @@ 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. @@ -2931,8 +2907,7 @@ trait Trees { self: Universe => trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef]) /** Transforms a `ValDef`. */ def transformValDef(tree: ValDef): ValDef = - if (tree eq emptyValDef) tree - else transform(tree).asInstanceOf[ValDef] + if (tree.isEmpty) 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/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index b1b0c5b60b..9f41f0336e 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -47,6 +47,8 @@ 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 2f2b02975c..43902c1930 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -334,8 +334,6 @@ 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 f8c670827a..faa161d6b1 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.canHaveAttrs) () + if (t eq EmptyTree) () 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 a8085a4c58..80d247c0ea 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.canHaveAttrs) { + if (printTypes && tree.isTerm && !tree.isEmpty) { print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}") } } @@ -542,10 +542,8 @@ trait Printers extends api.Printers { self: SymbolTable => print(")") case EmptyTree => print("EmptyTree") - case self.emptyValDef => + case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef => print("emptyValDef") - case self.pendingSuperCall => - print("pendingSuperCall") case tree: Tree => val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol val isError = hasSymbol && 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 c870d8972d..5e7f5777b2 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -730,7 +730,6 @@ trait StdNames { val null_ : NameType = "null" val ofDim: NameType = "ofDim" val origin: NameType = "origin" - 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 72ad84edec..4ffd198dc4 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -2515,7 +2515,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => } override def outerSource: Symbol = - if (originalName == nme.OUTER) initialize.referenced + // SI-6888 Approximate the name to workaround the deficiencies in `nme.originalName` + // in the face of clases named '$'. SI-2806 remains open to address the deeper problem. + if (originalName endsWith (nme.OUTER)) initialize.referenced else NoSymbol def setModuleClass(clazz: Symbol): TermSymbol = { diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 98c1afb323..2cc848d458 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -342,9 +342,6 @@ 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 @@ -509,10 +506,6 @@ 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) - } /** Applications in Scala can have one of the following shapes: * diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index a528a9ced8..5522c47cfa 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -36,7 +36,6 @@ 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,6 +228,14 @@ 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 { @@ -592,7 +599,6 @@ 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]) = @@ -955,23 +961,12 @@ trait Trees extends api.Trees { self: SymbolTable => def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) - 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) - + object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) { + override def isEmpty = true super.setPos(NoPosition) - override def setPos(pos: Position) = unsupported("setPos", pos) - - super.setType(NoType) - override def tpe_=(t: Type) = if (t != NoType) unsupported("tpe_=", t) + override def setPos(pos: Position) = { assert(false); this } } - 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) @@ -1039,9 +1034,6 @@ 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: _*) @@ -1122,7 +1114,7 @@ trait Trees extends api.Trees { self: SymbolTable => traverse(annot); traverse(arg) case Template(parents, self, body) => traverseTrees(parents) - if (self ne emptyValDef) traverse(self) + if (!self.isEmpty) traverse(self) traverseStats(body, tree.symbol) case Block(stats, expr) => traverseTrees(stats); traverse(expr) diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index ec3501d5bc..81368df7a6 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -47,6 +47,4 @@ abstract class MutableSettings extends AbsSettings { def XoldPatmat: BooleanSetting def XnoPatmatAnalysis: BooleanSetting def XfullLubs: BooleanSetting - def companionsInPkgObjs: BooleanSetting - } diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala index eeb87fafcc..007df3b6e2 100644 --- a/src/reflect/scala/reflect/macros/Attachments.scala +++ b/src/reflect/scala/reflect/macros/Attachments.scala @@ -56,6 +56,8 @@ abstract class Attachments { self => // SI-7018: This used to be an inner class of `Attachments`, but that led to a memory leak in the // IDE via $outer pointers. +// Forward compatibility note: This class used to be Attachments$NonemptyAttachments. +// However it's private, therefore it transcends the compatibility policy for 2.10.x. private final class NonemptyAttachments[P >: Null](override val pos: P, override val all: Set[Any]) extends Attachments { type Pos = P def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index 2d5b76f094..0e0cf3fc40 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -43,7 +43,6 @@ private[reflect] class Settings extends MutableSettings { val printtypes = new BooleanSetting(false) val uniqid = new BooleanSetting(false) val verbose = new BooleanSetting(false) - val companionsInPkgObjs = new BooleanSetting(false) val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) diff --git a/test/files/neg/anyval-anyref-parent.check b/test/files/neg/anyval-anyref-parent.check index 8c2aa36583..fe20e5de81 100644 --- a/test/files/neg/anyval-anyref-parent.check +++ b/test/files/neg/anyval-anyref-parent.check @@ -3,7 +3,7 @@ trait Foo2 extends AnyVal // fail ^ anyval-anyref-parent.scala:5: error: Any does not have a constructor class Bar1 extends Any // fail - ^ + ^ anyval-anyref-parent.scala:6: error: value class needs to have exactly one public val parameter class Bar2(x: Int) extends AnyVal // fail ^ diff --git a/test/files/neg/cyclics-import.check b/test/files/neg/cyclics-import.check index be09fca374..ef355fab0a 100644 --- a/test/files/neg/cyclics-import.check +++ b/test/files/neg/cyclics-import.check @@ -3,4 +3,13 @@ Note: this is often due in part to a class depending on a definition nested with If applicable, you may wish to try moving some members into another object. import User.UserStatus._ ^ -one error found +cyclics-import.scala:12: error: not found: type Value + type UserStatus = Value + ^ +cyclics-import.scala:14: error: not found: value Value + val Active = Value("1") + ^ +cyclics-import.scala:15: error: not found: value Value + val Disabled = Value("2") + ^ +four errors found diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index f6bd703e1f..ea7c323b74 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -100,7 +100,7 @@ Error occurred in an application involving default arguments. ^ names-defaults-neg.scala:86: error: module extending its companion class cannot use default constructor arguments object C extends C() - ^ + ^ names-defaults-neg.scala:90: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not). def deprNam1(x: Int, @deprecatedName('x) y: String) = 0 ^ diff --git a/test/files/neg/protected-constructors.check b/test/files/neg/protected-constructors.check index e295917050..f137158ed6 100644 --- a/test/files/neg/protected-constructors.check +++ b/test/files/neg/protected-constructors.check @@ -19,4 +19,7 @@ protected-constructors.scala:15: error: class Foo3 in object Ding cannot be acce object Ding in package dingus where target is defined class Bar3 extends Ding.Foo3("abc") ^ -four errors found +protected-constructors.scala:15: error: too many arguments for constructor Object: ()Object + class Bar3 extends Ding.Foo3("abc") + ^ +5 errors found diff --git a/test/files/neg/t2148.check b/test/files/neg/t2148.check index 27b5dce507..5113b48e51 100644 --- a/test/files/neg/t2148.check +++ b/test/files/neg/t2148.check @@ -1,4 +1,4 @@ -t2148.scala:9: error: A is not a legal prefix for a constructor +t2148.scala:9: error: type A is not a stable prefix val b = new A with A#A1 ^ one error found diff --git a/test/files/neg/t409.check b/test/files/neg/t409.check index 0edc0d03cd..433d64d25d 100644 --- a/test/files/neg/t409.check +++ b/test/files/neg/t409.check @@ -1,4 +1,4 @@ -t409.scala:6: error: class Case1 needs to be a trait to be mixed in +t409.scala:6: error: traits or objects may not have parameters class Toto extends Expr with Case1(12); - ^ + ^ one error found diff --git a/test/files/neg/t5529.check b/test/files/neg/t5529.check index da3f84e1ec..5d2175fa79 100644 --- a/test/files/neg/t5529.check +++ b/test/files/neg/t5529.check @@ -4,4 +4,7 @@ t5529.scala:12: error: File is already defined as class File t5529.scala:10: error: class type required but test.Test.File found sealed class Dir extends File { } ^ -two errors found +t5529.scala:10: error: test.Test.File does not have a constructor + sealed class Dir extends File { } + ^ +three errors found diff --git a/test/files/neg/t5696.check b/test/files/neg/t5696.check index e0fb61b839..72b7781fc4 100644 --- a/test/files/neg/t5696.check +++ b/test/files/neg/t5696.check @@ -15,5 +15,5 @@ t5696.scala:38: error: too many argument lists for constructor invocation ^ t5696.scala:46: error: too many argument lists for constructor invocation object x extends G(1)(2) {} - ^ + ^ 6 errors found diff --git a/test/files/neg/t5954.check b/test/files/neg/t5954.check index 3ca47cd430..ed10658b24 100644 --- a/test/files/neg/t5954.check +++ b/test/files/neg/t5954.check @@ -1,16 +1,16 @@ -t5954.scala:36: error: implementation restriction: package object A cannot contain case class D. Instead, class D should be placed directly in package A. +t5954.scala:36: error: class D should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. case class D() ^ -t5954.scala:35: error: implementation restriction: package object A cannot contain companion object C. Instead, object C should be placed directly in package A. +t5954.scala:35: error: object C should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. object C ^ -t5954.scala:34: error: implementation restriction: package object A cannot contain companion trait C. Instead, trait C should be placed directly in package A. +t5954.scala:34: error: trait C should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. trait C ^ -t5954.scala:33: error: implementation restriction: package object A cannot contain companion object B. Instead, object B should be placed directly in package A. +t5954.scala:33: error: object B should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. object B ^ -t5954.scala:32: error: implementation restriction: package object A cannot contain companion class B. Instead, class B should be placed directly in package A. +t5954.scala:32: error: class B should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. class B ^ 5 errors found diff --git a/test/files/neg/t5954.flags b/test/files/neg/t5954.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t5954.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t5954.scala b/test/files/neg/t5954.scala index 9e6f5392c7..3ccb5ed3ff 100644 --- a/test/files/neg/t5954.scala +++ b/test/files/neg/t5954.scala @@ -1,4 +1,4 @@ -// if you ever think you've fixed the underlying reason for the implementation restrictions +// if you ever think you've fixed the underlying reason for the warning // imposed by SI-5954, then here's a test that should pass with two "succes"es // //import scala.tools.partest._ diff --git a/test/files/neg/t667.check b/test/files/neg/t667.check index e68c6dea00..d4367bc87b 100644 --- a/test/files/neg/t667.check +++ b/test/files/neg/t667.check @@ -1,4 +1,4 @@ -t667.scala:8: error: illegal cyclic reference involving class Ni +t667.scala:8: error: class Ni inherits itself class Ni extends super.Ni with Ni; - ^ + ^ one error found diff --git a/test/files/neg/t877.check b/test/files/neg/t877.check index c3d4ab6584..5f25bd439c 100644 --- a/test/files/neg/t877.check +++ b/test/files/neg/t877.check @@ -1,7 +1,7 @@ t877.scala:3: error: Invalid literal number trait Foo extends A(22A, Bug!) {} ^ -t877.scala:3: error: ')' expected but eof found. +t877.scala:3: error: parents of traits may not have parameters trait Foo extends A(22A, Bug!) {} - ^ + ^ two errors found diff --git a/test/files/pos/SI-7060.flags b/test/files/pos/SI-7060.flags new file mode 100644 index 0000000000..c926ad6493 --- /dev/null +++ b/test/files/pos/SI-7060.flags @@ -0,0 +1 @@ +-Yinline -Ydead-code diff --git a/test/files/pos/SI-7060.scala b/test/files/pos/SI-7060.scala new file mode 100644 index 0000000000..c87620e020 --- /dev/null +++ b/test/files/pos/SI-7060.scala @@ -0,0 +1,11 @@ +object Test { + + @inline final def mbarray_apply_minibox(array: Any, tag: Byte): Long = + if (tag == 0) { + array.asInstanceOf[Array[Long]](0) + } else + array.asInstanceOf[Array[Byte]](0).toLong + + def crash_method(): Unit = + mbarray_apply_minibox(null, 0) +} diff --git a/test/files/pos/SI-7100.scala b/test/files/pos/SI-7100.scala new file mode 100644 index 0000000000..7cb6356ec8 --- /dev/null +++ b/test/files/pos/SI-7100.scala @@ -0,0 +1,6 @@ +class Buffer { + def f[@specialized(Int) T](): T = 0 match { + case 0 => 0.asInstanceOf[T] + case 1 => 0.asInstanceOf[T] + } +} diff --git a/test/files/pos/package-case.flags b/test/files/pos/package-case.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/package-case.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t2130-1.flags b/test/files/pos/t2130-1.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t2130-1.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t2130-2.flags b/test/files/pos/t2130-2.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t2130-2.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t3999b.flags b/test/files/pos/t3999b.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t3999b.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t4052.flags b/test/files/pos/t4052.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t4052.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t5082.scala b/test/files/pos/t5082.scala new file mode 100644 index 0000000000..63eeda38ba --- /dev/null +++ b/test/files/pos/t5082.scala @@ -0,0 +1,14 @@ +trait Something[T] +object Test { class A } +case class Test() extends Something[Test.A] + +object User { + val Test() = Test() +} + +object Wrap { + trait Something[T] + object Test { class A } + case class Test(a: Int, b: Int)(c: String) extends Something[Test.A] + val Test(x, y) = Test(1, 2)(""); (x + y).toString +} diff --git a/test/files/presentation/doc.check b/test/files/presentation/doc.check index 62b3bfc2e3..e33756773d 100755..100644 --- a/test/files/presentation/doc.check +++ b/test/files/presentation/doc.check @@ -1,3 +1,4 @@ +reload: Test.scala body:Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This is a test comment), Text(.)))), Text( )))))) @example:Body(List(Paragraph(Chain(List(Summary(Monospace(Text("abb".permutations = Iterator(abb, bab, bba))))))))) diff --git a/test/files/presentation/doc.scala b/test/files/presentation/doc/doc.scala index 4b0d6baa1f..475d92b861 100755 --- a/test/files/presentation/doc.scala +++ b/test/files/presentation/doc/doc.scala @@ -1,5 +1,5 @@ import scala.tools.nsc.doc -import scala.tools.nsc.doc.base.LinkTo +import scala.tools.nsc.doc.base._ import scala.tools.nsc.doc.base.comment._ import scala.tools.nsc.interactive._ import scala.tools.nsc.interactive.tests._ @@ -28,12 +28,33 @@ object Test extends InteractiveTest { |trait Commented {} |class User(c: %sCommented)""".stripMargin.format(comment, tags take nTags mkString "\n", caret) - override def main(args: Array[String]) { - val documenter = new Doc(settings) { - val global: compiler.type = compiler - + override lazy val compiler = { + new { + override val settings = { + prepareSettings(Test.this.settings) + Test.this.settings + } + } with Global(settings, compilerReporter) with MemberLookupBase with CommentFactoryBase { + val global: this.type = this def chooseLink(links: List[LinkTo]): LinkTo = links.head + def internalLink(sym: Symbol, site: Symbol) = None + def toString(link: LinkTo) = link.toString + + def getComment(sym: Symbol, source: SourceFile) = { + val docResponse = new Response[(String, String, Position)] + askDocComment(sym, sym.owner, source, docResponse) + docResponse.get.left.toOption flatMap { + case (expanded, raw, pos) => + if (expanded.isEmpty) + None + else + Some(ask { () => parseAtSymbol(expanded, raw, pos, Some(sym.owner)) }) + } + } } + } + + override def runDefaultTests() { for (i <- 1 to tags.length) { val markedText = text(i) val idx = markedText.indexOf(caret) @@ -52,18 +73,17 @@ object Test extends InteractiveTest { treeResponse.get.left.toOption match { case Some(tree) => val sym = tree.tpe.typeSymbol - documenter.retrieve(sym, sym.owner) match { - case Some(HtmlResult(comment)) => - import comment._ - val tags: List[(String, Iterable[Body])] = - List(("@example", example), ("@version", version), ("@since", since.toList), ("@todo", todo), ("@note", note), ("@see", see)) - val str = ("body:" + body + "\n") + - tags.map{ case (name, bodies) => name + ":" + bodies.mkString("\n") }.mkString("\n") - reporter.println(str) - case Some(_) => reporter.println("Got unexpected result") - case None => reporter.println("Got no result") + compiler.getComment(sym, batch) match { + case None => println("Got no doc comment") + case Some(comment) => + import comment._ + val tags: List[(String, Iterable[Body])] = + List(("@example", example), ("@version", version), ("@since", since.toList), ("@todo", todo), ("@note", note), ("@see", see)) + val str = ("body:" + body + "\n") + + tags.map{ case (name, bodies) => name + ":" + bodies.mkString("\n") }.mkString("\n") + println(str) } - case None => reporter.println("Couldn't find a typedTree") + case None => println("Couldn't find a typedTree") } } } diff --git a/test/files/presentation/ide-t1001326.check b/test/files/presentation/ide-t1001326.check new file mode 100644 index 0000000000..0ac15faed4 --- /dev/null +++ b/test/files/presentation/ide-t1001326.check @@ -0,0 +1,4 @@ +Unique OK +Unattributed OK +NeverModify OK +AlwaysParseTree OK
\ No newline at end of file diff --git a/test/files/presentation/ide-t1001326/Test.scala b/test/files/presentation/ide-t1001326/Test.scala new file mode 100644 index 0000000000..3091da4b40 --- /dev/null +++ b/test/files/presentation/ide-t1001326/Test.scala @@ -0,0 +1,91 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + + override def execute(): Unit = { + val sf = sourceFiles.find(_.file.name == "A.scala").head + uniqueParseTree_t1001326(sf) + unattributedParseTree_t1001326(sf) + neverModifyParseTree_t1001326(sf) + shouldAlwaysReturnParseTree_t1001326(sf) + } + + /** + * Asking twice for a parseTree on the same source should always return a new tree + */ + private def uniqueParseTree_t1001326(sf: SourceFile) { + val parseTree1 = compiler.parseTree(sf) + val parseTree2 = compiler.parseTree(sf) + if (parseTree1 != parseTree2) { + reporter.println("Unique OK") + } else { + reporter.println("Unique FAILED") + } + } + + /** + * A parseTree should never contain any symbols or types + */ + private def unattributedParseTree_t1001326(sf: SourceFile) { + if (noSymbolsOrTypes(compiler.parseTree(sf))) { + reporter.println("Unattributed OK") + } else { + reporter.println("Unattributed FAILED") + } + } + + /** + * Once you have obtained a parseTree it should never change + */ + private def neverModifyParseTree_t1001326(sf: SourceFile) { + val parsedTree = compiler.parseTree(sf) + loadSourceAndWaitUntilTypechecked(sf) + if (noSymbolsOrTypes(parsedTree)) { + reporter.println("NeverModify OK") + } else { + reporter.println("NeverModify FAILED") + } + } + + /** + * Should always return a parse tree + */ + private def shouldAlwaysReturnParseTree_t1001326(sf: SourceFile) { + loadSourceAndWaitUntilTypechecked(sf) + if (noSymbolsOrTypes(compiler.parseTree(sf))) { + reporter.println("AlwaysParseTree OK") + } else { + reporter.println("AlwaysParseTree FAILED") + } + } + + /** + * Load a source and block while it is type-checking. + */ + private def loadSourceAndWaitUntilTypechecked(sf: SourceFile): Unit = { + compiler.askToDoFirst(sf) + val res = new Response[Unit] + compiler.askReload(List(sf), res) + res.get + askLoadedTyped(sf).get + } + + /** + * Traverses a tree and makes sure that there are no types or symbols present in the tree with + * the exception of the symbol for the package 'scala'. This is because that symbol will be + * present in some of the nodes that the compiler generates. + */ + private def noSymbolsOrTypes(tree: compiler.Tree): Boolean = { + tree.forAll { t => + (t.symbol == null || + t.symbol == compiler.NoSymbol || + t.symbol == compiler.definitions.ScalaPackage // ignore the symbol for the scala package for now + ) && ( + t.tpe == null || + t.tpe == compiler.NoType) + } + } + +}
\ No newline at end of file diff --git a/test/files/presentation/ide-t1001326/src/a/A.scala b/test/files/presentation/ide-t1001326/src/a/A.scala new file mode 100644 index 0000000000..c82ca02231 --- /dev/null +++ b/test/files/presentation/ide-t1001326/src/a/A.scala @@ -0,0 +1,5 @@ +package a + +class A { + def foo(s: String) = s + s +}
\ No newline at end of file diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check index 8856fef5b3..7d8d181306 100644 --- a/test/files/run/analyzerPlugins.check +++ b/test/files/run/analyzerPlugins.check @@ -22,12 +22,12 @@ pluginsPt(?, Trees$Annotated) [7] pluginsPt(?, Trees$Apply) [8] pluginsPt(?, Trees$ApplyImplicitView) [2] pluginsPt(?, Trees$Assign) [7] -pluginsPt(?, Trees$Block) [4] +pluginsPt(?, Trees$Block) [7] pluginsPt(?, Trees$ClassDef) [2] pluginsPt(?, Trees$DefDef) [14] -pluginsPt(?, Trees$Ident) [51] +pluginsPt(?, Trees$Ident) [49] pluginsPt(?, Trees$If) [2] -pluginsPt(?, Trees$Literal) [16] +pluginsPt(?, Trees$Literal) [20] pluginsPt(?, Trees$New) [5] pluginsPt(?, Trees$PackageDef) [1] pluginsPt(?, Trees$Return) [1] @@ -37,9 +37,9 @@ pluginsPt(?, Trees$This) [20] pluginsPt(?, Trees$TypeApply) [3] pluginsPt(?, Trees$TypeBoundsTree) [2] pluginsPt(?, Trees$TypeDef) [1] -pluginsPt(?, Trees$TypeTree) [38] +pluginsPt(?, Trees$TypeTree) [37] pluginsPt(?, Trees$Typed) [1] -pluginsPt(?, Trees$ValDef) [21] +pluginsPt(?, Trees$ValDef) [23] pluginsPt(Any, Trees$Literal) [2] pluginsPt(Any, Trees$Typed) [1] pluginsPt(Array[Any], Trees$ArrayValue) [1] @@ -53,7 +53,7 @@ pluginsPt(Int @testAnn, Trees$Literal) [1] pluginsPt(Int, Trees$Apply) [1] pluginsPt(Int, Trees$Ident) [2] pluginsPt(Int, Trees$If) [1] -pluginsPt(Int, Trees$Literal) [5] +pluginsPt(Int, Trees$Literal) [6] pluginsPt(Int, Trees$Select) [3] pluginsPt(List, Trees$Apply) [1] pluginsPt(List[Any], Trees$Select) [1] @@ -82,8 +82,8 @@ pluginsTypeSig(value lub1, Trees$ValDef) [2] pluginsTypeSig(value lub2, Trees$ValDef) [2] pluginsTypeSig(value param, Trees$ValDef) [2] pluginsTypeSig(value str, Trees$ValDef) [1] -pluginsTypeSig(value x, Trees$ValDef) [4] -pluginsTypeSig(value y, Trees$ValDef) [4] +pluginsTypeSig(value x, Trees$ValDef) [5] +pluginsTypeSig(value y, Trees$ValDef) [5] pluginsTypeSig(variable count, Trees$ValDef) [3] pluginsTypeSigAccessor(value annotField) [1] pluginsTypeSigAccessor(value inferField) [1] @@ -110,7 +110,7 @@ pluginsTyped(<notype>, Trees$ClassDef) [2] pluginsTyped(<notype>, Trees$DefDef) [14] pluginsTyped(<notype>, Trees$PackageDef) [1] pluginsTyped(<notype>, Trees$TypeDef) [1] -pluginsTyped(<notype>, Trees$ValDef) [21] +pluginsTyped(<notype>, Trees$ValDef) [23] pluginsTyped(<root>, Trees$Ident) [1] pluginsTyped(=> Boolean @testAnn, Trees$Select) [1] pluginsTyped(=> Double, Trees$Select) [4] @@ -124,7 +124,7 @@ pluginsTyped(A, Trees$TypeTree) [4] pluginsTyped(A.super.type, Trees$Super) [1] pluginsTyped(A.this.type, Trees$This) [11] pluginsTyped(Any, Trees$TypeTree) [1] -pluginsTyped(AnyRef, Trees$Select) [4] +pluginsTyped(AnyRef, Trees$Select) [2] pluginsTyped(Array[Any], Trees$ArrayValue) [1] pluginsTyped(Boolean @testAnn, Trees$Select) [1] pluginsTyped(Boolean @testAnn, Trees$TypeTree) [4] @@ -137,12 +137,12 @@ pluginsTyped(Int @testAnn, Trees$TypeTree) [2] pluginsTyped(Int @testAnn, Trees$Typed) [2] pluginsTyped(Int(0), Trees$Literal) [3] pluginsTyped(Int(1) @testAnn, Trees$Typed) [1] -pluginsTyped(Int(1), Trees$Literal) [8] +pluginsTyped(Int(1), Trees$Literal) [9] pluginsTyped(Int(2), Trees$Literal) [1] pluginsTyped(Int, Trees$Apply) [1] pluginsTyped(Int, Trees$Ident) [2] pluginsTyped(Int, Trees$If) [2] -pluginsTyped(Int, Trees$Select) [15] +pluginsTyped(Int, Trees$Select) [17] pluginsTyped(Int, Trees$TypeTree) [13] pluginsTyped(List, Trees$Apply) [1] pluginsTyped(List, Trees$Select) [1] @@ -160,27 +160,26 @@ pluginsTyped(String("huhu"), Trees$Literal) [1] pluginsTyped(String("str") @testAnn, Trees$Typed) [1] pluginsTyped(String("str"), Trees$Literal) [1] pluginsTyped(String("str"), Trees$Typed) [1] -pluginsTyped(String("two"), Trees$Literal) [2] +pluginsTyped(String("two"), Trees$Literal) [3] pluginsTyped(String, Trees$Apply) [2] pluginsTyped(String, Trees$Block) [2] pluginsTyped(String, Trees$Ident) [1] pluginsTyped(String, Trees$Select) [9] -pluginsTyped(String, Trees$TypeTree) [7] +pluginsTyped(String, Trees$TypeTree) [8] pluginsTyped(Unit, Trees$Apply) [2] pluginsTyped(Unit, Trees$Assign) [8] -pluginsTyped(Unit, Trees$Block) [4] +pluginsTyped(Unit, Trees$Block) [7] pluginsTyped(Unit, Trees$If) [1] -pluginsTyped(Unit, Trees$Literal) [5] +pluginsTyped(Unit, Trees$Literal) [8] pluginsTyped(Unit, Trees$TypeTree) [1] pluginsTyped([A](xs: A*)List[A], Trees$Select) [1] pluginsTyped([T <: Int]=> Int, Trees$Select) [1] pluginsTyped([T0 >: ? <: ?]()T0, Trees$Select) [1] pluginsTyped([T](xs: Array[T])scala.collection.mutable.WrappedArray[T], Trees$Select) [1] -pluginsTyped(annotation.type, Trees$Select) [4] +pluginsTyped(annotation.type, Trees$Select) [2] pluginsTyped(math.type, Trees$Select) [9] pluginsTyped(scala.annotation.Annotation, Trees$Apply) [1] pluginsTyped(scala.annotation.TypeConstraint, Trees$Select) [4] -pluginsTyped(scala.annotation.TypeConstraint, Trees$TypeTree) [2] pluginsTyped(scala.collection.immutable.List.type, Trees$Select) [2] pluginsTyped(scala.collection.immutable.StringOps, Trees$ApplyImplicitView) [2] pluginsTyped(scala.collection.mutable.WrappedArray[Any], Trees$Apply) [1] diff --git a/test/files/run/array-addition.check b/test/files/run/array-addition.check deleted file mode 100644 index 7bfbd9c711..0000000000 --- a/test/files/run/array-addition.check +++ /dev/null @@ -1,4 +0,0 @@ -Array(1, 2, 3, 4) -Array(1, 2, 3, 4) -Array(1) -Array(1) diff --git a/test/files/run/array-addition.scala b/test/files/run/array-addition.scala deleted file mode 100644 index 8def48e85c..0000000000 --- a/test/files/run/array-addition.scala +++ /dev/null @@ -1,11 +0,0 @@ -object Test { - def prettyPrintArray(x: Array[_]) = println("Array(" + x.mkString(", ") + ")") - - def main(args: Array[String]): Unit = { - prettyPrintArray(Array(1,2,3) :+ 4) - prettyPrintArray(1 +: Array(2,3,4)) - prettyPrintArray(Array() :+ 1) - prettyPrintArray(1 +: Array()) - } -} - diff --git a/test/files/run/t5064.check b/test/files/run/t5064.check index 61ccfd16e7..077006abd9 100644 --- a/test/files/run/t5064.check +++ b/test/files/run/t5064.check @@ -1,6 +1,6 @@ -[53] T5064.super.<init>() -[53] T5064.super.<init> -[53] this +[12] T5064.super.<init>() +[12] T5064.super.<init> +[12] this [16:23] immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1})) [16:20] immutable.this.List.apply <16:20> immutable.this.List diff --git a/test/files/run/t5603.check b/test/files/run/t5603.check index 3b2eb55313..5127d3c1c7 100644 --- a/test/files/run/t5603.check +++ b/test/files/run/t5603.check @@ -12,7 +12,7 @@ [95:101]<paramaccessor> private[this] val i: [98:101]Int = _; <119:139>def <init>([95]i: [98]Int) = <119:139>{ <119:139>val nameElse = <134:139>"Bob"; - [NoPosition][NoPosition][NoPosition]super.<init>(); + [94][94][94]super.<init>(); [94]() }; [168:184]val name = [179:184]"avc"; @@ -20,7 +20,7 @@ }; [215:241]object Test extends [227:241][235:238]App { [227]def <init>() = [227]{ - [NoPosition][NoPosition][NoPosition]super.<init>(); + [227][227][227]super.<init>(); [227]() }; [NoPosition]<empty> diff --git a/test/files/run/t6113.check b/test/files/run/t6113.check new file mode 100644 index 0000000000..65fb3cd090 --- /dev/null +++ b/test/files/run/t6113.check @@ -0,0 +1 @@ +Foo[[X](Int, X)] diff --git a/test/files/run/t6113.scala b/test/files/run/t6113.scala new file mode 100644 index 0000000000..321cae86a3 --- /dev/null +++ b/test/files/run/t6113.scala @@ -0,0 +1,6 @@ +trait Foo[C[_]] + +object Test extends App { + import scala.reflect.runtime.universe._ + println(typeOf[Foo[({type l[X] = (Int, X)})#l]]) +}
\ No newline at end of file diff --git a/test/files/run/t6288.check b/test/files/run/t6288.check index 4895c2c007..e6467edc95 100644 --- a/test/files/run/t6288.check +++ b/test/files/run/t6288.check @@ -1,8 +1,8 @@ [[syntax trees at end of patmat]] // newSource1 [7]package [7]<empty> { [7]object Case3 extends [13][106]scala.AnyRef { - [106]def <init>(): [13]Case3.type = [106]{ - [106][106][106]Case3.super.<init>(); + [13]def <init>(): [13]Case3.type = [13]{ + [13][13][13]Case3.super.<init>(); [13]() }; [21]def unapply([29]z: [32]<type: [32]scala.Any>): [21]Option[Int] = [56][52][52]scala.Some.apply[[52]Int]([58]-1); @@ -24,8 +24,8 @@ } }; [113]object Case4 extends [119][217]scala.AnyRef { - [217]def <init>(): [119]Case4.type = [217]{ - [217][217][217]Case4.super.<init>(); + [119]def <init>(): [119]Case4.type = [119]{ + [119][119][119]Case4.super.<init>(); [119]() }; [127]def unapplySeq([138]z: [141]<type: [141]scala.Any>): [127]Option[List[Int]] = [167]scala.None; @@ -50,8 +50,8 @@ } }; [224]object Case5 extends [230][312]scala.AnyRef { - [312]def <init>(): [230]Case5.type = [312]{ - [312][312][312]Case5.super.<init>(); + [230]def <init>(): [230]Case5.type = [230]{ + [230][230][230]Case5.super.<init>(); [230]() }; [238]def unapply([246]z: [249]<type: [249]scala.Any>): [238]Boolean = [265]true; diff --git a/test/files/run/t6288b-jump-position.check b/test/files/run/t6288b-jump-position.check index ece88b18f0..83ba810958 100644 --- a/test/files/run/t6288b-jump-position.check +++ b/test/files/run/t6288b-jump-position.check @@ -65,9 +65,9 @@ object Case3 extends Object { blocks: [1] 1: - 12 THIS(Case3) - 12 CALL_METHOD java.lang.Object.<init> (super()) - 12 RETURN(UNIT) + 1 THIS(Case3) + 1 CALL_METHOD java.lang.Object.<init> (super()) + 1 RETURN(UNIT) } Exception handlers: diff --git a/test/files/run/t6888.check b/test/files/run/t6888.check new file mode 100644 index 0000000000..4e8a2de2db --- /dev/null +++ b/test/files/run/t6888.check @@ -0,0 +1,3 @@ +2 +3 +3 diff --git a/test/files/run/t6888.scala b/test/files/run/t6888.scala new file mode 100644 index 0000000000..0c64cbe5b6 --- /dev/null +++ b/test/files/run/t6888.scala @@ -0,0 +1,19 @@ +class C { + val x = 1 + object $ { + val y = x + x + class abc$ { + def xy = x + y + } + object abc$ { + def xy = x + y + } + } +} + +object Test extends App { + val c = new C() + println(c.$.y) + println(c.$.abc$.xy) + println(new c.$.abc$().xy) +} diff --git a/test/files/run/t7064-old-style-supercalls.check b/test/files/run/t7064-old-style-supercalls.check new file mode 100644 index 0000000000..0cfbf08886 --- /dev/null +++ b/test/files/run/t7064-old-style-supercalls.check @@ -0,0 +1 @@ +2 diff --git a/test/files/run/t7064-old-style-supercalls.scala b/test/files/run/t7064-old-style-supercalls.scala new file mode 100644 index 0000000000..cffa7b1888 --- /dev/null +++ b/test/files/run/t7064-old-style-supercalls.scala @@ -0,0 +1,48 @@ +import scala.reflect.runtime.universe._ +import Flag._ +import definitions._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval + +object Test extends App { + val PARAMACCESSOR = (1L << 29).asInstanceOf[FlagSet] + + // these trees can be acquired by running the following incantation: + // echo 'class C(val x: Int); class D extends C(2)' > foo.scala + // ./scalac -Xprint:parser -Yshow-trees-stringified -Yshow-trees-compact foo.scala + + val c = ClassDef( + Modifiers(), newTypeName("C"), List(), + Template( + List(Select(Ident(ScalaPackage), newTypeName("AnyRef"))), + emptyValDef, + List( + ValDef(Modifiers(PARAMACCESSOR), newTermName("x"), Ident(newTypeName("Int")), EmptyTree), + DefDef( + Modifiers(), + nme.CONSTRUCTOR, + List(), + List(List(ValDef(Modifiers(PARAM | PARAMACCESSOR), newTermName("x"), Ident(newTypeName("Int")), EmptyTree))), + TypeTree(), + Block( + List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), + Literal(Constant(()))))))) + val d = ClassDef( + Modifiers(), newTypeName("D"), List(), + Template( + List(Ident(newTypeName("C"))), + emptyValDef, + List( + DefDef( + Modifiers(), + nme.CONSTRUCTOR, + List(), + List(List()), + TypeTree(), + Block( + List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List(Literal(Constant(2))))), + Literal(Constant(()))))))) + val result = Select(Apply(Select(New(Ident(newTypeName("D"))), nme.CONSTRUCTOR), List()), newTermName("x")) + println(cm.mkToolBox().eval(Block(List(c, d), result))) +}
\ No newline at end of file |