Skip to content

Commit

Permalink
Properly refine type of inlined unapply pattern
Browse files Browse the repository at this point in the history
Fixes #17525

[Cherry-picked 9bfa854]
  • Loading branch information
nicolasstucki authored and Kordyjan committed Dec 7, 2023
1 parent d1847fe commit 5a672d5
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 16 deletions.
37 changes: 21 additions & 16 deletions compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package inlines

import ast.*, core.*
import Flags.*, Symbols.*, Types.*, Decorators.*, Constants.*, Contexts.*
import StdNames.tpnme
import StdNames.{tpnme, nme}
import transform.SymUtils._
import typer.*
import NameKinds.BodyRetainerName
Expand Down Expand Up @@ -189,28 +189,33 @@ object Inlines:
// transforms the patterns into terms, the `inlinePatterns` phase removes this anonymous class by β-reducing
// the call to the `unapply`.

val UnApply(fun, trailingImplicits, patterns) = unapp

val sym = unapp.symbol

var unapplySym1: Symbol = NoSymbol // created from within AnonClass() and used afterwards
val fun = unapp.fun
val sym = fun.symbol

val newUnapply = AnonClass(ctx.owner, List(defn.ObjectType), sym.coord) { cls =>
// `fun` is a partially applied method that contains all type applications of the method.
// The methodic type `fun.tpe.widen` is the type of the function starting from the scrutinee argument
// and its type parameters are instantiated.
val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, fun.tpe.widen, coord = sym.coord).entered
val unapply = DefDef(unapplySym.asTerm, argss =>
val body = fun.appliedToArgss(argss).withSpan(unapp.span)
if body.symbol.is(Transparent) then inlineCall(body)(using ctx.withOwner(unapplySym))
else body
)
unapplySym1 = unapplySym
List(unapply)
val unapplyInfo = fun.tpe.widen
val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, unapplyInfo, coord = sym.coord).entered

val unapply = DefDef(unapplySym.asTerm, argss => fun.appliedToArgss(argss).withSpan(unapp.span))

if sym.is(Transparent) then
// Inline the body and refine the type of the unapply method
val inlinedBody = inlineCall(unapply.rhs)(using ctx.withOwner(unapplySym))
val refinedResultType = inlinedBody.tpe.widen
def refinedResult(info: Type): Type = info match
case info: LambdaType => info.newLikeThis(info.paramNames, info.paramInfos, refinedResult(info.resultType))
case _ => refinedResultType
unapplySym.info = refinedResult(unapplyInfo)
List(cpy.DefDef(unapply)(tpt = TypeTree(refinedResultType), rhs = inlinedBody))
else
List(unapply)
}

val newFun = newUnapply.select(unapplySym1).withSpan(unapp.span)
cpy.UnApply(unapp)(newFun, trailingImplicits, patterns)
val newFun = newUnapply.select(sym.name).withSpan(unapp.span)
cpy.UnApply(unapp)(fun = newFun)
end inlinedUnapply

/** For a retained inline method, another method that keeps track of
Expand Down
5 changes: 5 additions & 0 deletions tests/pos/i17525.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Extract {
transparent inline def unapply(value: String): Option[Tuple] = Some((1, "two"))
}
def fail(): Unit = "" match { case Extract(a, b) => f(a, b) }
def f(n: Int, s: String): Unit = ()

0 comments on commit 5a672d5

Please sign in to comment.