Skip to content
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

Unsound use of metaprogramming quotes: future-stage type evidence shouldn't be usable in the current stage #9353

Open
LPTK opened this issue Jul 12, 2020 · 2 comments
Labels
area:gadt area:metaprogramming:quotes itype:bug itype:soundness

Comments

@LPTK
Copy link
Contributor

@LPTK LPTK commented Jul 12, 2020

While reviewing my thesis, Oleg Kiselyov pointed out a subtlety in the interaction of GADTs with staging in MetaOCaml: GADT constraints should be marked by stage to prevent the use of future-stage constraints in the current stage, which would be unsound. He gave the following example, which is a test in the MetaOCaml distribution:

type _ t = T : string t
let f : type a. a t option code -> a -> unit code =
  fun c x -> .< match .~c with
  | None -> ()
  | Some T -> .~(print_endline x; .<()>.) >.
let _ = f .< None >. 0

(As an answer to the problem, MetaOCaml rejects pattern-matches of GADTs within quotes, so that does not compile.)

Sure enough, we can reproduce something similar in Scala, without even having to use a GADT, since Scala has first-class support for subtype evidence:

scala> import scala.quoted.staging._

scala> given Toolbox = Toolbox.make(getClass.getClassLoader)
def given_Toolbox: quoted.staging.Toolbox

scala> trait T { type A >: Any <: Nothing }
// defined trait T

scala> withQuoteContext { '{ (x: T) => ${ 42: x.A } } }
    java.lang.ClassCastException: java.base/java.lang.Integer cannot be cast to scala.runtime.Nothing$
@LPTK LPTK added the itype:bug label Jul 12, 2020
@abgruszecki
Copy link
Contributor

@abgruszecki abgruszecki commented Jul 12, 2020

Note that we (I think) can recreate the same issue with pattern-matching on GADTs. Since:

MetaOCaml rejects pattern-matches of GADTs within quotes, so that does not compile.

we could just not infer any GADT constraints when pattern matching inside quotes. Major upside is that this is trivial to implement.

(This doesn't do anything about the specific issue above, though)

@LPTK
Copy link
Contributor Author

@LPTK LPTK commented Jul 12, 2020

@AleksanderBG, yes, unsurprisingly we can reproduce the issue with GADTs too:

scala> enum Foo[A] { case Bar extends Foo[String] }
// defined class Foo

scala> import quoted._

scala> def foo[A: Type](using QuoteContext) = (a: A) => '{
     |   (x: Foo[A]) => x match { case Foo.Bar => ${ print(a: String); '{} } } }

scala> withQuoteContext { foo[Int].apply(42) }
    java.lang.ClassCastException: java.base/java.lang.Integer cannot be cast to java.base/java.lang.String

@abgruszecki abgruszecki added itype:soundness and removed unsoundness labels Oct 4, 2021
@nicolasstucki nicolasstucki added area:metaprogramming:quotes and removed area:metaprogramming labels Jun 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:gadt area:metaprogramming:quotes itype:bug itype:soundness
Projects
None yet
Development

No branches or pull requests

4 participants