Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

clean up synthesizePartialFunction

implement the following review comments by @retronym:
- [x] Please clothe this naked assert.
- [x] Use match to dissect targs and check isFullyDefined.
- [x] Instead of `targs.head`/`targs.last`, use `val argTp :: resTp :: Nil = targs`.
- [x] Add a quasi-quote-style comment for `apply`.
- [x] Factor out mkCastPreservingAnnotations.
  • Loading branch information...
commit 51f574ac9ff0dbcb665f48a8c1a380c59f2bb641 1 parent e314ff1
@adriaanm adriaanm authored
View
5 src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -253,6 +253,11 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
}
}
+ // drop annotations generated by CPS plugin etc, since its annotationchecker rejects T @cps[U] <: Any
+ // let's assume for now annotations don't affect casts, drop them there, and bring them back using the outer Typed tree
+ def mkCastPreservingAnnotations(tree: Tree, pt: Type) =
+ Typed(mkCast(tree, pt.withoutAnnotations.dealias), TypeTree(pt))
+
/** Generate a cast for tree Tree representing Array with
* elem type elemtp to expected type pt.
*/
View
9 src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -1478,14 +1478,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya
def and(a: Tree, b: Tree): Tree = a AND b
- // drop annotations generated by CPS plugin etc, since its annotationchecker rejects T @cps[U] <: Any
- // let's assume for now annotations don't affect casts, drop them there, and bring them back using the outer Typed tree
- private def mkCast(t: Tree, tp: Type) =
- Typed(gen.mkAsInstanceOf(t, tp.withoutAnnotations, true, false), TypeTree() setType tp)
-
// the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly)
- def _asInstanceOf(t: Tree, tp: Type): Tree = if (t.tpe != NoType && t.isTyped && typesConform(t.tpe, tp)) t else mkCast(t, tp)
- def _asInstanceOf(b: Symbol, tp: Type): Tree = if (typesConform(b.info, tp)) REF(b) else mkCast(REF(b), tp)
+ def _asInstanceOf(t: Tree, tp: Type): Tree = if (t.tpe != NoType && t.isTyped && typesConform(t.tpe, tp)) t else gen.mkCastPreservingAnnotations(t, tp)
+ def _asInstanceOf(b: Symbol, tp: Type): Tree = if (typesConform(b.info, tp)) REF(b) else gen.mkCastPreservingAnnotations(REF(b), tp)
def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), tp.withoutAnnotations, true, false)
// if (typesConform(b.info, tpX)) { patmatDebug("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE }
View
27 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2612,21 +2612,21 @@ trait Typers extends Modes with Adaptations with Tags {
* however, note that pattern matching codegen is designed to run *before* uncurry
*/
def synthesizePartialFunction(paramName: TermName, paramPos: Position, tree: Tree, mode: Int, pt0: Type): Tree = {
- assert(pt0.typeSymbol == PartialFunctionClass)
+ assert(pt0.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt0.")
val pt = deskolemizeGADTSkolems(pt0)
val targs = pt.normalize.typeArgs
- // if targs.head isn't fully defined, we can't translate --> error
- if (targs.isEmpty || !isFullyDefined(targs.head)) {
- MissingParameterTypeAnonMatchError(tree, pt)
- return setError(tree)
+ // if targs.head isn't fully defined, we can translate --> error
+ targs match {
+ case argTp :: _ if isFullyDefined(argTp) => // ok
+ case _ => // uh-oh
+ MissingParameterTypeAnonMatchError(tree, pt)
+ return setError(tree)
}
- val argTp = targs.head
-
- // NOTE: targs.last still might not be fully defined
- val resTp = targs.last
+ // NOTE: resTp still might not be fully defined
+ val argTp :: resTp :: Nil = targs
// targs must conform to Any for us to synthesize an applyOrElse (fallback to apply otherwise -- typically for @cps annotated targs)
val targsValidParams = targs forall (_ <:< AnyClass.tpe)
@@ -2650,10 +2650,12 @@ trait Typers extends Modes with Adaptations with Tags {
// we don't want/need the match to see the `A1` type that we must use for variance reasons in the method signature
//
// this failed: replace `selector` by `Typed(selector, TypeTree(argTp))` -- as it's an upcast, this should never fail,
- // `(x: A1): A` doesn't always type check, even though `A1 <: A`, due to singleton types
+ // `(x: A1): A` doesn't always type check, even though `A1 <: A`, due to singleton types (test/files/pos/t4269.scala)
// hence the cast, which will be erased in posterasure
- Typed(gen.mkAsInstanceOf(Ident(paramName), argTp.withoutAnnotations, true, false), TypeTree(argTp)))
- )
+ // (the cast originally caused extremely weird types to show up
+ // in test/scaladoc/run/SI-5933.scala because `variantToSkolem` was missing `tpSym.initialize`)
+ gen.mkCastPreservingAnnotations(Ident(paramName), argTp)
+ ))
def mkParam(methodSym: Symbol, tp: Type = argTp) =
methodSym.newValueParameter(paramName, paramPos.focus, SYNTHETIC) setInfo tp
@@ -2706,6 +2708,7 @@ trait Typers extends Modes with Adaptations with Tags {
}
// only used for @cps annotated partial functions
+ // `def apply(x: $argTp): $matchResTp = $selector match { $cases }`
def applyMethod = {
val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL | OVERRIDE)
val paramSym = mkParam(methodSym)
Please sign in to comment.
Something went wrong with that request. Please try again.