Skip to content

Right associative extension method allow apparent forward reference between parameters #16815

Closed
@Sporarum

Description

@Sporarum

Compiler version

Scala 3.2.2

Minimized code

extension [C1 <: Int](c2: (C1, C2)) // C2 looks like invalid forward reference
  def ra2_:[C2 <: C1](c1: (C1, C2)): C2 = 
    ???

https://scastie.scala-lang.org/4LgQkgomTNijNcj1BjhGPw

More examples here (tests all confusing situations):
https://scastie.scala-lang.org/B4eX394PQbazeycIPqWiXQ

Expectation

Should not compile

Why it happens

Right associative extension methods go through a confusing swap*, for example the method above becomes:

<extension> def ra2_:[C1 <: Int][C2 <: C1](c1: (C1, C2))(c2: (C1, C2))

Which is indeed a valid method (if you ignore the curried type clauses), even though the original is invalid

*At the time of writing, it is described incorrectly in the reference, and a fixed version for it is here

Why it matters

While it is fine to give surprising tricks to language experts, in this case, this can have very confusing repercussions for normal users:

Type C2 = String

extension [C1 <: Int](c2: (C1, C2)) // C2 looks like it is an alias of String, but is actually a subtype of Int !
  def ra2_:[C2 <: C1](c1: (C1, C2)): C2 = 
    ???

How to fix it

My proposal is the following:
In case the swapped groups of clauses (leftParams trailingUsing and rightTyParam rightParam) have any reference to something defined in the other group, throw an error
The error should clearly explain why it is not allowed, and maybe solutions for the problem

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions