From 35122d6cda84bb2df69ca51c6b1b80e61693bf6f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 15 Aug 2013 15:02:18 -0700 Subject: Minor improvement in pattern typer inference. This exploits the infrastructure developed for checking the checkability of type patterns to improve pattern type inference, which suffered from a similar deficit. There was a hack for SI-2486, the best I could manage at the time I wrote it; that is replaced with the principled approach. --- .../scala/tools/nsc/typechecker/Infer.scala | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 8ca0d82e93..2f86e23415 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1227,7 +1227,6 @@ trait Infer extends Checkable { val tpparams = freeTypeParamsOfTerms(pattp) def ptMatchesPattp = pt matchesPattern pattp.widen - def pattpMatchesPt = pattp matchesPattern pt /* If we can absolutely rule out a match we can fail early. * This is the case if the scrutinee has no unresolved type arguments @@ -1237,9 +1236,15 @@ trait Infer extends Checkable { IncompatibleScrutineeTypeError(tree0, pattp, pt) return ErrorType } + // This performs the "reverse" propagation of type information already used + // in pattern matcher checkability testing. See pos/t2486.scala for sample + // code which would not compile without such propagation. + def propagated = propagateKnownTypes(pt, pattp.widen.typeSymbol) - checkCheckable(tree0, pattp, pt, inPattern = true, canRemedy) + checkCheckable(tree0, pattp, pt0, inPattern = true, canRemedy) if (pattp <:< pt) () + else if (pattp <:< propagated) + log(s"!($pattp <:< $pt), but after propagateKnownTypes we find ($pattp <:< $propagated) - pattern inference improved") else { debuglog("free type params (1) = " + tpparams) @@ -1256,9 +1261,7 @@ trait Infer extends Checkable { val ptvars = ptparams map freshVar val pt1 = pt.instantiateTypeParams(ptparams, ptvars) - // See ticket #2486 for an example of code which would incorrectly - // fail if we didn't allow for pattpMatchesPt. - if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars) || pattpMatchesPt) + if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars)) ptvars foreach instantiateTypeVar else { PatternTypeIncompatibleWithPtError1(tree0, pattp, pt) @@ -1311,10 +1314,10 @@ trait Infer extends Checkable { // properly, we can avoid it by ignoring type parameters which // have type constructors amongst their bounds. See SI-4070. def isFreeTypeParamOfTerm(sym: Symbol) = ( - sym.isAbstractType - && sym.owner.isTerm - && !sym.info.bounds.exists(_.typeParams.nonEmpty) - ) + sym.isAbstractType + && sym.owner.isTerm + && !sym.info.bounds.exists(_.typeParams.nonEmpty) + ) // Intentionally *not* using `Type#typeSymbol` here, which would normalize `tp` // and collect symbols from the result type of any resulting `PolyType`s, which -- cgit v1.2.3