From 83978dfd10d3877429cd35c58a30bb70797332c7 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 20 May 2022 23:51:20 +0100 Subject: [PATCH] Extract unapply types like typedUnApply Inside typedUnApply, argTypes depend on the result of applying the unapply function (unapplyFn) on a "dummy arg", which results in calling "safeSubstParams" (while constructing the tpd.Apply) instead of just calling MethodType#instantiate. Not doing the same thing in SpaceEngine#signature results in different types that don't cancel each other, so we make SpaceEngine follow Typer/Applications/TypeAssigner. --- .../dotty/tools/dotc/transform/patmat/Space.scala | 2 +- .../src/dotty/tools/dotc/typer/TypeAssigner.scala | 7 +++++-- tests/pos/i15226.scala | 12 ++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i15226.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index fb4fbd653ee5..9d2aef95f7f7 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -556,7 +556,7 @@ class SpaceEngine(using Context) extends SpaceLogic { // Case unapplySeq: // 1. return the type `List[T]` where `T` is the element type of the unapplySeq return type `Seq[T]` - val resTp = mt.instantiate(scrutineeTp :: Nil).finalResultType + val resTp = ctx.typeAssigner.safeSubstMethodParams(mt, scrutineeTp :: Nil).finalResultType val sig = if (resTp.isRef(defn.BooleanClass)) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 80068d8632e6..d04431374827 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -279,12 +279,15 @@ trait TypeAssigner { tp } + def safeSubstMethodParams(mt: MethodType, argTypes: List[Type])(using Context): Type = + if mt.isResultDependent then safeSubstParams(mt.resultType, mt.paramRefs, argTypes) + else mt.resultType + def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(using Context): Apply = { val ownType = fn.tpe.widen match { case fntpe: MethodType => if (sameLength(fntpe.paramInfos, args) || ctx.phase.prev.relaxedTyping) - if (fntpe.isResultDependent) safeSubstParams(fntpe.resultType, fntpe.paramRefs, args.tpes) - else fntpe.resultType + safeSubstMethodParams(fntpe, args.tpes) else errorType(i"wrong number of arguments at ${ctx.phase.prev} for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.srcPos) case t => diff --git a/tests/pos/i15226.scala b/tests/pos/i15226.scala new file mode 100644 index 000000000000..d40b21e4cedb --- /dev/null +++ b/tests/pos/i15226.scala @@ -0,0 +1,12 @@ +// scalac: -Werror +class Proj { type State = String } + +sealed trait ProjState: + val a: Proj + val b: a.State + +object ProjState: + def unapply(pj: ProjState): Some[(pj.a.type, pj.b.type)] = Some((pj.a, pj.b)) + +def test(pj: ProjState) = pj match + case ProjState(p, s) =>