diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-06-27 16:18:56 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-06-27 16:18:56 +0200 |
commit | 03af96588cbab178d4520e7604319fd5a52ddb24 (patch) | |
tree | 95d759126288315f403e421199901f1f5262f809 /src/compiler | |
parent | 6887029f100e2c3a90534768da074472f39cf14f (diff) | |
parent | fbfce33cb03bc2b41dd0f46fa9f4630036b4f2ca (diff) | |
download | scala-03af96588cbab178d4520e7604319fd5a52ddb24.tar.gz scala-03af96588cbab178d4520e7604319fd5a52ddb24.tar.bz2 scala-03af96588cbab178d4520e7604319fd5a52ddb24.zip |
Merge remote-tracking branch 'origin/2.11.x' into merge/2.11.x-2.12.x-20140627
Diffstat (limited to 'src/compiler')
6 files changed, 66 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 35eab94333..cb785de4b3 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1169,8 +1169,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (option) reporter.warning(pos, msg) else if (!(warnings contains pos)) warnings += ((pos, msg)) def summarize() = - if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)) - warning("there were %d %s warning(s); re-run with %s for details".format(warnings.size, what, option.name)) + if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)){ + val warningEvent = if (warnings.size > 1) s"were ${ warnings.size } $what warnings" else s"was one $what warning" + warning(s"there $warningEvent; re-run with ${ option.name } for details") + } } def newSourceFile(code: String, filename: String = "<console>") = diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 714f189ead..d9d1192772 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -328,11 +328,14 @@ abstract class TailCalls extends Transform { ) case CaseDef(pat, guard, body) => + // CaseDefs are already translated and guards were moved into the body. + // If this was not the case, guards would have to be transformed here as well. + assert(guard.isEmpty) deriveCaseDef(tree)(transform) case If(cond, thenp, elsep) => treeCopy.If(tree, - cond, + noTailTransform(cond), transform(thenp), transform(elsep) ) @@ -363,7 +366,7 @@ abstract class TailCalls extends Transform { rewriteApply(tapply, fun, targs, vargs) case Apply(fun, args) if fun.symbol == Boolean_or || fun.symbol == Boolean_and => - treeCopy.Apply(tree, fun, transformTrees(args)) + treeCopy.Apply(tree, noTailTransform(fun), transformTrees(args)) // this is to detect tailcalls in translated matches // it's a one-argument call to a label that is in a tailposition and that looks like label(x) {x} diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index fde0aca584..0899507bab 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -505,7 +505,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { } - import global.{ConstantType, Constant, SingletonType, Literal, Ident, singleType} + import global.{ConstantType, Constant, EmptyScope, SingletonType, Literal, Ident, refinedType, singleType, TypeBounds, NoSymbol} import global.definitions._ @@ -538,23 +538,30 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { private val trees = mutable.HashSet.empty[Tree] // hashconsing trees (modulo value-equality) - private[TreesAndTypesDomain] def uniqueTpForTree(t: Tree): Type = - // a new type for every unstable symbol -- only stable value are uniqued - // technically, an unreachable value may change between cases - // thus, the failure of a case that matches on a mutable value does not exclude the next case succeeding - // (and thuuuuus, the latter case must be considered reachable) - if (!t.symbol.isStable) t.tpe.narrow + private[TreesAndTypesDomain] def uniqueTpForTree(t: Tree): Type = { + def freshExistentialSubtype(tp: Type): Type = { + // SI-8611 tp.narrow is tempting, but unsuitable. See `testRefinedTypeSI8611` for an explanation. + NoSymbol.freshExistential("").setInfo(TypeBounds.upper(tp)).tpe + } + + if (!t.symbol.isStable) { + // Create a fresh type for each unstable value, since we can never correlate it to another value. + // For example `case X => case X =>` should not complaing about the second case being unreachable, + // if X is mutable. + freshExistentialSubtype(t.tpe) + } else trees find (a => a.correspondsStructure(t)(sameValue)) match { case Some(orig) => - debug.patmat("unique tp for tree: "+ ((orig, orig.tpe))) + debug.patmat("unique tp for tree: " + ((orig, orig.tpe))) orig.tpe case _ => // duplicate, don't mutate old tree (TODO: use a map tree -> type instead?) - val treeWithNarrowedType = t.duplicate setType t.tpe.narrow + val treeWithNarrowedType = t.duplicate setType freshExistentialSubtype(t.tpe) debug.patmat("uniqued: "+ ((t, t.tpe, treeWithNarrowedType.tpe))) trees += treeWithNarrowedType treeWithNarrowedType.tpe } + } } sealed abstract class Const { diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 894f959319..e1a663ea41 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -104,11 +104,18 @@ trait TreeAndTypeAnalysis extends Debugging { // TODO case _ if tp.isTupleType => // recurse into component types case modSym: ModuleClassSymbol => Some(List(tp)) + case sym: RefinementClassSymbol => + val parentSubtypes: List[Option[List[Type]]] = tp.parents.map(parent => enumerateSubtypes(parent)) + if (parentSubtypes exists (_.isDefined)) + // If any of the parents is enumerable, then the refinement type is enumerable. + Some( + // We must only include subtypes of the parents that conform to `tp`. + // See neg/virtpatmat_exhaust_compound.scala for an example. + parentSubtypes flatMap (_.getOrElse(Nil)) filter (_ <:< tp) + ) + else None // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte - case sym if !sym.isSealed || isPrimitiveValueClass(sym) => - debug.patmat("enum unsealed "+ ((tp, sym, sym.isSealed, isPrimitiveValueClass(sym)))) - None - case sym => + case sym if sym.isSealed => val subclasses = debug.patmatResult(s"enum $sym sealed, subclasses")( // symbols which are both sealed and abstract need not be covered themselves, because // all of their children must be and they cannot otherwise be created. @@ -136,6 +143,9 @@ trait TreeAndTypeAnalysis extends Debugging { else None } }) + case sym => + debug.patmat("enum unsealed "+ ((tp, sym, sym.isSealed, isPrimitiveValueClass(sym)))) + None } // approximate a type to the static type that is fully checkable at run time, diff --git a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala index fa6e5399eb..5a70d4c524 100644 --- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala +++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala @@ -190,6 +190,16 @@ trait AnalyzerPlugins { self: Analyzer => def pluginsTypedMacroBody(typer: Typer, ddef: DefDef): Option[Tree] = None /** + * Figures out whether the given macro definition is blackbox or whitebox. + * + * Default implementation provided in `self.standardIsBlackbox` loads the macro impl binding + * and fetches boxity from the "isBlackbox" field of the macro signature. + * + * $nonCumulativeReturnValueDoc. + */ + def pluginsIsBlackbox(macroDef: Symbol): Option[Boolean] = None + + /** * Expands an application of a def macro (i.e. of a symbol that has the MACRO flag set), * possibly using the current typer mode and the provided prototype. * @@ -375,6 +385,14 @@ trait AnalyzerPlugins { self: Analyzer => def custom(plugin: MacroPlugin) = plugin.pluginsTypedMacroBody(typer, ddef) }) + /** @see MacroPlugin.pluginsIsBlackbox */ + def pluginsIsBlackbox(macroDef: Symbol): Boolean = invoke(new NonCumulativeOp[Boolean] { + def position = macroDef.pos + def description = "compute boxity for this macro definition" + def default = standardIsBlackbox(macroDef) + def custom(plugin: MacroPlugin) = plugin.pluginsIsBlackbox(macroDef) + }) + /** @see MacroPlugin.pluginsMacroExpand */ def pluginsMacroExpand(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Tree = invoke(new NonCumulativeOp[Tree] { def position = expandee.pos diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index f4456998c0..ef74beec62 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -263,7 +263,12 @@ trait Macros extends MacroRuntimes with Traces with Helpers { } def isBlackbox(expandee: Tree): Boolean = isBlackbox(dissectApplied(expandee).core.symbol) - def isBlackbox(macroDef: Symbol): Boolean = { + def isBlackbox(macroDef: Symbol): Boolean = pluginsIsBlackbox(macroDef) + + /** Default implementation of `isBlackbox`. + * Can be overridden by analyzer plugins (see AnalyzerPlugins.pluginsIsBlackbox for more details) + */ + def standardIsBlackbox(macroDef: Symbol): Boolean = { val fastTrackBoxity = fastTrack.get(macroDef).map(_.isBlackbox) val bindingBoxity = loadMacroImplBinding(macroDef).map(_.isBlackbox) fastTrackBoxity orElse bindingBoxity getOrElse false @@ -417,9 +422,10 @@ trait Macros extends MacroRuntimes with Traces with Helpers { val wrappedArgs = mapWithIndex(args)((arg, j) => { val fingerprint = implParams(min(j, implParams.length - 1)) + val duplicatedArg = duplicateAndKeepPositions(arg) fingerprint match { - case LiftedTyped => context.Expr[Nothing](arg.duplicate)(TypeTag.Nothing) // TODO: SI-5752 - case LiftedUntyped => arg.duplicate + case LiftedTyped => context.Expr[Nothing](duplicatedArg)(TypeTag.Nothing) // TODO: SI-5752 + case LiftedUntyped => duplicatedArg case _ => abort(s"unexpected fingerprint $fingerprint in $binding with paramss being $paramss " + s"corresponding to arg $arg in $argss") } |