Skip to content

Cannot splice arbitary type in macros #8865

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
yilinwei opened this issue May 3, 2020 · 7 comments · Fixed by #10852
Closed

Cannot splice arbitary type in macros #8865

yilinwei opened this issue May 3, 2020 · 7 comments · Fixed by #10852

Comments

@yilinwei
Copy link
Contributor

yilinwei commented May 3, 2020

Minimized example

import scala.quoted._
object Macro {

  def impl[A : Type](using qctx: QuoteContext): Expr[A] = {
    import qctx.tasty._
    import util._
    val tpe = typeOf[A].seal
    '{ (a: ${tpe}) => ???}
    '{???}
  }
}

Output

[error] 9 |    '{ (a: ${tpe}) => ???}
[error]   |           ^^^^^^
[error]   |           tpe.$splice cannot be used as a value type

Expectation

It should be possible to splice the type. It's also not possible to splice types which are obtained from TASTY reflect.

If we cast to Type[_ <: Any], the above snippet works. Because of this I suspect that the code isn't sound and I should be doing some form of check before splicing.

@yilinwei yilinwei changed the title Cannot splice arbitary type Cannot splice arbitary type in macros May 3, 2020
@nicolasstucki
Copy link
Contributor

Indeed, Type[_ <: Any] is not allowed to avoid soundness issues with wildcards, it should have been rejected (see #8871). Similarly, is this example tpe has type Type[_ <: AnyKind] which should fail if spliced, but it fails because it is not used as a value type (#8871).

@nicolasstucki
Copy link
Contributor

The way to make this work is by creating an existential type X for the type such that tpe is typed as quoted.Type[X]. The safe way to do this is with a quoted pattern:

    typeOf[A].seal match
      case '[$tpe] =>
        '{ (a: $tpe) => ???}

Maybe we should revisit the API for sealing types. We should have an API that always provides an existential type for the quoted.Type. Maybe using a polymorphic function type.

@smarter
Copy link
Member

smarter commented May 4, 2020

The way to make this work is by creating an existential type X for the type such that tpe is typed as quoted.Type[X]

We have logic in the compiler to do this sort of things automatically for wildcard types it's called skolemization, maybe this could be extended to deal with quotes: https://github.com/lampepfl/dotty/blob/5d6d6aa3797d000800d68f027574aeaee47aa3c2/compiler/src/dotty/tools/dotc/typer/Typer.scala#L3211-L3216

@nicolasstucki
Copy link
Contributor

Maybe it should be something like

typeOf[A].sealIn { [U] => '{ (a: U) => ???} }

where the type gets a name U and an implicit Type[T] in scope

def sealIn[T](using ctx: Context)(f: [U] => scala.quoted.Type[U] ?=> T): T 

Those are the same things we probide when we do

 typeOf[A].seal match
      case '[$tpe] =>
        '{ (a: $tpe) => ???}

The issue is that there is an implementation restriction on polymorphic types with implicits.

| Implementation restriction: polymorphic function literals must have a value parameter

@smarter would it be possible to remove this restriction?

@smarter
Copy link
Member

smarter commented May 8, 2020

Probably, I don't remember why this restriction is in place currently. But I'm not sure I understand why this would be needed here, if you already have a stable value then it should be possible to use it even if its type contains a wildcard type I think.

@neko-kai
Copy link
Contributor

neko-kai commented May 8, 2020

@smarter There was something about raw polymorphic values being unsound or dangerous, so they're restricted to Function* type, I guess excluding context functions wasn't intentional.

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Dec 18, 2020
@nicolasstucki
Copy link
Contributor

The current way to do it is using quoted patterns (see #8865 (comment)).

If we get support for the alternative using polymorphic function type we will be able to implement that outside the standard library.

@nicolasstucki nicolasstucki linked a pull request Dec 18, 2020 that will close this issue
nicolasstucki added a commit that referenced this issue Dec 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants