From 7ea0d976a1e368c91be22994e3d42aa1673ab76f Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 13 Jun 2022 11:39:57 +0200 Subject: [PATCH] Make simplify replace type parameters inside method types Simplify usually replaces a constrained TypeParamRef with the associated TypeVar, which is necessary so that the TypeParamRef is properly instantiated afterwards. But it did not recurse inside method types, since that might change signatures. This commit adds an auxiliary TypeMap over method types that just instantiates TypeParamRefs without applying any of the other transformations of simplify. --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 8 +++++++- compiler/src/dotty/tools/dotc/core/Types.scala | 3 ++- tests/pos/i15428.scala | 11 +++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i15428.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 01ad6fdb0724..7d51562708b1 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -175,7 +175,13 @@ object TypeOps: val normed = tp.tryNormalize if (normed.exists) normed else mapOver case tp: MethodicType => - tp // See documentation of `Types#simplified` + // See documentation of `Types#simplified` + val addTypeVars = new TypeMap: + val constraint = ctx.typerState.constraint + def apply(t: Type): Type = t match + case t: TypeParamRef => constraint.typeVarOfParam(t).orElse(t) + case _ => this.mapOver(t) + addTypeVars(tp) case tp: SkolemType => // Mapping over a skolem creates a new skolem which by definition won't // be =:= to the original one. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6a5d48866158..40cf82ceec62 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1890,7 +1890,8 @@ object Types { * but its simplification is `Serializable`). This means that simplification * should never be used in a `MethodicType`, because that could * lead to a different `signature`. Since this isn't very useful anyway, - * this method handles this by never simplifying inside a `MethodicType`. + * this method handles this by never simplifying inside a `MethodicType`, + * except for replacing type parameters with associated type variables. */ def simplified(using Context): Type = TypeOps.simplify(this, null) diff --git a/tests/pos/i15428.scala b/tests/pos/i15428.scala new file mode 100644 index 000000000000..e2143f3f62c2 --- /dev/null +++ b/tests/pos/i15428.scala @@ -0,0 +1,11 @@ +import reflect.Selectable.reflectiveSelectable + +trait Foo: + def f(): Long + +def h() = k((_: Foo) => ???) + +trait Bar[TB] +given Bar[Foo] = ??? + +def k[Tk, Ptr <: { def f(): Tk }](function: Ptr => Int)(using alloc: Bar[Ptr]): Tk = ???