Skip to content

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

Open
@LPTK

Description

@LPTK

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$

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:gadtarea:metaprogramming:quotesIssues related to quotes and splicesitype:bugitype:soundnessSoundness bug (it lets us compile code that crashes at runtime with a ClassCastException)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions