Skip to content

Commit 148551a

Browse files
authored
Merge pull request #749 from smarter/fix/escaping-refs-2
Typer#escapingRefs: don't let the types of lower bounds escape
2 parents 8bfaada + f13fe71 commit 148551a

File tree

3 files changed

+15
-14
lines changed

3 files changed

+15
-14
lines changed

src/dotty/tools/dotc/core/Types.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,14 @@ object Types {
239239

240240
/** The parts of this type which are type or term refs and which
241241
* satisfy predicate `p`.
242+
*
243+
* @param p The predicate to satisfy
244+
* @param excludeLowerBounds If set to true, the lower bounds of abstract
245+
* types will be ignored.
242246
*/
243-
def namedPartsWith(p: NamedType => Boolean)(implicit ctx: Context): collection.Set[NamedType] =
244-
new NamedPartsAccumulator(p).apply(mutable.LinkedHashSet(), this)
247+
def namedPartsWith(p: NamedType => Boolean, excludeLowerBounds: Boolean = false)
248+
(implicit ctx: Context): collection.Set[NamedType] =
249+
new NamedPartsAccumulator(p, excludeLowerBounds).apply(mutable.LinkedHashSet(), this)
245250

246251
/** Map function `f` over elements of an AndType, rebuilding with function `g` */
247252
def mapReduceAnd[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match {
@@ -3710,7 +3715,8 @@ object Types {
37103715
def apply(x: Boolean, tp: Type) = x || tp.isUnsafeNonvariant || foldOver(x, tp)
37113716
}
37123717

3713-
class NamedPartsAccumulator(p: NamedType => Boolean)(implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] {
3718+
class NamedPartsAccumulator(p: NamedType => Boolean, excludeLowerBounds: Boolean = false)
3719+
(implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] {
37143720
override def stopAtStatic = false
37153721
def maybeAdd(x: mutable.Set[NamedType], tp: NamedType) = if (p(tp)) x += tp else x
37163722
val seen: mutable.Set[Type] = mutable.Set()
@@ -3723,7 +3729,8 @@ object Types {
37233729
apply(foldOver(maybeAdd(x, tp), tp), tp.underlying)
37243730
case tp: TypeRef =>
37253731
foldOver(maybeAdd(x, tp), tp)
3726-
case TypeBounds(_, hi) =>
3732+
case TypeBounds(lo, hi) =>
3733+
if (!excludeLowerBounds) apply(x, lo)
37273734
apply(x, hi)
37283735
case tp: ThisType =>
37293736
apply(x, tp.tref)

src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,9 @@ trait ImplicitRunInfo { self: RunInfo =>
343343
}
344344
tp.classSymbols(liftingCtx) foreach addClassScope
345345
case _ =>
346-
for (part <- tp.namedPartsWith(_.isType))
346+
// We exclude lower bounds to conform to SLS 7.2:
347+
// "The parts of a type T are: [...] if T is an abstract type, the parts of its upper bound"
348+
for (part <- tp.namedPartsWith(_.isType, excludeLowerBounds = true))
347349
comps ++= iscopeRefs(part)
348350
}
349351
comps

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -577,16 +577,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
577577
}
578578

579579
def escapingRefs(block: Tree, localSyms: => List[Symbol])(implicit ctx: Context): collection.Set[NamedType] = {
580-
var hoisted: Set[Symbol] = Set()
581580
lazy val locals = localSyms.toSet
582-
def leakingTypes(tp: Type): collection.Set[NamedType] =
583-
tp namedPartsWith (tp => locals.contains(tp.symbol))
584-
def typeLeaks(tp: Type): Boolean = leakingTypes(tp).nonEmpty
585-
def classLeaks(sym: ClassSymbol): Boolean =
586-
(ctx.owner is Method) || // can't hoist classes out of method bodies
587-
(sym.info.parents exists typeLeaks) ||
588-
(sym.info.decls.toList exists (t => typeLeaks(t.info)))
589-
leakingTypes(block.tpe)
581+
block.tpe namedPartsWith (tp => locals.contains(tp.symbol))
590582
}
591583

592584
/** Check that expression's type can be expressed without references to locally defined

0 commit comments

Comments
 (0)