Skip to content

Commit

Permalink
Merge pull request scala#1623 from paulp/merge-2.10.x
Browse files Browse the repository at this point in the history
Merge 2.10.0-wip/.x into master
  • Loading branch information
adriaanm committed Nov 16, 2012
2 parents b091cbd + ed44df6 commit 6645fec
Show file tree
Hide file tree
Showing 25 changed files with 219 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/reify/Errors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/ast/NodePrinters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
41 changes: 32 additions & 9 deletions src/compiler/scala/tools/nsc/interactive/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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._

Expand All @@ -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 = {
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1378,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
Expand Down Expand Up @@ -1570,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)
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
6 changes: 6 additions & 0 deletions src/reflect/scala/reflect/internal/SymbolTable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package scala.reflect
package internal

import scala.annotation.elidable
import scala.collection.{ mutable, immutable }
import util._

Expand Down Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions src/reflect/scala/reflect/internal/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) &&
Expand Down Expand Up @@ -1259,6 +1262,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
val current = phase
try {
assertCorrectThread()
phase = phaseOf(infos.validFrom)
tp.complete(this)
} finally {
Expand Down Expand Up @@ -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 {
Expand Down
80 changes: 62 additions & 18 deletions src/reflect/scala/reflect/internal/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions src/reflect/scala/reflect/macros/compileTimeOnly.scala
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion test/files/neg/t6323a.check
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
t6323a.scala:11: `package`.this.materializeTypeTag[Test](scala.reflect.runtime.`package`.universe) is not a valid implicit value for reflect.runtime.universe.TypeTag[Test] because:
failed to typecheck the materialized tag:
cannot create a TypeTag referring to local class Test.Test
cannot create a TypeTag referring to local class Test.Test: use WeakTypeTag instead
val value = u.typeOf[Test]
^
t6323a.scala:11: error: No TypeTag available for Test
Expand Down
10 changes: 10 additions & 0 deletions test/files/neg/t6539.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Test_2.scala:2: error: cto may only be used as an argument to m
M.cto // error
^
Test_2.scala:3: error: cto may only be used as an argument to m
M.m(M.cto, ()) // error
^
Test_2.scala:5: error: cto may only be used as an argument to m
M.cto // error
^
three errors found
10 changes: 10 additions & 0 deletions test/files/neg/t6539/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import language.experimental.macros
import reflect.macros.Context

object M {
def m(a: Any, b: Any): Any = macro mImpl
def mImpl(c: Context)(a: c.Expr[Any], b: c.Expr[Any]) = a

@reflect.macros.compileTimeOnly("cto may only be used as an argument to " + "m")
def cto = 0
}
6 changes: 6 additions & 0 deletions test/files/neg/t6539/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Test {
M.cto // error
M.m(M.cto, ()) // error
M.m((), M.cto) // okay
M.cto // error
}
8 changes: 8 additions & 0 deletions test/files/run/t6644.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Testable(val c: String) extends AnyVal {
def matching(cases: Boolean*) = cases contains true
}

object Test extends App {
assert(new Testable("").matching(true, false))
}

5 changes: 5 additions & 0 deletions test/files/run/t6646.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Found NotNull
Found lower
Found 2
A single ident is always a pattern
A single ident is always a pattern
Loading

0 comments on commit 6645fec

Please sign in to comment.