@@ -19,6 +19,7 @@ import Inferencing._
19
19
import ProtoTypes ._
20
20
import transform .SymUtils ._
21
21
import reporting .diagnostic .messages ._
22
+ import reporting .trace
22
23
import config .Printers .{exhaustivity => debug }
23
24
import util .SourcePosition
24
25
@@ -110,7 +111,7 @@ trait SpaceLogic {
110
111
*
111
112
* This reduces noise in counterexamples.
112
113
*/
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 {
114
115
case Prod (tp, fun, sym, spaces, full) =>
115
116
val sp = Prod (tp, fun, sym, spaces.map(simplify(_)), full)
116
117
if (sp.params.contains(Empty )) Empty
@@ -137,10 +138,10 @@ trait SpaceLogic {
137
138
if (canDecompose(tp) && decompose(tp).isEmpty) Empty
138
139
else space
139
140
case _ => space
140
- }
141
+ })
141
142
142
143
/** 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 {
144
145
case Prod (tp, fun, sym, spaces, full) =>
145
146
spaces.map(flatten) match {
146
147
case Nil => Prod (tp, fun, sym, Nil , full) :: Nil
@@ -156,11 +157,11 @@ trait SpaceLogic {
156
157
}
157
158
158
159
/** 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) {
160
161
def tryDecompose1 (tp : Type ) = canDecompose(tp) && isSubspace(Or (decompose(tp)), b)
161
162
def tryDecompose2 (tp : Type ) = canDecompose(tp) && isSubspace(a, Or (decompose(tp)))
162
163
163
- val res = (simplify(a), b) match {
164
+ (simplify(a), b) match {
164
165
case (Empty , _) => true
165
166
case (_, Empty ) => false
166
167
case (Or (ss), _) =>
@@ -179,18 +180,14 @@ trait SpaceLogic {
179
180
case (Prod (_, fun1, sym1, ss1, _), Prod (_, fun2, sym2, ss2, _)) =>
180
181
sym1 == sym2 && isEqualType(fun1, fun2) && ss1.zip(ss2).forall((isSubspace _).tupled)
181
182
}
182
-
183
- debug.println(s " ${show(a)} < ${show(b)} = $res" )
184
-
185
- res
186
183
}
187
184
188
185
/** 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 ])) {
190
187
def tryDecompose1 (tp : Type ) = intersect(Or (decompose(tp)), b)
191
188
def tryDecompose2 (tp : Type ) = intersect(a, Or (decompose(tp)))
192
189
193
- val res : Space = (a, b) match {
190
+ (a, b) match {
194
191
case (Empty , _) | (_, Empty ) => Empty
195
192
case (_, Or (ss)) => Or (ss.map(intersect(a, _)).filterConserve(_ ne Empty ))
196
193
case (Or (ss), _) => Or (ss.map(intersect(_, b)).filterConserve(_ ne Empty ))
@@ -223,18 +220,14 @@ trait SpaceLogic {
223
220
else if (ss1.zip(ss2).exists(p => simplify(intersect(p._1, p._2)) == Empty )) Empty
224
221
else Prod (tp1, fun1, sym1, ss1.zip(ss2).map((intersect _).tupled), full)
225
222
}
226
-
227
- debug.println(s " ${show(a)} & ${show(b)} = ${show(res)}" )
228
-
229
- res
230
223
}
231
224
232
225
/** 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 ])) {
234
227
def tryDecompose1 (tp : Type ) = minus(Or (decompose(tp)), b)
235
228
def tryDecompose2 (tp : Type ) = minus(a, Or (decompose(tp)))
236
229
237
- val res = (a, b) match {
230
+ (a, b) match {
238
231
case (Empty , _) => Empty
239
232
case (_, Empty ) => a
240
233
case (Typ (tp1, _), Typ (tp2, _)) =>
@@ -273,10 +266,6 @@ trait SpaceLogic {
273
266
})
274
267
275
268
}
276
-
277
- debug.println(s " ${show(a)} - ${show(b)} = ${show(res)}" )
278
-
279
- res
280
269
}
281
270
}
282
271
@@ -307,20 +296,19 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
307
296
private val nullType = ConstantType (Constant (null ))
308
297
private val nullSpace = Typ (nullType)
309
298
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) {
311
300
// 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)
317
301
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)
319
306
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
+ }
324
312
}
325
313
326
314
/** Return the space that represents the pattern `pat` */
@@ -334,7 +322,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
334
322
case Ident (nme.WILDCARD ) =>
335
323
Or (Typ (pat.tpe.stripAnnots, false ) :: nullSpace :: Nil )
336
324
case Ident (_) | Select (_, _) =>
337
- Typ (pat.tpe.stripAnnots, false )
325
+ Typ (erase( pat.tpe.stripAnnots) , false )
338
326
case Alternative (trees) => Or (trees.map(project(_)))
339
327
case Bind (_, pat) => project(pat)
340
328
case SeqLiteral (pats, _) => projectSeq(pats)
@@ -350,16 +338,17 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
350
338
Prod (erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1 ).map(project) :+ projectSeq(pats.drop(arity - 1 )),isIrrefutableUnapply(fun))
351
339
}
352
340
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)
355
344
case Typed (expr, tpt) =>
356
345
Typ (erase(expr.tpe.stripAnnots), true )
357
346
case This (_) =>
358
347
Typ (pat.tpe.stripAnnots, false )
359
348
case EmptyTree => // default rethrow clause of try/catch, check tests/patmat/try2.scala
360
349
Typ (WildcardType , false )
361
350
case _ =>
362
- debug.println (s " unknown pattern: $pat" )
351
+ ctx.error (s " unknown pattern: $pat" , pat.sourcePos )
363
352
Empty
364
353
}
365
354
@@ -375,19 +364,54 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
375
364
(arity, elemTp, resultTp)
376
365
}
377
366
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) {
380
397
def isPatternTypeSymbol (sym : Symbol ) = ! sym.isClass && sym.is(Case )
381
398
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
388
414
}
389
-
390
- map(tp)
391
415
}
392
416
393
417
/** Space of the pattern: unapplySeq(a, b, c: _*)
@@ -635,7 +659,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
635
659
636
660
def doShow (s : Space , mergeList : Boolean = false ): String = s match {
637
661
case Empty => " "
638
- case Typ (c : ConstantType , _) => c.value.value.toString
662
+ case Typ (c : ConstantType , _) => " " + c.value.value
639
663
case Typ (tp : TermRef , _) => tp.symbol.showName
640
664
case Typ (tp, decomposed) =>
641
665
val sym = tp.widen.classSymbol
0 commit comments