diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 9568698893b7..38ecc65d56d7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -401,6 +401,7 @@ object TypeOps: def avoid(tp: Type, symsToAvoid: => List[Symbol])(using Context): Type = { val widenMap = new ApproximatingTypeMap { @threadUnsafe lazy val forbidden = symsToAvoid.toSet + @threadUnsafe lazy val localParamRefs = util.HashSet[Type]() def toAvoid(sym: Symbol) = !sym.isStatic && forbidden.contains(sym) def partsToAvoid = new NamedPartsAccumulator(tp => toAvoid(tp.symbol)) @@ -429,8 +430,11 @@ object TypeOps: case _ => emptyRange // should happen only in error cases } - case tp: ThisType if toAvoid(tp.cls) => - range(defn.NothingType, apply(classBound(tp.cls.classInfo))) + case tp: ThisType => + // ThisType is only used inside a class. + // Therefore, either they don't appear in the type to be avoided, or + // it must be a class that encloses the block whose type is to be avoided. + tp case tp: SkolemType if partsToAvoid(Nil, tp.info).nonEmpty => range(defn.NothingType, apply(tp.info)) case tp: TypeVar if mapCtx.typerState.constraint.contains(tp) => @@ -438,8 +442,13 @@ object TypeOps: tp.origin, fromBelow = variance > 0 || variance == 0 && tp.hasLowerBound)(using mapCtx) val lo1 = apply(lo) if (lo1 ne lo) lo1 else tp - case tp: LazyRef if isExpandingBounds => - emptyRange + case tp: LazyRef => + if localParamRefs.contains(tp.ref) then tp + else if isExpandingBounds then emptyRange + else mapOver(tp) + case tl: HKTypeLambda => + localParamRefs ++= tl.paramRefs + mapOver(tl) case _ => mapOver(tp) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ab025524a0b1..d3c710033c29 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2924,7 +2924,7 @@ object Types { tp match { case tp: TypeRef => apply(x, tp.prefix) case tp: RecThis => RecType.this eq tp.binder - case tp: LazyRef => true // To be safe, assume a reference exists + case tp: LazyRef => this(x, tp.ref) case _ => foldOver(x, tp) } } diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index c83e51e921d6..7e1e1a8b34ec 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -60,4 +60,3 @@ i9793.scala # lazy_implicit symbol has different position after pickling i8182.scala - diff --git a/tests/pos/i11464.scala b/tests/pos/i11464.scala new file mode 100644 index 000000000000..59da39dc8aa5 --- /dev/null +++ b/tests/pos/i11464.scala @@ -0,0 +1,16 @@ +trait Txn[T <: Txn[T]] + +trait Adjunct + +trait Type0 +trait Type[A1, Repr[~ <: Txn[~]] <: Expr[~, A1]] extends Type0 + +object Expr { + def test(peer: Type0): Adjunct = { + new AdjunctImpl(peer.asInstanceOf[Type[Any, ({ type R[~ <: Txn[~]] <: Expr[~, Any] }) # R]]) + } +} + +trait Expr[T <: Txn[T], +A] + +class AdjunctImpl[A, E[~ <: Txn[~]] <: Expr[~, A]](tpe: Type[A, E]) extends Adjunct