From 9afa629bc844340527361473e0326a64d9e6a5da Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 8 Mar 2023 18:40:14 +0000 Subject: [PATCH] AppliedTypes returned by baseType shouldn't have type lambdas as constructors In tests/pos/argDenot-alpakka.min.scala, we want `(([O] =>> Foo[O, S]) @uV)[Int]`.baseType(`Foo`) to return `Foo[Int]` rather than an applied type lambda, so that we can rely on the invariant that the type arguments of the type returned by baseType(cls) correspond to the type parameter of cls which `NamedType#argDenot` is implicitly relying on. This could be achieved by removing the initial if branch from the AppliedType case in baseTypeOf, since the recursive fallback will always work, but it makes sense to keep a special case for performance, so we just explicitly add as a condition to the fast-path that the type constructor of the AppliedType can't be a lambda. --- .../tools/dotc/core/SymDenotations.scala | 5 ++--- tests/pos/argDenot-alpakka.min.scala | 9 ++++++++ tests/pos/argDenot-alpakka.scala | 21 +++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/pos/argDenot-alpakka.min.scala create mode 100644 tests/pos/argDenot-alpakka.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0f94d52f5be9..beeaa2ee922e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2226,13 +2226,12 @@ object SymDenotations { def computeApplied = { btrCache(tp) = NoPrefix val baseTp = - if (tycon.typeSymbol eq symbol) tp - else (tycon.typeParams: @unchecked) match { + if (tycon.typeSymbol eq symbol) && !tycon.isLambdaSub then tp + else (tycon.typeParams: @unchecked) match case LambdaParam(_, _) :: _ => recur(tp.superType) case tparams: List[Symbol @unchecked] => recur(tycon).substApprox(tparams, args) - } record(tp, baseTp) baseTp } diff --git a/tests/pos/argDenot-alpakka.min.scala b/tests/pos/argDenot-alpakka.min.scala new file mode 100644 index 000000000000..0e509be59cfd --- /dev/null +++ b/tests/pos/argDenot-alpakka.min.scala @@ -0,0 +1,9 @@ +import scala.annotation.unchecked.uncheckedVariance as uV + +trait Test: + def test[S] = + val a: (([O] =>> Foo[O, S]) @uV)[Int] = ??? + a.m() + +class Foo[X, Y]: + def m(): Y = ??? diff --git a/tests/pos/argDenot-alpakka.scala b/tests/pos/argDenot-alpakka.scala new file mode 100644 index 000000000000..41d6ad52ac97 --- /dev/null +++ b/tests/pos/argDenot-alpakka.scala @@ -0,0 +1,21 @@ +import scala.annotation.unchecked.uncheckedVariance as uV + +trait Test: + def split[I, M](in: Flow[I, Byte, M]): SubFlow[Byte, M, in.Repr] + def test = + split(new Flow[Int, Byte, Unit]) + .via[Char] + .merge + .filter() + +trait FlowOps[+Out, +Mat]: + type Repr[+O] <: FlowOps[O, Mat] { type Repr[+O] = FlowOps.this.Repr[O] } + def via[O]: Repr[O] = ??? + def filter(): Repr[Out] = ??? + +class Flow[-In, +Out, +Mat] extends FlowOps[Out, Mat]: + type Repr[+O] = Flow[In @uV, O, Mat @uV] + +class SubFlow[+Out, +Mat, +F[+_]] extends FlowOps[Out, Mat]: + type Repr[+O] = SubFlow[O, Mat @uV, F @uV] + def merge: F[Out] = ???