summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-05-16 22:30:24 -0700
committerPaul Phillips <paulp@improving.org>2013-05-16 22:34:16 -0700
commit0c3ca2248d55eeeee2db6693e5fc46b9ba049eda (patch)
tree71686d0b99fc1d4a245ddb24efe50398b0c00c78 /src/compiler/scala/tools
parentc663ecf8677eda3fe8c91170b614eb7166b18711 (diff)
parent13b4628aabb8e7a293a382dcab6db5848f672f94 (diff)
downloadscala-0c3ca2248d55eeeee2db6693e5fc46b9ba049eda.tar.gz
scala-0c3ca2248d55eeeee2db6693e5fc46b9ba049eda.tar.bz2
scala-0c3ca2248d55eeeee2db6693e5fc46b9ba049eda.zip
Merge branch 'master' into HEAD
* master: SI-7469 Remove @deprecated scala.util.logging SI-3943 Test case for already-fixed Java interop bug Fix formatting for couple of docs in the compiler SI-7476 Add documentation to GenericTraversableTemplate SI-7469 Remove @deprecated scala.util.parsing.ast SI-7469 Remove @deprecated MurmurHash elements SI-7469 Remove deprecated elements in s.u.parsing.combinator SI-7469 Make @deprecated elems in scala.concurrent private[scala] removes duplication in inferImplicitValue SI-7047 fixes silent for c.inferImplicitXXX SI-7167 implicit macros decide what is divergence macroExpandAll is now triggered in all invocations of typed SI-5923 instantiates targs in deferred macro applications SI-6406 Restore deprecated API SI-6039 Harden against irrelevant filesystem details Limit unnecessary calls to Type#toString. fix typo in comment SI-7432 add testcases SI-7432 Range.min should throw NoSuchElementException on empty range AbstractFile.getDirectory does not return null when outDir is "." Conflicts: src/compiler/scala/tools/nsc/typechecker/Typers.scala
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala8
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala35
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala23
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala2
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala11
9 files changed, 90 insertions, 36 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 250feb69bf..98fb6bd0ef 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -234,10 +234,14 @@ abstract class SymbolLoaders {
}
}
if (!root.isEmptyPackageClass) {
+ // Only enter packages which contain a class or a non-empty package
for (pkg <- classpath.packages) {
- enterPackage(root, pkg.name, new PackageLoader(pkg))
+ if (pkg.isEmptyOfClassfiles) {
+ log(s"Discarding $root/$pkg as it contains no classfiles.")
+ }
+ else
+ enterPackage(root, pkg.name, new PackageLoader(pkg))
}
-
openPackageModule(root)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 9e867917f9..6f422fcc90 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -89,12 +89,12 @@ abstract class TailCalls extends Transform {
*/
class TailCallElimination(unit: CompilationUnit) extends Transformer {
private def defaultReason = "it contains a recursive call not in tail position"
- private val failPositions = perRunCaches.newMap[TailContext, Position]()
- private val failReasons = perRunCaches.newMap[TailContext, String]()
+ private val failPositions = perRunCaches.newMap[TailContext, Position]() withDefault (_.methodPos)
+ private val failReasons = perRunCaches.newMap[TailContext, String]() withDefaultValue defaultReason
private def tailrecFailure(ctx: TailContext) {
- val method = ctx.method
- val failReason = failReasons.getOrElse(ctx, defaultReason)
- val failPos = failPositions.getOrElse(ctx, ctx.methodPos)
+ val method = ctx.method
+ val failReason = failReasons(ctx)
+ val failPos = failPositions(ctx)
unit.error(failPos, s"could not optimize @tailrec annotated $method: $failReason")
}
@@ -237,7 +237,7 @@ abstract class TailCalls extends Transform {
if (!ctx.isEligible) fail("it is neither private nor final so can be overridden")
else if (!isRecursiveCall) {
- if (receiverIsSuper) failHere("it contains a recursive call targeting supertype " + receiver.tpe)
+ if (receiverIsSuper) failHere("it contains a recursive call targeting a supertype")
else failHere(defaultReason)
}
else if (!matchesTypeArgs) failHere("it is called recursively with different type arguments")
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
index 8be8b72130..63834ae51e 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
@@ -129,8 +129,9 @@ trait Interface extends ast.TreeDSL {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Interface with user-defined match monad?
- * if there's a `__match` in scope, we use this as the match strategy, assuming it conforms to MatchStrategy as defined below:
+ * if there's a <code>__match</code> in scope, we use this as the match strategy, assuming it conforms to MatchStrategy as defined below:
+ {{{
type Matcher[P[_], M[+_], A] = {
def flatMap[B](f: P[A] => M[B]): M[B]
def orElse[B >: A](alternative: => M[B]): M[B]
@@ -144,12 +145,14 @@ trait Interface extends ast.TreeDSL {
def one[T](x: P[T]): M[T]
def guard[T](cond: P[Boolean], then: => P[T]): M[T]
}
+ }}}
* P and M are derived from one's signature (`def one[T](x: P[T]): M[T]`)
- * if no `__match` is found, we assume the following implementation (and generate optimized code accordingly)
+ * if no <code>__match</code> is found, we assume the following implementation (and generate optimized code accordingly)
+ {{{
object __match extends MatchStrategy[({type Id[x] = x})#Id, Option] {
def zero = None
def one[T](x: T) = Some(x)
@@ -157,6 +160,7 @@ trait Interface extends ast.TreeDSL {
def guard[T](cond: Boolean, then: => T): Option[T] = if(cond) Some(then) else None
def runOrElse[T, U](x: T)(f: T => Option[U]): U = f(x) getOrElse (throw new MatchError(x))
}
+ }}}
*/
trait MatchMonadInterface {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 21c33aad0d..9794497667 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -213,7 +213,7 @@ trait Contexts { self: Analyzer =>
def isRootImport: Boolean = false
/** Types for which implicit arguments are currently searched */
- var openImplicits: List[(Type,Tree)] = List()
+ var openImplicits: List[OpenImplicit] = List()
/* For a named application block (`Tree`) the corresponding `NamedApplyInfo`. */
var namedApplyBlockInfo: Option[(Tree, NamedApplyInfo)] = None
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index f27c15180e..05db86635a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -100,6 +100,21 @@ trait Implicits {
result
}
+ /** A friendly wrapper over inferImplicit to be used in macro contexts and toolboxes.
+ */
+ def inferImplicit(tree: Tree, pt: Type, isView: Boolean, context: Context, silent: Boolean, withMacrosDisabled: Boolean, pos: Position, onError: (Position, String) => Unit): Tree = {
+ val wrapper1 = if (!withMacrosDisabled) (context.withMacrosEnabled[SearchResult] _) else (context.withMacrosDisabled[SearchResult] _)
+ def wrapper(inference: => SearchResult) = wrapper1(inference)
+ val result = wrapper(inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos))
+ if (result.isFailure && !silent) {
+ val err = context.firstError
+ val errPos = err.map(_.errPos).getOrElse(pos)
+ val errMsg = err.map(_.errMsg).getOrElse("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
+ onError(errPos, errMsg)
+ }
+ result.tree
+ }
+
/** Find all views from type `tp` (in which `tpars` are free)
*
* Note that the trees in the search results in the returned list share the same type variables.
@@ -224,6 +239,10 @@ trait Implicits {
)
}
+ /** A class which is used to track pending implicits to prevent infinite implicit searches.
+ */
+ case class OpenImplicit(info: ImplicitInfo, pt: Type, tree: Tree)
+
/** A sentinel indicating no implicit was found */
val NoImplicitInfo = new ImplicitInfo(null, NoType, NoSymbol) {
// equals used to be implemented in ImplicitInfo with an `if(this eq NoImplicitInfo)`
@@ -407,13 +426,25 @@ trait Implicits {
* @pre `info.tpe` does not contain an error
*/
private def typedImplicit(info: ImplicitInfo, ptChecked: Boolean, isLocal: Boolean): SearchResult = {
- (context.openImplicits find { case (tp, tree1) => tree1.symbol == tree.symbol && dominates(pt, tp)}) match {
+ // SI-7167 let implicit macros decide what amounts for a divergent implicit search
+ // imagine a macro writer which wants to synthesize a complex implicit Complex[T] by making recursive calls to Complex[U] for its parts
+ // e.g. we have `class Foo(val bar: Bar)` and `class Bar(val x: Int)`
+ // then it's quite reasonable for the macro writer to synthesize Complex[Foo] by calling `inferImplicitValue(typeOf[Complex[Bar])`
+ // however if we didn't insert the `info.sym.isMacro` check here, then under some circumstances
+ // (e.g. as described here http://groups.google.com/group/scala-internals/browse_thread/thread/545462b377b0ac0a)
+ // `dominates` might decide that `Bar` dominates `Foo` and therefore a recursive implicit search should be prohibited
+ // now when we yield control of divergent expansions to the macro writer, what happens next?
+ // in the worst case, if the macro writer is careless, we'll get a StackOverflowException from repeated macro calls
+ // otherwise, the macro writer could check `c.openMacros` and `c.openImplicits` and do `c.abort` when expansions are deemed to be divergent
+ // upon receiving `c.abort` the typechecker will decide that the corresponding implicit search has failed
+ // which will fail the entire stack of implicit searches, producing a nice error message provided by the programmer
+ (context.openImplicits find { case OpenImplicit(info, tp, tree1) => !info.sym.isMacro && tree1.symbol == tree.symbol && dominates(pt, tp)}) match {
case Some(pending) =>
//println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG
DivergentSearchFailure
case None =>
try {
- context.openImplicits = (pt, tree) :: context.openImplicits
+ context.openImplicits = OpenImplicit(info, pt, tree) :: context.openImplicits
// println(" "*context.openImplicits.length+"typed implicit "+info+" for "+pt) //@MDEBUG
val result = typedImplicit0(info, ptChecked, isLocal)
if (result.isDivergent) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 31cc8bd93c..2cd2f9380b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -396,7 +396,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
case Fallback(fallback) =>
typed1Expr(fallback)
case Delayed(delayed) =>
- delayed
+ typer.instantiate(delayed, EXPRmode, WildcardType)
case Skipped(skipped) =>
skipped
case Failure(failure) =>
@@ -780,6 +780,29 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
expanded2
}
}
+ override def onDelayed(delayed: Tree) = {
+ // If we've been delayed (i.e. bailed out of the expansion because of undetermined type params present in the expandee),
+ // then there are two possible situations we're in:
+ // 1) We're in POLYmode, when the typer tests the waters wrt type inference
+ // (e.g. as in typedArgToPoly in doTypedApply).
+ // 2) We're out of POLYmode, which means that the typer is out of tricks to infer our type
+ // (e.g. if we're an argument to a function call, then this means that no previous argument lists
+ // can determine our type variables for us).
+ //
+ // Situation #1 is okay for us, since there's no pressure. In POLYmode we're just verifying that
+ // there's nothing outrageously wrong with our undetermined type params (from what I understand!).
+ //
+ // Situation #2 requires measures to be taken. If we're in it, then noone's going to help us infer
+ // the undetermined type params. Therefore we need to do something ourselves or otherwise this
+ // expandee will forever remaing not expanded (see SI-5692). A traditional way out of this conundrum
+ // is to call `instantiate` and let the inferencer try to find the way out. It works for simple cases,
+ // but sometimes, if the inferencer lacks information, it will be forced to approximate. This prevents
+ // an important class of macros, fundep materializers, from working, which I perceive is a problem we need to solve.
+ // For details see SI-7470.
+ val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode
+ if (shouldInstantiate) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
+ else delayed
+ }
}
expander(expandee)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 5cce4865cc..5b1f7160b7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1233,29 +1233,21 @@ trait Typers extends Adaptations with Tags {
}
if (tree.isType)
adaptType()
+ else if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree))
+ macroExpandApply(this, tree, mode, pt)
else if (mode.typingPatternFun)
adaptConstrPattern()
else if (shouldInsertApply(tree))
insertApply()
else if (hasUndetsInMonoMode) { // (9)
assert(!context.inTypeConstructor, context) //@M
- if (mode.typingExprNotFun && pt.typeSymbol == UnitClass)
- instantiateExpectingUnit(tree, mode)
- else
- instantiate(tree, mode, pt)
+ instantiatePossiblyExpectingUnit(tree, mode, pt)
}
else if (tree.tpe <:< pt)
tree
else
fallbackAfterVanillaAdapt()
}
- def expandMacroAndVanillaAdapt(): Tree = {
- if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree)) {
- val tree1 = macroExpandApply(this, tree, mode, pt)
- if (tree == tree1) vanillaAdapt(tree) else tree1
- }
- else vanillaAdapt(tree)
- }
// begin adapt
tree.tpe match {
@@ -1294,7 +1286,7 @@ trait Typers extends Adaptations with Tags {
case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode && !treeInfo.isMacroApplicationOrBlock(tree) =>
instantiateToMethodType(mt)
case _ =>
- expandMacroAndVanillaAdapt()
+ vanillaAdapt(tree)
}
}
@@ -1315,6 +1307,13 @@ trait Typers extends Adaptations with Tags {
}
}
+ def instantiatePossiblyExpectingUnit(tree: Tree, mode: Mode, pt: Type): Tree = {
+ if (mode.typingExprNotFun && pt.typeSymbol == UnitClass)
+ instantiateExpectingUnit(tree, mode)
+ else
+ instantiate(tree, mode, pt)
+ }
+
private def isAdaptableWithView(qual: Tree) = {
val qtpe = qual.tpe.widen
( !isPastTyper
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index 7f9b81e1ec..536a281e6c 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -211,6 +211,8 @@ abstract class ClassPath[T] {
def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.')
def validSourceFile(name: String) = endsScala(name) || endsJava(name)
+ def isEmptyOfClassfiles: Boolean = classes.isEmpty && packages.forall(_.isEmptyOfClassfiles)
+
/**
* Find a ClassRep given a class name of the form "package.subpackage.ClassName".
* Does not support nested classes on .NET
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 602982337f..59408096a3 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -180,16 +180,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
transformDuringTyper(tree, withImplicitViewsDisabled = false, withMacrosDisabled = withMacrosDisabled)(
(currentTyper, tree) => {
trace("inferring implicit %s (macros = %s): ".format(if (isView) "view" else "value", !withMacrosDisabled))(showAttributed(pt, true, true, settings.Yshowsymkinds.value))
- val context = currentTyper.context
- val result = analyzer.inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos)
- if (result.isFailure) {
- // @H: what's the point of tracing an empty tree?
- trace("implicit search has failed. to find out the reason, turn on -Xlog-implicits: ")(result.tree)
- context.firstError foreach { err =>
- throw ToolBoxError("reflective implicit search has failed: %s".format(err.errMsg))
- }
- }
- result.tree
+ analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg))
})
def compile(expr0: Tree): () => Any = {