summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
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 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
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
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala74
1 files changed, 49 insertions, 25 deletions
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) =>