summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala (renamed from src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala)125
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala74
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala85
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala5
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala3
8 files changed, 187 insertions, 119 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 8c6c927640..959ce427bb 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -462,6 +462,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
val global: Global.this.type = Global.this
} with Analyzer
+ // phaseName = "patmat"
+ object patmat extends {
+ val global: Global.this.type = Global.this
+ val runsAfter = List("typer")
+ val runsRightAfter = Some("typer")
+ } with PatternMatching
+
// phaseName = "superaccessors"
object superAccessors extends {
val global: Global.this.type = Global.this
@@ -682,6 +689,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
analyzer.namerFactory -> "resolve names, attach symbols to named trees",
analyzer.packageObjects -> "load package objects",
analyzer.typerFactory -> "the meat and potatoes: type the trees",
+ patmat -> "translate match expressions",
superAccessors -> "add super accessors in traits and nested classes",
extensionMethods -> "add extension methods for inline classes",
pickler -> "serialize symbol tables",
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 34b37073fd..a355db4d9a 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -234,6 +234,11 @@ trait Trees extends reflect.internal.Trees { self: Global =>
}
}
+ // used when a phase is disabled
+ object noopTransformer extends Transformer {
+ override def transformUnit(unit: CompilationUnit): Unit = {}
+ }
+
override protected def xtransform(transformer: super.Transformer, tree: Tree): Tree = tree match {
case DocDef(comment, definition) =>
transformer.treeCopy.DocDef(tree, comment, transformer.transform(definition))
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index b3f4b10865..702f279596 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -1,5 +1,6 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
+ *
+ * Copyright 2012 LAMP/EPFL
* @author Adriaan Moors
*/
@@ -9,33 +10,84 @@ package typechecker
import symtab._
import Flags.{MUTABLE, METHOD, LABEL, SYNTHETIC}
import language.postfixOps
+import scala.tools.nsc.transform.TypingTransformers
+import scala.tools.nsc.transform.Transform
-/** Translate pattern matching into method calls (these methods form a zero-plus monad), similar in spirit to how for-comprehensions are compiled.
+/** Translate pattern matching.
+ *
+ * Either into optimized if/then/else's,
+ * or virtualized as method calls (these methods form a zero-plus monad), similar in spirit to how for-comprehensions are compiled.
*
* For each case, express all patterns as extractor calls, guards as 0-ary extractors, and sequence them using `flatMap`
* (lifting the body of the case into the monad using `one`).
*
* Cases are combined into a pattern match using the `orElse` combinator (the implicit failure case is expressed using the monad's `zero`).
-
+ *
* TODO:
- * - interaction with CPS
+ * - exhaustivity
+ * - DCE (unreachability/refutability/optimization)
+ * - use TypeTags for type testing
* - Array patterns
* - implement spec more closely (see TODO's)
- * - DCE
- * - use TypeTags for type testing
*
* (longer-term) TODO:
* - user-defined unapplyProd
* - recover GADT typing by locally inserting implicit witnesses to type equalities derived from the current case, and considering these witnesses during subtyping (?)
* - recover exhaustivity and unreachability checking using a variation on the type-safe builder pattern
*/
-trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
- import global._
+trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL { // self: Analyzer =>
+ val global: Global // need to repeat here because otherwise last mixin defines global as
+ // SymbolTable. If we had DOT this would not be an issue
+ import global._ // the global environment
+ import definitions._ // standard classes and methods
+ import CODE._
+
+ val phaseName: String = "patmat"
+
+ def newTransformer(unit: CompilationUnit): Transformer =
+ if (opt.virtPatmat) new MatchTransformer(unit)
+ else noopTransformer
+
+ // duplicated from CPSUtils (avoid dependency from compiler -> cps plugin...)
+ private lazy val MarkerCPSAdaptPlus = definitions.getClassIfDefined("scala.util.continuations.cpsPlus")
+ private lazy val MarkerCPSAdaptMinus = definitions.getClassIfDefined("scala.util.continuations.cpsMinus")
+ private lazy val MarkerCPSSynth = definitions.getClassIfDefined("scala.util.continuations.cpsSynth")
+ private lazy val stripTriggerCPSAnns = List(MarkerCPSSynth, MarkerCPSAdaptMinus, MarkerCPSAdaptPlus)
+ private lazy val MarkerCPSTypes = definitions.getClassIfDefined("scala.util.continuations.cpsParam")
+ private lazy val strippedCPSAnns = MarkerCPSTypes :: stripTriggerCPSAnns
+ private def removeCPSAdaptAnnotations(tp: Type) = tp filterAnnotations (ann => !(strippedCPSAnns exists (ann matches _)))
+
+ class MatchTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
+ override def transform(tree: Tree): Tree = tree match {
+ case Match(sel, cases) =>
+ val selX = transform(sel)
+ val casesX = transformTrees(cases).asInstanceOf[List[CaseDef]]
+
+ val origTp = tree.tpe
+ val matchX = treeCopy.Match(tree, selX, casesX)
+
+ // when one of the internal cps-type-state annotations is present, strip all CPS annotations
+ // a cps-type-state-annotated type makes no sense as an expected type (matchX.tpe is used as pt in translateMatch)
+ // (only test availability of MarkerCPSAdaptPlus assuming they are either all available or none of them are)
+ if (MarkerCPSAdaptPlus != NoSymbol && (stripTriggerCPSAnns exists tree.tpe.hasAnnotation))
+ matchX modifyType removeCPSAdaptAnnotations
+
+ localTyper.typed(translator.translateMatch(matchX)) setType origTp
+ case Try(block, catches, finalizer) =>
+ treeCopy.Try(tree, transform(block), translator.translateTry(transformTrees(catches).asInstanceOf[List[CaseDef]], tree.tpe, tree.pos), transform(finalizer))
+ case _ => super.transform(tree)
+ }
+
+ def translator: MatchTranslation with CodegenCore = {
+ new OptimizingMatchTranslator(localTyper)
+ }
+ }
+
import definitions._
+ import analyzer._ //Typer
val SYNTH_CASE = Flags.CASE | SYNTHETIC
- object TranslatedMatchAttachment
case class DefaultOverrideMatchAttachment(default: Tree)
object vpmName {
@@ -54,22 +106,6 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
def counted(str: String, i: Int) = newTermName(str+i)
}
- object MatchTranslator {
- def apply(typer: Typer): MatchTranslation with CodegenCore = {
- import typer._
- // typing `_match` to decide which MatchTranslator to create adds 4% to quick.comp.timer
- val matchStrategy: Tree = (
- if (!context.isNameInScope(vpmName._match)) null // fast path, avoiding the next line if there's no __match to be seen
- else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) match {
- case SilentResultValue(ms) => ms
- case _ => null
- }
- )
- if (matchStrategy eq null) new OptimizingMatchTranslator(typer)
- else new PureMatchTranslator(typer, matchStrategy)
- }
- }
-
class PureMatchTranslator(val typer: Typer, val matchStrategy: Tree) extends MatchTranslation with TreeMakers with PureCodegen
class OptimizingMatchTranslator(val typer: Typer) extends MatchTranslation with TreeMakers with MatchOptimizations
@@ -255,7 +291,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
val pos = patTree.pos
def translateExtractorPattern(extractor: ExtractorCall): TranslationStep = {
- if (!extractor.isTyped) throw new TypeError(pos, "Could not typecheck extractor call: "+ extractor)
+ if (!extractor.isTyped) ErrorUtils.issueNormalTypeError(patTree, "Could not typecheck extractor call: "+ extractor)(context)
// if (extractor.resultInMonad == ErrorType) throw new TypeError(pos, "Unsupported extractor type: "+ extractor.tpe)
// must use type `tp`, which is provided by extractor's result, not the type expected by binder,
@@ -320,7 +356,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
**/
case Apply(fun, args) =>
ExtractorCall.fromCaseClass(fun, args) map translateExtractorPattern getOrElse {
- error("cannot find unapply member for "+ fun +" with args "+ args)
+ ErrorUtils.issueNormalTypeError(patTree, "Could not find unapply member for "+ fun +" with args "+ args)(context)
noFurtherSubPats()
}
@@ -576,18 +612,29 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
ProductExtractorTreeMaker(binder, lengthGuard(binder), Substitution(subPatBinders, subPatRefs(binder)))
}
-/* TODO: remove special case when the following bug is fixed
-class Foo(x: Other) { x._1 } // BUG: can't refer to _1 if its defining class has not been type checked yet
-case class Other(y: String)
--- this is ok:
-case class Other(y: String)
-class Foo(x: Other) { x._1 } // no error in this order
-*/
+ // reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
override protected def tupleSel(binder: Symbol)(i: Int): Tree = { import CODE._
- // reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
- val caseAccs = binder.info.typeSymbol.caseFieldAccessors
- if (caseAccs isDefinedAt (i-1)) REF(binder) DOT caseAccs(i-1)
- else codegen.tupleSel(binder)(i)
+ // caseFieldAccessors is messed up after typers (reversed, names mangled for non-public fields)
+ // TODO: figure out why...
+ val accessors = binder.caseFieldAccessors
+ // luckily, the constrParamAccessors are still sorted properly, so sort the field-accessors using them
+ // (need to undo name-mangling, including the sneaky trailing whitespace)
+ val constrParamAccessors = binder.constrParamAccessors
+
+ def indexInCPA(acc: Symbol) =
+ constrParamAccessors indexWhere { orig =>
+ // println("compare: "+ (orig, acc, orig.name, acc.name, (acc.name == orig.name), (acc.name startsWith (orig.name append "$"))))
+ val origName = orig.name.toString.trim
+ val accName = acc.name.toString.trim
+ (accName == origName) || (accName startsWith (origName + "$"))
+ }
+
+ // println("caseFieldAccessors: "+ (accessors, binder.caseFieldAccessors map indexInCPA))
+ // println("constrParamAccessors: "+ constrParamAccessors)
+
+ val accessorsSorted = accessors sortBy indexInCPA
+ if (accessorsSorted isDefinedAt (i-1)) REF(binder) DOT accessorsSorted(i-1)
+ else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN
}
override def toString(): String = "case class "+ (if (constructorTp eq null) fun else paramType.typeSymbol) +" with arguments "+ args
@@ -1610,7 +1657,7 @@ class Foo(x: Other) { x._1 } // no error in this order
else (REF(scrutSym) DOT (nme.toInt))
Some(BLOCK(
VAL(scrutSym) === scrut,
- Match(scrutToInt, caseDefsWithDefault) withAttachment TranslatedMatchAttachment // add switch annotation
+ Match(scrutToInt, caseDefsWithDefault) // a switch
))
}
} else None
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 31d064c824..57e82ed706 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -299,6 +299,7 @@ trait SyntheticMethods extends ast.TreeDSL {
newAcc resetFlag (ACCESSOR | PARAMACCESSOR)
ddef.rhs.duplicate
}
+ // TODO: shouldn't the next line be: `original resetFlag CASEACCESSOR`?
ddef.symbol resetFlag CASEACCESSOR
lb += logResult("case accessor new")(newAcc)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 553cafe966..b827f2ac1a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -26,12 +26,14 @@ import util.Statistics._
* @author Martin Odersky
* @version 1.0
*/
-trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser {
+trait Typers extends Modes with Adaptations with Taggings {
self: Analyzer =>
import global._
import definitions._
+ import patmat.DefaultOverrideMatchAttachment
+
final def forArgMode(fun: Tree, mode: Int) =
if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode
else mode
@@ -83,8 +85,11 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
private def isPastTyper = phase.id > currentRun.typerPhase.id
- // don't translate matches in presentation compiler: it loses vital symbols that are needed to do hyperlinking
- @inline private def doMatchTranslation = !forInteractive && opt.virtPatmat && (phase.id < currentRun.uncurryPhase.id)
+ // when true:
+ // - we may virtualize matches (if -Xexperimental and there's a suitable __match in scope)
+ // - we synthesize PartialFunction implementations for `x => x match {...}` and `match {...}` when the expected type is PartialFunction
+ // this is disabled by: -Xoldpatmat, scaladoc or interactive compilation
+ @inline private def newPatternMatching = opt.virtPatmat && !forScaladoc && !forInteractive // && (phase.id < currentRun.uncurryPhase.id)
abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tagging with TyperContextErrors {
import context0.unit
@@ -2226,19 +2231,43 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
treeCopy.Match(tree, selector1, casesAdapted) setType resTp
}
- // match has been typed, now translate it
- def translatedMatch(match_ : Match) = MatchTranslator(this).translateMatch(match_)
+ // match has been typed -- virtualize it if we're feeling experimental
+ // (virtualized matches are expanded during type checking so they have the full context available)
+ // otherwise, do nothing: matches are translated during phase `patmat` (unless -Xoldpatmat)
+ def virtualizedMatch(match_ : Match, mode: Int, pt: Type) = {
+ import patmat.{vpmName, PureMatchTranslator, OptimizingMatchTranslator}
+
+ // TODO: add fallback __match sentinel to predef
+ val matchStrategy: Tree =
+ if (!(newPatternMatching && opt.experimental && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen
+ else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) match {
+ case SilentResultValue(ms) => ms
+ case _ => null
+ }
- // synthesize and type check a (Partial)Function implementation based on a match specified by `cases`
- // Match(EmptyTree, cases) ==> new <Partial>Function { def apply<OrElse>(params) = `translateMatch('`(param1,...,paramN)` match { cases }')` }
+ if (matchStrategy ne null) // virtualize
+ typed((new PureMatchTranslator(this.asInstanceOf[patmat.global.analyzer.Typer] /*TODO*/, matchStrategy)).translateMatch(match_), mode, pt)
+ else
+ match_ // will be translated in phase `patmat`
+ }
+
+ // synthesize and type check a PartialFunction implementation based on a match specified by `cases`
+ // Match(EmptyTree, cases) ==> new PartialFunction { def apply<OrElse>(params) = `translateMatch('`(param1,...,paramN)` match { cases }')` }
// for fresh params, the selector of the match we'll translated simply gathers those in a tuple
+ // NOTE: restricted to PartialFunction -- leave Function trees if the expected type does not demand a partial function
class MatchFunTyper(tree: Tree, cases: List[CaseDef], mode: Int, pt0: Type) {
+ // TODO: remove FunctionN support -- this is currently designed so that it can emit FunctionN and PartialFunction subclasses
+ // however, we should leave Function nodes until Uncurry so phases after typer can still detect normal Function trees
+ // we need to synthesize PartialFunction impls, though, to avoid nastiness in Uncurry in transforming&duplicating generated pattern matcher trees
+ // TODO: remove PartialFunction support from UnCurry
private val pt = deskolemizeGADTSkolems(pt0)
private val targs = pt.normalize.typeArgs
private val arity = if (isFunctionType(pt)) targs.length - 1 else 1 // TODO pt should always be a (Partial)Function, right?
private val ptRes = if (targs.isEmpty) WildcardType else targs.last // may not be fully defined
private val isPartial = pt.typeSymbol == PartialFunctionClass
+ assert(isPartial)
+
private val anonClass = context.owner.newAnonymousFunctionClass(tree.pos)
private val funThis = This(anonClass)
@@ -2291,7 +2320,7 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
methodSym setInfoAndEnter MethodType(paramSyms, resTp)
- DefDef(methodSym, methodBodyTyper.translatedMatch(match_))
+ DefDef(methodSym, methodBodyTyper.virtualizedMatch(match_, mode, pt))
}
}
@@ -2330,7 +2359,7 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
match_ setType B1.tpe
// the default uses applyOrElse's first parameter since the scrut's type has been widened
- val body = methodBodyTyper.translatedMatch(match_ withAttachment DefaultOverrideMatchAttachment(REF(default) APPLY (REF(x))))
+ val body = methodBodyTyper.virtualizedMatch(match_ withAttachment DefaultOverrideMatchAttachment(REF(default) APPLY (REF(x))), mode, pt)
DefDef(methodSym, body)
}
@@ -2348,13 +2377,13 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe)
val match_ = methodBodyTyper.typedMatch(selector, casesTrue, mode, BooleanClass.tpe)
- val body = methodBodyTyper.translatedMatch(match_ withAttachment DefaultOverrideMatchAttachment(FALSE_typed))
+ val body = methodBodyTyper.virtualizedMatch(match_ withAttachment DefaultOverrideMatchAttachment(FALSE_typed), mode, pt)
DefDef(methodSym, body)
}
}
- val members = if (isPartial) {
+ lazy val members = if (isPartial) {
// somehow @cps annotations upset the typer when looking at applyOrElse's signature, but not apply's
// TODO: figure out the details (T @cps[U] is not a subtype of Any, but then why does it work for the apply method?)
if (targs forall (_ <:< AnyClass.tpe)) List(applyOrElseMethodDef, isDefinedAtMethod)
@@ -2433,7 +2462,7 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
fun.body match {
// later phase indicates scaladoc is calling (where shit is messed up, I tell you)
// -- so fall back to old patmat, which is more forgiving
- case Match(sel, cases) if (sel ne EmptyTree) && doMatchTranslation =>
+ case Match(sel, cases) if (sel ne EmptyTree) && newPatternMatching && (pt.typeSymbol == PartialFunctionClass) =>
// go to outer context -- must discard the context that was created for the Function since we're discarding the function
// thus, its symbol, which serves as the current context.owner, is not the right owner
// you won't know you're using the wrong owner until lambda lift crashes (unless you know better than to use the wrong owner)
@@ -3823,11 +3852,13 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
}
}
- def typedTranslatedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree =
+ // under -Xexperimental (and not -Xoldpatmat), and when there's a suitable __match in scope, virtualize the pattern match
+ // otherwise, type the Match and leave it until phase `patmat` (immediately after typer)
+ // empty-selector matches are transformed into synthetic PartialFunction implementations when the expected type demands it
+ def typedVirtualizedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree =
if (selector == EmptyTree) {
- if (doMatchTranslation) (new MatchFunTyper(tree, cases, mode, pt)).translated
+ if (newPatternMatching && (pt.typeSymbol == PartialFunctionClass)) (new MatchFunTyper(tree, cases, mode, pt)).translated
else {
- if (opt.virtPatmat) debugwarn("virtpatmat should not encounter empty-selector matches "+ tree)
val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1
val params = for (i <- List.range(0, arity)) yield
atPos(tree.pos.focusStart) {
@@ -3839,12 +3870,8 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
val body = treeCopy.Match(tree, selector1, cases)
typed1(atPos(tree.pos) { Function(params, body) }, mode, pt)
}
- } else {
- if (!doMatchTranslation || (tree firstAttachment {case TranslatedMatchAttachment => } nonEmpty))
- typedMatch(selector, cases, mode, pt, tree)
- else
- typed(translatedMatch(typedMatch(selector, cases, mode, pt, tree)), mode, pt)
- }
+ } else
+ virtualizedMatch(typedMatch(selector, cases, mode, pt, tree), mode, pt)
def typedReturn(expr: Tree) = {
val enclMethod = context.enclMethod
@@ -4686,7 +4713,7 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
typedIf(cond, thenp, elsep)
case tree @ Match(selector, cases) =>
- typedTranslatedMatch(tree, selector, cases)
+ typedVirtualizedMatch(tree, selector, cases)
case Return(expr) =>
typedReturn(expr)
@@ -4702,9 +4729,6 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
catches1 = catches1 map (adaptCase(_, mode, owntype))
}
- if (doMatchTranslation)
- catches1 = (MatchTranslator(this)).translateTry(catches1, owntype, tree.pos)
-
treeCopy.Try(tree, block1, catches1, finalizer1) setType owntype
case Throw(expr) =>
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index bed8e93d1b..862b19d0a4 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -3,8 +3,9 @@
package scala.tools.selectivecps
import scala.tools.nsc.Global
+import scala.tools.nsc.typechecker.Modes
-abstract class CPSAnnotationChecker extends CPSUtils {
+abstract class CPSAnnotationChecker extends CPSUtils with Modes {
val global: Global
import global._
import definitions._
@@ -177,59 +178,38 @@ abstract class CPSAnnotationChecker extends CPSUtils {
override def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = {
if (!cpsEnabled) return tree
- vprintln("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
+ vprintln("adapt annotations " + tree + " / " + tree.tpe + " / " + modeString(mode) + " / " + pt)
- val annots1 = cpsParamAnnotation(tree.tpe)
- val annots2 = cpsParamAnnotation(pt)
+ val patMode = (mode & global.analyzer.PATTERNmode) != 0
+ val exprMode = (mode & global.analyzer.EXPRmode) != 0
+ val byValMode = (mode & global.analyzer.BYVALmode) != 0
- if ((mode & global.analyzer.PATTERNmode) != 0) {
- if (!annots1.isEmpty) {
- return tree modifyType removeAllCPSAnnotations
- }
- }
+ val annotsTree = cpsParamAnnotation(tree.tpe)
+ val annotsExpected = cpsParamAnnotation(pt)
-/*
+ // not sure I rephrased this comment correctly:
+ // replacing `patMode` in the condition below by `patMode || ((mode & global.analyzer.TYPEmode) != 0 && (mode & global.analyzer.BYVALmode))`
// doesn't work correctly -- still relying on addAnnotations to remove things from ValDef symbols
- if ((mode & global.analyzer.TYPEmode) != 0 && (mode & global.analyzer.BYVALmode) != 0) {
- if (!annots1.isEmpty) {
- println("removing annotation from " + tree + "/" + tree.tpe)
- val s = tree.setType(removeAllCPSAnnotations(tree.tpe))
- println(s)
- s
- }
- }
-*/
-
- if ((mode & global.analyzer.EXPRmode) != 0) {
- if (annots1.isEmpty && !annots2.isEmpty && ((mode & global.analyzer.BYVALmode) == 0)) { // shiftUnit
- // add a marker annotation that will make tree.tpe behave as pt, subtyping wise
- // tree will look like having any possible annotation
- //println("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
- //val same = annots2 forall { case AnnotationInfo(atp: TypeRef, _, _) => atp.typeArgs(0) =:= atp.typeArgs(1) }
- // TBD: use same or not? see infer0.scala/infer1.scala
-
- // CAVEAT:
- // for monomorphic answer types we want to have @plus @cps (for better checking)
- // for answer type modification we want to have only @plus (because actual answer type may differ from pt)
-
- //val known = global.analyzer.isFullyDefined(pt)
-
- if (/*same &&*/ !hasPlusMarker(tree.tpe)) {
- //if (known)
- return tree modifyType (_ withAnnotations newPlusMarker() :: annots2) // needed for #1807
- //else
- // return tree.setType(tree.tpe.withAnnotations(adapt::Nil))
- }
- tree
- } else if (!annots1.isEmpty && ((mode & global.analyzer.BYVALmode) != 0)) { // dropping annotation
- // add a marker annotation that will make tree.tpe behave as pt, subtyping wise
- // tree will look like having no annotation
- if (!hasMinusMarker(tree.tpe)) {
- return tree modifyType addMinusMarker
- }
- }
- }
- tree
+ if (patMode && !annotsTree.isEmpty) tree modifyType removeAllCPSAnnotations
+ else if (exprMode && !byValMode && !hasPlusMarker(tree.tpe) && annotsTree.isEmpty && annotsExpected.nonEmpty) { // shiftUnit
+ // add a marker annotation that will make tree.tpe behave as pt, subtyping wise
+ // tree will look like having any possible annotation
+ //println("adapt annotations " + tree + " / " + tree.tpe + " / " + Integer.toHexString(mode) + " / " + pt)
+
+ // CAVEAT:
+ // for monomorphic answer types we want to have @plus @cps (for better checking)
+ // for answer type modification we want to have only @plus (because actual answer type may differ from pt)
+
+ val res = tree modifyType (_ withAnnotations newPlusMarker() :: annotsExpected) // needed for #1807
+ vprintln("adapted annotations (not by val) of " + tree + " to " + res.tpe)
+ res
+ } else if (exprMode && byValMode && !hasMinusMarker(tree.tpe) && annotsTree.nonEmpty) { // dropping annotation
+ // add a marker annotation that will make tree.tpe behave as pt, subtyping wise
+ // tree will look like having no annotation
+ val res = tree modifyType addMinusMarker
+ vprintln("adapted annotations (by val) of " + tree + " to " + res.tpe)
+ res
+ } else tree
}
def updateAttributesFromChildren(tpe: Type, childAnnots: List[AnnotationInfo], byName: List[Tree]): Type = {
@@ -454,11 +434,10 @@ abstract class CPSAnnotationChecker extends CPSUtils {
transChildrenInOrder(tree, tpe, List(cond), List(thenp, elsep))
case Match(select, cases) =>
- // TODO: can there be cases that are not CaseDefs?? check collect vs map!
- transChildrenInOrder(tree, tpe, List(select), cases:::(cases collect { case CaseDef(_, _, body) => body }))
+ transChildrenInOrder(tree, tpe, List(select), cases:::(cases map { case CaseDef(_, _, body) => body }))
case Try(block, catches, finalizer) =>
- val tpe1 = transChildrenInOrder(tree, tpe, Nil, block::catches:::(catches collect { case CaseDef(_, _, body) => body }))
+ val tpe1 = transChildrenInOrder(tree, tpe, Nil, block::catches:::(catches map { case CaseDef(_, _, body) => body }))
val annots = cpsParamAnnotation(tpe1)
if (annots.nonEmpty) {
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
index e1d699debc..e9e9cf0fab 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
@@ -241,6 +241,8 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
// where D$idef = def L$i(..) = {L$i.body; L${i+1}(..)}
case ldef @ LabelDef(name, params, rhs) =>
+ // println("trans LABELDEF "+(name, params, tree.tpe, hasAnswerTypeAnn(tree.tpe)))
+ // TODO why does the labeldef's type have a cpsMinus annotation, whereas the rhs does not? (BYVALmode missing/too much somewhere?)
if (hasAnswerTypeAnn(tree.tpe)) {
// currentOwner.newMethod(name, tree.pos, Flags.SYNTHETIC) setInfo ldef.symbol.info
val sym = ldef.symbol resetFlag Flags.LABEL
@@ -456,10 +458,11 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
val (anfStats, anfExpr) = rec(stms, cpsA, List())
// println("\nanf-block:\n"+ ((stms :+ expr) mkString ("{", "\n", "}")) +"\nBECAME\n"+ ((anfStats :+ anfExpr) mkString ("{", "\n", "}")))
-
+ // println("synth case? "+ (anfStats map (t => (t, t.isDef, gen.hasSynthCaseSymbol(t)))))
// SUPER UGLY HACK: handle virtpatmat-style matches, whose labels have already been turned into DefDefs
if (anfStats.nonEmpty && (anfStats forall (t => !t.isDef || gen.hasSynthCaseSymbol(t)))) {
val (prologue, rest) = (anfStats :+ anfExpr) span (s => !s.isInstanceOf[DefDef]) // find first case
+ // println("rest: "+ rest)
// val (defs, calls) = rest partition (_.isInstanceOf[DefDef])
if (rest nonEmpty){
// the filter drops the ()'s emitted when transValue encountered a LabelDef
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
index a78de8e6c8..dcb7cd601f 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
@@ -65,6 +65,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with
class CPSTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
+ private val patmatTransformer = patmat.newTransformer(unit)
override def transform(tree: Tree): Tree = {
if (!cpsEnabled) return tree
@@ -212,7 +213,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with
val catch2 = localTyper.typedCases(List(catchIfDefined), ThrowableClass.tpe, targettp)
//typedCases(tree, catches, ThrowableClass.tpe, pt)
- localTyper.typed(Block(List(funDef), treeCopy.Try(tree, treeCopy.Block(block1, stms, expr2), catch2, finalizer1)))
+ patmatTransformer.transform(localTyper.typed(Block(List(funDef), treeCopy.Try(tree, treeCopy.Block(block1, stms, expr2), catch2, finalizer1))))
/*