Skip to content

Commit bdafee6

Browse files
committed
Optimise SpaceEngine.signature for synthetic unapplies
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).
1 parent 28b8c55 commit bdafee6

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4706,6 +4706,7 @@ object Types extends TypeUtils {
47064706
type BT <: LambdaType
47074707
def paramNum: Int
47084708
def paramName: binder.ThisName = binder.paramNames(paramNum)
4709+
def paramInfo: binder.PInfo = binder.paramInfos(paramNum)
47094710

47104711
override def underlying(using Context): Type = {
47114712
// TODO: update paramInfos's type to nullable

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import core.*
77
import Constants.*, Contexts.*, Decorators.*, Flags.*, NullOpsDecorator.*, Symbols.*, Types.*
88
import Names.*, NameOps.*, StdNames.*
99
import ast.*, tpd.*
10-
import config.Printers.*
10+
import config.Printers.exhaustivity
1111
import printing.{ Printer, * }, Texts.*
1212
import reporting.*
1313
import typer.*, Applications.*, Inferencing.*, ProtoTypes.*
@@ -524,14 +524,36 @@ object SpaceEngine {
524524
val mt: MethodType = unapp.widen match {
525525
case mt: MethodType => mt
526526
case pt: PolyType =>
527+
if unappSym.is(Synthetic) then
528+
val mt = pt.resultType.asInstanceOf[MethodType]
529+
val unapplyArgType = mt.paramInfos.head
530+
val targs = scrutineeTp.baseType(unapplyArgType.classSymbol) match
531+
case AppliedType(_, targs) => targs
532+
case _ =>
533+
// Typically when the scrutinee is Null or Nothing (see i5067 and i5067b)
534+
// For performance, do `variances(unapplyArgType)` but without using TypeVars
535+
// so just find the variance, so we know if to min/max to the LB/UB or use a wildcard.
536+
object accu extends TypeAccumulator[VarianceMap[TypeParamRef]]:
537+
def apply(vmap: VarianceMap[TypeParamRef], tp: Type) = tp match
538+
case tp: TypeParamRef if tp.binder eq pt => vmap.recordLocalVariance(tp, variance)
539+
case _ => foldOver(vmap, tp)
540+
val vs = accu(VarianceMap.empty[TypeParamRef], unapplyArgType)
541+
pt.paramRefs.map: p =>
542+
vs.computedVariance(p).uncheckedNN match
543+
case -1 => p.paramInfo.lo
544+
case 1 => p.paramInfo.hi
545+
case _ => WildcardType(p.paramInfo)
546+
pt.instantiate(targs).asInstanceOf[MethodType]
547+
else
527548
val locked = ctx.typerState.ownedVars
528549
val tvars = constrained(pt)
529550
val mt = pt.instantiate(tvars).asInstanceOf[MethodType]
530-
scrutineeTp <:< mt.paramInfos(0)
551+
val unapplyArgType = mt.paramInfos.head
552+
scrutineeTp <:< unapplyArgType
531553
// force type inference to infer a narrower type: could be singleton
532554
// see tests/patmat/i4227.scala
533-
mt.paramInfos(0) <:< scrutineeTp
534-
maximizeType(mt.paramInfos(0), Spans.NoSpan)
555+
unapplyArgType <:< scrutineeTp
556+
maximizeType(unapplyArgType, Spans.NoSpan)
535557
if !(ctx.typerState.ownedVars -- locked).isEmpty then
536558
// constraining can create type vars out of wildcard types
537559
// (in legalBound, by using a LevelAvoidMap)
@@ -543,7 +565,7 @@ object SpaceEngine {
543565
// but I'd rather have an unassigned new-new type var, than an infinite loop.
544566
// After all, there's nothing strictly "wrong" with unassigned type vars,
545567
// it just fails TreeChecker's linting.
546-
maximizeType(mt.paramInfos(0), Spans.NoSpan)
568+
maximizeType(unapplyArgType, Spans.NoSpan)
547569
mt
548570
}
549571

0 commit comments

Comments
 (0)