From 7fa34d0633964f6b7acdaed67f7af8e3e8bcd928 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 15 Feb 2019 13:53:50 +0100 Subject: [PATCH 1/2] Fix #5844: Use an approximating type map to substitute parent type params Actual arguments could be wildcards, which means a normal substitution will not work. --- .../dotty/tools/dotc/core/Substituters.scala | 24 +++++++++++++++++ .../tools/dotc/core/SymDenotations.scala | 2 +- tests/pos/i5844.scala | 26 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i5844.scala diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index ab07a4d568fd..cdcaf2b4e3d6 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -195,4 +195,28 @@ trait Substituters { this: Context => final class SubstParamsMap(from: BindingType, to: List[Type]) extends DeepTypeMap { def apply(tp: Type): Type = substParams(tp, from, to, this) } + + /** An approximating substitution that can handle wildcards in the `to` list */ + final class SubstApproxMap(from: List[Symbol], to: List[Type])(implicit ctx: Context) extends ApproximatingTypeMap { + def apply(tp: Type): Type = tp match { + case tp: NamedType => + val sym = tp.symbol + var fs = from + var ts = to + while (fs.nonEmpty) { + if (fs.head eq sym) + return ts.head match { + case TypeBounds(lo, hi) => range(lo, hi) + case tp1 => tp1 + } + fs = fs.tail + ts = ts.tail + } + if (tp.prefix `eq` NoPrefix) tp else tp.derivedSelect(apply(tp.prefix)) + case _: ThisType | _: BoundType => + tp + case _ => + mapOver(tp) + } + } } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 14dfa73b1a1a..93b04c5bda3e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1790,7 +1790,7 @@ object SymDenotations { case LambdaParam(_, _) :: _ => recur(tp.superType) case tparams: List[Symbol @unchecked] => - recur(tycon).subst(tparams, args) + new ctx.SubstApproxMap(tparams, args).apply(recur(tycon)) } record(tp, baseTp) baseTp diff --git a/tests/pos/i5844.scala b/tests/pos/i5844.scala new file mode 100644 index 000000000000..ca735de7eaf0 --- /dev/null +++ b/tests/pos/i5844.scala @@ -0,0 +1,26 @@ +package p1 { + trait A + trait B[X, Y]{ + def m(): X + } + trait C[X] extends B[X, X & A] + + object O{ + def m(c: C[_]) = { + val x = c.m() + } + } +} +package p2 { + trait A + trait B[X]{ + def m(): X + } + trait C[X] extends B[X with A] + + object O{ + def m(c: C[_]) = { + val x: A = c.m() + } + } +} \ No newline at end of file From cf5d20e9dd15b3d756b3eb3bc45b15fec4a42de1 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 15 Feb 2019 16:57:53 +0100 Subject: [PATCH 2/2] Update compiler/src/dotty/tools/dotc/core/Substituters.scala Co-Authored-By: odersky --- compiler/src/dotty/tools/dotc/core/Substituters.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index cdcaf2b4e3d6..f39ec9a33913 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -212,7 +212,7 @@ trait Substituters { this: Context => fs = fs.tail ts = ts.tail } - if (tp.prefix `eq` NoPrefix) tp else tp.derivedSelect(apply(tp.prefix)) + if (tp.prefix `eq` NoPrefix) tp else derivedSelect(tp, apply(tp.prefix)) case _: ThisType | _: BoundType => tp case _ =>