diff options
Diffstat (limited to 'src')
14 files changed, 142 insertions, 37 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/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/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..1e0832f55a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1369,6 +1369,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 +1571,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..e39e005c17 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3037,7 +3037,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 diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index ed45010091..8e406b6f62 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -981,6 +981,7 @@ trait Definitions extends api.StandardDefinitions { lazy val BeanPropertyAttr = requiredClass[scala.beans.BeanProperty] lazy val BooleanBeanPropertyAttr = requiredClass[scala.beans.BooleanBeanProperty] lazy val CloneableAttr = requiredClass[scala.annotation.cloneable] + lazy val CompileTimeOnlyAttr = getClassIfDefined("scala.reflect.macros.compileTimeOnly") lazy val DeprecatedAttr = requiredClass[scala.deprecated] lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName] lazy val DeprecatedInheritanceAttr = requiredClass[scala.deprecatedInheritance] diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 68b5794b59..fb1bf9ed9d 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -6,6 +6,7 @@ package scala.reflect package internal +import scala.annotation.elidable import scala.collection.{ mutable, immutable } import util._ @@ -108,6 +109,11 @@ abstract class SymbolTable extends macros.Universe val global: SymbolTable.this.type = SymbolTable.this } with util.TraceSymbolActivity + /** Check that the executing thread is the compiler thread. No-op here, + * overridden in interactive.Global. */ + @elidable(elidable.WARNING) + def assertCorrectThread() {} + /** Are we compiling for Java SE? */ // def forJVM: Boolean diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 30e5ecd643..0ad0275fba 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -740,6 +740,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } + def isCompileTimeOnly = hasAnnotation(CompileTimeOnlyAttr) + def compileTimeOnlyMessage = getAnnotation(CompileTimeOnlyAttr) flatMap (_ stringArg 0) + /** Is this symbol an accessor method for outer? */ final def isOuterAccessor = { hasFlag(STABLE | ARTIFACT) && @@ -1259,6 +1262,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } val current = phase try { + assertCorrectThread() phase = phaseOf(infos.validFrom) tp.complete(this) } finally { @@ -1329,6 +1333,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => infos = infos.prev if (validTo < curPeriod) { + assertCorrectThread() // adapt any infos that come from previous runs val current = phase try { diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index ddfc1f2af0..7ae7cf1821 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -287,6 +287,68 @@ abstract class TreeInfo { isSelfConstrCall(tree1) || isSuperConstrCall(tree1) } + /** + * Does this tree represent an irrefutable pattern match + * in the position `for { <tree> <- expr }` based only + * on information at the `parser` phase? To qualify, there + * may be no subtree that will be interpreted as a + * Stable Identifier Pattern. + * + * For instance: + * + * {{{ + * foo @ (bar, (baz, quux)) + * }}} + * + * is a variable pattern; if the structure matches, + * then the remainder is inevitable. + * + * The following are not variable patterns. + * + * {{{ + * foo @ (bar, (`baz`, quux)) // back quoted ident, not at top level + * foo @ (bar, Quux) // UpperCase ident, not at top level + * }}} + * + * If the pattern is a simple identifier, it is always + * a variable pattern. For example, the following + * introduce new bindings: + * + * {{{ + * for { X <- xs } yield X + * for { `backquoted` <- xs } yield `backquoted` + * }}} + * + * Note that this differs from a case clause: + * + * {{{ + * object X + * scrut match { + * case X => // case _ if scrut == X + * } + * }}} + * + * Background: [[https://groups.google.com/d/msg/scala-internals/qwa_XOw_7Ks/IktkeTBYqg0J]] + * + */ + def isVarPatternDeep(tree: Tree): Boolean = { + def isVarPatternDeep0(tree: Tree): Boolean = { + tree match { + case Bind(name, pat) => isVarPatternDeep0(pat) + case Ident(name) => isVarPattern(tree) + case Apply(sel, args) => + ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName) + && (args forall isVarPatternDeep0) + ) + case _ => false + } + } + tree match { + case Ident(name) => true + case _ => isVarPatternDeep0(tree) + } + } + /** Is tree a variable pattern? */ def isVarPattern(pat: Tree): Boolean = pat match { case x: Ident => !x.isBackquoted && nme.isVariableName(x.name) @@ -372,24 +434,6 @@ abstract class TreeInfo { case _ => false } - /** Is this tree comprised of nothing but identifiers, - * but possibly in bindings or tuples? For instance - * - * foo @ (bar, (baz, quux)) - * - * is a variable pattern; if the structure matches, - * then the remainder is inevitable. - */ - def isVariablePattern(tree: Tree): Boolean = tree match { - case Bind(name, pat) => isVariablePattern(pat) - case Ident(name) => true - case Apply(sel, args) => - ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName) - && (args forall isVariablePattern) - ) - case _ => false - } - /** Is this argument node of the form <expr> : _* ? */ def isWildcardStarArg(tree: Tree): Boolean = tree match { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 3104c1e74e..06d769bcc5 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -143,6 +143,7 @@ trait Types extends api.Types { self: SymbolTable => /** Undo all changes to constraints to type variables upto `limit`. */ //OPT this method is public so we can do `manual inlining` def undoTo(limit: UndoPairs) { + assertCorrectThread() while ((log ne limit) && log.nonEmpty) { val (tv, constr) = log.head tv.constr = constr diff --git a/src/reflect/scala/reflect/macros/compileTimeOnly.scala b/src/reflect/scala/reflect/macros/compileTimeOnly.scala new file mode 100644 index 0000000000..5a3a352a53 --- /dev/null +++ b/src/reflect/scala/reflect/macros/compileTimeOnly.scala @@ -0,0 +1,16 @@ +package scala.reflect +package macros + +import scala.annotation.meta._ + +/** + * An annotation that designates a member should not be referred to after + * type checking (which includes macro expansion); it must only be used in + * the arguments of some other macro that will eliminate it from the AST. + * + * @param message the error message to print during compilation if a reference remains + * after type checking + * @since 2.10.1 + */ +@getter @setter @beanGetter @beanSetter +final class compileTimeOnly(message: String) extends scala.annotation.StaticAnnotation |