Skip to content

Commit e4ba788

Browse files
Add defn.FunctionNOf.{apply,unapply} (#18418)
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
2 parents 7c40fac + 1e7243a commit e4ba788

11 files changed

+38
-25
lines changed

compiler/src/dotty/tools/dotc/cc/Synthetics.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ object Synthetics:
140140
val (et: ExprType) = info: @unchecked
141141
val (enclThis: ThisType) = owner.thisType: @unchecked
142142
def mapFinalResult(tp: Type, f: Type => Type): Type =
143-
val defn.FunctionOf(args, res, isContextual) = tp: @unchecked
143+
val defn.FunctionNOf(args, res, isContextual) = tp: @unchecked
144144
if defn.isFunctionNType(res) then
145-
defn.FunctionOf(args, mapFinalResult(res, f), isContextual)
145+
defn.FunctionNOf(args, mapFinalResult(res, f), isContextual)
146146
else
147147
f(tp)
148148
ExprType(mapFinalResult(et.resType, CapturingType(_, CaptureSet(enclThis))))

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

+17-4
Original file line numberDiff line numberDiff line change
@@ -1139,10 +1139,9 @@ class Definitions {
11391139
object FunctionOf {
11401140
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
11411141
val mt = MethodType.companion(isContextual, false)(args, resultType)
1142-
if mt.hasErasedParams then
1143-
RefinedType(PolyFunctionClass.typeRef, nme.apply, mt)
1144-
else
1145-
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1142+
if mt.hasErasedParams then RefinedType(PolyFunctionClass.typeRef, nme.apply, mt)
1143+
else FunctionNOf(args, resultType, isContextual)
1144+
11461145
def unapply(ft: Type)(using Context): Option[(List[Type], Type, Boolean)] = {
11471146
ft.dealias match
11481147
case PolyFunctionOf(mt: MethodType) =>
@@ -1157,6 +1156,20 @@ class Definitions {
11571156
}
11581157
}
11591158

1159+
object FunctionNOf {
1160+
/** Create a `FunctionN` or `ContextFunctionN` type applied to the arguments and result type */
1161+
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
1162+
FunctionType(args.length, isContextual).appliedTo(args ::: resultType :: Nil)
1163+
1164+
/** Matches a (possibly aliased) `FunctionN[...]` or `ContextFunctionN[...]`.
1165+
* Extracts the list of function argument types, the result type and whether function is contextual.
1166+
*/
1167+
def unapply(tpe: AppliedType)(using Context): Option[(List[Type], Type, Boolean)] = {
1168+
if !isFunctionNType(tpe) then None
1169+
else Some(tpe.args.init, tpe.args.last, tpe.typeSymbol.name.isContextFunction)
1170+
}
1171+
}
1172+
11601173
object RefinedFunctionOf {
11611174
/** Matches a refined `PolyFunction`/`FunctionN[...]`/`ContextFunctionN[...]`.
11621175
* Extracts the method type type and apply info.

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

+1-1
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.PolyFunctionOf(_) =>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,7 @@ object Types {
19011901
case res: MethodType => res.toFunctionType(isJava)
19021902
case res => res
19031903
}
1904-
defn.FunctionOf(
1904+
defn.FunctionNOf(
19051905
mt.paramInfos.mapConserve(_.translateFromRepeated(toArray = isJava)),
19061906
result1, isContextual)
19071907
if mt.hasErasedParams then

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

+1-1
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

+1-1
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

+2-2
Original file line numberDiff line numberDiff line change
@@ -757,9 +757,9 @@ object TreeChecker {
757757
if isTerm then defn.QuotedExprClass.typeRef.appliedTo(tree1.typeOpt)
758758
else defn.QuotedTypeClass.typeRef.appliedTo(tree1.typeOpt)
759759
val contextualResult =
760-
defn.FunctionOf(List(defn.QuotesClass.typeRef), expectedResultType, isContextual = true)
760+
defn.FunctionNOf(List(defn.QuotesClass.typeRef), expectedResultType, isContextual = true)
761761
val expectedContentType =
762-
defn.FunctionOf(argQuotedTypes, contextualResult)
762+
defn.FunctionNOf(argQuotedTypes, contextualResult)
763763
assert(content.typeOpt =:= expectedContentType, i"unexpected content of hole\nexpected: ${expectedContentType}\nwas: ${content.typeOpt}")
764764

765765
tree1

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,7 @@ trait Applications extends Compatibility {
17311731
def apply(t: Type) = t match {
17321732
case t @ AppliedType(tycon, args) =>
17331733
def mapArg(arg: Type, tparam: TypeParamInfo) =
1734-
if (variance > 0 && tparam.paramVarianceSign < 0) defn.FunctionOf(arg :: Nil, defn.UnitType)
1734+
if (variance > 0 && tparam.paramVarianceSign < 0) defn.FunctionNOf(arg :: Nil, defn.UnitType)
17351735
else arg
17361736
mapOver(t.derivedAppliedType(tycon, args.zipWithConserve(tycon.typeParams)(mapArg)))
17371737
case _ => mapOver(t)
@@ -1964,7 +1964,7 @@ trait Applications extends Compatibility {
19641964
/** The shape of given tree as a type; cannot handle named arguments. */
19651965
def typeShape(tree: untpd.Tree): Type = tree match {
19661966
case untpd.Function(args, body) =>
1967-
defn.FunctionOf(
1967+
defn.FunctionNOf(
19681968
args.map(Function.const(defn.AnyType)), typeShape(body),
19691969
isContextual = untpd.isContextualClosure(tree))
19701970
case Match(EmptyTree, _) =>
@@ -2004,8 +2004,8 @@ trait Applications extends Compatibility {
20042004
def paramCount(ref: TermRef) =
20052005
val formals = ref.widen.firstParamTypes
20062006
if formals.length > idx then
2007-
formals(idx) match
2008-
case defn.FunctionOf(args, _, _) => args.length
2007+
formals(idx).dealias match
2008+
case defn.FunctionNOf(args, _, _) => args.length
20092009
case _ => -1
20102010
else -1
20112011

@@ -2090,8 +2090,8 @@ trait Applications extends Compatibility {
20902090
else resolveMapped(alts1, _.widen.appliedTo(targs1.tpes), pt1)
20912091

20922092
case pt =>
2093-
val compat0 = pt match
2094-
case defn.FunctionOf(args, resType, _) =>
2093+
val compat0 = pt.dealias match
2094+
case defn.FunctionNOf(args, resType, _) =>
20952095
narrowByTypes(alts, args, resType)
20962096
case _ =>
20972097
Nil
@@ -2280,7 +2280,7 @@ trait Applications extends Compatibility {
22802280
false
22812281
val commonFormal =
22822282
if (isPartial) defn.PartialFunctionOf(commonParamTypes.head, WildcardType)
2283-
else defn.FunctionOf(commonParamTypes, WildcardType, isContextual = untpd.isContextualClosure(arg))
2283+
else defn.FunctionNOf(commonParamTypes, WildcardType, isContextual = untpd.isContextualClosure(arg))
22842284
overload.println(i"pretype arg $arg with expected type $commonFormal")
22852285
if (commonParamTypes.forall(isFullyDefined(_, ForceDegree.flipBottom)))
22862286
withMode(Mode.ImplicitsEnabled) {

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,9 @@ object ProtoTypes {
384384
def allArgTypesAreCurrent()(using Context): Boolean =
385385
state.typedArg.size == args.length
386386

387-
private def isUndefined(tp: Type): Boolean = tp match {
387+
private def isUndefined(tp: Type): Boolean = tp.dealias match {
388388
case _: WildcardType => true
389-
case defn.FunctionOf(args, result, _) => args.exists(isUndefined) || isUndefined(result)
389+
case defn.FunctionNOf(args, result, _) => args.exists(isUndefined) || isUndefined(result)
390390
case _ => false
391391
}
392392

@@ -425,7 +425,7 @@ object ProtoTypes {
425425
case ValDef(_, tpt, _) if !tpt.isEmpty => typer.typedType(tpt).typeOpt
426426
case _ => WildcardType
427427
}
428-
targ = arg.withType(defn.FunctionOf(paramTypes, WildcardType))
428+
targ = arg.withType(defn.FunctionNOf(paramTypes, WildcardType))
429429
case Some(_) if !force =>
430430
targ = arg.withType(WildcardType)
431431
case _ =>

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ trait QuotesAndSplices {
122122
for arg <- typedArgs if arg.symbol.is(Mutable) do // TODO support these patterns. Possibly using scala.quoted.util.Var
123123
report.error("References to `var`s cannot be used in higher-order pattern", arg.srcPos)
124124
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
125-
val patType = if tree.args.isEmpty then pt else defn.FunctionOf(argTypes, pt)
125+
val patType = if tree.args.isEmpty then pt else defn.FunctionNOf(argTypes, pt)
126126
val pat = typedPattern(tree.body, defn.QuotedExprClass.typeRef.appliedTo(patType))(using quotePatternSpliceContext)
127127
val baseType = pat.tpe.baseType(defn.QuotedExprClass)
128128
val argType = if baseType.exists then baseType.argTypesHi.head else defn.NothingType
@@ -148,7 +148,7 @@ trait QuotesAndSplices {
148148
if isInBraces then // ${x}(...) match an application
149149
val typedArgs = args.map(arg => typedExpr(arg))
150150
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
151-
val splice1 = typedSplicePattern(splice, defn.FunctionOf(argTypes, pt))
151+
val splice1 = typedSplicePattern(splice, defn.FunctionNOf(argTypes, pt))
152152
untpd.cpy.Apply(tree)(splice1.select(nme.apply), typedArgs).withType(pt)
153153
else // $x(...) higher-order quasipattern
154154
if args.isEmpty then

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
104104
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
105105
def functionTypeEqual(baseFun: Type, actualArgs: List[Type],
106106
actualRet: Type, expected: Type) =
107-
expected =:= defn.FunctionOf(actualArgs, actualRet,
107+
expected =:= defn.FunctionNOf(actualArgs, actualRet,
108108
defn.isContextFunctionType(baseFun))
109109
val arity: Int =
110110
if defn.isFunctionNType(fun) then

0 commit comments

Comments
 (0)