Skip to content

Structurally typed Selectable compile error: Sequence argument type annotation * cannot be used here #20044

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

Closed
hmf opened this issue Mar 28, 2024 · 6 comments

Comments

@hmf
Copy link

hmf commented Mar 28, 2024

Compiler version

Version 3.4.1-RC2

Minimized code

In makeRecX(), if we return a RecordX, it works. Current code fails.

package structSelect

 
class RecordX(elems: (String, Any)*) extends Selectable:
  private val fields = elems.toList
  val name: String = "A" 
  val age: Int = 1
  def selectDynamic(name: String): Any = fields.find(_._1 == name).get._2
  def applyDynamic(name: String)(args: Any*): Any = ???

/*transparent inline*/ def makeRecX() =
  // Ok
  // RecordX("name" -> "Hemma", "age" -> 6).asInstanceOf[ RecordX ]
  // Fails
  RecordX("name" -> "Hemma", "age" -> 6).asInstanceOf[
    Selectable { 
      val name: String; 
      val age: Int; 
      def selectDynamic(name: String): Any;
      def applyDynamic(name: String)(args: Any*): Any
     } 
    ]

@main 
def mainRecordCheck(): Unit =

  val person5 = makeRecX()
  println(person5.name)

Example above in scastie

Output

[error] 78 |  println(person5.name)
[error]    |                      ^
[error]    |Sequence argument type annotation `*` cannot be used here:
[error]    |it is not the only argument to be passed to the corresponding repeated parameter Any*
[error] one error found

Expectation

I expected that to work. Although this error seems to be similar to this issue, it occurs in the simpler case when accessing a member (selectDynamic and not applyDynamic), hence this report.

@hmf hmf added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Mar 28, 2024
@hmf
Copy link
Author

hmf commented Mar 28, 2024

Same error when using dynamic. See this code.

package structSelect

 
class RecordX(elems: (String, Any)*) extends Selectable:
  private val fields = elems.toList
  val name: String = "A" 
  val age: Int = 1
  def selectDynamic(name: String): Any = fields.find(_._1 == name).get._2
  def applyDynamic(name: String)(args: Any*): Any = ???

/*transparent inline*/ def makeRecX() =
  // Ok
  // RecordX("name" -> "Hemma", "age" -> 6).asInstanceOf[ RecordX ]
  // Fails
  RecordX("name" -> "Hemma", "age" -> 6).asInstanceOf[
    Selectable { 
      val name: String; 
      val age: Int; 
      def selectDynamic(name: String): Any;
      def applyDynamic(name: String)(args: Any*): Any
     } 
    ]


import scala.language.dynamics

class RecordY(elems: (String, Any)*) extends Dynamic:
  private val fields = elems.toList
  val name: String = "A" 
  val age: Int = 1
  def selectDynamic(name: String): Any = fields.find(_._1 == name).get._2
  def applyDynamic(name: String)(args: Any*): Any = ???


/*transparent inline*/ def makeRecY() =
  // Ok
  // RecordX("name" -> "Hemma", "age" -> 6).asInstanceOf[ RecordX ]
  // Fails
  RecordY("name" -> "Hemma", "age" -> 6).asInstanceOf[
    Dynamic { 
      val name: String; 
      val age: Int; 
      def selectDynamic(name: String): Any;
      def applyDynamic(name: String)(args: Any*): Any
     } 
    ]


@main 
def mainRecordCheck(): Unit =

  val person5 = makeRecX()
  println(person5.name)

  val person6 = makeRecY()
  println(person6.name)

@prolativ
Copy link
Contributor

prolativ commented Mar 29, 2024

The problem here doesn't really seem to be related to varargs. If we compile the initial example with -Xprint:typer, we'll see that person5.name after the desugarings is seen by the compiler as

person5.applyDynamic("applyDynamic")(
            ["selectDynamic",["name" : Any]* : Any]*).$asInstanceOf[Any].
            $asInstanceOf[Any].$asInstanceOf[(person5.name : String)]

That's because the return type of makeRecX is Selectable { ... } while what you would actually need here is RecordX { ... }. Otherwise after the compiler desugars

person5.name

to

person5.selectDynamic("name").asInstanceOf[String]

it might further try desugaring it into

person5.applyDynamic("selectDynamic")("name").asInstanceOf[Any].asInstanceOf[String]

because selectDynamic is not a statically known member of Selectable

@hmf
Copy link
Author

hmf commented Mar 29, 2024

@prolativ Thank you for the explanation. At first glance what you say seems to make sense. But why would the compiler try further de-sugaring? Is their another condition where this must be so?

I am assuming the marker trait Selectable should never try to de-sugar any of its "own" members. Which leads me to ask, why are the required methods not "statically" known? I see in the source code these methods are not defined. I am assuming that the required methods are encoded into the compiler. Maybe this is an issue?

Reason I ask these questions is to know whether this issue has any chance of going forward or if I should close this.

TIA

@prolativ
Copy link
Contributor

Right, actually the compiler tries to go one step further with desugaring and gets into something like

person5.applyDynamic("applyDynamic")("selectDynamic", "name").asInstanceOf[Any].asInstanceOf[Any].asInstanceOf[String]

or actually

person5.applyDynamic("applyDynamic")(
            ["selectDynamic",["name" : Any]* : Any]*).$asInstanceOf[Any].
            $asInstanceOf[Any].$asInstanceOf[(person5.name : String)]

as the compiler sees it at this point.
And here indeed we're hitting the issue described in #18009.

In general selectDynamic and applyDynamic are not members of Selectable trait because their signatures can be arbitrary and both of these methods are optional and it's OK to declare only one of them. They could be extension methods as well, which brings a lot of flexibility but at the same time leads to issues like this

@hmf
Copy link
Author

hmf commented Mar 29, 2024

@prolativ Thank you once again. Had not considered the complexities regarding the Selectable methods.

@Gedochao Gedochao added area:typer stat:duplicate and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Apr 2, 2024
@Gedochao
Copy link
Contributor

Gedochao commented Apr 2, 2024

Let's track this under #18009, closing this issue as duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants