From b987eeb9fc84d0f3965bdee9f06796f0e279387d Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 18 Feb 2021 22:03:50 +0100 Subject: [PATCH 1/3] Fix #11464: avoid expanding local paramRef in HKTypeLambda --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 14 ++++++++++---- tests/pos/i11464.scala | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 tests/pos/i11464.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 9568698893b7..f29948c1eb87 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 + val locals = util.HashSet[Type]() def toAvoid(sym: Symbol) = !sym.isStatic && forbidden.contains(sym) def partsToAvoid = new NamedPartsAccumulator(tp => toAvoid(tp.symbol)) @@ -429,8 +430,8 @@ 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 => + 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 +439,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 locals.contains(tp.ref) then tp + else if isExpandingBounds then emptyRange + else mapOver(tp) + case tl: HKTypeLambda => + locals ++= tl.paramRefs + mapOver(tl) case _ => mapOver(tp) } 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 From 68f6ace1d95e032d9326b5723d091c1e65476669 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Sat, 20 Feb 2021 01:18:56 +0100 Subject: [PATCH 2/3] Enable pickling test Avoid unnecessary recursive types in the presence of LazyRef. --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- compiler/test/dotc/pos-test-pickling.blacklist | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) 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 - From 5ff7b104f4b23367eaa9e602a330d82c107dcf1d Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Tue, 2 Mar 2021 18:08:29 +0100 Subject: [PATCH 3/3] Address review --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index f29948c1eb87..38ecc65d56d7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -401,7 +401,7 @@ object TypeOps: def avoid(tp: Type, symsToAvoid: => List[Symbol])(using Context): Type = { val widenMap = new ApproximatingTypeMap { @threadUnsafe lazy val forbidden = symsToAvoid.toSet - val locals = util.HashSet[Type]() + @threadUnsafe lazy val localParamRefs = util.HashSet[Type]() def toAvoid(sym: Symbol) = !sym.isStatic && forbidden.contains(sym) def partsToAvoid = new NamedPartsAccumulator(tp => toAvoid(tp.symbol)) @@ -431,6 +431,9 @@ object TypeOps: emptyRange // should happen only in error cases } 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)) @@ -440,11 +443,11 @@ object TypeOps: val lo1 = apply(lo) if (lo1 ne lo) lo1 else tp case tp: LazyRef => - if locals.contains(tp.ref) then tp + if localParamRefs.contains(tp.ref) then tp else if isExpandingBounds then emptyRange else mapOver(tp) case tl: HKTypeLambda => - locals ++= tl.paramRefs + localParamRefs ++= tl.paramRefs mapOver(tl) case _ => mapOver(tp)