diff options
Diffstat (limited to 'src/compiler')
19 files changed, 115 insertions, 69 deletions
diff --git a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala index 1413065a27..a13a778b2f 100644 --- a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala +++ b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala @@ -53,7 +53,7 @@ abstract class DefaultMacroCompiler extends Resolvers (EmptyTree, TermName(""), Nil) } val bundleImplRef = MacroImplRefCompiler( - atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Ident(Predef_???)))), methName), targs)), + atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Literal(Constant(null))))), methName), targs)), isImplBundle = true ) val vanillaResult = tryCompile(vanillaImplRef) diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 0731d78a9b..689e6405d0 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -74,6 +74,11 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo { } } + // TODO these overrides, and the slow trickle of bugs that they solve (e.g. SI-8479), + // suggest that we should pursue an alternative design in which the DocDef nodes + // are eliminated from the tree before typer, and instead are modelled as tree + // attachments. + /** Is tree legal as a member definition of an interface? */ override def isInterfaceMember(tree: Tree): Boolean = tree match { @@ -81,6 +86,11 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo { case _ => super.isInterfaceMember(tree) } + override def isConstructorWithDefault(t: Tree) = t match { + case DocDef(_, definition) => isConstructorWithDefault(definition) + case _ => super.isConstructorWithDefault(t) + } + /** Is tree a pure (i.e. non-side-effecting) definition? */ override def isPureDef(tree: Tree): Boolean = tree match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 9e631febee..ffc45b21ea 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -654,9 +654,10 @@ self => def isIdentExcept(except: Name) = isIdent && in.name != except def isIdentOf(name: Name) = isIdent && in.name == name - def isUnaryOp = isIdent && raw.isUnary(in.name) - def isRawStar = isIdent && in.name == raw.STAR - def isRawBar = isIdent && in.name == raw.BAR + def isUnaryOp = isIdent && raw.isUnary(in.name) + def isRawStar = isRawIdent && in.name == raw.STAR + def isRawBar = isRawIdent && in.name == raw.BAR + def isRawIdent = in.token == IDENTIFIER def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw @@ -1001,19 +1002,30 @@ self => } def infixTypeRest(t: Tree, mode: InfixMode.Value): Tree = { - if (isIdent && in.name != nme.STAR) { - val opOffset = in.offset + // Detect postfix star for repeated args. + // Only RPAREN can follow, but accept COMMA and EQUALS for error's sake. + // Take RBRACE as a paren typo. + def checkRepeatedParam = if (isRawStar) { + lookingAhead (in.token match { + case RPAREN | COMMA | EQUALS | RBRACE => t + case _ => EmptyTree + }) + } else EmptyTree + def asInfix = { + val opOffset = in.offset val leftAssoc = treeInfo.isLeftAssoc(in.name) - if (mode != InfixMode.FirstOp) checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp) - val op = identForType() - val tycon = atPos(opOffset) { Ident(op) } + if (mode != InfixMode.FirstOp) + checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp) + val tycon = atPos(opOffset) { Ident(identForType()) } newLineOptWhenFollowing(isTypeIntroToken) def mkOp(t1: Tree) = atPos(t.pos.start, opOffset) { AppliedTypeTree(tycon, List(t, t1)) } if (leftAssoc) infixTypeRest(mkOp(compoundType()), InfixMode.LeftOp) else mkOp(infixType(InfixMode.RightOp)) - } else t + } + if (isIdent) checkRepeatedParam orElse asInfix + else t } /** {{{ diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index 32b5a98b98..7236bf70d5 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -55,8 +55,6 @@ trait JavaPlatform extends Platform { (sym isNonBottomSubClass BoxedBooleanClass) } - def doLoad(cls: ClassPath[AbstractFile]#ClassRep): Boolean = true - def needCompile(bin: AbstractFile, src: AbstractFile) = src.lastModified >= bin.lastModified } diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala index 499f8a9290..439cc1efb8 100644 --- a/src/compiler/scala/tools/nsc/backend/Platform.scala +++ b/src/compiler/scala/tools/nsc/backend/Platform.scala @@ -31,14 +31,6 @@ trait Platform { def isMaybeBoxed(sym: Symbol): Boolean /** - * Tells whether a class should be loaded and entered into the package - * scope. On .NET, this method returns `false` for all synthetic classes - * (anonymous classes, implementation classes, module classes), their - * symtab is encoded in the pickle of another class. - */ - def doLoad(cls: ClassPath[AbstractFile]#ClassRep): Boolean - - /** * Tells whether a class with both a binary and a source representation * (found in classpath and in sourcepath) should be re-compiled. Behaves * on the JVM similar to javac, i.e. if the source file is newer than the classfile, diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 1cea4bedda..0da66d43f7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -13,13 +13,12 @@ import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, Buffer } import scala.tools.nsc.symtab._ import scala.annotation.switch -import PartialFunction._ /** * @author Iulian Dragos * @version 1.0 */ -abstract class GenICode extends SubComponent { +abstract class GenICode extends SubComponent { import global._ import icodes._ import icodes.opcodes._ @@ -30,6 +29,9 @@ abstract class GenICode extends SubComponent { } import platform.isMaybeBoxed + private val bCodeICodeCommon: jvm.BCodeICodeCommon[global.type] = new jvm.BCodeICodeCommon(global) + import bCodeICodeCommon._ + val phaseName = "icode" override def newPhase(prev: Phase) = new ICodePhase(prev) @@ -1326,15 +1328,6 @@ abstract class GenICode extends SubComponent { List(tree) } - /** 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 - /** * Find the label denoted by `lsym` and enter it in context `ctx`. * diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 53142fbd87..92ebe5027a 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -23,6 +23,7 @@ import scala.tools.asm abstract class BCodeBodyBuilder extends BCodeSkelBuilder { import global._ import definitions._ + import bCodeICodeCommon._ /* * Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions. @@ -1020,17 +1021,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { tree :: Nil } - /* Some useful equality helpers. */ - def isNull(t: Tree) = { - t match { - case Literal(Constant(null)) => true - case _ => false - } - } - - /* 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 - /* Emit code to compare the two top-most stack values using the 'op' operator. */ private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType) { if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT @@ -1200,6 +1190,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { // expr == null -> expr eq null genLoad(l, ObjectReference) genCZJUMP(success, failure, icodes.EQ, ObjectReference) + } else if (isNonNullExpr(l)) { + // SI-7852 Avoid null check if L is statically non-null. + genLoad(l, ObjectReference) + genLoad(r, ObjectReference) + genCallMethod(Object_equals, icodes.opcodes.Dynamic) + genCZJUMP(success, failure, icodes.NE, BOOL) } else { // l == r -> if (l eq null) r eq null else l.equals(r) val eqEqTempLocal = locals.makeLocal(AnyRefReference, nme.EQEQ_LOCAL_VAR.toString) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala index cc3265c5f9..aa7e73a36b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala @@ -22,6 +22,8 @@ abstract class BCodeGlue extends SubComponent { import global._ + protected val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global) + object BType { import global.chrs diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 359e5d6c29..f800dbf9cd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -239,6 +239,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { } /* + * must-single-thread + */ + def serialVUID(csym: Symbol): Option[Long] = csym getAnnotation definitions.SerialVersionUIDAttr collect { + case AnnotationInfo(_, _, (_, LiteralAnnotArg(const)) :: Nil) => const.longValue + } + + /* * Populates the InnerClasses JVM attribute with `refedInnerClasses`. * In addition to inner classes mentioned somewhere in `jclass` (where `jclass` is a class file being emitted) * `refedInnerClasses` should contain those inner classes defined as direct member classes of `jclass` @@ -881,13 +888,6 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { val MIN_SWITCH_DENSITY = 0.7 /* - * must-single-thread - */ - def serialVUID(csym: Symbol): Option[Long] = csym getAnnotation definitions.SerialVersionUIDAttr collect { - case AnnotationInfo(_, Literal(const) :: _, _) => const.longValue - } - - /* * Add public static final field serialVersionUID with value `id` * * can-multi-thread diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala new file mode 100644 index 0000000000..50d20921d5 --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala @@ -0,0 +1,25 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.tools.nsc.backend.jvm + +import scala.tools.nsc.Global +import PartialFunction._ + +/** + * This trait contains code shared between GenBCode and GenICode that depends on types defined in + * the compiler cake (Global). + */ +final class BCodeICodeCommon[G <: Global](val global: G) { + import global._ + + /** 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 +} diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index a389816caf..b7f9b30e19 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -1142,9 +1142,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { def isParcelableClass = isAndroidParcelableClass(clasz.symbol) - def serialVUID: Option[Long] = clasz.symbol getAnnotation SerialVersionUIDAttr collect { - case AnnotationInfo(_, Literal(const) :: _, _) => const.longValue - } + def serialVUID: Option[Long] = genBCode.serialVUID(clasz.symbol) private def getSuperInterfaces(c: IClass): Array[String] = { diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 8b739958ff..447fa66ae4 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -251,7 +251,7 @@ abstract class SymbolLoaders { root.setInfo(new PackageClassInfoType(newScope, root)) if (!root.isRoot) { - for (classRep <- classpath.classes if platform.doLoad(classRep)) { + for (classRep <- classpath.classes) { initializeFromClassPath(root, classRep) } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index ea600bc586..d7cd92adf2 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -356,9 +356,13 @@ abstract class ClassfileParser { // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects // that are not in their correct place (see bug for details) - if (!settings.isScaladoc) - warning(s"Class $name not found - continuing with a stub.") - return NoSymbol.newClass(name.toTypeName) + + // TODO More consistency with use of stub symbols in `Unpickler` + // - better owner than `NoSymbol` + // - remove eager warning + val msg = s"Class $name not found - continuing with a stub." + if (!settings.isScaladoc) warning(msg) + return NoSymbol.newStubSymbol(name.toTypeName, msg) } val completer = new loaders.ClassfileLoader(file) var owner: Symbol = rootMirror.RootClass diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 2893cbdf45..894f959319 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -149,14 +149,15 @@ trait TreeAndTypeAnalysis extends Debugging { object typeArgsToWildcardsExceptArray extends TypeMap { // SI-6771 dealias would be enough today, but future proofing with the dealiasWiden. // See neg/t6771b.scala for elaboration - def apply(tp: Type): Type = tp.dealiasWiden match { + def apply(tp: Type): Type = tp.dealias match { case TypeRef(pre, sym, args) if args.nonEmpty && (sym ne ArrayClass) => TypeRef(pre, sym, args map (_ => WildcardType)) case _ => mapOver(tp) } } - debug.patmatResult(s"checkableType($tp)")(typeArgsToWildcardsExceptArray(tp)) + val result = typeArgsToWildcardsExceptArray(tp) + debug.patmatResult(s"checkableType($tp)")(result) } // a type is "uncheckable" (for exhaustivity) if we don't statically know its subtypes (i.e., it's unsealed) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala index 1902606d86..31b1ffa912 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala @@ -29,8 +29,12 @@ trait Solving extends Logic { type Clause = collection.Set[Lit] // a clause is a disjunction of distinct literals def clause(l: Lit*): Clause = ( - // neg/t7020.scala changes output 1% of the time, the non-determinism is quelled with this linked set - mutable.LinkedHashSet(l: _*) + if (l.lengthCompare(1) <= 0) { + l.toSet // SI-8531 Avoid LinkedHashSet's bulk for 0 and 1 element clauses + } else { + // neg/t7020.scala changes output 1% of the time, the non-determinism is quelled with this linked set + mutable.LinkedHashSet(l: _*) + } ) type Lit diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 9cf92ca5b9..f4456998c0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -42,7 +42,7 @@ import Fingerprint._ * (Expr(elems)) * (TypeTag(Int)) */ -trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { +trait Macros extends MacroRuntimes with Traces with Helpers { self: Analyzer => import global._ @@ -50,6 +50,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { import treeInfo.{isRepeatedParamType => _, _} import MacrosStats._ + lazy val fastTrack = new FastTrack[self.type](self) + def globalSettings = global.settings protected def findMacroClassLoader(): ClassLoader = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 23dc57d5b9..4382a2c6f7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -711,10 +711,7 @@ trait Namers extends MethodSynthesis { val m = ensureCompanionObject(tree, caseModuleDef) m.moduleClass.updateAttachment(new ClassForCaseCompanionAttachment(tree)) } - val hasDefault = impl.body exists { - case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault) - case _ => false - } + val hasDefault = impl.body exists treeInfo.isConstructorWithDefault if (hasDefault) { val m = ensureCompanionObject(tree) m.updateAttachment(new ConstructorDefaultsAttachment(tree, null)) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index b166bf988d..4540017b62 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -132,7 +132,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans defaultMethodNames.toList.distinct foreach { name => val methods = clazz.info.findMember(name, 0L, requiredFlags = METHOD, stableOnly = false).alternatives - val haveDefaults = methods filter (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name)) + def hasDefaultParam(tpe: Type): Boolean = tpe match { + case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe) + case _ => false + } + val haveDefaults = methods filter ( + if (settings.isScala211) + (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name)) + else + (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name)) + ) if (haveDefaults.lengthCompare(1) > 0) { val owners = haveDefaults map (_.owner) diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala index 8630ecf69e..64cf3d0847 100644 --- a/src/compiler/scala/tools/reflect/FastTrack.scala +++ b/src/compiler/scala/tools/reflect/FastTrack.scala @@ -10,14 +10,18 @@ import scala.tools.reflect.quasiquotes.{ Quasiquotes => QuasiquoteImpls } /** Optimizes system macro expansions by hardwiring them directly to their implementations * bypassing standard reflective load and invoke to avoid the overhead of Java/Scala reflection. */ -trait FastTrack { - self: Macros with Analyzer => +class FastTrack[MacrosAndAnalyzer <: Macros with Analyzer](val macros: MacrosAndAnalyzer) { + import macros._ import global._ import definitions._ import scala.language.implicitConversions import treeInfo.Applied + def contains(symbol: Symbol): Boolean = fastTrackCache().contains(symbol) + def apply(symbol: Symbol): FastTrackEntry = fastTrackCache().apply(symbol) + def get(symbol: Symbol): Option[FastTrackEntry] = fastTrackCache().get(symbol) + private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers private implicit def context2macroimplementations(c0: MacroContext): FormatInterpolator { val c: c0.type } = @@ -39,7 +43,6 @@ trait FastTrack { } /** A map from a set of pre-established macro symbols to their implementations. */ - def fastTrack: Map[Symbol, FastTrackEntry] = fastTrackCache() private val fastTrackCache = perRunCaches.newGeneric[Map[Symbol, FastTrackEntry]] { val runDefinitions = currentRun.runDefinitions import runDefinitions._ |