@@ -38,6 +38,8 @@ import Constants.{Constant, IntTag, LongTag}
3838import Denotations .SingleDenotation
3939import annotation .{constructorOnly , threadUnsafe }
4040
41+ import scala .util .control .NonFatal
42+
4143object Applications {
4244 import tpd ._
4345
@@ -2157,8 +2159,57 @@ trait Applications extends Compatibility {
21572159 }
21582160 }
21592161
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
21642215}
0 commit comments