diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-01-10 13:25:33 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-01-10 14:30:35 -0800 |
commit | 51f574ac9ff0dbcb665f48a8c1a380c59f2bb641 (patch) | |
tree | d0b31dfb0252b1af55e22acb2d854daf95dcdb51 | |
parent | e314ff1621ee26e1e4ec65abc6e360a7731bf488 (diff) | |
download | scala-51f574ac9ff0dbcb665f48a8c1a380c59f2bb641.tar.gz scala-51f574ac9ff0dbcb665f48a8c1a380c59f2bb641.tar.bz2 scala-51f574ac9ff0dbcb665f48a8c1a380c59f2bb641.zip |
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.
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/TreeGen.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 27 |
3 files changed, 22 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 5cb43575b8..96146b7343 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/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. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index fa8aff5cdd..d73fb680f2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/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 } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 441ea6898b..be00aebf1b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/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) |