-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Type.of drops an opaque type info if macro called from the same level type type defined #18283
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
The opaque type specification states
This implies that in reference to an opaque type at the same level the is type defined, is seen as a type alias. Therefore it is fine if it is dealiased. Note that the dealiased only happens on the quoted pattern matching. In that case Furthermore, in both cases |
I think that would be an acceptable if there was no "not guaranteed" part at least. Because right now the outcome is just non-deterministic.
and
Provide different results (given that Sorry if that sounds over-dramatic, but it's a huge letdown from opaque types - as result I cannot use them in my case classes at all, given that at any point the classes could be used in macros and compile-time error will be super hard (impossible for users) to debug. |
What is the intended use case? |
Example with skunk-tables - if I define in table class some member
The compiler complains that it expected def tupleToList: List[quotes.reflect.TypeRepr] =
import quotes.reflect.*
self.asType match
case '[t *: ts] => TypeRepr.of[t] :: TypeRepr.of[ts].tupleToList
case '[EmptyTuple] => Nil To def tupleToList: List[quotes.reflect.TypeRepr] =
import quotes.reflect.*
self match
case AppliedType(TypeRef(ThisType(_),"*:"), List(head, tail)) if tail.show == "scala.Tuple$package.EmptyTuple" =>
head :: Nil
case AppliedType(TypeRef(ThisType(_),"*:"), List(head, tail @ AppliedType(_, _))) =>
head :: tail.tupleToList
case end if end.show == "scala.Tuple$package.EmptyTuple" =>
Nil But there are other places where I don't know how to get rid of |
Could you show a small self-contained example of where this goes wrong? |
is it not really possible to define that opaque type somewhere else, (e.g. a nested object) and then re-export it from the scope where it was originally? |
This is what I did in the end, yes: opaque type TaskId = UUID
object Task:
type Id = TaskId
final case class Task(id: Task.Id) It works, but my broader concern that other users (of skunk-tables, or generally any macro-heavy lib that reflects on product types and summons implicit for their members) will have hard times debugging that. And even broader concern about opaque types in general. This is not the first time I hit a similar problem (#17211) and I'm wondering if my expectations of opaque types are wrong or nobody has raised this.
Do you mean without mentioned lib? |
If you want to see the underlying type of |
This would be more safe: type TaskId = Task.Id
object Task:
opaque type Id = UUID
final case class Task(id: Task.Id) |
Compiler version
3.3.0, 3.3.1-RC4
Minimized code
Output
Expectation
I do expect to have the opaque type preserved in all situations.
I still haven't managed to catch the exact conditions when it fails (not sure that "same level" is to blame). Here's another situation where the behavior doesn't match the expectation:
Output:
And with this
run
it has expected result:The text was updated successfully, but these errors were encountered: