summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2012-04-30 13:35:06 +0200
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-05-02 12:30:30 +0200
commit1b8dc120dd156e34e43132134dfa1f228cd1f497 (patch)
treedf4d7470be30a64af9ed073fd8fc411dc9f8d98f
parentbc860f3a31db8b6f37c9931f2bf4712fed06d486 (diff)
downloadscala-1b8dc120dd156e34e43132134dfa1f228cd1f497.tar.gz
scala-1b8dc120dd156e34e43132134dfa1f228cd1f497.tar.bz2
scala-1b8dc120dd156e34e43132134dfa1f228cd1f497.zip
moving patmat to its own phase
sort field accessors, necessary after typers -- apparently... don't throw TypeError, use issueTypeError don't run patmat phase when -Xoldpatmat only virtualize matches when -Xexperimental recycle cps type of match for re-typechecking: 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) don't synth FunctionN impls during typer, only do this for PartialFunction updated check now function synth for match is deferred until uncurry patmat-transform try/catch with match in cps cleanup in selective anf remove TODO: can there be cases that are not CaseDefs -- nope
-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
-rw-r--r--test/files/neg/gadts1.check5
-rw-r--r--test/files/neg/patmat-type-check.check14
-rw-r--r--test/files/neg/t0418.check5
-rw-r--r--test/files/neg/t112706A.check5
-rw-r--r--test/files/neg/t3392.check5
-rw-r--r--test/files/neg/t418.check5
-rw-r--r--test/files/neg/t4515.check4
-rw-r--r--test/files/neg/t5589neg.check5
-rw-r--r--test/files/run/inner-parse.check1
-rw-r--r--test/files/run/programmatic-main.check47
-rw-r--r--test/files/run/virtpatmat_staging.flags2
19 files changed, 222 insertions, 182 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))))
/*
diff --git a/test/files/neg/gadts1.check b/test/files/neg/gadts1.check
index 0441f604c9..44d2b114d6 100644
--- a/test/files/neg/gadts1.check
+++ b/test/files/neg/gadts1.check
@@ -11,7 +11,4 @@ gadts1.scala:20: error: type mismatch;
required: a
case Cell[a](x: Int) => c.x = 5
^
-gadts1.scala:20: error: Could not typecheck extractor call: case class <none> with arguments List((x @ (_: Int)))
- case Cell[a](x: Int) => c.x = 5
- ^
-four errors found
+three errors found
diff --git a/test/files/neg/patmat-type-check.check b/test/files/neg/patmat-type-check.check
index ab4451f089..e045841ce1 100644
--- a/test/files/neg/patmat-type-check.check
+++ b/test/files/neg/patmat-type-check.check
@@ -3,31 +3,19 @@ patmat-type-check.scala:22: error: scrutinee is incompatible with pattern type;
required: String
def f1 = "bob".reverse match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:22: error: value _1 is not a member of object Seq
- def f1 = "bob".reverse match { case Seq('b', 'o', 'b') => true } // fail
- ^
patmat-type-check.scala:23: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: Array[Char]
def f2 = "bob".toArray match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:23: error: value _1 is not a member of object Seq
- def f2 = "bob".toArray match { case Seq('b', 'o', 'b') => true } // fail
- ^
patmat-type-check.scala:27: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: Test.Bop2
def f3(x: Bop2) = x match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:27: error: value _1 is not a member of object Seq
- def f3(x: Bop2) = x match { case Seq('b', 'o', 'b') => true } // fail
- ^
patmat-type-check.scala:30: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: Test.Bop3[Char]
def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail
^
-patmat-type-check.scala:30: error: value _1 is not a member of object Seq
- def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail
- ^
-8 errors found
+four errors found
diff --git a/test/files/neg/t0418.check b/test/files/neg/t0418.check
index 50931a1bca..4e9ad2f9ae 100644
--- a/test/files/neg/t0418.check
+++ b/test/files/neg/t0418.check
@@ -4,7 +4,4 @@ t0418.scala:2: error: not found: value Foo12340771
t0418.scala:2: error: not found: value x
null match { case Foo12340771.Bar(x) => x }
^
-t0418.scala:2: error: Could not typecheck extractor call: case class <none> with arguments List((x @ _))
- null match { case Foo12340771.Bar(x) => x }
- ^
-three errors found
+two errors found
diff --git a/test/files/neg/t112706A.check b/test/files/neg/t112706A.check
index fb18b31be1..30d0c3ec91 100644
--- a/test/files/neg/t112706A.check
+++ b/test/files/neg/t112706A.check
@@ -3,7 +3,4 @@ t112706A.scala:5: error: constructor cannot be instantiated to expected type;
required: String
case Tuple2(node,_) =>
^
-t112706A.scala:5: error: Could not typecheck extractor call: case class Tuple2 with arguments List((node @ _), _)
- case Tuple2(node,_) =>
- ^
-two errors found
+one error found
diff --git a/test/files/neg/t3392.check b/test/files/neg/t3392.check
index 3a39098c4e..842d63eec9 100644
--- a/test/files/neg/t3392.check
+++ b/test/files/neg/t3392.check
@@ -1,7 +1,4 @@
t3392.scala:9: error: not found: value x
case x@A(x/*<-- refers to the pattern that includes this comment*/.Ex(42)) =>
^
-t3392.scala:9: error: Could not typecheck extractor call: case class <none> with arguments List(42)
- case x@A(x/*<-- refers to the pattern that includes this comment*/.Ex(42)) =>
- ^
-two errors found
+one error found
diff --git a/test/files/neg/t418.check b/test/files/neg/t418.check
index c06088ba9d..1489547823 100644
--- a/test/files/neg/t418.check
+++ b/test/files/neg/t418.check
@@ -4,7 +4,4 @@ t418.scala:2: error: not found: value Foo12340771
t418.scala:2: error: not found: value x
null match { case Foo12340771.Bar(x) => x }
^
-t418.scala:2: error: Could not typecheck extractor call: case class <none> with arguments List((x @ _))
- null match { case Foo12340771.Bar(x) => x }
- ^
-three errors found
+two errors found
diff --git a/test/files/neg/t4515.check b/test/files/neg/t4515.check
index 856d252a0f..a60d16295f 100644
--- a/test/files/neg/t4515.check
+++ b/test/files/neg/t4515.check
@@ -1,6 +1,6 @@
t4515.scala:37: error: type mismatch;
- found : _0(in method apply) where type _0(in method apply)
- required: (some other)_0(in method apply)
+ found : _0(in value $anonfun) where type _0(in value $anonfun)
+ required: (some other)_0(in value $anonfun)
handler.onEvent(target, ctx.getEvent, node, ctx)
^
one error found
diff --git a/test/files/neg/t5589neg.check b/test/files/neg/t5589neg.check
index fb6858a397..b3ff16d7e4 100644
--- a/test/files/neg/t5589neg.check
+++ b/test/files/neg/t5589neg.check
@@ -22,9 +22,6 @@ t5589neg.scala:4: error: constructor cannot be instantiated to expected type;
t5589neg.scala:4: error: not found: value y2
def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2))
^
-t5589neg.scala:4: error: Could not typecheck extractor call: case class Tuple1 with arguments List((y2 @ _))
- def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2))
- ^
t5589neg.scala:5: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (String, Int)
@@ -37,4 +34,4 @@ t5589neg.scala:5: error: not found: value y2
def f8(x: Either[Int, (String, Int)]) = for ((y1, y2, y3) <- x.right) yield ((y1, y2))
^
two warnings found
-8 errors found
+7 errors found
diff --git a/test/files/run/inner-parse.check b/test/files/run/inner-parse.check
index 87ea9ddeb5..e4a30714bd 100644
--- a/test/files/run/inner-parse.check
+++ b/test/files/run/inner-parse.check
@@ -5,6 +5,7 @@ class Test$$anonfun$main$1 extends scala.runtime.AbstractFunction1$mcVL$sp
descriptor <clinit> ()V
descriptor apply (Lscala/Tuple2;)V
descriptor apply (Ljava/lang/Object;)Ljava/lang/Object;
+ descriptor apply (Ljava/lang/Object;)V
descriptor cwd$1 Ljava/lang/String;
descriptor serialVersionUID J
descriptor <init> (Ljava/lang/String;)V
diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check
index d16e2c5178..bdf76ddce1 100644
--- a/test/files/run/programmatic-main.check
+++ b/test/files/run/programmatic-main.check
@@ -4,27 +4,28 @@
namer 2 resolve names, attach symbols to named trees
packageobjects 3 load package objects
typer 4 the meat and potatoes: type the trees
- superaccessors 5 add super accessors in traits and nested classes
- extmethods 6 add extension methods for inline classes
- pickler 7 serialize symbol tables
- refchecks 8 reference/override checking, translate nested objects
- uncurry 9 uncurry, translate function values to anonymous classes
- tailcalls 10 replace tail calls by jumps
- specialize 11 @specialized-driven class and method specialization
- explicitouter 12 this refs to outer pointers, translate patterns
- erasure 13 erase types, add interfaces for traits
- posterasure 14 clean up erased inline classes
- lazyvals 15 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 16 move nested functions to top level
- constructors 17 move field definitions into constructors
- flatten 18 eliminate inner classes
- mixin 19 mixin composition
- cleanup 20 platform-specific cleanups, generate reflective calls
- icode 21 generate portable intermediate code
- inliner 22 optimization: do inlining
-inlineExceptionHandlers 23 optimization: inline exception handlers
- closelim 24 optimization: eliminate uncalled closures
- dce 25 optimization: eliminate dead code
- jvm 26 generate JVM bytecode
- terminal 27 The last phase in the compiler chain
+ patmat 5 translate match expressions
+ superaccessors 6 add super accessors in traits and nested classes
+ extmethods 7 add extension methods for inline classes
+ pickler 8 serialize symbol tables
+ refchecks 9 reference/override checking, translate nested objects
+ uncurry 10 uncurry, translate function values to anonymous classes
+ tailcalls 11 replace tail calls by jumps
+ specialize 12 @specialized-driven class and method specialization
+ explicitouter 13 this refs to outer pointers, translate patterns
+ erasure 14 erase types, add interfaces for traits
+ posterasure 15 clean up erased inline classes
+ lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
+ lambdalift 17 move nested functions to top level
+ constructors 18 move field definitions into constructors
+ flatten 19 eliminate inner classes
+ mixin 20 mixin composition
+ cleanup 21 platform-specific cleanups, generate reflective calls
+ icode 22 generate portable intermediate code
+ inliner 23 optimization: do inlining
+inlineExceptionHandlers 24 optimization: inline exception handlers
+ closelim 25 optimization: eliminate uncalled closures
+ dce 26 optimization: eliminate dead code
+ jvm 27 generate JVM bytecode
+ terminal 28 The last phase in the compiler chain
diff --git a/test/files/run/virtpatmat_staging.flags b/test/files/run/virtpatmat_staging.flags
index 3f5a3100e4..48fd867160 100644
--- a/test/files/run/virtpatmat_staging.flags
+++ b/test/files/run/virtpatmat_staging.flags
@@ -1 +1 @@
- -Xexperimental
+-Xexperimental