diff options
Diffstat (limited to 'src/compiler')
26 files changed, 359 insertions, 364 deletions
diff --git a/src/compiler/scala/reflect/macros/util/Helpers.scala b/src/compiler/scala/reflect/macros/util/Helpers.scala index f12582a3a1..f40c6bb7e6 100644 --- a/src/compiler/scala/reflect/macros/util/Helpers.scala +++ b/src/compiler/scala/reflect/macros/util/Helpers.scala @@ -23,25 +23,27 @@ trait Helpers { * or to streamline creation of the list of macro arguments. */ def transformTypeTagEvidenceParams(macroImplRef: Tree, transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = { + val MacroContextUniverse = definitions.MacroContextUniverse val treeInfo.MacroImplReference(isBundle, _, macroImpl, _) = macroImplRef val paramss = macroImpl.paramss - if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do - val rc = - if (isBundle) macroImpl.owner.tpe.member(nme.c) - else { - def cparam = paramss.head.head - if (paramss.head.isEmpty || !(cparam.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do - cparam - } + val ContextParam = paramss match { + case Nil | _ :+ Nil => NoSymbol // no implicit parameters in the signature => nothing to do + case _ if isBundle => macroImpl.owner.tpe member nme.c + case (cparam :: _) :: _ if cparam.tpe <:< MacroContextClass.tpe => cparam + case _ => NoSymbol // no context parameter in the signature => nothing to do + } def transformTag(param: Symbol): Symbol = param.tpe.dealias match { - case TypeRef(SingleType(SingleType(_, ac), universe), WeakTypeTagClass, targ :: Nil) - if ac == rc && universe == MacroContextUniverse => - transform(param, targ.typeSymbol) - case _ => - param + case TypeRef(SingleType(SingleType(_, ContextParam), MacroContextUniverse), WeakTypeTagClass, targ :: Nil) => transform(param, targ.typeSymbol) + case _ => param + } + ContextParam match { + case NoSymbol => paramss + case _ => + paramss.last map transformTag filter (_.exists) match { + case Nil => paramss.init + case transformed => paramss.init :+ transformed + } } - val transformed = paramss.last map transformTag filter (_ ne NoSymbol) - if (transformed.isEmpty) paramss.init else paramss.init :+ transformed } /** Increases metalevel of the type, i.e. transforms: diff --git a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala index 2ce2fb3eaa..899aa93a3b 100644 --- a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala @@ -27,7 +27,7 @@ class OfflineCompilerCommand(arguments: List[String], settings: FscSettings) ext val baseDirectory = { val pwd = System.getenv("PWD") if (pwd == null || isWin) Directory.Current getOrElse Directory("/") - else Directory(pwd) + else Directory(pwd) } currentDir.value = baseDirectory.path } diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index f2e5c9b1eb..7cf2f8559b 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -18,8 +18,14 @@ trait DocComments { self: Global => val cookedDocComments = mutable.HashMap[Symbol, String]() - /** The raw doc comment map */ - val docComments = mutable.HashMap[Symbol, DocComment]() + /** The raw doc comment map + * + * In IDE, background compilation runs get interrupted by + * reloading new sourcefiles. This is weak to avoid + * memleaks due to the doc of their cached symbols + * (e.g. in baseTypeSeq) between periodic doc reloads. + */ + val docComments = mutable.WeakHashMap[Symbol, DocComment]() def clearDocComments() { cookedDocComments.clear() diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index caab299635..9c8e13a1a9 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -282,7 +282,7 @@ abstract class NodePrinters { traverseList("[]", "type parameter")(tparams) vparamss match { case Nil => println("Nil") - case Nil :: Nil => println("List(Nil)") + case ListOfNil => println("List(Nil)") case ps :: Nil => printLine("", "1 parameter list") ps foreach traverse diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 07e24900e9..50aad8e043 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -303,6 +303,15 @@ self => def o2p(offset: Int): Position def r2p(start: Int, mid: Int, end: Int): Position + /** Creates a range position from the given start offset to + * the value of in.lastOffset. + */ + def rangeSince(start: Int): Position = r2p(start, start, in.lastOffset) + + /** Like in.skipToken, but returns a range position surrounding the skipped token. + */ + def skipTokenRange(): Position = rangeSince(in.skipToken()) + /** whether a non-continuable syntax error has been seen */ private var lastErrorOffset : Int = -1 @@ -568,8 +577,9 @@ self => and } - def expectedMsgTemplate(exp: String, fnd: String) = s"$exp expected but $fnd found." - def expectedMsg(token: Int): String = expectedMsgTemplate(token2string(token), token2string(in.token)) + def expectedMsgTemplate(expected: String, found: String): String = s"$expected expected but $found found." + def expectedMsg(expected: Int, found: Int): String = expectedMsgTemplate(token2string(expected), token2string(found)) + def expectedMsg(token: Int): String = expectedMsg(token, in.token) /** Consume one token of the specified type, or signal an error if it is not there. */ def accept(token: Int): Int = { @@ -587,6 +597,10 @@ self => if (in.token == token) in.nextToken() offset } + /** If the given token is available for consumption, consume it and return true. + * Otherwise, do nothing and return false. + */ + def acceptIfPresent(token: Int) = (in.token == token) && { accept(token) ; true } /** {{{ * semi = nl {nl} | `;` @@ -703,14 +717,24 @@ self => /* ---------- TREE CONSTRUCTION ------------------------------------------- */ - def atPos[T <: Tree](offset: Int)(t: T): T = atPos(r2p(offset, offset, in.lastOffset max offset))(t) - def atPos[T <: Tree](start: Int, point: Int)(t: T): T = atPos(r2p(start, point, in.lastOffset max start))(t) + def atPos[T <: Tree](start: Int)(t: T): T = atPos[T](start, start)(t) + def atPos[T <: Tree](start: Int, point: Int)(t: T): T = atPos[T](start, point, in.lastOffset max start)(t) def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T = atPos(r2p(start, point, end))(t) def atPos[T <: Tree](pos: Position)(t: T): T = global.atPos(pos)(t) def atInPos[T <: Tree](t: T): T = atPos(o2p(in.offset))(t) def setInPos[T <: Tree](t: T): T = t setPos o2p(in.offset) + /** Use with caution. */ + def peekahead(): Unit = { + in.prev copyFrom in + in.nextToken() + } + def pushback(): Unit = { + in.next copyFrom in + in copyFrom in.prev + } + /** Convert tree to formal parameter list. */ def convertToParams(tree: Tree): List[ValDef] = tree match { case Parens(ts) => ts map convertToParam @@ -749,10 +773,9 @@ self => if (!sepFirst) ts += part - while (in.token == separator) { - in.nextToken() + while (acceptIfPresent(separator)) ts += part - } + ts.toList } @inline final def commaSeparated[T](part: => T): List[T] = tokenSeparated(COMMA, sepFirst = false, part) @@ -829,10 +852,8 @@ self => private def tupleInfixType(start: Int) = { in.nextToken() - if (in.token == RPAREN) { - in.nextToken() + if (acceptIfPresent(RPAREN)) atPos(start, accept(ARROW)) { makeFunctionTypeTree(Nil, typ()) } - } else { val ts = functionTypes() accept(RPAREN) @@ -936,13 +957,8 @@ self => ) def compoundTypeRest(t: Tree): Tree = { - val ts = new ListBuffer[Tree] += t - while (in.token == WITH) { - in.nextToken() - ts += annotType() - } + val types = t :: tokenSeparated(WITH, sepFirst = true, annotType()) newLineOptWhenFollowedBy(LBRACE) - val types = ts.toList val braceOffset = in.offset val hasRefinement = in.token == LBRACE val refinements = if (hasRefinement) refinement() else Nil @@ -956,7 +972,7 @@ self => } // The second case includes an empty refinement - refinements is empty, but // it still gets a CompoundTypeTree. - ts.toList match { + types match { case tp :: Nil if !hasRefinement => tp // single type, no refinement, already positioned case tps => atPos(t.pos.startOrPoint)(CompoundTypeTree(Template(tps, emptyValDef, refinements))) } @@ -1024,19 +1040,19 @@ self => def path(thisOK: Boolean, typeOK: Boolean): Tree = { val start = in.offset var t: Tree = null - if (in.token == THIS) { - in.nextToken() + if (acceptIfPresent(THIS)) { t = atPos(start) { This(tpnme.EMPTY) } if (!thisOK || in.token == DOT) { t = selectors(t, typeOK, accept(DOT)) } - } else if (in.token == SUPER) { - in.nextToken() + } + else if (acceptIfPresent(SUPER)) { t = atPos(start) { Super(This(tpnme.EMPTY), mixinQualifierOpt()) } accept(DOT) t = selector(t) if (in.token == DOT) t = selectors(t, typeOK, in.skipToken()) - } else { + } + else { val tok = in.token val name = ident() t = atPos(start) { @@ -1045,18 +1061,18 @@ self => } if (in.token == DOT) { val dotOffset = in.skipToken() - if (in.token == THIS) { - in.nextToken() + if (acceptIfPresent(THIS)) { t = atPos(start) { This(name.toTypeName) } if (!thisOK || in.token == DOT) t = selectors(t, typeOK, accept(DOT)) - } else if (in.token == SUPER) { - in.nextToken() + } + else if (acceptIfPresent(SUPER)) { t = atPos(start) { Super(This(name.toTypeName), mixinQualifierOpt()) } accept(DOT) t = selector(t) if (in.token == DOT) t = selectors(t, typeOK, in.skipToken()) - } else { + } + else { t = selectors(t, typeOK, dotOffset) } } @@ -1065,10 +1081,8 @@ self => } def selectors(t: Tree, typeOK: Boolean, dotOffset: Int): Tree = - if (typeOK && in.token == TYPE) { - in.nextToken() + if (typeOK && acceptIfPresent(TYPE)) atPos(t.pos.startOrPoint, dotOffset) { SingletonTypeTree(t) } - } else { val t1 = selector(t) if (in.token == DOT) { selectors(t1, typeOK, in.skipToken()) } @@ -1165,10 +1179,10 @@ self => private def freshPlaceholder(): Tree = { val start = in.offset val pname = freshName("x$") - in.nextToken() + accept(USCORE) val id = atPos(start)(Ident(pname)) val param = atPos(id.pos.focus)(gen.mkSyntheticParam(pname.toTermName)) - placeholderParams = param :: placeholderParams + placeholderParams ::= param id } @@ -1211,7 +1225,7 @@ self => /* ------------- NEW LINES ------------------------------------------------- */ def newLineOpt() { - if (in.token == NEWLINE) in.nextToken() + acceptIfPresent(NEWLINE) } def newLinesOpt() { @@ -1235,9 +1249,7 @@ self => * TypedOpt ::= [`:' Type] * }}} */ - def typedOpt(): Tree = - if (in.token == COLON) { in.nextToken(); typ() } - else TypeTree() + def typedOpt(): Tree = if (acceptIfPresent(COLON)) typ() else TypeTree() def typeOrInfixType(location: Int): Tree = if (location == Local) typ() @@ -1261,16 +1273,9 @@ self => /* ----------- EXPRESSIONS ------------------------------------------------ */ - def condExpr(): Tree = { - if (in.token == LPAREN) { - in.nextToken() - val r = expr() - accept(RPAREN) - r - } else { - accept(LPAREN) - newLiteral(true) - } + def condExpr(): Tree = in.token match { + case LPAREN => inParens(expr()) + case _ => syntaxErrorOrIncompleteAnd("parenthesized conditional expression expected", skipIt = false)(newLiteral(true)) } /* hook for IDE, unlike expression can be stubbed @@ -1311,8 +1316,7 @@ self => val cond = condExpr() newLinesOpt() val thenp = expr() - val elsep = if (in.token == ELSE) { in.nextToken(); expr() } - else literalUnit + val elsep = if (acceptIfPresent(ELSE)) expr() else literalUnit If(cond, thenp, elsep) } parseIf @@ -1321,23 +1325,19 @@ self => val body = in.token match { case LBRACE => inBracesOrUnit(block()) case LPAREN => inParensOrUnit(expr()) - case _ => expr() + case _ => expr() } def catchFromExpr() = List(makeCatchFromExpr(expr())) - val catches: List[CaseDef] = - if (in.token != CATCH) Nil - else { - in.nextToken() + val catches: List[CaseDef] = ( + if (!acceptIfPresent(CATCH)) Nil else { if (in.token != LBRACE) catchFromExpr() else inBracesOrNil { if (isCaseDefStart) caseClauses() else catchFromExpr() } } - val finalizer = in.token match { - case FINALLY => in.nextToken(); expr() - case _ => EmptyTree - } + ) + val finalizer = if (acceptIfPresent(FINALLY)) expr() else EmptyTree Try(body, catches, finalizer) } parseTry @@ -1348,7 +1348,7 @@ self => val cond = condExpr() newLinesOpt() val body = expr() - makeWhile(start, cond, body) + makeWhile(cond, body) } } parseWhile @@ -1367,16 +1367,15 @@ self => case FOR => val start = in.skipToken() def parseFor = atPos(start) { - val enums = + val enums = ( if (in.token == LBRACE) inBracesOrNil(enumerators()) else inParensOrNil(enumerators()) + ) newLinesOpt() - if (in.token == YIELD) { - in.nextToken() + if (acceptIfPresent(YIELD)) makeForYield(enums, expr()) - } else { + else makeFor(enums, expr()) - } } def adjustStart(tree: Tree) = if (tree.pos.isRange && start < tree.pos.start) @@ -1403,7 +1402,7 @@ self => if (in.token == EQUALS) { t match { case Ident(_) | Select(_, _) | Apply(_, _) => - t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) } + t = atPos(t.pos.startOrPoint, in.skipToken()) { gen.mkAssign(t, expr()) } case _ => } } else if (in.token == COLON) { @@ -1467,9 +1466,8 @@ self => val param0 = convertToParam { atPos(in.offset) { Ident(ident()) match { - case expr if in.token == COLON => - in.nextToken() ; Typed(expr, typeOrInfixType(location)) - case expr => expr + case expr if acceptIfPresent(COLON) => Typed(expr, typeOrInfixType(location)) + case expr => expr } } } @@ -1545,32 +1543,28 @@ self => * }}} */ def simpleExpr(): Tree = { - var canApply = true - val t = - if (isLiteral) literal() - else in.token match { - case XMLSTART => - xmlLiteral() - case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => - path(thisOK = true, typeOK = false) - case USCORE => - freshPlaceholder() - case LPAREN => - atPos(in.offset)(makeParens(commaSeparated(expr()))) - case LBRACE => - canApply = false - blockExpr() - case NEW => - canApply = false - val nstart = in.skipToken() - val npos = r2p(nstart, nstart, in.lastOffset) - val tstart = in.offset - val (parents, self, stats) = template() - val cpos = r2p(tstart, tstart, in.lastOffset max tstart) - gen.mkNew(parents, self, stats, npos, cpos) - case _ => - syntaxErrorOrIncompleteAnd("illegal start of simple expression", skipIt = true)(errorTermTree) - } + val canApply = in.token match { + case LBRACE | NEW => false + case _ => true + } + def mkNew(): Tree = { + val npos = skipTokenRange() + val tstart = in.offset + val (parents, self, stats) = template() + val cpos = rangeSince(tstart) + + gen.mkNew(parents, self, stats, npos, cpos) + } + val t = in.token match { + case _ if isLiteral => literal() + case XMLSTART => xmlLiteral() + case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => path(thisOK = true, typeOK = false) + case USCORE => freshPlaceholder() + case LPAREN => atPos(in.offset)(makeParens(commaSeparated(expr()))) + case LBRACE => blockExpr() + case NEW => mkNew() + case _ => syntaxErrorOrIncompleteAnd("illegal start of simple expression", skipIt = true)(errorTermTree) + } simpleExprRest(t, canApply = canApply) } @@ -1677,9 +1671,9 @@ self => * Guard ::= if PostfixExpr * }}} */ - def guard(): Tree = - if (in.token == IF) { in.nextToken(); stripParens(postfixExpr()) } - else EmptyTree + def guard(): Tree = if (acceptIfPresent(IF)) guardExpr() else EmptyTree + + def guardExpr(): Tree = stripParens(postfixExpr()) /** {{{ * Enumerators ::= Generator {semi Enumerator} @@ -1704,27 +1698,26 @@ self => * }}} */ def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) { - val start = in.offset - val hasVal = in.token == VAL - if (hasVal) - in.nextToken() + val start = in.offset + val hasVal = acceptIfPresent(VAL) + val pat = noSeq.pattern1() + val point = in.offset + val equalsBody = equalsExprOpt() + val hasEq = !equalsBody.isEmpty + + if (hasVal && !hasEq) + syntaxError(in.offset, "val in for comprehension must be followed by assignment") + else if (hasEq && !eqOK) + syntaxError(point, "for comprehension must start with generator: " + expectedMsg(expected = LARROW, found = EQUALS)) + else if (hasVal) + deprecationWarning(start, "val keyword in for comprehension is deprecated") + + val rhs = equalsBody orElse { accept(LARROW) ; expr() } - val pat = noSeq.pattern1() - val point = in.offset - val hasEq = in.token == EQUALS - - if (hasVal) { - if (hasEq) deprecationWarning(in.offset, "val keyword in for comprehension is deprecated") - else syntaxError(in.offset, "val in for comprehension must be followed by assignment") - } - - if (hasEq && eqOK) in.nextToken() - else accept(LARROW) - val rhs = expr() enums += makeGenerator(r2p(start, point, in.lastOffset max start), pat, hasEq, rhs) // why max above? IDE stress tests have shown that lastOffset could be less than start, // I guess this happens if instead if a for-expression we sit on a closing paren. - while (in.token == IF) enums += makeFilter(in.offset, guard()) + enums ++= tokenSeparated(IF, sepFirst = true, makeFilter(in.offset, guardExpr())) } def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.endOrPoint), tree) @@ -1832,14 +1825,6 @@ self => var top = simplePattern(badPattern3) // after peekahead def acceptWildStar() = atPos(top.pos.startOrPoint, in.prev.offset)(Star(stripParens(top))) - def peekahead() = { - in.prev copyFrom in - in.nextToken() - } - def pushback() = { - in.next copyFrom in - in copyFrom in.prev - } // See SI-3189, SI-4832 for motivation. Cf SI-3480 for counter-motivation. // TODO: dredge out the remnants of regexp patterns. // /{/ peek for _*) or _*} (for xml escape) @@ -2013,16 +1998,15 @@ self => * }}} */ def accessQualifierOpt(mods: Modifiers): Modifiers = { - var result = mods - if (in.token == LBRACKET) { - in.nextToken() - if (mods.hasAccessBoundary) - syntaxError("duplicate private/protected qualifier", skipIt = false) - result = if (in.token == THIS) { in.nextToken(); mods | Flags.LOCAL } - else Modifiers(mods.flags, identForType()) - accept(RBRACKET) + def newModifiers(): Modifiers = ( + if (acceptIfPresent(THIS)) mods | Flags.LOCAL // private/protected[this] + else Modifiers(mods.flags, identForType()) // private/protected[foo] + ) + in.token match { + case LBRACKET if mods.hasAccessBoundary => syntaxError("duplicate private/protected qualifier", skipIt = false) ; mods + case LBRACKET => inBrackets(newModifiers()) + case _ => mods } - result } private val flagTokens: Map[Int, Long] = Map( @@ -2160,25 +2144,24 @@ self => } paramType() } - val default = - if (in.token == EQUALS) { - in.nextToken() + val default = ( + if (acceptIfPresent(EQUALS)) { mods |= Flags.DEFAULTPARAM expr() - } else EmptyTree + } + else EmptyTree + ) atPos(start, if (name == nme.ERROR) start else nameOffset) { ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default) } } - def paramClause(): List[ValDef] = { - if (in.token == RPAREN) - return Nil + def paramClause(): List[ValDef] = in.token match { + case RPAREN => Nil + case _ => + if (acceptIfPresent(IMPLICIT)) + implicitmod = Flags.IMPLICIT - if (in.token == IMPLICIT) { - in.nextToken() - implicitmod = Flags.IMPLICIT - } - commaSeparated(param()) + commaSeparated(param()) } val vds = new ListBuffer[List[ValDef]] val start = in.offset @@ -2186,8 +2169,7 @@ self => if (ofCaseClass && in.token != LPAREN) syntaxError(in.lastOffset, "case classes without a parameter list are not allowed;\n"+ "use either case objects or case classes with an explicit `()' as a parameter list.") - while (implicitmod == 0 && in.token == LPAREN) { - in.nextToken() + while (implicitmod == 0 && acceptIfPresent(LPAREN)) { vds += paramClause() accept(RPAREN) caseParam = false @@ -2211,18 +2193,16 @@ self => def paramType(): Tree = paramType(useStartAsPosition = false) def paramType(useStartAsPosition: Boolean): Tree = { val start = in.offset - in.token match { - case ARROW => + if (acceptIfPresent(ARROW)) + atPos(start)(byNameApplication(typ())) + else { + val t = typ() + if (isRawStar) { in.nextToken() - atPos(start)(byNameApplication(typ())) - case _ => - val t = typ() - if (isRawStar) { - in.nextToken() - if (useStartAsPosition) atPos(start)(repeatedApplication(t)) - else atPos(t.pos.startOrPoint, t.pos.point)(repeatedApplication(t)) - } - else t + if (useStartAsPosition) atPos(start)(repeatedApplication(t)) + else atPos(t.pos.startOrPoint, t.pos.point)(repeatedApplication(t)) + } + else t } } @@ -2257,14 +2237,13 @@ self => } if (contextBoundBuf ne null) { while (in.token == VIEWBOUND) { - contextBoundBuf += atPos(in.skipToken()) { - makeFunctionTypeTree(List(Ident(pname)), typ()) - } + contextBoundBuf += atPos(in.skipToken())(makeFunctionTypeTree(List(Ident(pname)), typ())) } while (in.token == COLON) { - contextBoundBuf += atPos(in.skipToken()) { - AppliedTypeTree(typ(), List(Ident(pname))) - } + val start = in.skipToken() + val tycon = typ() + val applied = atPos(tycon.pos withStart start)(AppliedTypeTree(tycon, Ident(pname) :: Nil)) + contextBoundBuf += applied } } param @@ -2290,7 +2269,7 @@ self => t setPos o2p(in.offset) } - def bound(tok: Int): Tree = if (in.token == tok) { in.nextToken(); typ() } else EmptyTree + def bound(tok: Int): Tree = if (acceptIfPresent(tok)) typ() else EmptyTree /* -------- DEFS ------------------------------------------- */ @@ -2302,11 +2281,10 @@ self => def importClause(): List[Tree] = { val offset = accept(IMPORT) commaSeparated(importExpr()) match { - case Nil => Nil + case Nil => Nil case t :: rest => // The first import should start at the position of the keyword. - t.setPos(t.pos.withStart(offset)) - t :: rest + (t setPos (t.pos withStart offset)) :: rest } } @@ -2335,12 +2313,9 @@ self => case _ => val nameOffset = in.offset val name = ident() - if (in.token == DOT) { + if (acceptIfPresent(DOT)) // import foo.bar.ident.<unknown> and so create a select node and recurse. - val t = atPos(start, if (name == nme.ERROR) in.offset else nameOffset)(Select(expr, name)) - in.nextToken() - return loop(t) - } + return loop(atPos(start, if (name == nme.ERROR) in.offset else nameOffset)(Select(expr, name))) // import foo.bar.Baz; else List(makeImportSelector(name, nameOffset)) } @@ -2371,30 +2346,27 @@ self => selectors } - def wildcardOrIdent() = { - if (in.token == USCORE) { in.nextToken() ; nme.WILDCARD } - else ident() - } + def wildcardOrIdent() = if (acceptIfPresent(USCORE)) nme.WILDCARD else ident() /** {{{ * ImportSelector ::= Id [`=>' Id | `=>' `_'] * }}} */ def importSelector(): ImportSelector = { - val start = in.offset - val name = wildcardOrIdent() - var renameOffset = -1 - val rename = in.token match { - case ARROW => - in.nextToken() - renameOffset = in.offset - wildcardOrIdent() - case _ if name == nme.WILDCARD => null - case _ => - renameOffset = start - name - } - ImportSelector(name, start, rename, renameOffset) + val start = in.offset + val name = wildcardOrIdent() + + // The first case is overly cleverly using named arguments to reverse the + // positions of the last two parameters, because reading the rename will + // move the value of in.offset. Hey, I didn't invent side effects, I too am + // a victim here. I can't find a single place where the rename position + // is used anyway. + if (acceptIfPresent(ARROW)) + ImportSelector(name, start, renamePos = in.offset, rename = wildcardOrIdent()) + else if (name == nme.WILDCARD) + ImportSelector(name, start, null, -1) + else + ImportSelector(name, start, name, start) } /** {{{ @@ -2433,6 +2405,8 @@ self => defOrDcl(caseAwareTokenOffset, modifiers() withAnnotations annots) } + def equalsExprOpt(): Tree = if (acceptIfPresent(EQUALS)) expr() else EmptyTree + /** {{{ * PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr * ValDcl ::= Id {`,' Id} `:' Type @@ -2440,45 +2414,55 @@ self => * }}} */ def patDefOrDcl(pos : Int, mods: Modifiers): List[Tree] = { - var newmods = mods in.nextToken() - val lhs = commaSeparated(stripParens(noSeq.pattern2())) - val tp = typedOpt() - val rhs = - if (tp.isEmpty || in.token == EQUALS) { - accept(EQUALS) - if (!tp.isEmpty && newmods.isMutable && - (lhs.toList forall (_.isInstanceOf[Ident])) && in.token == USCORE) { - in.nextToken() - newmods = newmods | Flags.DEFAULTINIT - EmptyTree - } else { - expr() - } - } else { - newmods = newmods | Flags.DEFERRED - EmptyTree - } - def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = { - //Console.println("DEBUG: p = "+p.toString()); // DEBUG - val trees = - makePatDef(newmods, - if (tp.isEmpty) p - else Typed(p, tp) setPos (p.pos union tp.pos), - rhs) - if (newmods.isDeferred) { - trees match { - case List(ValDef(_, _, _, EmptyTree)) => - if (mods.isLazy) syntaxError(p.pos, "lazy values may not be abstract", skipIt = false) - case _ => syntaxError(p.pos, "pattern definition may not be abstract", skipIt = false) - } + + val lhses = commaSeparated(stripParens(noSeq.pattern2())) + val lhs = lhses.last + val tpt = typedOpt() + val ascriptedLhs = if (tpt.isEmpty) lhs else atPos(lhs.pos union tpt.pos)(Typed(lhs, tpt)) + val hasEq = acceptIfPresent(EQUALS) + // SI-7854 an underscore following the equals doesn't necessarily mean default initialization. + val isDefaultInit = hasEq && in.token == USCORE && { + peekahead() + isStatSep || isStatSeqEnd || { pushback() ; false } + } + val rhs = if (hasEq && !isDefaultInit) expr() else EmptyTree + def allIdents = lhses forall (_.isInstanceOf[Ident]) + + def defaultInitFlag(): Long = { + if (!allIdents) + syntaxError(lhs.pos, "pattern definition is ineligible for default initialization", skipIt = false) + else if (!mods.isMutable) + syntaxError(lhs.pos, "only vars are eligible for default initialization", skipIt = false) + else if (tpt.isEmpty) + syntaxError(lhs.pos, "an explicit type is required for default initialization", skipIt = false) + + Flags.DEFAULTINIT + } + def deferredFlag(): Long = { + if (mods.isLazy) // e.g. lazy val foo: Int + syntaxError(lhs.pos, "lazy values may not be abstract", skipIt = false) + else if (!allIdents) // e.g. val Some(x) + syntaxError(lhs.pos, "pattern definition may not be abstract", skipIt = false) + + Flags.DEFERRED + } + val newmods = mods | ( + if (isDefaultInit) defaultInitFlag() + else if (rhs.isEmpty) deferredFlag() + else 0L + ) + + def makeValDefs(decl: Tree): List[Tree] = { + val newTpt = if (tpt.isEmpty) decl else Typed(decl, tpt.duplicate setPos tpt.pos.focus) setPos decl.pos.focus + makePatDef(newmods, newTpt, rhs.duplicate setPos rhs.pos.focus) match { + case tree :: Nil => (tree setPos decl.pos) :: Nil + case trees => trees map (_ setPos decl.pos.focus) } - trees } - val trees = (lhs.toList.init flatMap (mkDefs(_, tp.duplicate, rhs.duplicate))) ::: mkDefs(lhs.last, tp, rhs) - val hd = trees.head - hd setPos hd.pos.withStart(pos) - ensureNonOverlapping(hd, trees.tail) + + val trees = (lhses.init flatMap makeValDefs) ::: makePatDef(newmods, ascriptedLhs, rhs) + ensureNonOverlapping(trees.last, trees.init) trees } @@ -2523,7 +2507,8 @@ self => in.nextToken() if (in.token == THIS) { atPos(start, in.skipToken()) { - val vparamss = paramClauses(nme.CONSTRUCTOR, classContextBounds map (_.duplicate), ofCaseClass = false) + val cbounds = classContextBounds map (_.duplicate) + val vparamss = paramClauses(nme.CONSTRUCTOR, cbounds, ofCaseClass = false) newLineOptWhenFollowedBy(LBRACE) val rhs = in.token match { case LBRACE => atPos(in.offset) { constrBlock(vparamss) } @@ -2547,7 +2532,8 @@ self => // i.e. (B[T] or T => B) val contextBoundBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, contextBoundBuf) - val vparamss = paramClauses(name, contextBoundBuf.toList, ofCaseClass = false) + val cbounds = contextBoundBuf.toList + val vparamss = paramClauses(name, cbounds, ofCaseClass = false) newLineOptWhenFollowedBy(LBRACE) var restype = fromWithinReturnType(typedOpt()) val rhs = @@ -2707,8 +2693,9 @@ self => val result = gen.mkClassDef(mods1, name, tparams, template) // Context bounds generate implicit parameters (part of the template) with types // from tparams: we need to ensure these don't overlap - if (!classContextBounds.isEmpty) + if (classContextBounds.nonEmpty) ensureNonOverlapping(template, tparams) + result } } @@ -2770,18 +2757,15 @@ self => * }}} */ def templateParents(): List[Tree] = { - val parents = new ListBuffer[Tree] - def readAppliedParent() = { + def readAppliedParent(): Tree = { val start = in.offset val parent = startAnnotType() - parents += (in.token match { + in.token match { case LPAREN => atPos(start)((parent /: multipleArgumentExprs())(Apply.apply)) case _ => parent - }) + } } - readAppliedParent() - while (in.token == WITH) { in.nextToken(); readAppliedParent() } - parents.toList + tokenSeparated(WITH, sepFirst = false, readAppliedParent()) } /** {{{ @@ -2815,9 +2799,9 @@ self => def ensureEarlyDef(tree: Tree): Tree = tree match { case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => copyValDef(vdef)(mods = mods | Flags.PRESUPER) - case tdef @ TypeDef(mods, name, tparams, rhs) => + case tdef @ TypeDef(mods, _, _, _) => deprecationWarning(tdef.pos.point, "early type members are deprecated. Move them to the regular body: the semantics are the same.") - treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs) + copyTypeDef(tdef)(mods = mods | Flags.PRESUPER) case docdef @ DocDef(comm, rhs) => treeCopy.DocDef(docdef, comm, rhs) case stat if !stat.isEmpty => @@ -2852,7 +2836,6 @@ self => ) val parentPos = o2p(in.offset) val tstart1 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart - atPos(tstart1) { // Exclude only the 9 primitives plus AnyVal. if (inScalaRootPackage && ScalaValueClassNames.contains(name)) @@ -3103,10 +3086,9 @@ self => def compilationUnit(): PackageDef = checkNoEscapingPlaceholders { def topstats(): List[Tree] = { val ts = new ListBuffer[Tree] - while (in.token == SEMI) in.nextToken() + while (acceptIfPresent(SEMI)) () val start = in.offset - if (in.token == PACKAGE) { - in.nextToken() + if (acceptIfPresent(PACKAGE)) { if (in.token == OBJECT) { // TODO - this next line is supposed to be // ts += packageObjectDef(start) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 6957f85689..5ef40923b4 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -52,6 +52,15 @@ trait Scanners extends ScannersCommon { type Offset = Int trait TokenData extends CommonTokenData { + override def toString = s""" + |TokenData( + | token $token ${token2string(token)} + | offset $offset + | last $lastOffset + | name $name + | strVal $strVal + | base $base + |)""".stripMargin.trim /** the next token */ var token: Int = EMPTY diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 91ff530e05..fba74330a6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -191,14 +191,6 @@ abstract class TreeBuilder { } } - /** Create a tree representing an assignment <lhs = rhs> */ - def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match { - case Apply(fn, args) => - Apply(atPos(fn.pos) { Select(fn, nme.update) }, args ::: List(rhs)) - case _ => - Assign(lhs, rhs) - } - /** Tree for `od op`, start is start0 if od.pos is borked. */ def makePostfixSelect(start0: Int, end: Int, od: Tree, op: Name): Tree = { val start = if (od.pos.isDefined) od.pos.startOrPoint else start0 @@ -206,22 +198,21 @@ abstract class TreeBuilder { } /** Create tree representing a while loop */ - def makeWhile(startPos: Int, cond: Tree, body: Tree): Tree = { - val lname = freshTermName(nme.WHILE_PREFIX) - def default = wrappingPos(List(cond, body)) match { - case p if p.isDefined => p.endOrPoint - case _ => startPos - } - val continu = atPos(o2p(body.pos pointOrElse default)) { Apply(Ident(lname), Nil) } - val rhs = If(cond, Block(List(body), continu), Literal(Constant(()))) - LabelDef(lname, Nil, rhs) + def makeWhile(cond: Tree, body: Tree): Tree = { + val lname = freshTermName(nme.WHILE_PREFIX) + val continu = atPos(cond.pos.focus)(Apply(Ident(lname), Nil)) + val rhs = atPos(cond.pos union body.pos)(If(cond, atPos(body.pos)(Block(body :: Nil, continu)), Literal(Constant(())))) + + atPos(rhs.pos)(LabelDef(lname, Nil, rhs)) } /** Create tree representing a do-while loop */ def makeDoWhile(lname: TermName, body: Tree, cond: Tree): Tree = { - val continu = Apply(Ident(lname), Nil) - val rhs = Block(List(body), If(cond, continu, Literal(Constant(())))) - LabelDef(lname, Nil, rhs) + val continu = atPos(cond.pos.focus)(Apply(Ident(lname), Nil)) + val condition = atPos(cond.pos)(If(cond, continu, Literal(Constant(())))) + val rhs = atPos(cond.pos union body.pos)(Block(body :: Nil, condition)) + + atPos(rhs.pos)(LabelDef(lname, Nil, rhs)) } /** Create block of statements `stats` */ @@ -313,19 +304,13 @@ abstract class TreeBuilder { * The closure is assigned a transparent position with the point at pos.point and * the limits given by pat and body. */ - def makeClosure(pos: Position, pat: Tree, body: Tree): Tree = { - def splitpos = wrappingPos(List(pat, body)).withPoint(pos.point).makeTransparent - matchVarPattern(pat) match { - case Some((name, tpt)) => - Function( - List(atPos(pat.pos) { ValDef(Modifiers(PARAM), name.toTermName, tpt, EmptyTree) }), - body) setPos splitpos - case None => - atPos(splitpos) { - makeVisitor(List(CaseDef(pat, EmptyTree, body)), checkExhaustive = false) - } + def makeClosure(pos: Position, pat: Tree, body: Tree): Tree = + atPos((pos union pat.pos union body.pos).makeTransparent) { + matchVarPattern(pat) match { + case Some((name, tpt)) => Function(atPos(pat.pos)(ValDef(Modifiers(PARAM), name.toTermName, tpt, EmptyTree)) :: Nil, body) + case None => makeVisitor(CaseDef(pat, body) :: Nil, checkExhaustive = false) + } } - } /* Make an application qual.meth(pat => body) positioned at `pos`. */ @@ -503,7 +488,7 @@ abstract class TreeBuilder { tmp, TypeTree(), matchExpr) } var cnt = 0 - val restDefs = for ((vname, tpt, pos) <- vars) yield atPos(pos) { + val restDefs = for ((vname, tpt, pos) <- vars) yield atPos(pos.focus) { cnt += 1 ValDef(mods, vname.toTermName, tpt, Select(Ident(tmp), newTermName("_" + cnt))) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala b/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala index 0856f2f09d..8bcdb6dbd2 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala @@ -3,10 +3,8 @@ * @author Martin Odersky */ - package scala.tools.nsc package backend package icode class CheckerException(s: String) extends Exception(s) - diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 843299398b..a80fee876e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1319,6 +1319,8 @@ abstract class GenICode extends SubComponent { /** Some useful equality helpers. */ def isNull(t: Tree) = cond(t) { case Literal(Constant(null)) => true } + def isLiteral(t: Tree) = cond(t) { case Literal(_) => true } + def isNonNullExpr(t: Tree) = isLiteral(t) || ((t.symbol ne null) && t.symbol.isModule) /* If l or r is constant null, returns the other ; otherwise null */ def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null @@ -1514,6 +1516,23 @@ abstract class GenICode extends SubComponent { val branchesReachable = !ctx1.bb.ignore ctx1.bb emitOnly CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ObjectReference) branchesReachable + } else if (isNonNullExpr(l)) { + // Avoid null check if L is statically non-null. + // + // "" == expr -> "".equals(expr) + // Nil == expr -> Nil.equals(expr) + // + // Common enough (through pattern matching) to treat this specially here rather than + // hoping that -Yconst-opt is enabled. The impossible branches for null checks lead + // to spurious "branch not covered" warnings in Jacoco code coverage. + var ctx1 = genLoad(l, ctx, ObjectReference) + val branchesReachable = !ctx1.bb.ignore + ctx1 = genLoad(r, ctx1, ObjectReference) + ctx1.bb emitOnly( + CALL_METHOD(Object_equals, Dynamic), + CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL) + ) + branchesReachable } else { val eqEqTempLocal = getTempLocal var ctx1 = genLoad(l, ctx, ObjectReference) diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 2c8fda85f4..633e71a756 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -93,7 +93,7 @@ trait TypeKinds { self: ICodes => /** * this is directly assignable to other if no coercion or * casting is needed to convert this to other. It's a distinct - * relationship from <:< because on the JVM, BOOL, BYTE, CHAR, + * relationship from <:< because on the JVM, BOOL, BYTE, CHAR, * SHORT need no coercion to INT even though JVM arrays * are covariant, ARRAY[SHORT] is not a subtype of ARRAY[INT] */ @@ -101,7 +101,7 @@ trait TypeKinds { self: ICodes => case INT => this.isIntSizedType case _ => this <:< other } - + /** Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?) */ def isWideType: Boolean = false diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 182209dfe6..eff7d3211e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -866,11 +866,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { // a plain class lacking companion module, for details see `isCandidateForForwarders`). // ----------------------------------------------------------------------------------------- - val ExcludedForwarderFlags = { - import symtab.Flags._ - // Should include DEFERRED but this breaks findMember. - ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO ) - } + val ExcludedForwarderFlags = genASM.ExcludedForwarderFlags /* Adds a @remote annotation, actual use unknown. * diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala index 2c3bf26958..01c4ff5a52 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala @@ -18,10 +18,10 @@ trait GenJVMASM { import icodes._ import definitions._ - protected val ExcludedForwarderFlags = { + val ExcludedForwarderFlags = { import Flags._ // Should include DEFERRED but this breaks findMember. - ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO ) + ( SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO ) } protected def isJavaEntryPoint(icls: IClass) = { diff --git a/src/compiler/scala/tools/nsc/package.scala b/src/compiler/scala/tools/nsc/package.scala index 761fd79358..817a4a5c88 100644 --- a/src/compiler/scala/tools/nsc/package.scala +++ b/src/compiler/scala/tools/nsc/package.scala @@ -23,5 +23,6 @@ package object nsc { type MissingRequirementError = scala.reflect.internal.MissingRequirementError val MissingRequirementError = scala.reflect.internal.MissingRequirementError - val ListOfNil = List(Nil) + @deprecated("Use scala.reflect.internal.util.ListOfNil", "2.11.0") + lazy val ListOfNil = scala.reflect.internal.util.ListOfNil } diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index fdb5c72c3d..52c6ddc6ee 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -9,6 +9,7 @@ package reporters import java.io.{ BufferedReader, IOException, PrintWriter } import scala.reflect.internal.util._ +import StringOps._ /** * This class implements a Reporter that displays messages on a text @@ -40,7 +41,10 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr StringOps.countElementsAsString((severity).count, label(severity)) /** Prints the message. */ - def printMessage(msg: String) { writer.print(msg + "\n"); writer.flush() } + def printMessage(msg: String) { + writer print trimAllTrailingSpace(msg) + "\n" + writer.flush() + } /** Prints the message with the given position indication. */ def printMessage(posIn: Position, msg: String) { diff --git a/src/compiler/scala/tools/nsc/settings/FscSettings.scala b/src/compiler/scala/tools/nsc/settings/FscSettings.scala index 34c8e8df9a..8c2b510bfd 100644 --- a/src/compiler/scala/tools/nsc/settings/FscSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/FscSettings.scala @@ -44,7 +44,7 @@ class FscSettings(error: String => Unit) extends Settings(error) { // we need to ensure the files specified with relative locations are absolutized based on the currentDir (r, args map {a => absolutizePath(a)}) } - + /** * Take an individual path and if it's not absolute turns it into an absolute path based on currentDir. * If it's already absolute then it's left alone. diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index a2bf5bf9e5..b2e071579e 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -90,7 +90,7 @@ abstract class ExplicitOuter extends InfoTransform sym expandName clazz sym.referenced = clazz - sym setInfo MethodType(Nil, restpe.widen) + sym setInfo MethodType(Nil, restpe) } def newOuterField(clazz: Symbol) = { val accFlags = SYNTHETIC | ARTIFACT | PARAMACCESSOR | ( if (clazz.isEffectivelyFinal) PrivateLocal else PROTECTED ) @@ -276,18 +276,16 @@ abstract class ExplicitOuter extends InfoTransform else outerPath(outerSelect(base), from.outerClass, to) } - override def transform(tree: Tree): Tree = { + def sym = tree.symbol val savedOuterParam = outerParam try { tree match { case Template(_, _, _) => outerParam = NoSymbol - case DefDef(_, _, _, vparamss, _, _) => - if (tree.symbol.isClassConstructor && isInner(tree.symbol.owner)) { - outerParam = vparamss.head.head.symbol - assert(outerParam.name startsWith nme.OUTER, outerParam.name) - } + case DefDef(_, _, _, (param :: _) :: _, _, _) if sym.isClassConstructor && isInner(sym.owner) => + outerParam = param.symbol + assert(outerParam.name startsWith nme.OUTER, outerParam.name) case _ => } super.transform(tree) @@ -361,10 +359,9 @@ abstract class ExplicitOuter extends InfoTransform /** The definition tree of the outer accessor of current class */ def outerAccessorDef: Tree = localTyper typed { - outerAccessor(currentClass) match { - case acc if acc.isDeferred => DefDef(acc, EmptyTree) - case acc => DefDef(acc, Select(This(currentClass), outerField(currentClass))) - } + val acc = outerAccessor(currentClass) + val rhs = if (acc.isDeferred) EmptyTree else Select(This(currentClass), outerField(currentClass)) + DefDef(acc, rhs) } /** The definition tree of the outer accessor for class mixinClass. diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index 45aa1106f0..f7b194a6ca 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -292,6 +292,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { trait TreesAndTypesDomain extends PropositionalLogic with CheckableTreeAndTypeAnalysis { type Type = global.Type type Tree = global.Tree + import global.definitions.ConstantNull // resets hash consing -- only supposed to be called by TreeMakersToProps def prepareNewAnalysis(): Unit = { Var.resetUniques(); Const.resetUniques() } @@ -320,7 +321,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { val staticTpCheckable: Type = checkableType(staticTp) private[this] var _mayBeNull = false - def registerNull(): Unit = { ensureCanModify(); if (NullTp <:< staticTpCheckable) _mayBeNull = true } + def registerNull(): Unit = { ensureCanModify(); if (ConstantNull <:< staticTpCheckable) _mayBeNull = true } def mayBeNull: Boolean = _mayBeNull // case None => domain is unknown, @@ -568,7 +569,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { object TypeConst extends TypeConstExtractor { def apply(tp: Type) = { - if (tp =:= NullTp) NullConst + if (tp =:= ConstantNull) NullConst else if (tp.isInstanceOf[SingletonType]) ValueConst.fromType(tp) else Const.unique(tp, new TypeConst(tp)) } @@ -577,7 +578,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { // corresponds to a type test that does not imply any value-equality (well, except for outer checks, which we don't model yet) sealed class TypeConst(val tp: Type) extends Const { - assert(!(tp =:= NullTp)) + assert(!(tp =:= ConstantNull)) /*private[this] val id: Int = */ Const.nextTypeId val wideTp = widenToClass(tp) @@ -598,7 +599,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { } def apply(p: Tree) = { val tp = p.tpe.normalize - if (tp =:= NullTp) NullConst + if (tp =:= ConstantNull) NullConst else { val wideTp = widenToClass(tp) @@ -626,16 +627,14 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { } sealed class ValueConst(val tp: Type, val wideTp: Type, override val toString: String) extends Const { // debug.patmat("VC"+(tp, wideTp, toString)) - assert(!(tp =:= NullTp)) // TODO: assert(!tp.isStable) + assert(!(tp =:= ConstantNull)) // TODO: assert(!tp.isStable) /*private[this] val id: Int = */Const.nextValueId def isValue = true } - - lazy val NullTp = ConstantType(Constant(null)) case object NullConst extends Const { - def tp = NullTp - def wideTp = NullTp + def tp = ConstantNull + def wideTp = ConstantNull def isValue = true override def toString = "null" diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 8feb87210e..7eb899d9d7 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -50,7 +50,7 @@ trait TreeAndTypeAnalysis extends Debugging { case UnitClass => Some(List(UnitTpe)) case BooleanClass => - Some((List(ConstantType(Constant(true)), ConstantType(Constant(false))))) + Some(ConstantTrue :: ConstantFalse :: Nil) // TODO case _ if tp.isTupleType => // recurse into component types case modSym: ModuleClassSymbol => Some(List(tp)) @@ -271,9 +271,9 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT case SubstOnlyTreeMaker(_, _) => True case GuardTreeMaker(guard) => guard.tpe match { - case ConstantType(Constant(true)) => True - case ConstantType(Constant(false)) => False - case _ => handleUnknown(tm) + case ConstantTrue => True + case ConstantFalse => False + case _ => handleUnknown(tm) } case ExtractorTreeMaker(_, _, _) | ProductExtractorTreeMaker(_, _) | diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala index ba78438b66..8a04c67582 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala @@ -402,23 +402,15 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { private def noGuards(cs: List[CaseDef]): Boolean = !cs.exists(isGuardedCase) // must do this before removing guards from cases and collapsing (SI-6011, SI-6048) - private def unreachableCase(cs: List[CaseDef]): Option[CaseDef] = { - var cases = cs - var unreachable: Option[CaseDef] = None - - while (cases.nonEmpty && unreachable.isEmpty) { - val currCase = cases.head - if (isDefault(currCase) && cases.tail.nonEmpty) // subsumed by the `else if` that follows, but faster - unreachable = Some(cases.tail.head) - else if (!isGuardedCase(currCase) || currCase.guard.tpe =:= ConstantType(Constant(true))) - unreachable = cases.tail.find(caseImplies(currCase)) - else if (currCase.guard.tpe =:= ConstantType(Constant(false))) - unreachable = Some(currCase) - - cases = cases.tail + private def unreachableCase(cases: List[CaseDef]): Option[CaseDef] = { + def loop(cases: List[CaseDef]): Option[CaseDef] = cases match { + case head :: next :: _ if isDefault(head) => Some(next) // subsumed by the next case, but faster + case head :: rest if !isGuardedCase(head) || head.guard.tpe =:= ConstantTrue => rest find caseImplies(head) orElse loop(rest) + case head :: _ if head.guard.tpe =:= ConstantFalse => Some(head) + case _ :: rest => loop(rest) + case _ => None } - - unreachable + loop(cases) } // empty list ==> failure diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index cf26ec3398..317685682d 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -288,8 +288,8 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { def irrefutableExtractorType(tp: Type): Boolean = tp.resultType.dealias match { case TypeRef(_, SomeClass, _) => true // probably not useful since this type won't be inferred nor can it be written down (yet) - case ConstantType(Constant(true)) => true - case _ => false + case ConstantTrue => true + case _ => false } def unapply(xtm: ExtractorTreeMaker): Option[(Tree, Symbol)] = xtm match { diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala index 114bcba5df..6267585ea8 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala @@ -9,6 +9,7 @@ package scala.tools.nsc.transform.patmat import scala.collection.mutable import scala.reflect.internal.util.Statistics import scala.language.postfixOps +import scala.reflect.internal.util.Collections._ // naive CNF translation and simple DPLL solver trait Solving extends Logic { @@ -205,9 +206,8 @@ trait Solving extends Logic { // SI-7020 Linked- for deterministic counter examples. val pos = new mutable.LinkedHashSet[Sym]() val neg = new mutable.LinkedHashSet[Sym]() - f.foreach{_.foreach{ lit => - if (lit.pos) pos += lit.sym else neg += lit.sym - }} + mforeach(f)(lit => if (lit.pos) pos += lit.sym else neg += lit.sym) + // appearing in both positive and negative val impures: mutable.LinkedHashSet[Sym] = pos intersect neg // appearing only in either positive/negative positions diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 9ac0b0835a..347426d42a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1183,8 +1183,8 @@ trait Namers extends MethodSynthesis { // value parameters of the base class (whose defaults might be overridden) var baseParamss = (vparamss, overridden.tpe.paramss) match { // match empty and missing parameter list - case (Nil, List(Nil)) => Nil - case (List(Nil), Nil) => ListOfNil + case (Nil, ListOfNil) => Nil + case (ListOfNil, Nil) => ListOfNil case (_, paramss) => paramss } assert( diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 3a188c0044..e44c83aa56 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -171,8 +171,8 @@ abstract class TreeCheckers extends Analyzer { ) - def errorFn(msg: Any): Unit = Console.err println "[check: %s] %s".format(phase.prev, msg) - def errorFn(pos: Position, msg: Any): Unit = errorFn(posstr(pos) + ": " + msg) + def errorFn(pos: Position, msg: Any): Unit = currentUnit.warning(pos, "[check: %s] %s".format(phase.prev, msg)) + def errorFn(msg: Any): Unit = errorFn(NoPosition, msg) def informFn(msg: Any) { if (settings.verbose || settings.debug) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 3ac0b398ee..e07c68de8a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -43,12 +43,17 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper final val shortenImports = false + // allows override of the behavior of the resetTyper method w.r.t comments + def resetDocComments() = { + clearDocComments() + } + def resetTyper() { //println("resetTyper called") resetContexts() resetImplicits() transformed.clear() - clearDocComments() + resetDocComments() } object UnTyper extends Traverser { @@ -2606,7 +2611,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } val rhs = methodBodyTyper.virtualizedMatch(match_, mode, B1.tpe) - val defdef = newDefDef(methodSym, rhs)(vparamss = mapParamss(methodSym)(newParam)) + val defdef = newDefDef(methodSym, rhs)(vparamss = mapParamss(methodSym)(newParam), tpt = TypeTree(B1.tpe)) (defdef, matchResTp) } @@ -4873,7 +4878,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // Unfortunately implicit not found strings looks for all the world like // missing interpolators. def isArgToImplicitNotFound = context.enclosingApply.tree match { - case Apply(fn, _) => fn.symbol.enclClass == ImplicitNotFoundClass + case Apply(fn, _) => fn.symbol != null && fn.symbol.enclClass == ImplicitNotFoundClass case _ => false } tree.value match { diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index b77a536caf..2d905d5436 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -297,7 +297,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => // reporter doesn't accumulate errors, but the front-end does def throwIfErrors() = { if (frontEnd.hasErrors) throw ToolBoxError( - "reflective compilation has failed: " + EOL + EOL + (frontEnd.infos map (_.msg) mkString EOL) + "reflective compilation has failed:" + EOL + EOL + (frontEnd.infos map (_.msg) mkString EOL) ) } } @@ -319,7 +319,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val instance = new ToolBoxGlobal(command.settings, frontEndToReporter(frontEnd, command.settings)) if (frontEnd.hasErrors) { throw ToolBoxError( - "reflective compilation has failed: cannot initialize the compiler: " + EOL + EOL + + "reflective compilation has failed: cannot initialize the compiler:" + EOL + EOL + (frontEnd.infos map (_.msg) mkString EOL) ) } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index c2d8bcdcd6..0d1fb6be07 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -10,7 +10,7 @@ trait Reifiers { self: Quasiquotes => import global.build.{SyntacticClassDef, SyntacticTraitDef, SyntacticModuleDef, SyntacticDefDef, SyntacticValDef, SyntacticVarDef, SyntacticBlock, SyntacticApplied, SyntacticTypeApplied, - SyntacticFunction, SyntacticNew} + SyntacticFunction, SyntacticNew, SyntacticAssign} import global.treeInfo._ import global.definitions._ import Cardinality._ @@ -71,9 +71,9 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) case SyntacticVarDef(mods, name, tpt, rhs) => reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs) - case SyntacticApplied(fun, argss) if argss.length > 1 => - reifyBuildCall(nme.SyntacticApplied, fun, argss) - case SyntacticApplied(fun, argss @ (_ :+ (_ :+ Placeholder(_, _, DotDotDot)))) => + case SyntacticAssign(lhs, rhs) => + reifyBuildCall(nme.SyntacticAssign, lhs, rhs) + case SyntacticApplied(fun, argss) if argss.nonEmpty => reifyBuildCall(nme.SyntacticApplied, fun, argss) case SyntacticTypeApplied(fun, targs) if targs.nonEmpty => reifyBuildCall(nme.SyntacticTypeApplied, fun, targs) |