From 24dff883751fb5a0920f8889e6570914a0f73a26 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 15 Jan 2014 19:02:41 +0100 Subject: Relax type checking rule for pattern matching. Previously, if S is the selector type and P is the type of the unapply argument, we demanded either S <: P or P <: S We now also admit P <: S' where S' can be obtained from S by dropping refinements. This lets some patterns in RefinedPrinters typecheck which did not typecheck before. It seems we can afford to be a little bit more liberal here, and thereby approximate the weaker "isPopulated" criterion of Scala2x. --- src/dotty/tools/dotc/typer/Applications.scala | 32 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'src/dotty/tools/dotc/typer/Applications.scala') diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index d5f9bded1..6b73740bb 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -621,18 +621,27 @@ trait Applications extends Compatibility { self: Typer => } } + /** Can `subtp` be made to be a subtype of `tp`, possibly by dropping some + * refinements in `tp`? + */ + def isSubTypeOfParent(subtp: Type, tp: Type): Boolean = + if (subtp <:< tp) true + else tp match { + case RefinedType(parent, _) => isSubTypeOfParent(subtp, parent) + case _ => false + } + unapply.tpe.widen match { case mt: MethodType if mt.paramTypes.length == 1 && !mt.isDependent => val unapplyArgType = mt.paramTypes.head unapp.println(s"unapp arg tpe = ${unapplyArgType.show}, pt = ${pt.show}") - def wpt = widenForMatchSelector(pt) + def wpt = widenForMatchSelector(pt) // needed? val ownType = if (pt <:< unapplyArgType) { fullyDefinedType(unapplyArgType, "extractor argument", tree.pos) unapp.println(i"case 1 $unapplyArgType ${ctx.typerState.constraint}") pt - } - else if (unapplyArgType <:< wpt) { + } else if (isSubTypeOfParent(unapplyArgType, wpt)) { maximizeType(unapplyArgType) match { case Some(tvar) => def msg = @@ -640,16 +649,15 @@ trait Applications extends Compatibility { self: Typer => |that makes it a subtype of selector type $pt. |Non-variant type variable ${tvar.origin} cannot be uniquely instantiated.""".stripMargin if (fromScala2x) { - // We can't issue an error here, because in Scala 2, ::[B] is invariant - // whereas List[+T] is covariant. According to the strict rule, a pattern - // match of a List[C] against a case x :: xs is illegal, because - // B cannot be uniquely instantiated. Of course :: should have been - // covariant in the first place, but in the Scala libraries it isn't. - // So for now we allow these kinds of patterns, even though they - // can open unsoundness holes. See SI-7952 for an example of the hole this opens. + // We can't issue an error here, because in Scala 2, ::[B] is invariant + // whereas List[+T] is covariant. According to the strict rule, a pattern + // match of a List[C] against a case x :: xs is illegal, because + // B cannot be uniquely instantiated. Of course :: should have been + // covariant in the first place, but in the Scala libraries it isn't. + // So for now we allow these kinds of patterns, even though they + // can open unsoundness holes. See SI-7952 for an example of the hole this opens. if (ctx.settings.verbose.value) ctx.warning(msg, tree.pos) - } - else { + } else { unapp.println(s" ${unapply.symbol.owner} ${unapply.symbol.owner is Scala2x}") ctx.error(msg, tree.pos) } -- cgit v1.2.3