diff options
Diffstat (limited to 'src/compiler')
11 files changed, 126 insertions, 84 deletions
diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala index 2cb9f22c72..a72233274e 100644 --- a/src/compiler/scala/reflect/reify/Errors.scala +++ b/src/compiler/scala/reflect/reify/Errors.scala @@ -27,7 +27,7 @@ trait Errors { } def CannotReifyWeakType(details: Any) = { - val msg = "cannot create a TypeTag" + details + val msg = "cannot create a TypeTag" + details + ": use WeakTypeTag instead" throw new ReificationException(defaultErrorPosition, msg) } diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 275cfcd123..deea4de707 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -102,7 +102,7 @@ abstract class NodePrinters { buf.clear() if (settings.XshowtreesStringified.value) buf.append(tree.toString + EOL) if (settings.XshowtreesCompact.value) { - buf.append(showRaw(tree)) + buf.append(showRaw(tree, printIds = settings.uniqid.value, printTypes = settings.printtypes.value)) } else { level = 0 traverse(tree) diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index f143e4da3c..49b772ed2c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -285,7 +285,7 @@ abstract class TreeBuilder { def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = { val pat1 = patvarTransformer.transform(pat) val rhs1 = - if (valeq || treeInfo.isVariablePattern(pat)) rhs + if (valeq || treeInfo.isVarPatternDeep(pat)) rhs else makeFilter(rhs, pat1.duplicate, nme.CHECK_IF_REFUTABLE_STRING) if (valeq) ValEq(pos, pat1, rhs1) diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 92673157e4..4dedbcfd3d 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -16,18 +16,23 @@ import scala.tools.nsc.reporters._ import scala.tools.nsc.symtab._ import scala.tools.nsc.typechecker.DivergentImplicit import symtab.Flags.{ACCESSOR, PARAMACCESSOR} +import scala.annotation.elidable import scala.language.implicitConversions /** The main class of the presentation compiler in an interactive environment such as an IDE */ -class Global(settings: Settings, _reporter: Reporter, projectName: String = "") - extends scala.tools.nsc.Global(settings, _reporter) - with CompilerControl - with RangePositions - with ContextTrees - with RichCompilationUnits - with ScratchPadMaker - with Picklers { +class Global(settings: Settings, _reporter: Reporter, projectName: String = "") extends { + /* Is the compiler initializing? Early def, so that the field is true during the + * execution of the super constructor. + */ + private var initializing = true +} with scala.tools.nsc.Global(settings, _reporter) + with CompilerControl + with RangePositions + with ContextTrees + with RichCompilationUnits + with ScratchPadMaker + with Picklers { import definitions._ @@ -47,6 +52,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") import log.logreplay debugLog("logger: " + log.getClass + " writing to " + (new java.io.File(logName)).getAbsolutePath) debugLog("classpath: "+classPath) + Console.err.println("\n ======= CHECK THREAD ACCESS compiler build ========\n") private var curTime = System.nanoTime private def timeStep = { @@ -429,7 +435,18 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") private var threadId = 0 /** The current presentation compiler runner */ - @volatile private[interactive] var compileRunner = newRunnerThread() + @volatile private[interactive] var compileRunner: Thread = newRunnerThread() + + /** Check that the currenyly executing thread is the presentation compiler thread. + * + * Compiler initialization may happen on a different thread (signalled by globalPhase being NoPhase) + */ + @elidable(elidable.WARNING) + override def assertCorrectThread() { + assert(initializing || (Thread.currentThread() eq compileRunner), + "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") + } /** Create a new presentation compiler runner. */ @@ -1107,6 +1124,12 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") alt } } + + /** The compiler has been initialized. Constructors are evaluated in textual order, + * so this is set to true only after all super constructors and the primary constructor + * have been executed. + */ + initializing = false } object CancelException extends Exception diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 16f6c80101..847ca574a9 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -624,11 +624,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL { // // See SI-6611; we must *only* do this for literal vararg arrays. case Apply(appMeth, List(Apply(wrapRefArrayMeth, List(arg @ StripCast(ArrayValue(_, _)))), _)) - if (wrapRefArrayMeth.symbol == Predef_wrapRefArray && - appMeth.symbol == ArrayModule_overloadedApply.suchThat { - _.tpe.resultType.dealias.typeSymbol == ObjectClass // [T: ClassTag](xs: T*): Array[T] post erasure - }) => + if wrapRefArrayMeth.symbol == Predef_wrapRefArray && appMeth.symbol == ArrayModule_genericApply => super.transform(arg) + case Apply(appMeth, List(elem0, Apply(wrapArrayMeth, List(rest @ ArrayValue(elemtpt, _))))) + if wrapArrayMeth.symbol == Predef_wrapArray(elemtpt.tpe) && appMeth.symbol == ArrayModule_apply(elemtpt.tpe) => + super.transform(treeCopy.ArrayValue(rest, rest.elemtpt, elem0 :: rest.elems)) case _ => super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index b70d94a081..521d732664 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -221,9 +221,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { deriveDefDef(tree)(_ => atOwner(origMeth)( localTyper.typedPos(rhs.pos)( - (callPrefix /: vparamss) { - case (fn, params) => Apply(fn, params map (param => Ident(param.symbol))) - } + gen.mkForwarder(callPrefix, mmap(vparamss)(_.symbol)) ) ) ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 78380ad054..a8d7de6362 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -761,25 +761,44 @@ trait Contexts { self: Analyzer => * info of the package object. However to avoid cycles we'll check * what other ways we can before pushing that way. */ - def isInPackageObject(sym: Symbol, pkg: Symbol) = { - val pkgClass = if (pkg.isTerm) pkg.moduleClass else pkg + def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = { + def uninitialized(what: String) = { + log(s"Cannot look for $sym in package object of $pkg; $what is not initialized.") + false + } + def pkgClass = if (pkg.isTerm) pkg.moduleClass else pkg def matchesInfo = ( - pkg.isInitialized && { - // need to be careful here to not get a cyclic reference during bootstrap + // need to be careful here to not get a cyclic reference during bootstrap + if (pkg.isInitialized) { val module = pkg.info member nme.PACKAGEkw - module.isInitialized && (module.info.member(sym.name).alternatives contains sym) + if (module.isInitialized) + module.info.member(sym.name).alternatives contains sym + else + uninitialized("" + module) } + else uninitialized("" + pkg) ) def inPackageObject(sym: Symbol) = ( - !sym.isPackage - && !sym.owner.isPackageClass - && (sym.owner ne NoSymbol) - && (sym.owner.owner == pkgClass || matchesInfo) + // To be in the package object, one of these must be true: + // 1) sym.owner is a package object class, and sym.owner.owner is the package class for `pkg` + // 2) sym.owner is inherited by the correct package object class + // We try to establish 1) by inspecting the owners directly, and then we try + // to rule out 2), and only if both those fail do we resort to looking in the info. + !sym.isPackage && (sym.owner ne NoSymbol) && ( + if (sym.owner.isPackageObjectClass) + sym.owner.owner == pkgClass + else + !sym.owner.isPackageClass && matchesInfo + ) ) + // An overloaded symbol might not have the expected owner! + // The alternatives must be inspected directly. pkgClass.isPackageClass && ( - if (sym.isOverloaded) sym.alternatives forall inPackageObject - else inPackageObject(sym) + if (sym.isOverloaded) + sym.alternatives forall (isInPackageObject(_, pkg)) + else + inPackageObject(sym) ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index da2282c1dd..28bed0f1bf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -909,11 +909,10 @@ trait Namers extends MethodSynthesis { val modClass = companionSymbolOf(clazz, context).moduleClass modClass.attachments.get[ClassForCaseCompanionAttachment] foreach { cma => val cdef = cma.caseClass - def hasCopy(decls: Scope) = (decls lookup nme.copy) != NoSymbol + def hasCopy = (decls containsName nme.copy) || parents.exists(_ member nme.copy exists) + // SI-5956 needs (cdef.symbol == clazz): there can be multiple class symbols with the same name - if (cdef.symbol == clazz && !hasCopy(decls) && - !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) && - !parents.flatMap(_.baseClasses).distinct.exists(bc => hasCopy(bc.info.decls))) + if (cdef.symbol == clazz && !hasCopy) addCopyMethod(cdef, templateNamer) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index ab3476b91f..7cb420d2dc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -2034,9 +2034,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // CNF: a formula is a conjunction of clauses type Formula = Array[Clause] /** Override Array creation for efficiency (to not go through reflection). */ - private implicit val formulaTag: scala.reflect.ClassTag[Formula] = new scala.reflect.ClassTag[Formula] { - def runtimeClass: java.lang.Class[Formula] = classOf[Formula] - final override def newArray(len: Int): Array[Formula] = new Array[Formula](len) + private implicit val clauseTag: scala.reflect.ClassTag[Clause] = new scala.reflect.ClassTag[Clause] { + def runtimeClass: java.lang.Class[Clause] = classOf[Clause] + final override def newArray(len: Int): Array[Clause] = new Array[Clause](len) } def formula(c: Clause*): Formula = c.toArray def andFormula(a: Formula, b: Formula): Formula = a ++ b diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index dbd2a0e49b..9eb06dbdbf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -130,6 +130,15 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } } } + + // Check for doomed attempt to overload applyDynamic + if (clazz isSubClass DynamicClass) { + clazz.info member nme.applyDynamic match { + case sym if sym.isOverloaded => unit.error(sym.pos, "implementation restriction: applyDynamic cannot be overloaded") + case _ => + } + } + if (settings.lint.value) { clazz.info.decls filter (x => x.isImplicit && x.typeParams.nonEmpty) foreach { sym => val alts = clazz.info.decl(sym.name).alternatives @@ -1369,6 +1378,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans ) } + private def checkCompileTimeOnly(sym: Symbol, pos: Position) = { + if (sym.isCompileTimeOnly) { + def defaultMsg = + s"""|Reference to ${sym.fullLocationString} should not have survived past type checking, + |it should have been processed and eliminated during expansion of an enclosing macro.""".stripMargin + // The getOrElse part should never happen, it's just here as a backstop. + unit.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg) + } + } + private def lessAccessible(otherSym: Symbol, memberSym: Symbol): Boolean = ( (otherSym != NoSymbol) && !otherSym.isProtected @@ -1561,6 +1580,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkDeprecated(sym, tree.pos) if (settings.Xmigration28.value) checkMigration(sym, tree.pos) + checkCompileTimeOnly(sym, tree.pos) if (sym eq NoSymbol) { unit.warning(tree.pos, "Select node has NoSymbol! " + tree + " / " + tree.tpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index c203e62786..0a0ab53852 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -853,6 +853,8 @@ trait Typers extends Modes with Adaptations with Tags { orElse { _ => debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original)) val tree1 = typed(resetAllAttrs(original), mode, WildcardType) + // Q: `typed` already calls `addAnnotations` and `adapt`. the only difference here is that + // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. tree1.tpe = addAnnotations(tree1, tree1.tpe) if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree) } @@ -3037,7 +3039,7 @@ trait Typers extends Modes with Adaptations with Tags { def checkNotMacro() = { if (fun.symbol != null && fun.symbol.filter(sym => sym != null && sym.isTermMacro && !sym.isErroneous) != NoSymbol) - duplErrorTree(NamedAndDefaultArgumentsNotSupportedForMacros(tree, fun)) + tryTupleApply getOrElse duplErrorTree(NamedAndDefaultArgumentsNotSupportedForMacros(tree, fun)) } if (mt.isErroneous) duplErrTree @@ -3871,7 +3873,7 @@ trait Typers extends Modes with Adaptations with Tags { * */ def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { - debuglog(s"mkInvoke($cxTree, $tree, $qual, $name)") + debuglog(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") acceptsApplyDynamicWithType(qual, name) map { tp => // tp eq NoType => can call xxxDynamic, but not passing any type args (unless specified explicitly by the user) // in scala-virtualized, when not NoType, tp is passed as type argument (for selection on a staged Struct) @@ -4426,15 +4428,6 @@ trait Typers extends Modes with Adaptations with Tags { if (useTry) tryTypedApply(fun2, args) else doTypedApply(tree, fun2, args, mode, pt) - /* - if (fun2.hasSymbolField && fun2.symbol.isConstructor && (mode & EXPRmode) != 0) { - res.tpe = res.tpe.notNull - } - */ - // TODO: In theory we should be able to call: - //if (fun2.hasSymbolField && fun2.symbol.name == nme.apply && fun2.symbol.owner == ArrayClass) { - // But this causes cyclic reference for Array class in Cleanup. It is easy to overcome this - // by calling ArrayClass.info here (or some other place before specialize). if (fun2.symbol == Array_apply && !res.isErrorTyped) { val checked = gen.mkCheckInit(res) // this check is needed to avoid infinite recursion in Duplicators @@ -4449,38 +4442,36 @@ trait Typers extends Modes with Adaptations with Tags { } } - def typedApply(tree: Apply) = { - val fun = tree.fun - val args = tree.args - fun match { - case Block(stats, expr) => - typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt) - case _ => - normalTypedApply(tree, fun, args) match { - case Apply(Select(New(tpt), name), args) - if (tpt.tpe != null && - tpt.tpe.typeSymbol == ArrayClass && - args.length == 1 && - erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor - // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len) - // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times - // [Eugene] no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions) - val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe) - val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.toTypeConstructor, List(tpe))).last - val newArrayApp = atPos(tree.pos) { - val tag = resolveClassTag(tree.pos, tagType) - if (tag.isEmpty) MissingClassTagError(tree, tagType) - else new ApplyToImplicitArgs(Select(tag, nme.newArray), args) + // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len) + // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len) + // where Array HK gets applied (N-1) times + object ArrayInstantiation { + def unapply(tree: Apply) = tree match { + case Apply(Select(New(tpt), name), arg :: Nil) if tpt.tpe != null && tpt.tpe.typeSymbol == ArrayClass => + Some(tpt.tpe) collect { + case erasure.GenericArray(level, componentType) => + val tagType = (1 until level).foldLeft(componentType)((res, _) => arrayType(res)) + + resolveClassTag(tree.pos, tagType) match { + case EmptyTree => MissingClassTagError(tree, tagType) + case tag => atPos(tree.pos)(new ApplyToImplicitArgs(Select(tag, nme.newArray), arg :: Nil)) } - typed(newArrayApp, mode, pt) - case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => //SI-5696 - TooManyArgumentListsForConstructor(tree) - case tree1 => - tree1 } + case _ => None } } + def typedApply(tree: Apply) = tree match { + case Apply(Block(stats, expr), args) => + typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt) + case Apply(fun, args) => + normalTypedApply(tree, fun, args) match { + case ArrayInstantiation(tree1) => typed(tree1, mode, pt) + case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => TooManyArgumentListsForConstructor(tree) //SI-5696 + case tree1 => tree1 + } + } + def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = { val prefix = name.toTermName stripSuffix nme.EQL def mkAssign(vble: Tree): Tree = @@ -4534,8 +4525,6 @@ trait Typers extends Modes with Adaptations with Tags { case This(_) => qual1.symbol case _ => qual1.tpe.typeSymbol } - //println(clazz+"/"+qual1.tpe.typeSymbol+"/"+qual1) - def findMixinSuper(site: Type): Type = { var ps = site.parents filter (_.typeSymbol.name == mix) if (ps.isEmpty) @@ -4543,11 +4532,6 @@ trait Typers extends Modes with Adaptations with Tags { if (ps.isEmpty) { debuglog("Fatal: couldn't find site " + site + " in " + site.parents.map(_.typeSymbol.name)) if (phase.erasedTypes && context.enclClass.owner.isImplClass) { - // println(qual1) - // println(clazz) - // println(site) - // println(site.parents) - // println(mix) // the reference to super class got lost during erasure restrictionError(tree.pos, unit, "traits may not select fields or methods from super[C] where C is a class") ErrorType @@ -5212,7 +5196,6 @@ trait Typers extends Modes with Adaptations with Tags { lastTreeToTyper = tree indentTyping() - var alreadyTyped = false val startByType = if (Statistics.canEnable) Statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null if (Statistics.canEnable) Statistics.incCounter(visitsByType, tree.getClass) try { @@ -5222,7 +5205,7 @@ trait Typers extends Modes with Adaptations with Tags { if (tree.hasSymbolField) tree.symbol = NoSymbol } - alreadyTyped = tree.tpe ne null + val alreadyTyped = tree.tpe ne null val tree1: Tree = if (alreadyTyped) tree else { printTyping( ptLine("typing %s: pt = %s".format(ptTree(tree), pt), |