Skip to content

Commit

Permalink
Optimise SpaceEngine.signature for synthetic unapplies
Browse files Browse the repository at this point in the history
Instead of creating type vars, constraining against them, then
instantiating them, just instantiate the PolyType with the scrutinee
type args (or the lo/hi bound or bounded wildcard from the param).
  • Loading branch information
dwijnand committed Oct 16, 2024
1 parent 28b8c55 commit bdafee6
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4706,6 +4706,7 @@ object Types extends TypeUtils {
type BT <: LambdaType
def paramNum: Int
def paramName: binder.ThisName = binder.paramNames(paramNum)
def paramInfo: binder.PInfo = binder.paramInfos(paramNum)

override def underlying(using Context): Type = {
// TODO: update paramInfos's type to nullable
Expand Down
32 changes: 27 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import core.*
import Constants.*, Contexts.*, Decorators.*, Flags.*, NullOpsDecorator.*, Symbols.*, Types.*
import Names.*, NameOps.*, StdNames.*
import ast.*, tpd.*
import config.Printers.*
import config.Printers.exhaustivity
import printing.{ Printer, * }, Texts.*
import reporting.*
import typer.*, Applications.*, Inferencing.*, ProtoTypes.*
Expand Down Expand Up @@ -524,14 +524,36 @@ object SpaceEngine {
val mt: MethodType = unapp.widen match {
case mt: MethodType => mt
case pt: PolyType =>
if unappSym.is(Synthetic) then
val mt = pt.resultType.asInstanceOf[MethodType]
val unapplyArgType = mt.paramInfos.head
val targs = scrutineeTp.baseType(unapplyArgType.classSymbol) match
case AppliedType(_, targs) => targs
case _ =>
// Typically when the scrutinee is Null or Nothing (see i5067 and i5067b)
// For performance, do `variances(unapplyArgType)` but without using TypeVars
// so just find the variance, so we know if to min/max to the LB/UB or use a wildcard.
object accu extends TypeAccumulator[VarianceMap[TypeParamRef]]:
def apply(vmap: VarianceMap[TypeParamRef], tp: Type) = tp match
case tp: TypeParamRef if tp.binder eq pt => vmap.recordLocalVariance(tp, variance)
case _ => foldOver(vmap, tp)
val vs = accu(VarianceMap.empty[TypeParamRef], unapplyArgType)
pt.paramRefs.map: p =>
vs.computedVariance(p).uncheckedNN match
case -1 => p.paramInfo.lo
case 1 => p.paramInfo.hi
case _ => WildcardType(p.paramInfo)
pt.instantiate(targs).asInstanceOf[MethodType]
else
val locked = ctx.typerState.ownedVars
val tvars = constrained(pt)
val mt = pt.instantiate(tvars).asInstanceOf[MethodType]
scrutineeTp <:< mt.paramInfos(0)
val unapplyArgType = mt.paramInfos.head
scrutineeTp <:< unapplyArgType
// force type inference to infer a narrower type: could be singleton
// see tests/patmat/i4227.scala
mt.paramInfos(0) <:< scrutineeTp
maximizeType(mt.paramInfos(0), Spans.NoSpan)
unapplyArgType <:< scrutineeTp
maximizeType(unapplyArgType, Spans.NoSpan)
if !(ctx.typerState.ownedVars -- locked).isEmpty then
// constraining can create type vars out of wildcard types
// (in legalBound, by using a LevelAvoidMap)
Expand All @@ -543,7 +565,7 @@ object SpaceEngine {
// but I'd rather have an unassigned new-new type var, than an infinite loop.
// After all, there's nothing strictly "wrong" with unassigned type vars,
// it just fails TreeChecker's linting.
maximizeType(mt.paramInfos(0), Spans.NoSpan)
maximizeType(unapplyArgType, Spans.NoSpan)
mt
}

Expand Down

0 comments on commit bdafee6

Please sign in to comment.