Skip to content

Commit 0cad37b

Browse files
committed
Add defn.FunctionNOf.{apply,unapply}
This provides variant to `defn.FunctionOf` that only deals with proper `FunctionN` and `ContextFunctionN` types. This avoids some overhead. A difference between the two `unapply`s is that this one does not dealias the type, it needs to be dealiased at call site. Part of #18305 [Cherry-picked d78c157][modified]
1 parent 53eeabf commit 0cad37b

10 files changed

+39
-23
lines changed

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,10 +1102,8 @@ class Definitions {
11021102
object FunctionOf {
11031103
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
11041104
val mt = MethodType.companion(isContextual, false)(args, resultType)
1105-
if mt.hasErasedParams then
1106-
RefinedType(ErasedFunctionClass.typeRef, nme.apply, mt)
1107-
else
1108-
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1105+
if mt.hasErasedParams then RefinedType(ErasedFunctionClass.typeRef, nme.apply, mt)
1106+
else FunctionNOf(args, resultType, isContextual)
11091107
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean)] = {
11101108
ft.dealias match
11111109
case ErasedFunctionOf(mt) =>
@@ -1132,6 +1130,24 @@ class Definitions {
11321130
case _ => None
11331131
}
11341132

1133+
object FunctionNOf {
1134+
/** Create a `FunctionN` or `ContextFunctionN` type applied to the arguments and result type */
1135+
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
1136+
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1137+
1138+
/** Matches a (possibly aliased) `FunctionN[...]` or `ContextFunctionN[...]`.
1139+
* Extracts the list of function argument types, the result type and whether function is contextual.
1140+
*/
1141+
def unapply(tpe: Type)(using Context): Option[(List[Type], Type, Boolean)] = {
1142+
val tsym = tpe.typeSymbol
1143+
if isFunctionSymbol(tsym) && tpe.isRef(tsym) then
1144+
val targs = tpe.argInfos
1145+
if (targs.isEmpty) None
1146+
else Some(targs.init, targs.last, tsym.name.isContextFunction)
1147+
else None
1148+
}
1149+
}
1150+
11351151
object RefinedFunctionOf {
11361152
/** Matches a refined `PolyFunction`/`FunctionN[...]`/`ContextFunctionN[...]`.
11371153
* Extracts the method type type and apply info.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
932932
case tp: TermRef =>
933933
sigName(underlyingOfTermRef(tp))
934934
case ExprType(rt) =>
935-
sigName(defn.FunctionOf(Nil, rt))
935+
sigName(defn.FunctionNOf(Nil, rt))
936936
case tp: TypeVar if !tp.isInstantiated =>
937937
tpnme.Uninstantiated
938938
case tp @ defn.PolyOrErasedFunctionOf(_) =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,7 @@ object Types {
18741874
case res: MethodType => res.toFunctionType(isJava)
18751875
case res => res
18761876
}
1877-
val funType = defn.FunctionOf(
1877+
val funType = defn.FunctionNOf(
18781878
mt.paramInfos.mapConserve(_.translateFromRepeated(toArray = isJava)),
18791879
result1, isContextual)
18801880
if alwaysDependent || mt.isResultDependent then

compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ object PickleQuotes {
326326
defn.QuotedExprClass.typeRef.appliedTo(defn.AnyType)),
327327
args =>
328328
val cases = holeContents.zipWithIndex.map { case (splice, idx) =>
329-
val defn.FunctionOf(argTypes, defn.FunctionOf(quotesType :: _, _, _), _) = splice.tpe: @unchecked
329+
val defn.FunctionNOf(argTypes, defn.FunctionNOf(quotesType :: _, _, _), _) = splice.tpe: @unchecked
330330
val rhs = {
331331
val spliceArgs = argTypes.zipWithIndex.map { (argType, i) =>
332332
args(1).select(nme.apply).appliedTo(Literal(Constant(i))).asInstance(argType)

compiler/src/dotty/tools/dotc/transform/SpecializeFunctions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class SpecializeFunctions extends MiniPhase {
8888
// Need to cast to regular function, since specialized apply methods
8989
// are not members of ContextFunction0. The cast will be eliminated in
9090
// erasure.
91-
qual.cast(defn.FunctionOf(Nil, res))
91+
qual.cast(defn.FunctionNOf(Nil, res))
9292
case _ =>
9393
qual
9494
qual1.select(specializedApply)

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -728,9 +728,9 @@ object TreeChecker {
728728
if isTerm then defn.QuotedExprClass.typeRef.appliedTo(tree1.typeOpt)
729729
else defn.QuotedTypeClass.typeRef.appliedTo(tree1.typeOpt)
730730
val contextualResult =
731-
defn.FunctionOf(List(defn.QuotesClass.typeRef), expectedResultType, isContextual = true)
731+
defn.FunctionNOf(List(defn.QuotesClass.typeRef), expectedResultType, isContextual = true)
732732
val expectedContentType =
733-
defn.FunctionOf(argQuotedTypes, contextualResult)
733+
defn.FunctionNOf(argQuotedTypes, contextualResult)
734734
assert(content.typeOpt =:= expectedContentType, i"unexpected content of hole\nexpected: ${expectedContentType}\nwas: ${content.typeOpt}")
735735

736736
tree1

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,7 +1717,7 @@ trait Applications extends Compatibility {
17171717
def apply(t: Type) = t match {
17181718
case t @ AppliedType(tycon, args) =>
17191719
def mapArg(arg: Type, tparam: TypeParamInfo) =
1720-
if (variance > 0 && tparam.paramVarianceSign < 0) defn.FunctionOf(arg :: Nil, defn.UnitType)
1720+
if (variance > 0 && tparam.paramVarianceSign < 0) defn.FunctionNOf(arg :: Nil, defn.UnitType)
17211721
else arg
17221722
mapOver(t.derivedAppliedType(tycon, args.zipWithConserve(tycon.typeParams)(mapArg)))
17231723
case _ => mapOver(t)
@@ -1944,7 +1944,7 @@ trait Applications extends Compatibility {
19441944
/** The shape of given tree as a type; cannot handle named arguments. */
19451945
def typeShape(tree: untpd.Tree): Type = tree match {
19461946
case untpd.Function(args, body) =>
1947-
defn.FunctionOf(
1947+
defn.FunctionNOf(
19481948
args.map(Function.const(defn.AnyType)), typeShape(body),
19491949
isContextual = untpd.isContextualClosure(tree))
19501950
case Match(EmptyTree, _) =>
@@ -1984,8 +1984,8 @@ trait Applications extends Compatibility {
19841984
def paramCount(ref: TermRef) =
19851985
val formals = ref.widen.firstParamTypes
19861986
if formals.length > idx then
1987-
formals(idx) match
1988-
case defn.FunctionOf(args, _, _) => args.length
1987+
formals(idx).dealias match
1988+
case defn.FunctionNOf(args, _, _) => args.length
19891989
case _ => -1
19901990
else -1
19911991

@@ -2070,8 +2070,8 @@ trait Applications extends Compatibility {
20702070
else resolveMapped(alts1, _.widen.appliedTo(targs1.tpes), pt1)
20712071

20722072
case pt =>
2073-
val compat0 = pt match
2074-
case defn.FunctionOf(args, resType, _) =>
2073+
val compat0 = pt.dealias match
2074+
case defn.FunctionNOf(args, resType, _) =>
20752075
narrowByTypes(alts, args, resType)
20762076
case _ =>
20772077
Nil
@@ -2260,7 +2260,7 @@ trait Applications extends Compatibility {
22602260
false
22612261
val commonFormal =
22622262
if (isPartial) defn.PartialFunctionOf(commonParamTypes.head, WildcardType)
2263-
else defn.FunctionOf(commonParamTypes, WildcardType, isContextual = untpd.isContextualClosure(arg))
2263+
else defn.FunctionNOf(commonParamTypes, WildcardType, isContextual = untpd.isContextualClosure(arg))
22642264
overload.println(i"pretype arg $arg with expected type $commonFormal")
22652265
if (commonParamTypes.forall(isFullyDefined(_, ForceDegree.flipBottom)))
22662266
withMode(Mode.ImplicitsEnabled) {

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,9 @@ object ProtoTypes {
371371
def allArgTypesAreCurrent()(using Context): Boolean =
372372
state.typedArg.size == args.length
373373

374-
private def isUndefined(tp: Type): Boolean = tp match {
374+
private def isUndefined(tp: Type): Boolean = tp.dealias match {
375375
case _: WildcardType => true
376-
case defn.FunctionOf(args, result, _) => args.exists(isUndefined) || isUndefined(result)
376+
case defn.FunctionNOf(args, result, _) => args.exists(isUndefined) || isUndefined(result)
377377
case _ => false
378378
}
379379

@@ -412,7 +412,7 @@ object ProtoTypes {
412412
case ValDef(_, tpt, _) if !tpt.isEmpty => typer.typedType(tpt).typeOpt
413413
case _ => WildcardType
414414
}
415-
targ = arg.withType(defn.FunctionOf(paramTypes, WildcardType))
415+
targ = arg.withType(defn.FunctionNOf(paramTypes, WildcardType))
416416
case Some(_) if !force =>
417417
targ = arg.withType(WildcardType)
418418
case _ =>

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ trait QuotesAndSplices {
116116
for arg <- typedArgs if arg.symbol.is(Mutable) do // TODO support these patterns. Possibly using scala.quoted.util.Var
117117
report.error("References to `var`s cannot be used in higher-order pattern", arg.srcPos)
118118
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
119-
val patType = if tree.args.isEmpty then pt else defn.FunctionOf(argTypes, pt)
119+
val patType = if tree.args.isEmpty then pt else defn.FunctionNOf(argTypes, pt)
120120
val pat = typedPattern(tree.body, defn.QuotedExprClass.typeRef.appliedTo(patType))(
121121
using spliceContext.retractMode(Mode.QuotedPattern).addMode(Mode.Pattern).withOwner(patternOuterContext(ctx).owner))
122122
val baseType = pat.tpe.baseType(defn.QuotedExprClass)
@@ -143,7 +143,7 @@ trait QuotesAndSplices {
143143
if isInBraces then // ${x}(...) match an application
144144
val typedArgs = args.map(arg => typedExpr(arg))
145145
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
146-
val splice1 = typedSplicePattern(splice, defn.FunctionOf(argTypes, pt))
146+
val splice1 = typedSplicePattern(splice, defn.FunctionNOf(argTypes, pt))
147147
untpd.cpy.Apply(tree)(splice1.select(nme.apply), typedArgs).withType(pt)
148148
else // $x(...) higher-order quasipattern
149149
if args.isEmpty then

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
102102
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
103103
def functionTypeEqual(baseFun: Type, actualArgs: List[Type],
104104
actualRet: Type, expected: Type) =
105-
expected =:= defn.FunctionOf(actualArgs, actualRet,
105+
expected =:= defn.FunctionNOf(actualArgs, actualRet,
106106
defn.isContextFunctionType(baseFun))
107107
val arity: Int =
108108
if fun.derivesFrom(defn.ErasedFunctionClass) then -1 // TODO support?

0 commit comments

Comments
 (0)