diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-01-31 00:33:19 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-02-07 21:58:47 +0100 |
commit | 55c9b9c280ac9bc36bbac09397c7646f8dcf4583 (patch) | |
tree | cdfc1cd396eaba78f0150968634722bcb8df8bd7 /src/reflect | |
parent | 81d8f9d3da656cfb05f125ba7cf70ca51a477240 (diff) | |
download | scala-55c9b9c280ac9bc36bbac09397c7646f8dcf4583.tar.gz scala-55c9b9c280ac9bc36bbac09397c7646f8dcf4583.tar.bz2 scala-55c9b9c280ac9bc36bbac09397c7646f8dcf4583.zip |
SI-6146 More accurate prefixes for sealed subtypes.
When analysing exhaustivity/reachability of type tests
and equality tests, the pattern matcher must construct
a set of sealed subtypes based on the prefix of the
static type of and the set of sealed descendent symbols
of that type.
Previously, it was using `memberType` for this purpose.
In simple cases, this is sufficient:
scala> class C { class I1; object O { class I2 } }; object D extends C
defined class C
defined module D
scala> typeOf[D.type] memberType typeOf[C#I1].typeSymbol
res0: u.Type = D.I1
But, as reported in this bug, it fails when there is an
additional level of nesting:
scala> typeOf[D.type] memberType typeOf[c.O.I2 forSome { val c: C }].typeSymbol
res5: u.Type = C.O.I2
This commit introduces `nestedMemberType`, which uses `memberType`
recursively up the prefix chain prefix chain.
scala> nestedMemberType(typeOf[c.O.I2 forSome { val c: C }].typeSymbol, typeOf[D.type], typeOf[C].typeSymbol)
res6: u.Type = D.O.Id
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0dd98fb6ae..b708ca0fd6 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -586,9 +586,9 @@ trait Types extends api.Types { self: SymbolTable => * Expands type aliases and converts higher-kinded TypeRefs to PolyTypes. * Functions on types are also implemented as PolyTypes. * - * Example: (in the below, <List> is the type constructor of List) - * TypeRef(pre, <List>, List()) is replaced by - * PolyType(X, TypeRef(pre, <List>, List(X))) + * Example: (in the below, `<List>` is the type constructor of List) + * TypeRef(pre, `<List>`, List()) is replaced by + * PolyType(X, TypeRef(pre, `<List>`, List(X))) */ def normalize = this // @MAT @@ -4974,6 +4974,51 @@ trait Types extends api.Types { self: SymbolTable => } } + /** + * A more persistent version of `Type#memberType` which does not require + * that the symbol is a direct member of the prefix. + * + * For instance: + * + * {{{ + * class C[T] { + * sealed trait F[A] + * object X { + * object S1 extends F[T] + * } + * class S2 extends F[T] + * } + * object O extends C[Int] { + * def foo(f: F[Int]) = f match {...} // need to enumerate sealed subtypes of the scrutinee here. + * } + * class S3 extends O.F[String] + * + * nestedMemberType(<S1>, <O.type>, <C>) = O.X.S1.type + * nestedMemberType(<S2>, <O.type>, <C>) = O.S2.type + * nestedMemberType(<S3>, <O.type>, <C>) = S3.type + * }}} + * + * @param sym The symbol of the subtype + * @param pre The prefix from which the symbol is seen + * @param owner + */ + def nestedMemberType(sym: Symbol, pre: Type, owner: Symbol): Type = { + def loop(tp: Type): Type = + if (tp.isTrivial) tp + else if (tp.prefix.typeSymbol isNonBottomSubClass owner) { + val widened = tp match { + case _: ConstantType => tp // Java enum constants: don't widen to the enum type! + case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. + } + widened asSeenFrom (pre, tp.typeSymbol.owner) + } + else loop(tp.prefix) memberType tp.typeSymbol + + val result = loop(sym.tpeHK) + assert(sym.isTerm || result.typeSymbol == sym, s"($result).typeSymbol = ${result.typeSymbol}; expected ${sym}") + result + } + /** The most deeply nested owner that contains all the symbols * of thistype or prefixless typerefs/singletype occurrences in given type. */ |