@@ -19,6 +19,7 @@ import Inferencing._
1919import ProtoTypes ._
2020import transform .SymUtils ._
2121import reporting .diagnostic .messages ._
22+ import reporting .trace
2223import config .Printers .{exhaustivity => debug }
2324import util .SourcePosition
2425
@@ -110,7 +111,7 @@ trait SpaceLogic {
110111 *
111112 * This reduces noise in counterexamples.
112113 */
113- def simplify (space : Space , aggressive : Boolean = false ): Space = space match {
114+ def simplify (space : Space , aggressive : Boolean = false )( implicit ctx : Context ) : Space = trace( s " simplify ${show(space)} , aggressive = $aggressive --> " , debug, x => show(x. asInstanceOf [ Space ]))( space match {
114115 case Prod (tp, fun, sym, spaces, full) =>
115116 val sp = Prod (tp, fun, sym, spaces.map(simplify(_)), full)
116117 if (sp.params.contains(Empty )) Empty
@@ -137,10 +138,10 @@ trait SpaceLogic {
137138 if (canDecompose(tp) && decompose(tp).isEmpty) Empty
138139 else space
139140 case _ => space
140- }
141+ })
141142
142143 /** Flatten space to get rid of `Or` for pretty print */
143- def flatten (space : Space ): List [Space ] = space match {
144+ def flatten (space : Space )( implicit ctx : Context ) : List [Space ] = space match {
144145 case Prod (tp, fun, sym, spaces, full) =>
145146 spaces.map(flatten) match {
146147 case Nil => Prod (tp, fun, sym, Nil , full) :: Nil
@@ -156,11 +157,11 @@ trait SpaceLogic {
156157 }
157158
158159 /** Is `a` a subspace of `b`? Equivalent to `a - b == Empty`, but faster */
159- def isSubspace (a : Space , b : Space ): Boolean = {
160+ def isSubspace (a : Space , b : Space )( implicit ctx : Context ) : Boolean = trace( s " ${show(a)} < ${show(b)} " , debug) {
160161 def tryDecompose1 (tp : Type ) = canDecompose(tp) && isSubspace(Or (decompose(tp)), b)
161162 def tryDecompose2 (tp : Type ) = canDecompose(tp) && isSubspace(a, Or (decompose(tp)))
162163
163- val res = (simplify(a), b) match {
164+ (simplify(a), b) match {
164165 case (Empty , _) => true
165166 case (_, Empty ) => false
166167 case (Or (ss), _) =>
@@ -179,18 +180,14 @@ trait SpaceLogic {
179180 case (Prod (_, fun1, sym1, ss1, _), Prod (_, fun2, sym2, ss2, _)) =>
180181 sym1 == sym2 && isEqualType(fun1, fun2) && ss1.zip(ss2).forall((isSubspace _).tupled)
181182 }
182-
183- debug.println(s " ${show(a)} < ${show(b)} = $res" )
184-
185- res
186183 }
187184
188185 /** Intersection of two spaces */
189- def intersect (a : Space , b : Space ): Space = {
186+ def intersect (a : Space , b : Space )( implicit ctx : Context ) : Space = trace( s " ${show(a)} & ${show(b)} " , debug, x => show(x. asInstanceOf [ Space ])) {
190187 def tryDecompose1 (tp : Type ) = intersect(Or (decompose(tp)), b)
191188 def tryDecompose2 (tp : Type ) = intersect(a, Or (decompose(tp)))
192189
193- val res : Space = (a, b) match {
190+ (a, b) match {
194191 case (Empty , _) | (_, Empty ) => Empty
195192 case (_, Or (ss)) => Or (ss.map(intersect(a, _)).filterConserve(_ ne Empty ))
196193 case (Or (ss), _) => Or (ss.map(intersect(_, b)).filterConserve(_ ne Empty ))
@@ -223,18 +220,14 @@ trait SpaceLogic {
223220 else if (ss1.zip(ss2).exists(p => simplify(intersect(p._1, p._2)) == Empty )) Empty
224221 else Prod (tp1, fun1, sym1, ss1.zip(ss2).map((intersect _).tupled), full)
225222 }
226-
227- debug.println(s " ${show(a)} & ${show(b)} = ${show(res)}" )
228-
229- res
230223 }
231224
232225 /** The space of a not covered by b */
233- def minus (a : Space , b : Space ): Space = {
226+ def minus (a : Space , b : Space )( implicit ctx : Context ) : Space = trace( s " ${show(a)} - ${show(b)} " , debug, x => show(x. asInstanceOf [ Space ])) {
234227 def tryDecompose1 (tp : Type ) = minus(Or (decompose(tp)), b)
235228 def tryDecompose2 (tp : Type ) = minus(a, Or (decompose(tp)))
236229
237- val res = (a, b) match {
230+ (a, b) match {
238231 case (Empty , _) => Empty
239232 case (_, Empty ) => a
240233 case (Typ (tp1, _), Typ (tp2, _)) =>
@@ -273,10 +266,6 @@ trait SpaceLogic {
273266 })
274267
275268 }
276-
277- debug.println(s " ${show(a)} - ${show(b)} = ${show(res)}" )
278-
279- res
280269 }
281270}
282271
@@ -307,20 +296,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
307296 private val nullType = ConstantType (Constant (null ))
308297 private val nullSpace = Typ (nullType)
309298
310- override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ): Space = {
299+ override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ): Space = trace( s " atomic intersection: ${ AndType (tp1, tp2).show} " , debug) {
311300 // Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1)
312- if (tp1 == nullType || tp2 == nullType) {
313- // Since projections of types don't include null, intersection with null is empty.
314- return Empty
315- }
316- val res = ctx.typeComparer.disjoint(tp1, tp2)
317301
318- debug.println(s " atomic intersection: ${AndType (tp1, tp2).show} = ${! res}" )
302+ // Since projections of types don't include null, intersection with null is empty.
303+ if (tp1 == nullType || tp2 == nullType) Empty
304+ else {
305+ val res = ctx.typeComparer.disjoint(tp1, tp2)
319306
320- if (res) Empty
321- else if (tp1.isSingleton) Typ (tp1, true )
322- else if (tp2.isSingleton) Typ (tp2, true )
323- else Typ (AndType (tp1, tp2), true )
307+ if (res) Empty
308+ else if (tp1.isSingleton) Typ (tp1, true )
309+ else if (tp2.isSingleton) Typ (tp2, true )
310+ else Typ (AndType (tp1, tp2), true )
311+ }
324312 }
325313
326314 /** Return the space that represents the pattern `pat` */
@@ -334,7 +322,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
334322 case Ident (nme.WILDCARD ) =>
335323 Or (Typ (pat.tpe.stripAnnots, false ) :: nullSpace :: Nil )
336324 case Ident (_) | Select (_, _) =>
337- Typ (pat.tpe.stripAnnots, false )
325+ Typ (erase( pat.tpe.stripAnnots) , false )
338326 case Alternative (trees) => Or (trees.map(project(_)))
339327 case Bind (_, pat) => project(pat)
340328 case SeqLiteral (pats, _) => projectSeq(pats)
@@ -350,16 +338,17 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
350338 Prod (erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1 ).map(project) :+ projectSeq(pats.drop(arity - 1 )),isIrrefutableUnapply(fun))
351339 }
352340 else
353- Prod (erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.map(project), isIrrefutableUnapply(fun))
354- case Typed (pat @ UnApply (_, _, _), _) => project(pat)
341+ Prod (erase(pat.tpe.stripAnnots), erase(fun.tpe), fun.symbol, pats.map(project), isIrrefutableUnapply(fun))
342+ case Typed (pat : UnApply , _) =>
343+ project(pat)
355344 case Typed (expr, tpt) =>
356345 Typ (erase(expr.tpe.stripAnnots), true )
357346 case This (_) =>
358347 Typ (pat.tpe.stripAnnots, false )
359348 case EmptyTree => // default rethrow clause of try/catch, check tests/patmat/try2.scala
360349 Typ (WildcardType , false )
361350 case _ =>
362- debug.println (s " unknown pattern: $pat" )
351+ ctx.error (s " unknown pattern: $pat" , pat.sourcePos )
363352 Empty
364353 }
365354
@@ -375,19 +364,54 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
375364 (arity, elemTp, resultTp)
376365 }
377366
378- /* Erase pattern bound types with WildcardType */
379- def erase (tp : Type ): Type = {
367+ /** Erase pattern bound types with WildcardType
368+ *
369+ * For example, the type `C[T$1]` should match any `C[_]`, thus
370+ * `v` should be `WildcardType` instead of `T$1`:
371+ *
372+ * sealed trait B
373+ * case class C[T](v: T) extends B
374+ * (b: B) match {
375+ * case C(v) => // case C.unapply[T$1 @ T$1](v @ _):C[T$1]
376+ * }
377+ *
378+ * However, we cannot use WildcardType for Array[_], due to that
379+ * `Array[WildcardType] <: Array[Array[WildcardType]]`, which may
380+ * cause false unreachable warnings. See tests/patmat/t2425.scala
381+ *
382+ * We cannot use type erasure here, as it would lose the constraints
383+ * involving GADTs. For example, in the following code, type
384+ * erasure would loose the constraint that `x` and `y` must be
385+ * the same type, resulting in false inexhaustive warnings:
386+ *
387+ * sealed trait Expr[T]
388+ * case class IntExpr(x: Int) extends Expr[Int]
389+ * case class BooleanExpr(b: Boolean) extends Expr[Boolean]
390+ *
391+ * def foo[T](x: Expr[T], y: Expr[T]) = (x, y) match {
392+ * case (IntExpr(_), IntExpr(_)) =>
393+ * case (BooleanExpr(_), BooleanExpr(_)) =>
394+ * }
395+ */
396+ private def erase (tp : Type , inArray : Boolean = false ): Type = trace(i " $tp erased to " , debug) {
380397 def isPatternTypeSymbol (sym : Symbol ) = ! sym.isClass && sym.is(Case )
381398
382- val map = new TypeMap {
383- def apply (tp : Type ) = tp match {
384- case tref : TypeRef if isPatternTypeSymbol(tref.typeSymbol) =>
385- tref.underlying.bounds
386- case _ => mapOver(tp)
387- }
399+ tp match {
400+ case tp @ AppliedType (tycon, args) =>
401+ if (tycon.isRef(defn.ArrayClass )) tp.derivedAppliedType(tycon, args.map(arg => erase(arg, inArray = true )))
402+ else tp.derivedAppliedType(tycon, args.map(arg => erase(arg, inArray = false )))
403+ case OrType (tp1, tp2) =>
404+ OrType (erase(tp1, inArray), erase(tp2, inArray))
405+ case AndType (tp1, tp2) =>
406+ AndType (erase(tp1, inArray), erase(tp2, inArray))
407+ case tp @ RefinedType (parent, _, _) =>
408+ erase(parent)
409+ case tref : TypeRef if isPatternTypeSymbol(tref.typeSymbol) =>
410+ if (inArray) tref.underlying else WildcardType (tref.underlying.bounds)
411+ case mt : MethodType =>
412+ mt.derivedLambdaType(mt.paramNames, mt.paramInfos.map(info => erase(info)), erase(mt.resType))
413+ case _ => tp
388414 }
389-
390- map(tp)
391415 }
392416
393417 /** Space of the pattern: unapplySeq(a, b, c: _*)
@@ -635,7 +659,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
635659
636660 def doShow (s : Space , mergeList : Boolean = false ): String = s match {
637661 case Empty => " "
638- case Typ (c : ConstantType , _) => c.value.value.toString
662+ case Typ (c : ConstantType , _) => " " + c.value.value
639663 case Typ (tp : TermRef , _) => tp.symbol.showName
640664 case Typ (tp, decomposed) =>
641665 val sym = tp.widen.classSymbol
0 commit comments