diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2015-10-01 20:31:06 +0200 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2015-10-09 14:56:49 +0200 |
commit | 48acd08ac7e6346ffa573163fc1993cbdae458cd (patch) | |
tree | d53a5e05810ebbf8e047eddc4dc1465b9943dec3 | |
parent | 5f7e2901b0d13d0201874ada72a107820870e274 (diff) | |
download | dotty-48acd08ac7e6346ffa573163fc1993cbdae458cd.tar.gz dotty-48acd08ac7e6346ffa573163fc1993cbdae458cd.tar.bz2 dotty-48acd08ac7e6346ffa573163fc1993cbdae458cd.zip |
TypeAssigner#avoid: more precise types for inner classes
When we need to avoid `A` in the class `A#B`, we can try to replace `A`
by a supertype. Previously, we only tried to replace `A#B` itself by a
supertype.
Fixes #711.
-rw-r--r-- | src/dotty/tools/dotc/typer/TypeAssigner.scala | 12 | ||||
-rw-r--r-- | tests/pos/escapingRefs.scala | 12 |
2 files changed, 22 insertions, 2 deletions
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index ba8d44110..496380b3a 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -31,10 +31,12 @@ trait TypeAssigner { /** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`. * Approximation steps are: * - * - follow aliases if the original refers to a forbidden symbol + * - follow aliases and upper bounds if the original refers to a forbidden symbol * - widen termrefs that refer to a forbidden symbol * - replace ClassInfos of forbidden classes by the intersection of their parents, refined by all * non-private fields, methods, and type members. + * - if the prefix of a class refers to a forbidden symbol, first try to replace the prefix, + * if this is not possible, replace the ClassInfo as above. * - drop refinements referring to a forbidden symbol. */ def avoid(tp: Type, symsToAvoid: => List[Symbol])(implicit ctx: Context): Type = { @@ -52,7 +54,7 @@ trait TypeAssigner { case _ => false } - def apply(tp: Type) = tp match { + def apply(tp: Type): Type = tp match { case tp: TermRef if toAvoid(tp) && variance > 0 => apply(tp.info.widenExpr) case tp: TypeRef if (forbidden contains tp.symbol) || toAvoid(tp.prefix) => @@ -60,6 +62,12 @@ trait TypeAssigner { case TypeAlias(ref) => apply(ref) case info: ClassInfo if variance > 0 => + if (!(forbidden contains tp.symbol)) { + val prefix = apply(tp.prefix) + val tp1 = tp.derivedSelect(prefix) + if (tp1.typeSymbol.exists) + return tp1 + } val parentType = info.instantiatedParents.reduceLeft(ctx.typeComparer.andType(_, _)) def addRefinement(parent: Type, decl: Symbol) = { val inherited = diff --git a/tests/pos/escapingRefs.scala b/tests/pos/escapingRefs.scala new file mode 100644 index 000000000..a7960bee4 --- /dev/null +++ b/tests/pos/escapingRefs.scala @@ -0,0 +1,12 @@ +class Outer { + class Inner +} + +object Test { + def test = { + val a: Outer#Inner = { + val o = new Outer + new o.Inner + } + } +} |