From 0113990dda75da8e8d154db3de2e0040c76e068c Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Sun, 13 Sep 2020 21:05:46 +0200 Subject: [PATCH 1/6] Add test --- tests/pos/i9782.scala | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/pos/i9782.scala diff --git a/tests/pos/i9782.scala b/tests/pos/i9782.scala new file mode 100644 index 000000000000..434440c24156 --- /dev/null +++ b/tests/pos/i9782.scala @@ -0,0 +1,19 @@ +trait Txn[T <: Txn[T]] + +trait Elem[T <: Txn[T]] + +trait Obj[T <: Txn[T]] extends Elem[T] + +trait Copy[In <: Txn[In], Out <: Txn[Out]] { + def copyImpl[Repr[~ <: Txn[~]] <: Elem[~]](in: Repr[In]): Repr[Out] + + def apply[Repr[~ <: Txn[~]] <: Elem[~]](in: Repr[In]): Repr[Out] = { + val out = copyImpl[Repr](in) + (in, out) match { + case (inObj: Obj[In], outObj: Obj[Out]) => // problem here + println("copy the attributes") + case _ => + } + out + } +} From 0be70e7416360fdb8559afdb8064d3554a60edaf Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Sun, 13 Sep 2020 21:10:45 +0200 Subject: [PATCH 2/6] Add minimized test --- tests/pos-special/isInstanceOf/i9782.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/pos-special/isInstanceOf/i9782.scala diff --git a/tests/pos-special/isInstanceOf/i9782.scala b/tests/pos-special/isInstanceOf/i9782.scala new file mode 100644 index 000000000000..e277951769bf --- /dev/null +++ b/tests/pos-special/isInstanceOf/i9782.scala @@ -0,0 +1,15 @@ +trait Txn[T <: Txn[T]] + +trait Elem[T <: Txn[T]] + +trait Obj[T <: Txn[T]] extends Elem[T] + +class Test { + + def apply[Repr[~ <: Txn[~]] <: Elem[~], In <: Txn[In]](in: Repr[In]): Unit = { + in match { + case inObj: Obj[In] => // problem here + case _ => + } + } +} From 81da0f61c1295305cf5bfacd52c841de2da986f1 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Mon, 14 Sep 2020 14:47:45 +0200 Subject: [PATCH 3/6] Fix #9782: hanlde F-bounds in isInstanceOf check --- compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 0c22825e73b4..cdfb4a77c2b0 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -81,8 +81,9 @@ object TypeTestsCasts { case _: MatchType => tp // break cycles case tp: TypeRef if isBounds(tp.underlying) => - val lo = apply(tp.info.loBound) - val hi = apply(tp.info.hiBound) + def lo = apply(tp.info.loBound.subst(tp.symbol :: Nil, WildcardType :: Nil)) + def hi = apply(tp.info.hiBound.subst(tp.symbol :: Nil, WildcardType :: Nil)) + range(lo, hi) case _ => mapOver(tp) From 65dbc1baca9c18c918c22d4d38b7077ddd5bcf56 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Tue, 15 Sep 2020 11:19:11 +0200 Subject: [PATCH 4/6] More precisely approximating bound type parameter with type variables --- .../dotty/tools/dotc/transform/TypeTestsCasts.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index cdfb4a77c2b0..369e76c6eeda 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -26,8 +26,9 @@ import config.Printers.{ transforms => debug } */ object TypeTestsCasts { import ast.tpd._ - import typer.Inferencing.maximizeType - import typer.ProtoTypes.constrained + import typer._ + import typer.Inferencing._ + import typer.ProtoTypes._ /** Whether `(x:X).isInstanceOf[P]` can be checked at runtime? * @@ -77,14 +78,12 @@ object TypeTestsCasts { /** Approximate type parameters depending on variance */ def stripTypeParam(tp: Type)(using Context) = new ApproximatingTypeMap { + val boundTypeParams = util.HashMap[TypeRef, TypeVar]() def apply(tp: Type): Type = tp match { case _: MatchType => tp // break cycles case tp: TypeRef if isBounds(tp.underlying) => - def lo = apply(tp.info.loBound.subst(tp.symbol :: Nil, WildcardType :: Nil)) - def hi = apply(tp.info.hiBound.subst(tp.symbol :: Nil, WildcardType :: Nil)) - - range(lo, hi) + boundTypeParams.getOrElseUpdate(tp, newTypeVar(tp.underlying.toBounds)) case _ => mapOver(tp) } @@ -127,6 +126,7 @@ object TypeTestsCasts { debug.println("P1 <:< P = " + res) res + } def recur(X: Type, P: Type): Boolean = (X <:< P) || (P.dealias match { From b7d8fcbdf27be5954c22d4a1330bada6b2bd1152 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Tue, 15 Sep 2020 14:27:43 +0200 Subject: [PATCH 5/6] Code refactoring --- compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 369e76c6eeda..f2f81a4a9ac8 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -82,7 +82,7 @@ object TypeTestsCasts { def apply(tp: Type): Type = tp match { case _: MatchType => tp // break cycles - case tp: TypeRef if isBounds(tp.underlying) => + case tp: TypeRef if !tp.symbol.isClass => boundTypeParams.getOrElseUpdate(tp, newTypeVar(tp.underlying.toBounds)) case _ => mapOver(tp) From 2dcdda26f8ddf96ff8f01fad5f8fc6b73ec06d39 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 16 Sep 2020 16:49:42 +0200 Subject: [PATCH 6/6] Refactor imports --- compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index f2f81a4a9ac8..240489fc87a3 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -26,9 +26,8 @@ import config.Printers.{ transforms => debug } */ object TypeTestsCasts { import ast.tpd._ - import typer._ - import typer.Inferencing._ - import typer.ProtoTypes._ + import typer.Inferencing.maximizeType + import typer.ProtoTypes.{ constrained, newTypeVar } /** Whether `(x:X).isInstanceOf[P]` can be checked at runtime? *