Skip to content

Commit 0f39f38

Browse files
committed
Handle dependent context functions
Add `FunctionTypeOfMethod` extractor that matches any kind of function and return its method type. We use this extractor instead of `ContextFunctionType` to all of * `ContextFunctionN[...]` * `ContextFunctionN[...] { def apply(using ...): R }` where `R` might be dependent on the parameters. * `PolyFunction { def apply(using ...): R }` where `R` might be dependent on the parameters. Currently this one would have at least one erased parameter.
1 parent 6e370a9 commit 0f39f38

File tree

3 files changed

+24
-7
lines changed

3 files changed

+24
-7
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
954954
def isStructuralTermSelectOrApply(tree: Tree)(using Context): Boolean = {
955955
def isStructuralTermSelect(tree: Select) =
956956
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match
957-
case defn.PolyFunctionOf(_) =>
957+
case defn.FunctionTypeOfMethod(_) =>
958958
false
959959
case RefinedType(parent, rname, rinfo) =>
960960
rname == tree.name || hasRefinement(parent)

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,22 @@ class Definitions {
11081108
// - .linkedClass: the ClassSymbol of the enumeration (class E)
11091109
sym.owner.linkedClass.typeRef
11101110

1111+
object FunctionTypeOfMethod {
1112+
/** Matches a `FunctionN[...]`/`ContextFunctionN[...]` or refined `PolyFunction`/`FunctionN[...]`/`ContextFunctionN[...]`.
1113+
* Extracts the method type type and apply info.
1114+
*/
1115+
def unapply(ft: Type)(using Context): Option[MethodOrPoly] = {
1116+
ft match
1117+
case RefinedType(parent, nme.apply, mt: MethodOrPoly)
1118+
if parent.derivesFrom(defn.PolyFunctionClass) || isFunctionNType(parent) =>
1119+
Some(mt)
1120+
case FunctionOf(argTypes, resultType, isContextual) =>
1121+
val methodType = if isContextual then ContextualMethodType else MethodType
1122+
Some(methodType(argTypes, resultType))
1123+
case _ => None
1124+
}
1125+
}
1126+
11111127
object FunctionOf {
11121128
def apply(args: List[Type], resultType: Type, isContextual: Boolean = false)(using Context): Type =
11131129
val mt = MethodType.companion(isContextual, false)(args, resultType)

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ object ContextFunctionResults:
5858
*/
5959
def contextResultsAreErased(sym: Symbol)(using Context): Boolean =
6060
def allErased(tp: Type): Boolean = tp.dealias match
61-
case defn.ContextFunctionType(_, resTpe, erasedParams) => !erasedParams.contains(false) && allErased(resTpe)
61+
case ft @ defn.FunctionTypeOfMethod(mt: MethodType) if mt.isContextualMethod =>
62+
!mt.erasedParams.contains(false) && allErased(mt.resType)
6263
case _ => true
6364
contextResultCount(sym) > 0 && allErased(sym.info.finalResultType)
6465

@@ -72,8 +73,8 @@ object ContextFunctionResults:
7273
integrateContextResults(rt, crCount)
7374
case tp: MethodOrPoly =>
7475
tp.derivedLambdaType(resType = integrateContextResults(tp.resType, crCount))
75-
case defn.ContextFunctionType(argTypes, resType, erasedParams) =>
76-
MethodType(argTypes, integrateContextResults(resType, crCount - 1))
76+
case defn.FunctionTypeOfMethod(mt) if mt.isContextualMethod =>
77+
mt.derivedLambdaType(resType = integrateContextResults(mt.resType, crCount - 1))
7778

7879
/** The total number of parameters of method `sym`, not counting
7980
* erased parameters, but including context result parameters.
@@ -103,7 +104,7 @@ object ContextFunctionResults:
103104
def recur(tp: Type, n: Int): Type =
104105
if n == 0 then tp
105106
else tp match
106-
case defn.ContextFunctionType(_, resTpe, _) => recur(resTpe, n - 1)
107+
case defn.FunctionTypeOfMethod(mt) => recur(mt.resType, n - 1)
107108
recur(meth.info.finalResultType, depth)
108109

109110
/** Should selection `tree` be eliminated since it refers to an `apply`
@@ -117,8 +118,8 @@ object ContextFunctionResults:
117118
else tree match
118119
case Select(qual, name) =>
119120
if name == nme.apply then
120-
qual.tpe match
121-
case defn.ContextFunctionType(_, _, _) =>
121+
qual.tpe.nn.dealias match
122+
case defn.FunctionTypeOfMethod(mt) if mt.isContextualMethod =>
122123
integrateSelect(qual, n + 1)
123124
case _ if defn.isContextFunctionClass(tree.symbol.maybeOwner) => // for TermRefs
124125
integrateSelect(qual, n + 1)

0 commit comments

Comments
 (0)