-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Extension methods ambiguity when type argument is added #14451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
May be related to #14450 |
If you paste your examples you should see the reason why this doesn't work. extension (dfVal: Foo)
def prevOK(step: Int): Foo = ???
def prevOK: Foo = ??? you get def prevOK(dfVal: Foo)(step: Int): Foo
def prevOK(dfVal: Foo): Foo This is an overloaded method with a different number of parameter lists but the compiler is smart enough to distinguish between them at compile time in most cases. But in case of extension (dfVal: Foo)
def prevErr[S <: Int](step: S): Foo = ???
def prevErr: Foo = ??? you get def prevErr(dfVal: Foo): [S <: Int](step: S): Foo
def prevErr(dfVal: Foo): Foo Now both of the overloaded variants take just a single parameter but they have different return types and it's not clear for the compiler which one you would like when writing val err = (new Foo).prevErr The reason for a different desugaring is that currently you cannot have a method like You can make your example compile by specifying the result type explicitly, e.g. val err: Foo = (new Foo).prevErr |
Ok. Thanks. I guess that in the meanwhile it's another one for my growing list of examples where extension methods cannot replace implicit classes. |
This is somewhat misleading, the actual translation would be pretty printed as: def prevErr(dfVal: Foo)[S <: Int](step: S): Foo
def prevErr(dfVal: Foo): Foo The actual representation is a Clause Interweaving doesn't change the representation inside the compiler, it uses the one introduced by #10950 I believe the check that allows Even if that is not the case, merging Clause Interweaving would not solve the problem, as it doesn't change the representation used |
My previous message could be simplified to: This method is completely allowed inside the compiler |
It's good to document the workaround. We can move the type argument to the extension in many cases: extension [S <: Int](dfVal: Foo)
def prevErr(step: S): Foo = ???
def prevErr: Foo = ???
val err = (new Foo).prevErr |
It turns out this is relatively easy to fix: It does not require clause interleaving, but it would have made overloading with it very limited |
Fixes #14451 Implicitly assumed type clauses could only be at the beginning, which is wrong since: ```scala extension (x: Int) def foo[T](y: T) = ??? ``` de-sugars to something like: ```scala def foo(x: Int)[T](y: T) = ??? ``` To fix it, I implement `stripInferrable`, a variant of `stripImplicit` which also drops type clauses, and use it in `resultIsMethod` I suspect the other uses of `stripImplicit` could be simplified, or even fixed (assuming they make the same mistake as `resultIsMethod`), by using `stripInferrable`
Just adding a type argument causes the compiler to report ambiguity where there is none.
Compiler version
v3.1.2-RC1
Minimized code
https://scastie.scala-lang.org/cI1XmUISRwmnIqc8rOThSw
Output
Expectation
No error.
The text was updated successfully, but these errors were encountered: