aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2015-10-01 20:31:06 +0200
committerGuillaume Martres <smarter@ubuntu.com>2015-10-09 14:56:49 +0200
commit48acd08ac7e6346ffa573163fc1993cbdae458cd (patch)
treed53a5e05810ebbf8e047eddc4dc1465b9943dec3
parent5f7e2901b0d13d0201874ada72a107820870e274 (diff)
downloaddotty-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.scala12
-rw-r--r--tests/pos/escapingRefs.scala12
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
+ }
+ }
+}