diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-05-28 15:20:01 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-06-10 17:00:19 +0200 |
commit | ad9d87b1faad22c1a2e05351757c0a940e2a0ef2 (patch) | |
tree | e2cf3962e0b6e772fbc73923a8c14af620825ecf | |
parent | ddb29a8105bc3b692bc129cbd8ed111baae7076d (diff) | |
download | scala-ad9d87b1faad22c1a2e05351757c0a940e2a0ef2.tar.gz scala-ad9d87b1faad22c1a2e05351757c0a940e2a0ef2.tar.bz2 scala-ad9d87b1faad22c1a2e05351757c0a940e2a0ef2.zip |
SI-8631 Treat `A with Sealed` as enumerable for pattern matching
Enumerate the subtypes of sealed parent types of refinement
types, and filter those that conform to the refinement type.
Such types can crop up easily when LUB-bing case classes which
add `Product with Serializable` to the mix.
4 files changed, 55 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 894f959319..3ef9b8c0b4 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -105,6 +105,16 @@ trait TreeAndTypeAnalysis extends Debugging { case modSym: ModuleClassSymbol => Some(List(tp)) // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte + case sym: RefinementClassSymbol => + val parentSubtypes: List[Option[List[Type]]] = tp.parents.map(parent => enumerateSubtypes(parent)) + if (parentSubtypes exists (_.isDefined)) + // If any of the parents is enumerable, then the refinement type is enumerable. + Some( + // We must only include subtypes of the parents that conform to `tp`. + // See neg/virtpatmat_exhaust_compound.scala for an example. + parentSubtypes flatMap (_.getOrElse(Nil)) filter (_ <:< tp) + ) + else None case sym if !sym.isSealed || isPrimitiveValueClass(sym) => debug.patmat("enum unsealed "+ ((tp, sym, sym.isSealed, isPrimitiveValueClass(sym)))) None diff --git a/test/files/neg/virtpatmat_exhaust_compound.check b/test/files/neg/virtpatmat_exhaust_compound.check new file mode 100644 index 0000000000..72e0340682 --- /dev/null +++ b/test/files/neg/virtpatmat_exhaust_compound.check @@ -0,0 +1,15 @@ +virtpatmat_exhaust_compound.scala:14: warning: match may not be exhaustive. +It would fail on the following inputs: O1, O2, O4 + a match { + ^ +virtpatmat_exhaust_compound.scala:18: warning: match may not be exhaustive. +It would fail on the following input: O4 + def t1(a: Product with Base with Base2) = a match { + ^ +virtpatmat_exhaust_compound.scala:22: warning: match may not be exhaustive. +It would fail on the following input: O2 + def t2(a: Product with Base { def foo: Int }) = a match { + ^ +error: No warnings can be incurred under -Xfatal-warnings. +three warnings found +one error found diff --git a/test/files/neg/virtpatmat_exhaust_compound.flags b/test/files/neg/virtpatmat_exhaust_compound.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/virtpatmat_exhaust_compound.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/virtpatmat_exhaust_compound.scala b/test/files/neg/virtpatmat_exhaust_compound.scala new file mode 100644 index 0000000000..386c7af98d --- /dev/null +++ b/test/files/neg/virtpatmat_exhaust_compound.scala @@ -0,0 +1,29 @@ +sealed trait Base +case object O1 extends Base +case object O2 extends Base { + def foo: Int = 0 +} + +sealed trait Base2 +case object O3 extends Base2 + +case object O4 extends Base with Base2 + +object Test { + val a /*: Product with Serialiable with Base */ = if (true) O1 else O2 + a match { + case null => + } + + def t1(a: Product with Base with Base2) = a match { + case null => // O1..O3 should *not* be possible here + } + + def t2(a: Product with Base { def foo: Int }) = a match { + case null => // O2 in the domain + } + + def t3(a: Product with Base { def bar: Int }) = a match { + case null => // nothing in the domain + } +} |