diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2015-08-05 22:07:49 +0200 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-03-24 16:22:06 +0100 |
commit | e7dc46fc2ee685708af566a78fa97f7faccd5dcd (patch) | |
tree | 1d8129476ad88779dc0ad8f30a181c03d49db30e /src | |
parent | 1b29119b8ed1a2c3b382dfca01d6dde71f6ae733 (diff) | |
download | dotty-e7dc46fc2ee685708af566a78fa97f7faccd5dcd.tar.gz dotty-e7dc46fc2ee685708af566a78fa97f7faccd5dcd.tar.bz2 dotty-e7dc46fc2ee685708af566a78fa97f7faccd5dcd.zip |
Typer#escapingRefs: don't let the types of lower bounds escape
In 0efa171e8ccca0d49fc6d800fd21e29f7b7336fd I changed the definition of
NamedPartsAccumulator to exclude lower bounds as this is required for the
implicit search, but NamedPartsAccumulator is also used by
Typer#escapingRefs so in the following code:
class Foo[T]
val z = {
class C
??? : Foo[_ >: C]
}
the type of z was inferred to be Foo[_ >: C] instead of Foo.
To avoid this, NamedPartsAccumulator will only exclude lower bounds if
the parameter excludeLowerBounds is explicitely set to true.
No test because there is no way to detect that a type has escaped, this
might be something that could be added to TreeChecker.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 15 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 4 |
2 files changed, 14 insertions, 5 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 3801f1914..c502162ab 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -257,9 +257,14 @@ object Types { /** The parts of this type which are type or term refs and which * satisfy predicate `p`. + * + * @param p The predicate to satisfy + * @param excludeLowerBounds If set to true, the lower bounds of abstract + * types will be ignored. */ - def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): collection.Set[NamedType] = - new NamedPartsAccumulator(p).apply(mutable.LinkedHashSet(), this) + def namedPartsWith(p: NamedType => Boolean, excludeLowerBounds: Boolean = false) + (implicit ctx: Context): collection.Set[NamedType] = + new NamedPartsAccumulator(p, excludeLowerBounds).apply(mutable.LinkedHashSet(), this) /** Map function `f` over elements of an AndType, rebuilding with function `g` */ def mapReduceAnd[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match { @@ -3331,7 +3336,8 @@ object Types { def apply(x: Boolean, tp: Type) = x || tp.isUnsafeNonvariant || foldOver(x, tp) } - class NamedPartsAccumulator(p: NamedType => Boolean)(implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] { + class NamedPartsAccumulator(p: NamedType => Boolean, excludeLowerBounds: Boolean = false) + (implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] { override def stopAtStatic = false def maybeAdd(x: mutable.Set[NamedType], tp: NamedType) = if (p(tp)) x += tp else x val seen: mutable.Set[Type] = mutable.Set() @@ -3344,7 +3350,8 @@ object Types { apply(foldOver(maybeAdd(x, tp), tp), tp.underlying) case tp: TypeRef => foldOver(maybeAdd(x, tp), tp) - case TypeBounds(_, hi) => + case TypeBounds(lo, hi) => + if (!excludeLowerBounds) apply(x, lo) apply(x, hi) case tp: ThisType => apply(x, tp.underlying) diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 5b336c2e9..446b39799 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -329,7 +329,9 @@ trait ImplicitRunInfo { self: RunInfo => } tp.classSymbols(liftingCtx) foreach addClassScope case _ => - for (part <- tp.namedPartsWith(_.isType)) + // We exclude lower bounds to conform to SLS 7.2: + // "The parts of a type T are: [...] if T is an abstract type, the parts of its upper bound" + for (part <- tp.namedPartsWith(_.isType, excludeLowerBounds = true)) comps ++= iscopeRefs(part) } comps |