Skip to content

Commit c90d8b5

Browse files
committed
Fix scala#6900: Support chained polymorphic extension methods
Given a tree `qual.foo`, when we typecheck `qual` we now that the result must have a member named `foo`, if it doesn't we'll try to adapt it through implicit conversion / extension method selection to something which does have such a member. Given a tree `qual.foo.bar`, the same process happens, but when we perform the implicit conversion on `qual` we actually now more about the member `foo`: it must have a member named `bar`, however in general we cannot use this information: this member might actually require another conversion and we don't chain conversions as a rule. Therefore, we need to ignore the expected type of the member, this is implemented by `ProtoTypes#selectionProto` wrapping the expected member type in `IgnoredProto`. However, the following failed before this commit: given bla[A] { def (a: A) foo[C]: C => A = _ => a } 1.foo[String].foo[String] This happens because when `Applications#extMethodApply` extracts the type arguments of the extension method from its expected type, it might end up unpealing an `IgnoredProto`. The solution is to rewrap the new expeted type into an `IgnoredProto` if the original was ignored.
1 parent 54b08e1 commit c90d8b5

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,13 +1837,19 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
18371837
* <methodRef>(<receiver>) or
18381838
* <methodRef>[<type-args>](<receiver>)
18391839
*
1840-
* where <type-args> comes from `pt` if it is a PolyProto.
1840+
* where <type-args> comes from `pt` if it is a (possibly ignored) PolyProto.
18411841
*/
18421842
def extMethodApply(methodRef: untpd.Tree, receiver: Tree, pt: Type)(implicit ctx: Context) = {
1843-
val (core, pt1) = pt.revealIgnored match {
1844-
case PolyProto(targs, restpe) => (untpd.TypeApply(methodRef, targs.map(untpd.TypedSplice(_))), restpe)
1845-
case _ => (methodRef, pt)
1843+
def integrateTypeArgs(current: Type, wasIgnored: Boolean): (untpd.Tree, Type) = current match {
1844+
case IgnoredProto(ignored) =>
1845+
integrateTypeArgs(ignored, wasIgnored = true)
1846+
case PolyProto(targs, restpe) =>
1847+
val core = untpd.TypeApply(methodRef, targs.map(untpd.TypedSplice(_)))
1848+
(core, if (wasIgnored) IgnoredProto(restpe) else restpe)
1849+
case _ =>
1850+
(methodRef, pt)
18461851
}
1852+
val (core, pt1) = integrateTypeArgs(pt, wasIgnored = false)
18471853
val app =
18481854
typed(untpd.Apply(core, untpd.TypedSplice(receiver) :: Nil), pt1, ctx.typerState.ownedVars)(
18491855
ctx.addMode(Mode.SynthesizeExtMethodReceiver))

0 commit comments

Comments
 (0)