-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Wrong staging level for quoted structural/refinement type with type member #22648
Comments
In search of a workaround, how could I create a type like Object {
type T
def make: T
} manually, i.e. using the FWIW, here's a failed attempt: RecursiveType(self =>
val tp0 = TypeRepr.of[Object]
val tp1 = Refinement(tp0, "T", TypeBounds.empty)
val tp2 = Refinement(tp1, "make", MethodType(MethodTypeKind.Plain)(paramNames = Nil)(
mt => Nil,
mt => ???, // How to refer to type `T` in the return type of `make`?
// Note that there's no TypeRef constructor to construct TypeRef(self.recThis, "T")
))
tp2
) Thanks for any suggestions. |
What's your use case, actually? import scala.quoted.*
trait MakerTaker:
type T
def make: T
def take(t: T): Unit
transparent inline def foo =
${ fooImpl }
def fooImpl(using Quotes): Expr[MakerTaker] =
'{
new MakerTaker {
type T = Unit
def make: T = ()
def take(t: T): Unit = ()
}
} If you need |
It's the latter, i.e. completely arbitrary members, incl. type members. I don't think
(I did realize quotes are going to be too limited for generating the code from dynamic data anyway, but still, it is a legit bug, and still, I don't have a way of defining the type ascription via I seem to be getting some mileage from dotty.tools.dotc.core.Types.TypeRef(owner, name)
.asInstanceOf[TypeRepr] but I'm sure I'm shooting myself in the foot.
Read a schema specification file (like OpenAPI) and get a typed Scala API, without a separate codegen pass. The type definitions from the spec would be the type members of my structural type. |
Actually, it seems like the original snippet almost compile import scala.quoted.*
transparent inline def foo =
${ fooImpl }
def fooImpl(using Quotes): Expr[Any] =
'{
new AnyRef {
type T = Unit
def make: T = ()
def take(t: T): Unit = ()
}: {
type T = Unit
def make: T
def take(t: T): Unit
}
} Here I only added |
That's an interesting observation. In fact, I can run your snippet with an additional import: import scala.reflect.Selectable.reflectiveSelectable
println(foo.make) (prints However, I indeed want to keep the type |
You can still abstract over the actual value of import scala.quoted.*
transparent inline def foo[A](inline value: A) =
${ fooImpl[A]('value) }
def fooImpl[A : Type](value: Expr[A])(using Quotes): Expr[Any] =
value match
case '{ $v: t } =>
'{
new AnyRef {
type T = t
def make: T = $v
def take(t: T): Unit = ()
}: {
type T = t
def make: T
def take(t: T): Unit
}
} Here, |
Though the user of the generated code would still see what |
How about this workaround then? import scala.quoted.*
transparent inline def foo =
${ fooImpl }
def fooImpl(using Quotes): Expr[Any] =
type MakerTaker = {
type T
def make: T
def take(t: T): Unit
}
'{
new AnyRef {
type T = Unit
def make: T = ()
def take(t: T): Unit = ()
}: MakerTaker
} |
That compiles, but doesn't work - prints workaround.scala : go.scala : import scala.reflect.Selectable.reflectiveSelectable
println(foo.make)
|
I guess that's because how the refinement with an abstract import scala.quoted.*
transparent inline def foo =
${ fooImpl }
def fooImpl(using Quotes): Expr[Any] =
type MakerTaker = {
type T
def make: T
def take(t: T): Unit
}
'{
new AnyRef {
type T = List[Int]
def make: T = Nil
def take(t: T): Unit = ()
}: MakerTaker
} and in this case |
Hmm, so a special (and incorrect) handling of Other than that, it does look like a working workaround. Unfortunately though, through no fault of macros/quotes, it doesn't get me where I want to go, as even without macros click for the no-macro version
Foo.take(Foo.make) gives me [error] Structural access not allowed on method take because it has a parameter type with an unstable erasure
[error] println(Foo.take(Foo.make))
[error] ^^^^^^^^^^^^^^^^^^ 🤷♂. UPDATE: Extra boxing does resolve that. import scala.reflect.Selectable.reflectiveSelectable
case class Box[T](value: T)
val Foo =
new AnyRef {
type T = List[Int]
def make: Box[T] = Box(Nil)
def take(t: Box[T]): Unit = ()
}: {
type T
def make: Box[T]
def take(t: Box[T]): Unit
}
println(Foo.take(Foo.make))
|
Compiler version
3.6.3
Minimized code
Output
Expectation
Should compile, as there is no stage mismatch.
A workaround would be appreciated.
The text was updated successfully, but these errors were encountered: