@@ -38,6 +38,8 @@ import Constants.{Constant, IntTag, LongTag}
38
38
import Denotations .SingleDenotation
39
39
import annotation .{constructorOnly , threadUnsafe }
40
40
41
+ import scala .util .control .NonFatal
42
+
41
43
object Applications {
42
44
import tpd ._
43
45
@@ -2157,8 +2159,57 @@ trait Applications extends Compatibility {
2157
2159
}
2158
2160
}
2159
2161
2160
- def isApplicableExtensionMethod (ref : TermRef , receiver : Type )(using Context ) =
2161
- ref.symbol.is(ExtensionMethod )
2162
- && ! receiver.isBottomType
2163
- && isApplicableMethodRef(ref, receiver :: Nil , WildcardType )
2162
+ /** Assuming methodRef is a reference to an extension method defined e.g. as
2163
+ *
2164
+ * extension [T1, T2](using A)(using B, C)(receiver: R)(using D)
2165
+ * def foo[T3](using E)(f: F): G = ???
2166
+ *
2167
+ * return the tree representing methodRef partially applied to the receiver
2168
+ * and all the implicit parameters preceding it (A, B, C)
2169
+ * with the type parameters of the extension (T1, T2) inferred.
2170
+ * None is returned if the implicit search fails for any of the leading implicit parameters
2171
+ * or if the receiver has a wrong type (note that in general the type of the receiver
2172
+ * might depend on the exact types of the found instances of the proceding implicits).
2173
+ * No implicit search is tried for implicits following the receiver or for parameters of the def (D, E).
2174
+ */
2175
+ def tryApplyingExtensionMethod (methodRef : TermRef , receiver : Tree )(using Context ): Option [Tree ] =
2176
+ // Drop all parameters sections of an extension method following the receiver.
2177
+ // The return type after truncation is not important
2178
+ def truncateExtension (tp : Type )(using Context ): Type = tp match
2179
+ case poly : PolyType =>
2180
+ poly.newLikeThis(poly.paramNames, poly.paramInfos, truncateExtension(poly.resType))
2181
+ case meth : MethodType if meth.isContextualMethod =>
2182
+ meth.newLikeThis(meth.paramNames, meth.paramInfos, truncateExtension(meth.resType))
2183
+ case meth : MethodType =>
2184
+ meth.newLikeThis(meth.paramNames, meth.paramInfos, defn.AnyType )
2185
+
2186
+ def replaceCallee (inTree : Tree , replacement : Tree )(using Context ): Tree = inTree match
2187
+ case Apply (fun, args) => Apply (replaceCallee(fun, replacement), args)
2188
+ case TypeApply (fun, args) => TypeApply (replaceCallee(fun, replacement), args)
2189
+ case _ => replacement
2190
+
2191
+ val methodRefTree = ref(methodRef)
2192
+ val truncatedSym = methodRef.symbol.asTerm.copy(info = truncateExtension(methodRef.info))
2193
+ val truncatedRefTree = untpd.TypedSplice (ref(truncatedSym)).withSpan(receiver.span)
2194
+ val newCtx = ctx.fresh.setNewScope.setReporter(new reporting.ThrowingReporter (ctx.reporter))
2195
+
2196
+ try
2197
+ val appliedTree = inContext(newCtx) {
2198
+ // Introducing an auxiliary symbol in a temporary scope.
2199
+ // Entering the symbol indirectly by `newCtx.enter`
2200
+ // could instead add the symbol to the enclosing class
2201
+ // which could break the REPL.
2202
+ newCtx.scope.openForMutations.enter(truncatedSym)
2203
+ newCtx.typer.extMethodApply(truncatedRefTree, receiver, WildcardType )
2204
+ }
2205
+ if appliedTree.tpe.exists && ! appliedTree.tpe.isError then
2206
+ Some (replaceCallee(appliedTree, methodRefTree))
2207
+ else
2208
+ None
2209
+ catch
2210
+ case NonFatal (_) => None
2211
+
2212
+ def isApplicableExtensionMethod (methodRef : TermRef , receiverType : Type )(using Context ): Boolean =
2213
+ methodRef.symbol.is(ExtensionMethod ) && ! receiverType.isBottomType &&
2214
+ tryApplyingExtensionMethod(methodRef, nullLiteral.asInstance(receiverType)).nonEmpty
2164
2215
}
0 commit comments