summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2012-03-29 10:50:15 +0200
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-03-30 09:19:03 +0200
commit118aef558fb71a79ddf0c7603aba462a92fffd21 (patch)
treec0f0bc003487d78a8f69318bdc138d730455a372
parent383d28daa161e46843fd99494f5c6fbc3e622fec (diff)
downloadscala-118aef558fb71a79ddf0c7603aba462a92fffd21.tar.gz
scala-118aef558fb71a79ddf0c7603aba462a92fffd21.tar.bz2
scala-118aef558fb71a79ddf0c7603aba462a92fffd21.zip
virtpatmat support for the new partialfunction
avoid casting default call in applyOrElse: the result type of the match is always B1, not the result type inferred from typing the cases
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala67
1 files changed, 54 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index aed29f27b5..a9c9dfab6a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2186,17 +2186,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
anonClass addAnnotation serialVersionUIDAnnotation
- def mkParams(methodSym: Symbol) = {
+ def deriveFormals =
+ selOverride match {
+ case None if targs.isEmpty => Nil
+ case None => targs.init // is there anything we can do if targs.isEmpty??
+ case Some((vparams, _)) =>
+ vparams map {p => if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe}
+ }
+
+ def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = {
selOverride match {
case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree)
case None =>
- val ps = methodSym newSyntheticValueParams targs.init // is there anything we can do if targs.isEmpty??
+ val ps = methodSym newSyntheticValueParams formals // is there anything we can do if targs.isEmpty??
val ids = ps map (p => Ident(p.name))
val sel = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) }
(ps, sel)
case Some((vparams, sel)) =>
- val newParamSyms = vparams map {p =>
- val tp = if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe
+ val newParamSyms = (vparams, formals).zipped map {(p, tp) =>
methodSym.newValueParameter(p.name, focusPos(p.pos), SYNTHETIC) setInfo tp
}
@@ -2209,7 +2216,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// need to duplicate the cases before typing them to generate the apply method, or the symbols will be all messed up
val casesTrue = if (isPartial) cases map (c => deriveCaseDef(c)(x => TRUE_typed).duplicate) else Nil
- val applyMethod = {
+ def applyMethod = {
// rig the show so we can get started typing the method body -- later we'll correct the infos...
anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass)
val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL)
@@ -2224,18 +2231,52 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
- val formalTypes = paramSyms map (_.tpe)
- val parents =
- if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe)
- else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe)
+ val methFormals = paramSyms map (_.tpe)
+ val parents = List(appliedType(AbstractFunctionClass(arity).typeConstructor, methFormals :+ resTp), SerializableClass.tpe)
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
methodSym setInfoAndEnter MethodType(paramSyms, resTp)
- // use apply's parameter since the scrut's type has been widened
- def missingCase(scrut_ignored: Tree) = (funThis DOT newTermName("missingCase")) (REF(paramSyms.head))
+ DefDef(methodSym, methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation))
+ }
+ }
+
+ // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ def applyOrElseMethodDef = {
+ // rig the show so we can get started typing the method body -- later we'll correct the infos...
+ // targs were type arguments for PartialFunction, so we know they will work for AbstractPartialFunction as well
+ def parents(targs: List[Type]) = List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe)
+
+ anonClass setInfo ClassInfoType(parents(targs), newScope, anonClass)
+ val methodSym = anonClass.newMethod(nme.applyOrElse, tree.pos, FINAL | OVERRIDE)
+
+ // create the parameter that corresponds to the function's parameter
+ val List(argTp) = deriveFormals
+ val A1 = methodSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argTp)
+ val (List(x), selector) = mkParams(methodSym, List(A1.tpe))
+
+ if (selector eq EmptyTree) EmptyTree
+ else {
+ // applyOrElse's default parameter:
+ val B1 = methodSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.empty //lower(resTp)
+ val default = methodSym newValueParameter(newTermName("default"), focusPos(tree.pos), SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe)
+
+ val paramSyms = List(x, default)
+ methodSym setInfoAndEnter polyType(List(A1, B1), MethodType(paramSyms, B1.tpe))
+
+ val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it)
+ paramSyms foreach (methodBodyTyper.context.scope enter _)
+
+ val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes)
+
+ anonClass setInfo ClassInfoType(parents(List(argTp, resTp)), newScope, anonClass)
+ B1 setInfo TypeBounds.lower(resTp)
+ anonClass.info.decls enter methodSym // methodSym's info need not change (B1's bound has been updated instead)
+
+ // use applyOrElse's first parameter since the scrut's type has been widened
+ def doDefault(scrut_ignored: Tree) = REF(default) APPLY (REF(x))
- val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None)
+ val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault))
DefDef(methodSym, body)
}
@@ -2257,7 +2298,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- val members = if (!isPartial) List(applyMethod) else List(applyMethod, isDefinedAtMethod)
+ val members = if (!isPartial) List(applyMethod) else List(applyOrElseMethodDef, isDefinedAtMethod)
if (members.head eq EmptyTree) setError(tree)
else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt)
}