From 7b8bafac23788dc73c0f65ebc6238e784efb59d1 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 26 Feb 2024 14:45:20 +0100 Subject: [PATCH 001/253] feat(engine): introduce a new generic printer --- engine/backends/coq/coq/coq_backend.ml | 1 + .../backends/coq/ssprove/ssprove_backend.ml | 3 +- engine/backends/fstar/fstar_backend.ml | 52 ++- engine/backends/proverif/proverif_backend.ml | 7 +- engine/default.nix | 2 + engine/lib/dune | 1 + .../new_generic_printer_api.ml | 92 +++++ .../new_generic_printer_base.ml | 175 ++++++++ .../new_generic_printer_base.mli | 23 ++ .../new_generic_printer_base_sig.ml | 373 ++++++++++++++++++ .../new_generic_printer_template.ml | 64 +++ .../new_generic_printer/new_rust_printer.ml | 170 ++++++++ .../new_generic_printer/new_rust_printer.mli | 4 + engine/lib/print_rust.ml | 112 ++++-- engine/profile.dump | 0 flake.lock | 24 ++ flake.nix | 22 +- hax-types/src/engine_api.rs | 28 ++ 18 files changed, 1109 insertions(+), 44 deletions(-) create mode 100644 engine/lib/new_generic_printer/new_generic_printer_api.ml create mode 100644 engine/lib/new_generic_printer/new_generic_printer_base.ml create mode 100644 engine/lib/new_generic_printer/new_generic_printer_base.mli create mode 100644 engine/lib/new_generic_printer/new_generic_printer_base_sig.ml create mode 100644 engine/lib/new_generic_printer/new_generic_printer_template.ml create mode 100644 engine/lib/new_generic_printer/new_rust_printer.ml create mode 100644 engine/lib/new_generic_printer/new_rust_printer.mli create mode 100644 engine/profile.dump diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 5e04b85cc..1f46b05fd 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -696,6 +696,7 @@ let translate _ (_bo : BackendOptions.t) (items : AST.item list) : path = mod_name ^ ".v"; contents = hardcoded_coq_headers ^ "\n" ^ string_of_items items ^ "\n"; + sourcemap = None; }) open Phase_utils diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index dd5bb2419..8c37530ba 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -2423,7 +2423,8 @@ let translate _ (_bo : BackendOptions.t) (items : AST.item list) : ^ "\n" in - Types.{ path = mod_name ^ ".v"; contents = file_content }) + Types. + { path = mod_name ^ ".v"; contents = file_content; sourcemap = None }) let apply_phases (_bo : BackendOptions.t) (i : Ast.Rust.item list) : AST.item list = diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 980c0cb28..76e9005c5 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1641,7 +1641,49 @@ let fstar_headers (bo : BackendOptions.t) = in [ opts; "open Core"; "open FStar.Mul" ] |> String.concat ~sep:"\n" -let translate m (bo : BackendOptions.t) (items : AST.item list) : +module NewGenericPrinter = New_rust_printer.Make (InputLanguage) + +(** Use the generic printer instead of the F* printer. For now, there +is no generic printer for F*, that's why we currently just use the +Rust generic printer. Thus currently this exists only for debugging +purposes. *) +let translate_as_experimental_rust m (bo : BackendOptions.t) + (items : AST.item list) : Types.file list = + let show_view Concrete_ident.{ crate; path; definition } = + crate :: (path @ [ definition ]) |> String.concat ~sep:"::" + in + U.group_items_by_namespace items + |> Map.to_alist + |> List.concat_map ~f:(fun (ns, items) -> + let mod_name = + String.concat ~sep:"." + (List.map + ~f:(map_first_letter String.uppercase) + (fst ns :: snd ns)) + in + let string_of_items _ _ items = + let r = NewGenericPrinter.items () items in + let str = New_generic_printer_api.AnnotatedString.to_string r in + let sm = New_generic_printer_api.AnnotatedString.to_sourcemap r in + let r = (str, sm) in + (r, r) + in + let impl, intf = string_of_items bo m items in + let make ~ext (body, sourcemap) = + if String.is_empty body then None + else + Some + Types. + { + path = mod_name ^ "." ^ ext; + contents = body; + sourcemap = Some sourcemap; + } + in + List.filter_map ~f:Fn.id [ make ~ext:"rs" impl ]) + +(** Translate as F* (the "legacy" printer) *) +let translate_as_fstar m (bo : BackendOptions.t) (items : AST.item list) : Types.file list = let show_view Concrete_ident.{ crate; path; definition } = crate :: (path @ [ definition ]) |> String.concat ~sep:"::" @@ -1673,11 +1715,19 @@ let translate m (bo : BackendOptions.t) (items : AST.item list) : contents = "module " ^ mod_name ^ "\n" ^ fstar_headers bo ^ "\n\n" ^ body ^ "\n"; + sourcemap = None; } in List.filter_map ~f:Fn.id [ make ~ext:"fst" impl; make ~ext:"fsti" intf ]) +let translate = + if + Sys.getenv "HAX_ENGINE_EXPERIMENTAL_RUST_PRINTER_INSTEAD_OF_FSTAR" + |> Option.is_some + then translate_as_experimental_rust + else translate_as_fstar + open Phase_utils module DepGraph = Dependencies.Make (InputLanguage) module DepGraphR = Dependencies.Make (Features.Rust) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 1cea56cc5..983cbae39 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -877,9 +877,12 @@ let translate m (bo : BackendOptions.t) (items : AST.item list) : ^ M.Processes.print items in let analysis_contents = M.Toplevel.print items in - let lib_file = Types.{ path = "lib.pvl"; contents = lib_contents } in + let lib_file = + Types.{ path = "lib.pvl"; contents = lib_contents; sourcemap = None } + in let analysis_file = - Types.{ path = "analysis.pv"; contents = analysis_contents } + Types. + { path = "analysis.pv"; contents = analysis_contents; sourcemap = None } in [ lib_file; analysis_file ] diff --git a/engine/default.nix b/engine/default.nix index 1a676c743..5f5202a0e 100644 --- a/engine/default.nix +++ b/engine/default.nix @@ -10,6 +10,7 @@ gnused, lib, removeReferencesTo, + ocaml-sourcemaps, }: let non_empty_list = ocamlPackages.buildDunePackage rec { pname = "non_empty_list"; @@ -66,6 +67,7 @@ re js_of_ocaml ocamlgraph + ocaml-sourcemaps ] ++ # F* dependencies diff --git a/engine/lib/dune b/engine/lib/dune index 149ea13e6..91d5acc2e 100644 --- a/engine/lib/dune +++ b/engine/lib/dune @@ -12,6 +12,7 @@ core logs re + sourcemaps ocamlgraph) (preprocessor_deps ; `ppx_inline` is used on the `Subtype` module, thus we need it at PPX time diff --git a/engine/lib/new_generic_printer/new_generic_printer_api.ml b/engine/lib/new_generic_printer/new_generic_printer_api.ml new file mode 100644 index 000000000..a537015d1 --- /dev/null +++ b/engine/lib/new_generic_printer/new_generic_printer_api.ml @@ -0,0 +1,92 @@ +open! Prelude +open New_generic_printer_base + +module AnnotatedString = struct + type t = string * Annotation.t list [@@deriving show, yojson, eq] + + let to_string = fst + + let to_spanned_strings ((s, annots) : t) : (Ast.span * string) list = + Annotation.split_with_string s annots + + let to_sourcemap : t -> Types.source_map = + snd >> List.filter_map ~f:Annotation.to_mapping >> Sourcemaps.Source_maps.mk + >> fun ({ + mappings; + sourceRoot; + sources; + sourcesContent; + names; + version; + file; + } : + Sourcemaps.Source_maps.t) -> + Types. + { mappings; sourceRoot; sources; sourcesContent; names; version; file } +end + +module Make (F : Features.T) = struct + module AST = Ast.Make (F) + open Ast.Make (F) + open SecretTypes + + type print_object = + < printer_name : string + ; get_span_data : unit -> Annotation.t list + ; ty : (par_state -> ty fn) no_override + ; pat : (par_state -> pat fn) no_override + ; arm : arm fn no_override + ; expr : (par_state -> expr fn) no_override + ; item : item fn no_override + ; items : item list fn > + (** In the end, an printer *object* should be of the type {!print_object}. *) + + module type API = sig + type aux_info + + val items : aux_info -> item list -> AnnotatedString.t + val item : aux_info -> item -> AnnotatedString.t + val expr : aux_info -> expr -> AnnotatedString.t + val pat : aux_info -> pat -> AnnotatedString.t + val ty : aux_info -> ty -> AnnotatedString.t + end + + module Api (NewPrint : sig + type aux_info + + val new_print : aux_info -> print_object + end) = + struct + open NewPrint + + let mk' (f : print_object -> 'a -> PPrint.document) (aux : aux_info) + (x : 'a) : AnnotatedString.t = + let printer = new_print aux in + let doc = f printer x in + let buf = Buffer.create 0 in + PPrint.ToBuffer.pretty 1.0 80 buf doc; + (Buffer.contents buf, printer#get_span_data ()) + + let mk (f : print_object -> 'a fn no_override) = + mk' (fun (po : print_object) -> + let f : 'a fn no_override = f po in + let f = !:f in + f) + + type aux_info = NewPrint.aux_info + + let items : aux_info -> item list -> AnnotatedString.t = + mk' (fun p -> p#items) + + let item : aux_info -> item -> AnnotatedString.t = mk (fun p -> p#item) + + let expr : aux_info -> expr -> AnnotatedString.t = + mk' (fun p -> !:(p#expr) AlreadyPar) + + let pat : aux_info -> pat -> AnnotatedString.t = + mk' (fun p -> !:(p#pat) AlreadyPar) + + let ty : aux_info -> ty -> AnnotatedString.t = + mk' (fun p -> !:(p#ty) AlreadyPar) + end +end diff --git a/engine/lib/new_generic_printer/new_generic_printer_base.ml b/engine/lib/new_generic_printer/new_generic_printer_base.ml new file mode 100644 index 000000000..63755f5f0 --- /dev/null +++ b/engine/lib/new_generic_printer/new_generic_printer_base.ml @@ -0,0 +1,175 @@ +open! Prelude +open! Ast +open PPrint + +module SecretTypes = struct + type 't no_override = 't + type 'location no_direct_call = unit +end + +let ( !: ) (type a) (f : a SecretTypes.no_override) : a = f + +include New_generic_printer_base_sig.Types + +module Make (F : Features.T) = struct + module AST = Ast.Make (F) + open Ast.Make (F) + open New_generic_printer_base_sig.Make (F) (SecretTypes) + + class virtual base : print_base_type = + object (print) + val mutable current_span = Span.default + val mutable span_data : Annotation.t list = [] + val mutable current_namespace : (string * string list) option = None + method get_span_data () = span_data + + method with_span ~(span : span) (f : unit -> document) : document = + let prev_span = current_span in + current_span <- span; + let doc = f () |> print#spanned_doc |> custom in + current_span <- prev_span; + doc + + method spanned_doc (doc : document) : custom = + let span = current_span in + object + method requirement : requirement = requirement doc + + method pretty : output -> state -> int -> bool -> unit = + fun o s i b -> + span_data <- + ({ line = s.line; col = s.column }, span) :: span_data; + pretty o s i b doc + + method compact : output -> unit = fun o -> compact o doc + end + + method expr_at = print#par_state >> print#expr + method ty_at = print#par_state >> print#ty + method pat_at = print#par_state >> print#pat + + method expr ctx (e : expr) = + let span = e.span in + print#with_span ~span (fun _ -> + try print#__expr ctx e + with Diagnostics.SpanFreeError.Exn (Data (_context, _kind)) -> + failwith "todo") + + method ty ctx full = + match full with + | TApp { ident = `Concrete ident; args } -> + print#ty_TApp_application ~full ident args |> group + | TApp + { + ident = `Primitive _ | `TupleCons _ | `TupleField _ | `Projector _; + _; + } -> + print#assertion_failure "TApp not concrete" + | TApp { ident = `TupleType size; args } -> + let args = + List.filter_map ~f:(function GType t -> Some t | _ -> None) args + in + if [%equal: int] (List.length args) size |> not then + print#assertion_failure "malformed [ty.TApp] tuple"; + print#ty_TApp_tuple ~full args + | TApp _ -> . + | _ -> print#ty_ () ctx full + + method pat ctx (full : pat) = + print#with_span ~span:full.span (fun _ -> print#pat_ () ctx full) + + method item i = + print#set_current_namespace + (print#namespace_of_concrete_ident i.ident |> Option.some); + print#with_span ~span:i.span (fun _ -> + try print#item_ () i + with Diagnostics.SpanFreeError.Exn (Data (context, kind)) -> + let error = Diagnostics.pretty_print_context_kind context kind in + (* let cast_item : item -> Ast.Full.item = Stdlib.Obj.magic in *) + (* let ast = cast_item i |> Print_rust.pitem_str in *) + let msg = + error ^ "\nLast available AST for this item:\n\n" ^ "ast" + in + (* TODO: if the printer is extremely broken, this results in a stack overflow *) + make_hax_error_item i.span i.ident msg |> print#item) + + method private __expr ctx full = + match full.e with + | App { f = { e = GlobalVar i; _ } as f; args; generic_args; _ } -> ( + let expect_one_arg where = + match args with + | [ arg ] -> arg + | _ -> print#assertion_failure @@ "Expected one arg at " ^ where + in + match i with + | `Concrete _ | `Primitive _ -> ( + match (args, i) with + | [], `Concrete i -> + print#expr_App_constant ~full i generic_args + | [], _ -> print#assertion_failure "Primitive app of arity 0" + | _ -> print#expr_App_application ~full f args generic_args) + | `TupleType _ | `TupleCons _ | `TupleField _ -> + print#assertion_failure "App: unexpected tuple" + | `Projector (`TupleField (nth, size)) -> + let arg = expect_one_arg "projector tuple field" in + print#expr_App_tuple_projection ~full ~size ~nth arg + | `Projector (`Concrete i) -> + let arg = expect_one_arg "projector concrete" in + print#expr_App_field_projection ~full i arg) + | App { f; args; generic_args; _ } -> + print#expr_App_application ~full f args generic_args + | Construct { constructor; fields; base; is_record; is_struct } -> ( + match constructor with + | `Concrete constructor -> + print#expr_Construct_inductive ~full ~is_record ~is_struct + ~constructor ~base fields + | `TupleCons _ -> + List.map ~f:snd fields |> print#expr_Construct_tuple ~full + | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> + print#assertion_failure "Construct unexpected constructors") + | App _ | Construct _ -> . + | _ -> print#expr_ () ctx full + + method arm (full : arm) = + print#with_span ~span:full.span (fun _ -> print#arm_ () full) + + method generic_param (full : generic_param) = + print#with_span ~span:full.span (fun _ -> print#generic_param_ () full) + + method param_ty (full : param) = + match full.typ_span with + | Some span -> print#with_span ~span (fun _ -> print#param_ty_ () full) + | None -> print#param_ty_ () full + + method impl_item (full : impl_item) = + print#with_span ~span:full.ii_span (fun _ -> print#impl_item_ () full) + + method trait_item (full : trait_item) = + print#with_span ~span:full.ti_span (fun _ -> print#trait_item_ () full) + + method attr (full : attr) = + print#with_span ~span:full.span (fun _ -> print#attr_ () full) + + method concrete_ident id = + let current_ns = print#get_current_namespace () in + let id_ns = print#namespace_of_concrete_ident id in + print#concrete_ident_ () + ~under_current_ns: + ([%equal: (string * string list) option] current_ns (Some id_ns)) + id + + method items = separate_map (twice hardline) print#item + method attrs = separate_map hardline print#attr + + method assertion_failure : 'any. string -> 'any = + fun details -> + let span = Span.to_thir current_span in + let kind = Types.AssertionFailure { details } in + let ctx = Diagnostics.Context.GenericPrinter print#printer_name in + Diagnostics.SpanFreeError.raise ~span ctx kind + + method set_current_namespace ns = current_namespace <- ns + method get_current_namespace () = current_namespace + method unreachable : 'any. unit -> 'any = failwith "Unreachable!" + end +end diff --git a/engine/lib/new_generic_printer/new_generic_printer_base.mli b/engine/lib/new_generic_printer/new_generic_printer_base.mli new file mode 100644 index 000000000..052b29cb1 --- /dev/null +++ b/engine/lib/new_generic_printer/new_generic_printer_base.mli @@ -0,0 +1,23 @@ +open! Prelude +open! Ast + +include module type of struct + (** Protects some methods from being called or overrided. *) + module SecretTypes = struct + type 't no_override = private 't + (** Hello *) + + type 'location no_direct_call = private unit + (** Hello *) + end + + include New_generic_printer_base_sig.Types +end + +val ( !: ) : 'a. 'a SecretTypes.no_override -> 'a + +module Make (F : Features.T) : sig + open New_generic_printer_base_sig.Make(F)(SecretTypes) + + class virtual base : print_base_type +end diff --git a/engine/lib/new_generic_printer/new_generic_printer_base_sig.ml b/engine/lib/new_generic_printer/new_generic_printer_base_sig.ml new file mode 100644 index 000000000..f786df7f2 --- /dev/null +++ b/engine/lib/new_generic_printer/new_generic_printer_base_sig.ml @@ -0,0 +1,373 @@ +[@@@warning "-37-34-27"] + +open! Prelude +open! Ast +open PPrint + +module Types = struct + (** Generic printer for the {!module:Ast} ASTs. It uses the [PPrint] +library, and additionaly computes {!Annotation.t}. *) + + (** Identifies a position in the AST. This is useful for figuring out +wether we should wrap a chunk of AST in parenthesis. or not *) + type ast_position = + | GenericValue_GType + | GenericValue_GConst + | Lhs_LhsArbitraryExpr + | Lhs_LhsArrayAccessor + | Ty_TArrow + | Ty_TRef + | Ty_Tuple + | Ty_TSlice + | Ty_TArray_typ + | Ty_TArray_length + | Expr_If_cond + | Expr_If_then + | Expr_If_else + | Expr_Array + | Expr_Assign + | Expr_Closure_param + | Expr_Closure_body + | Expr_Ascription_e + | Expr_Ascription_typ + | Expr_Let_lhs + | Expr_Let_rhs + | Expr_Let_body + | Expr_Match_scrutinee + | Expr_QuestionMark + | Expr_Borrow + | Expr_TupleProjection + | Expr_ConstructTuple + | Expr_FieldProjection + | Expr_App_f + | Expr_App_arg + | Expr_ConcreteInductive_base + | Expr_ConcreteInductive_field + | Pat_PBinding_subpat + | Pat_PDeref + | Pat_PArray + | Pat_ConstructTuple + | Pat_ConcreteInductive + | Pat_Ascription_pat + | Pat_Ascription_typ + | Pat_Or + | Param_pat + | Param_typ + | GenericParam_GPType + | GenericParam_GPConst + | Arm_pat + | Arm_body + | Item_Fn_body + [@@warning "-37"] + + module Annotation = struct + type loc = { line : int; col : int } [@@deriving show, yojson, eq] + type t = loc * span [@@deriving show, yojson, eq] + + let compare ((a, _) : t) ((b, _) : t) : int = + let line = Int.compare a.line b.line in + if Int.equal line 0 then Int.compare a.col b.col else line + + (** Converts a list of annotation and a string to a list of annotated string *) + let split_with_string (s : string) (annots : t list) = + let lines_position = + String.to_list s + |> List.filter_mapi ~f:(fun i ch -> + match ch with '\n' -> Some i | _ -> None) + |> List.to_array |> Array.get + in + let annots = List.sort ~compare annots in + let init = ({ line = 0; col = 0 }, None) in + let slices = + List.folding_map + ~f:(fun (start, start_span) (end_, end_span) -> + let span = Option.value ~default:end_span start_span in + ((end_, Some end_span), (span, start, end_))) + ~init annots + in + List.map slices ~f:(fun (span, start, end_) -> + let pos = lines_position start.line + start.col in + let len = lines_position end_.line + end_.col - pos in + (span, String.sub s ~pos ~len)) + + let to_mapping ((loc, span) : t) : Sourcemaps.Source_maps.mapping option = + let real_path (x : Types.file_name) = + match x with + | Real (LocalPath p) | Real (Remapped { local_path = Some p; _ }) -> + Some p + | _ -> None + in + let loc_to_loc ({ line; col } : loc) : Sourcemaps.Location.t = + { line; col } + in + let to_loc ({ col; line } : Types.loc) : loc = + { col = Int.of_string col; line = Int.of_string line - 1 } + in + let* span = + Span.to_thir span + |> List.find ~f:(fun (s : Types.span) -> + real_path s.filename |> Option.is_some) + in + let* src_filename = real_path span.filename in + let src_start = to_loc span.lo |> loc_to_loc in + let src_end = to_loc span.hi |> loc_to_loc in + let dst_start = loc_to_loc loc in + Some + Sourcemaps.Source_maps. + { + src = { start = src_start; end_ = Some src_end }; + gen = { start = dst_start; end_ = None }; + source = src_filename; + name = None; + } + end + + type annot_str = string * Annotation.t list [@@deriving show, yojson, eq] + + (** When printing a chunk of AST, should we wrap parenthesis +({!NeedsPar}) or not ({!AlreadyPar})? *) + type par_state = NeedsPar | AlreadyPar + + type 't fn = 't -> document +end + +open Types + +module Make + (F : Features.T) (SecretTypes : sig + type 't no_override + type 'location no_direct_call + end) = +struct + module AST = Ast.Make (F) + open Ast.Make (F) + open SecretTypes + + (** Raw generic printers base class. Those are useful for building a + printer, not for consuming printers. Consumers should use + the {!module:Api} functor. *) + class type virtual print_base_type = + object + + (** {1 Span handling} *) + + (** Every piece of string rendered is contextualized with span information automatically. *) + + method get_span_data : unit -> Annotation.t list + (** Retreive the mapping between locations in the rendered + string and Rust locations. *) + + method with_span : span:span -> (unit -> document) -> document + (** [with_span ~span f] runs `f` in the context of [span]. *) + + method spanned_doc : document -> custom + (** [spanned_doc doc] constructs a custom wrapping document for + [doc]. Rendering this document in [pretty] mode has a + side-effect: we push a [Annotation.t] to internal state. An + annotation maps a location within the rendered string to a Rust + span (that is, a location in the original Rust source code). *) + + (** {1 [*_at] methods} *) + + (** Always use [_at] methods rather than [] + ones. The former takes an [ast_position], that contextualizes + from where we are printing something. Printing the body of a + [let .. = ..;] expression (position [Expr_Let_body]) and + printing a function argument (position [Expr_App_arg]) will + probably require different parenthesizing: [ast_position] gives + contextual information upon which such parenthesizing decisions + can be taken. *) + + method expr_at : ast_position -> expr fn + (** Renders an [expr] at some [ast_position]. *) + + method ty_at : ast_position -> ty fn + (** Renders a [ty] at some [ast_position]. *) + + method pat_at : ast_position -> pat fn + (** Renders a [pat] at some [ast_position]. *) + + (** {1 Driver methods} *) + + (** The methods in this section are defined in two flavors: + `` and `_`. `` methods are not + overridable. Indeed, they take care of various things for + you: + + {ul {- catch exceptions and translate them as + pretty-printed errors with the original Rust AST;} + {- set contextual span information in a systematic way;} + {- disambiguate certain variant of the AST (see {!section-"specialized-printers"}).}} + + Your can override `_` methods. + *) + + (** {2 Expressions} *) + method expr : (par_state -> expr fn) no_override + (** Prints an expression. Pre-handles the variants [App] and + [Construct]: see {!section-"specialize-expr"}. *) + + method virtual expr_ : [ `Expr ] no_direct_call -> par_state -> expr fn + (** Overridable printer for expressions. Please mark the cases + [App] and [Construct] as unreachable. *) + + (** {2 Types} *) + method ty : (par_state -> ty fn) no_override + (** Prints a type. Pre-handles [TApp]. *) + + method virtual ty_ : [ `Ty ] no_direct_call -> par_state -> ty fn + (** Overridable printer for types. Please mark the case [TApp] + as unreachable. *) + + (** {2 Patterns} *) + method pat : (par_state -> pat fn) no_override + (** Prints a pattern. *) + + method virtual pat_ : [ `Pat ] no_direct_call -> par_state -> pat fn + (** Overridable printer for patterns. *) + + (** {2 Items} *) + method item : item fn no_override + (** Prints a item. *) + + method virtual item_ : [ `Item ] no_direct_call -> item fn + (** Overridable printer for items. *) + + (** {2 Arms} *) + method arm : arm fn no_override + (** Prints an arm (in a match). *) + + method virtual arm_ : [ `Arm ] no_direct_call -> arm fn + (** Overridable printer for arms (in matches).*) + + (** {2 Generic parameters} *) + method generic_param : generic_param fn no_override + (** Prints a generic parameter. *) + + method virtual generic_param_ : [ `GP ] no_direct_call -> generic_param fn + (** Overridable printer for generic parameters. *) + + (** {2 Parameters} *) + method param_ty : param fn no_override + (** Prints the type of a parameter. This is special because of `typ_span`. *) + + method virtual param_ty_ : [ `Param ] no_direct_call -> param fn + (** Overridable printer for parameter types. *) + + (** {2 Impl items} *) + method impl_item : impl_item fn no_override + (** Prints an impl item. *) + + method virtual impl_item_ : [ `II ] no_direct_call -> impl_item fn + (** Overridable printer for impl items. *) + + (** {2 Trait items} *) + method trait_item : trait_item fn no_override + (** Prints an trait item. *) + + method virtual trait_item_ : [ `TI ] no_direct_call -> trait_item fn + (** Overridable printer for trait items. *) + + (** {2 Attributes} *) + + method attr : attr fn no_override + (** Prints an attribute. *) + + method virtual attr_ : [ `Attr ] no_direct_call -> attr fn + (** Overridable printer for attributes. *) + + (** {2 Concrete idents} *) + + method concrete_ident : concrete_ident fn no_override + (** Prints a concrete ident. *) + + method virtual concrete_ident_ : + [ `CIdent ] no_direct_call -> under_current_ns:bool -> concrete_ident fn + (** Overridable printer for concrete idents. *) + + (** {1:specialized-printers Specialized printers} *) + + (** Some nodes in the AST are ambiguous as they encode multiple + language constructs: the `App` constructor of `expr` for + instance encodes (1) function applications, (2) fields + projectors, (3) constants... This is the same for `Construct`, + `TApp`, and some other. + + This section defines specialized methods for those language + constructs. When the variant `` of a type `` in + the AST is encoding various language constructs, we defined + various methods named `__`. *) + + (** {2:specialize-expr Specialized printers for [expr]} *) + + method virtual expr_App_constant : + full:expr -> concrete_ident -> generic_value list fn + (** [expr_App_constant ~full e generics] prints the constant + [e] with generics [generics]. [full] is the unspecialized [expr]. *) + + method virtual expr_App_application : + full:expr -> expr -> expr list -> generic_value list fn + (** [expr_App_application ~full e args generics] prints the + function application [e<...generics>(...args)]. [full] is the unspecialized [expr]. *) + + method virtual expr_App_tuple_projection : + full:expr -> size:int -> nth:int -> expr fn + (** [expr_App_tuple_projection ~full ~size ~nth expr] prints + the projection of the [nth] component of the tuple [expr] of + size [size]. [full] is the unspecialized [expr]. *) + + method virtual expr_App_field_projection : + full:expr -> concrete_ident -> expr fn + (** [expr_App_field_projection ~full field expr] prints the + projection of the field [field] in the expression [expr]. [full] + is the unspecialized [expr]. *) + + method virtual expr_Construct_inductive : + full:expr -> + is_record:bool -> + is_struct:bool -> + constructor:concrete_ident -> + base:(expr * F.construct_base) option -> + (global_ident * expr) list fn + (** [expr_Construct_inductive ~full ~is_record ~is_struct + ~constructor ~base fields] prints the construction of an + inductive with base [base] and fields [fields]. [full] is the + unspecialized [expr]. TODO doc is_record is_struct *) + + method virtual expr_Construct_tuple : full:expr -> expr list fn + + (** {2:specialize-expr Specialized printers for [ty]} *) + + method virtual ty_TApp_tuple : full:ty -> ty list fn + (** [ty_TApp_tuple ~full types] prints a tuple type with + compounds types [types]. [full] is the unspecialized [ty]. *) + + method virtual ty_TApp_application : + full:ty -> concrete_ident -> generic_value list fn + (** [ty_TApp_application ~full typ generic_args] prints the type + [typ<...generic_args>]. [full] is the unspecialized [ty]. *) + + method items : item list fn + + (** {1 Misc methods} *) + + (** {1 Convenience methods} *) + + method attrs : attrs fn + + method assertion_failure : 'any. string -> 'any + (** Helper that throws and reports an [Types.AssertionFailure] error. *) + + method set_current_namespace : (string * string list) option -> unit + method get_current_namespace : unit -> (string * string list) option + + method virtual namespace_of_concrete_ident : + concrete_ident -> string * string list + + method virtual printer_name : string + method virtual par_state : ast_position -> par_state + + method unreachable : 'any. unit -> 'any + (** Mark an unreachable place in the printer. *) + end +end diff --git a/engine/lib/new_generic_printer/new_generic_printer_template.ml b/engine/lib/new_generic_printer/new_generic_printer_template.ml new file mode 100644 index 000000000..b2f25df42 --- /dev/null +++ b/engine/lib/new_generic_printer/new_generic_printer_template.ml @@ -0,0 +1,64 @@ +module Make (F : Features.T) = struct + module AST = Ast.Make (F) + open Ast.Make (F) + module P = New_generic_printer_base.Make (F) + open PPrint + + let unimplemented s = string ("unimplemented: " ^ s) + + class print = + object + inherit P.base as _super + method ty_TApp_tuple ~full:_ _args = unimplemented "ty_TApp_tuple" + + method ty_TApp_application ~full:_ _f _args = + unimplemented "ty_TApp_application" + + method expr_App_constant ~full:_ _ident _generic_values = + unimplemented "expr_App_constant" + + method expr_App_application ~full:_ _f _args _generics = + unimplemented "expr_App_application" + + method expr_App_tuple_projection ~full:_ ~size:_ ~nth:_ _tuple = + unimplemented "expr_App_tuple_projection" + + method expr_App_field_projection ~full:_ _ident _data = + unimplemented "expr_App_field_projection" + + method expr_Construct_inductive ~full:_ ~is_record:_ ~is_struct:_ + ~constructor:_ ~base:_ _fields = + unimplemented "expr_Construct_inductive" + + method expr_Construct_tuple ~full:_ _components = + unimplemented "expr_Construct_tuple" + + method expr_ _ _ctx _expr = unimplemented "expr_" + method ty_ _ _ctx _typ = unimplemented "ty_" + method pat_ _ _ctx _pat = unimplemented "pat_" + method item_ _ _item = unimplemented "item_" + method arm_ _ _arm = unimplemented "arm_" + method generic_param_ _ _gp = unimplemented "generic_param_" + method param_ty_ _ _param_ty = unimplemented "param_ty_" + method impl_item_ _ _ii = unimplemented "impl_item_" + method trait_item_ _ _ti = unimplemented "trait_item_" + method attr_ _ _attr = unimplemented "attr_" + + method namespace_of_concrete_ident = + Concrete_ident.DefaultViewAPI.to_namespace + + method printer_name = "blank-template" + method par_state _ = AlreadyPar + + method concrete_ident_ _ ~under_current_ns:_ _ident = + unimplemented "concrete_ident_" + end + + open New_generic_printer_api.Make (F) + + include Api (struct + type aux_info = unit + + let new_print _ = (new print :> print_object) + end) +end diff --git a/engine/lib/new_generic_printer/new_rust_printer.ml b/engine/lib/new_generic_printer/new_rust_printer.ml new file mode 100644 index 000000000..2b2bf141b --- /dev/null +++ b/engine/lib/new_generic_printer/new_rust_printer.ml @@ -0,0 +1,170 @@ +open Prelude + +module Make (F : Features.T) = struct + module AST = Ast.Make (F) + open Ast.Make (F) + open New_generic_printer_base + module P = New_generic_printer_base.Make (F) + open PPrint + + let unimplemented s = string ("unimplemented: " ^ s) + + module View = Concrete_ident.DefaultViewAPI + + let iblock f = group >> jump 2 0 >> terminate (break 0) >> f >> group + let call = ( !: ) + + class print = + object (print) + inherit P.base as _super + method ty_TApp_tuple ~full:_ _args = unimplemented "ty_TApp_tuple" + + method ty_TApp_application ~full:_ _f _args = + unimplemented "ty_TApp_application" + + method expr_App_constant ~full:_ _ident _generic_values = + unimplemented "expr_App_constant" + + method expr_App_application ~full:_ f _args _generics = + print#expr_at Expr_App_f f + (* print#expr_at Expr_App_f f ^/^ separate_map space (print#expr_at Expr_App_arg) args *) + (* unimplemented "expr_App_application" *) + + method expr_App_tuple_projection ~full:_ ~size:_ ~nth:_ _tuple = + unimplemented "expr_App_tuple_projection" + + method expr_App_field_projection ~full:_ _ident _data = + unimplemented "expr_App_field_projection" + + method expr_Construct_inductive ~full:_ ~is_record:_ ~is_struct:_ + ~constructor:_ ~base:_ _fields = + unimplemented "expr_Construct_inductive" + + method expr_Construct_tuple ~full:_ _components = + unimplemented "expr_Construct_tuple" + + method expr_ _ ctx expr = + let wrap_parens = + group + >> match ctx with AlreadyPar -> Fn.id | NeedsPar -> iblock braces + in + match expr.e with + | If { cond; then_; else_ } -> + let if_then = + (string "if" ^//^ nest 2 (print#expr_at Expr_If_cond cond)) + ^/^ string "then" + ^//^ (print#expr_at Expr_If_then then_ |> braces |> nest 1) + in + (match else_ with + | None -> if_then + | Some else_ -> + if_then ^^ break 1 ^^ string "else" ^^ space + ^^ (print#expr_at Expr_If_else else_ |> iblock braces)) + |> wrap_parens + | Match { scrutinee; arms } -> + let header = + string "match" ^^ space + ^^ (print#expr_at Expr_Match_scrutinee scrutinee + |> terminate space |> iblock Fn.id) + |> group + in + let arms = + separate_map hardline + (call print#arm >> group >> nest 2 + >> precede (bar ^^ space) + >> group) + arms + in + header ^^ iblock braces arms + | Let { monadic; lhs; rhs; body } -> + (Option.map ~f:(fun monad -> print#expr_monadic_let ~monad) monadic + |> Option.value ~default:print#expr_let) + ~lhs ~rhs body + |> wrap_parens + | Literal l -> print#literal l + | Block (e, _) -> call print#expr ctx e + | _ -> unimplemented "expr_todo" + + method expr_monadic_let + : monad:supported_monads * F.monadic_binding -> + lhs:pat -> + rhs:expr -> + expr fn = + fun ~monad:_ ~lhs ~rhs body -> print#expr_let ~lhs ~rhs body + + method expr_let : lhs:pat -> rhs:expr -> expr fn = + fun ~lhs ~rhs body -> + string "let" + ^/^ iblock Fn.id (print#pat_at Expr_Let_lhs lhs) + ^/^ equals + ^/^ iblock Fn.id (print#expr_at Expr_Let_rhs rhs) + ^^ semi + ^/^ (print#expr_at Expr_Let_body body |> group) + + method literal = + function + | String s -> utf8string s |> dquotes + | Char c -> char c |> bquotes + | Int { value; negative; _ } -> + string value |> precede (if negative then minus else empty) + | Float { value; kind; negative } -> + string value + |> precede (if negative then minus else empty) + |> terminate + (string (match kind with F32 -> "f32" | F64 -> "f64")) + | Bool b -> OCaml.bool b + + method ty_ _ _ctx _typ = unimplemented "ty_" + method pat_ _ _ctx _pat = unimplemented "pat_" + + method item_ _ item = + match item.v with + | Fn { name; generics; body; params } -> + let params = + iblock parens (separate_map (comma ^^ break 1) print#param params) + in + let generics = + separate_map comma (call print#generic_param) generics.params + in + string "fn" ^^ space + ^^ call print#concrete_ident name + ^^ generics ^^ params + ^^ iblock braces (print#expr_at Item_Fn_body body) + | _ -> string "item not implemented" + + method param_ty_ _ _param_ty = unimplemented "param_ty_" + + method param (param : param) = + let { pat; typ = _; typ_span = _; attrs } = param in + print#attrs attrs ^^ print#pat_at Param_pat pat ^^ space ^^ colon + ^^ space ^^ !:(print#param_ty) param + + method arm_ _ _arm = unimplemented "arm_" + method generic_param_ _ _gp = unimplemented "generic_param_" + method impl_item_ _ _ii = unimplemented "impl_item_" + method trait_item_ _ _ti = unimplemented "trait_item_" + method attr_ _ _attr = unimplemented "attr_" + + method namespace_of_concrete_ident = + Concrete_ident.DefaultViewAPI.to_namespace + + method printer_name = "blank-template" + method par_state _ = AlreadyPar + + method concrete_ident_ _ ~under_current_ns id = + let id = View.to_view id in + let chunks = + if under_current_ns then [ id.definition ] + else id.crate :: (id.path @ [ id.definition ]) + in + separate_map (colon ^^ colon) utf8string chunks + end + + open New_generic_printer_api.Make (F) + + include Api (struct + type aux_info = unit + + let new_print _ = (new print :> print_object) + end) +end diff --git a/engine/lib/new_generic_printer/new_rust_printer.mli b/engine/lib/new_generic_printer/new_rust_printer.mli new file mode 100644 index 000000000..52178d3fa --- /dev/null +++ b/engine/lib/new_generic_printer/new_rust_printer.mli @@ -0,0 +1,4 @@ +module Make (F : Features.T) : sig + open New_generic_printer_api.Make(F) + include API with type aux_info = unit +end diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 7db091d74..3b97e12dd 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -662,37 +662,81 @@ let rustfmt_annotated (x : AnnotatedString.t) : AnnotatedString.t = if String.equal rf "no" then x else try rustfmt_annotated' x with RetokenizationFailure -> x -let pitem : item -> AnnotatedString.Output.t = - Raw.pitem >> rustfmt_annotated >> AnnotatedString.Output.convert - -let pitems : item list -> AnnotatedString.Output.t = - List.concat_map ~f:Raw.pitem - >> rustfmt_annotated >> AnnotatedString.Output.convert - -let pitem_str : item -> string = pitem >> AnnotatedString.Output.raw_string - -let pty_str (e : ty) : string = - let e = Raw.pty (Span.dummy ()) e in - let ( ! ) = AnnotatedString.pure @@ Span.dummy () in - let ( & ) = AnnotatedString.( & ) in - let prefix = "type TypeWrapper = " in - let suffix = ";" in - let item = !prefix & e & !suffix in - rustfmt_annotated item |> AnnotatedString.Output.convert - |> AnnotatedString.Output.raw_string |> Stdlib.String.trim - |> String.chop_suffix_if_exists ~suffix - |> String.chop_prefix_if_exists ~prefix - |> Stdlib.String.trim - -let pexpr_str (e : expr) : string = - let e = Raw.pexpr e in - let ( ! ) = AnnotatedString.pure @@ Span.dummy () in - let ( & ) = AnnotatedString.( & ) in - let prefix = "fn expr_wrapper() {" in - let suffix = "}" in - let item = !prefix & e & !suffix in - rustfmt_annotated item |> AnnotatedString.Output.convert - |> AnnotatedString.Output.raw_string |> Stdlib.String.trim - |> String.chop_suffix_if_exists ~suffix - |> String.chop_prefix_if_exists ~prefix - |> Stdlib.String.trim +module type T = sig + val pitem : item -> AnnotatedString.Output.t + val pitems : item list -> AnnotatedString.Output.t + val pitem_str : item -> string + val pexpr_str : expr -> string + val pty_str : ty -> string +end + +module Traditional : T = struct + let pitem : item -> AnnotatedString.Output.t = + Raw.pitem >> rustfmt_annotated >> AnnotatedString.Output.convert + + let pitems : item list -> AnnotatedString.Output.t = + List.concat_map ~f:Raw.pitem + >> rustfmt_annotated >> AnnotatedString.Output.convert + + let pitem_str : item -> string = pitem >> AnnotatedString.Output.raw_string + + let pexpr_str (e : expr) : string = + let e = Raw.pexpr e in + let ( ! ) = AnnotatedString.pure @@ Span.dummy () in + let ( & ) = AnnotatedString.( & ) in + let prefix = "fn expr_wrapper() {" in + let suffix = "}" in + let item = !prefix & e & !suffix in + rustfmt_annotated item |> AnnotatedString.Output.convert + |> AnnotatedString.Output.raw_string |> Stdlib.String.trim + |> String.chop_suffix_if_exists ~suffix + |> String.chop_prefix_if_exists ~prefix + |> Stdlib.String.trim + + let pty_str (e : ty) : string = + let e = Raw.pty (Span.dummy ()) e in + let ( ! ) = AnnotatedString.pure @@ Span.dummy () in + let ( & ) = AnnotatedString.( & ) in + let prefix = "type TypeWrapper = " in + let suffix = ";" in + let item = !prefix & e & !suffix in + rustfmt_annotated item |> AnnotatedString.Output.convert + |> AnnotatedString.Output.raw_string |> Stdlib.String.trim + |> String.chop_suffix_if_exists ~suffix + |> String.chop_prefix_if_exists ~prefix + |> Stdlib.String.trim +end + +module Experimental : T = struct + module NewRustGenericPrinter = New_rust_printer.Make (Features.Full) + + let pitem : item -> AnnotatedString.Output.t = + NewRustGenericPrinter.item () + >> New_generic_printer_api.AnnotatedString.to_spanned_strings + >> AnnotatedString.Output.convert + + let pitems : item list -> AnnotatedString.Output.t = + NewRustGenericPrinter.items () + >> New_generic_printer_api.AnnotatedString.to_spanned_strings + >> AnnotatedString.Output.convert + + let pexpr : expr -> AnnotatedString.Output.t = + NewRustGenericPrinter.expr () + >> New_generic_printer_api.AnnotatedString.to_spanned_strings + >> AnnotatedString.Output.convert + + let pitem_str : item -> string = + NewRustGenericPrinter.item () + >> New_generic_printer_api.AnnotatedString.to_string + + let pexpr_str : expr -> string = + NewRustGenericPrinter.expr () + >> New_generic_printer_api.AnnotatedString.to_string +end + +let experimental = + Sys.getenv "HAX_ENGINE_EXPERIMENTAL_RUST_PRINTER" |> Option.is_some + +include + (val if experimental then (module Experimental : T) + else (module Traditional : T)) diff --git a/engine/profile.dump b/engine/profile.dump new file mode 100644 index 000000000..e69de29bb diff --git a/flake.lock b/flake.lock index ba2824fa7..65baec36d 100644 --- a/flake.lock +++ b/flake.lock @@ -93,6 +93,29 @@ "type": "github" } }, + "ocaml-sourcemaps": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709059830, + "narHash": "sha256-K+g/h6xhE5uOBri1oCaOier3jeIwZrMGOSx79mz5FrU=", + "owner": "W95Psp", + "repo": "ocaml-sourcemaps", + "rev": "391ef51d2fad9884f7535e003b9c9f1a53536fbb", + "type": "github" + }, + "original": { + "owner": "W95Psp", + "repo": "ocaml-sourcemaps", + "type": "github" + } + }, "root": { "inputs": { "crane": "crane", @@ -100,6 +123,7 @@ "fstar": "fstar", "hacl-star": "hacl-star", "nixpkgs": "nixpkgs", + "ocaml-sourcemaps": "ocaml-sourcemaps", "rust-overlay": "rust-overlay" } }, diff --git a/flake.nix b/flake.nix index f51767ff4..a93b93e94 100644 --- a/flake.nix +++ b/flake.nix @@ -23,6 +23,14 @@ url = "github:hacl-star/hacl-star"; flake = false; }; + ocaml-sourcemaps = { + url = "github:W95Psp/ocaml-sourcemaps"; + flake = true; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; }; outputs = { @@ -56,6 +64,8 @@ cat "${hax-env-file}" | xargs -I{} echo "export {}" fi ''; + ocaml-sourcemaps = inputs.ocaml-sourcemaps.packages.${system}.default; + ocamlPackages = pkgs.ocamlPackages; in rec { packages = { inherit rustc ocamlformat rustfmt fstar hax-env; @@ -73,7 +83,7 @@ #!${pkgs.stdenv.shell} ${packages.hax-rust-frontend.hax-engine-names-extract}/bin/hax-engine-names-extract | sed 's|/nix/store/\(.\{6\}\)|/nix_store/\1-|g' ''; - inherit rustc; + inherit rustc ocaml-sourcemaps ocamlPackages; }; hax-rust-frontend = pkgs.callPackage ./cli { inherit rustc craneLib; @@ -164,11 +174,11 @@ }; packages = [ ocamlformat - pkgs.ocamlPackages.ocaml-lsp - pkgs.ocamlPackages.ocamlformat-rpc-lib - pkgs.ocamlPackages.ocaml-print-intf - pkgs.ocamlPackages.odoc - pkgs.ocamlPackages.utop + ocamlPackages.ocaml-lsp + ocamlPackages.ocamlformat-rpc-lib + ocamlPackages.ocaml-print-intf + ocamlPackages.odoc + ocamlPackages.utop pkgs.cargo-expand pkgs.cargo-insta diff --git a/hax-types/src/engine_api.rs b/hax-types/src/engine_api.rs index 1ea02b356..0face3761 100644 --- a/hax-types/src/engine_api.rs +++ b/hax-types/src/engine_api.rs @@ -14,11 +14,39 @@ pub struct EngineOptions { )>, } +#[allow(non_snake_case)] +#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +pub struct SourceMap { + pub mappings: String, + pub sourceRoot: String, + pub sources: Vec, + pub sourcesContent: Vec>, + pub names: Vec, + pub version: u8, + pub file: String, +} + +impl SourceMap { + pub fn inline_sources_content(&mut self) { + self.sourcesContent = vec![]; + for source in &self.sources { + let path = if self.sourceRoot.is_empty() { + source.clone() + } else { + format!("{}/{}", &self.sourceRoot, source) + }; + let contents = Some(std::fs::read_to_string(path).unwrap()); + self.sourcesContent.push(contents); + } + } +} + #[derive_group(Serializers)] #[derive(JsonSchema, Debug, Clone)] pub struct File { pub path: String, pub contents: String, + pub sourcemap: Option, } #[derive_group(Serializers)] From 2ee810c31dbc8af8af71f9cbd7fe3f2f4a3ccbe0 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 1 Jul 2024 11:09:06 +0200 Subject: [PATCH 002/253] fix: rustc update minor changes --- engine/lib/new_generic_printer/new_rust_printer.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/lib/new_generic_printer/new_rust_printer.ml b/engine/lib/new_generic_printer/new_rust_printer.ml index 2b2bf141b..86e2fda65 100644 --- a/engine/lib/new_generic_printer/new_rust_printer.ml +++ b/engine/lib/new_generic_printer/new_rust_printer.ml @@ -110,8 +110,7 @@ module Make (F : Features.T) = struct | Float { value; kind; negative } -> string value |> precede (if negative then minus else empty) - |> terminate - (string (match kind with F32 -> "f32" | F64 -> "f64")) + |> terminate (string (Ast.show_float_kind kind)) | Bool b -> OCaml.bool b method ty_ _ _ctx _typ = unimplemented "ty_" From c10e43f9eb9fcadc9222bed4e76cde3bf22d158f Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 30 Sep 2024 14:35:45 +0200 Subject: [PATCH 003/253] fix: minor fixes after rebasing --- engine/lib/new_generic_printer/new_rust_printer.ml | 4 ++-- engine/lib/print_rust.ml | 4 ++++ hax-types/src/engine_api.rs | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/engine/lib/new_generic_printer/new_rust_printer.ml b/engine/lib/new_generic_printer/new_rust_printer.ml index 86e2fda65..eb1e42425 100644 --- a/engine/lib/new_generic_printer/new_rust_printer.ml +++ b/engine/lib/new_generic_printer/new_rust_printer.ml @@ -82,7 +82,7 @@ module Make (F : Features.T) = struct ~lhs ~rhs body |> wrap_parens | Literal l -> print#literal l - | Block (e, _) -> call print#expr ctx e + | Block { e; _ } -> call print#expr ctx e | _ -> unimplemented "expr_todo" method expr_monadic_let @@ -118,7 +118,7 @@ module Make (F : Features.T) = struct method item_ _ item = match item.v with - | Fn { name; generics; body; params } -> + | Fn { name; generics; body; params; _ } -> let params = iblock parens (separate_map (comma ^^ break 1) print#param params) in diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 3b97e12dd..d40c94595 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -732,6 +732,10 @@ module Experimental : T = struct let pexpr_str : expr -> string = NewRustGenericPrinter.expr () >> New_generic_printer_api.AnnotatedString.to_string + + let pty_str : ty -> string = + NewRustGenericPrinter.ty () + >> New_generic_printer_api.AnnotatedString.to_string end let experimental = diff --git a/hax-types/src/engine_api.rs b/hax-types/src/engine_api.rs index 0face3761..4a0e4bfaf 100644 --- a/hax-types/src/engine_api.rs +++ b/hax-types/src/engine_api.rs @@ -14,8 +14,9 @@ pub struct EngineOptions { )>, } +#[derive_group(Serializers)] #[allow(non_snake_case)] -#[derive(JsonSchema, Debug, Clone, Serialize, Deserialize)] +#[derive(JsonSchema, Debug, Clone)] pub struct SourceMap { pub mappings: String, pub sourceRoot: String, From 03a84bd3d545c02b2d86a0caebe2b083bc6a37df Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 30 Sep 2024 14:39:20 +0200 Subject: [PATCH 004/253] refactor: rename `Generic_printer` to `Deprecated_generic_printer` --- engine/backends/proverif/proverif_backend.ml | 19 +++++++++++-------- .../deprecated_generic_printer.ml} | 4 ++-- .../deprecated_generic_printer.mli} | 2 +- .../deprecated_generic_printer_base.ml} | 0 4 files changed, 14 insertions(+), 11 deletions(-) rename engine/lib/{generic_printer/generic_printer.ml => deprecated_generic_printer/deprecated_generic_printer.ml} (99%) rename engine/lib/{generic_printer/generic_printer.mli => deprecated_generic_printer/deprecated_generic_printer.mli} (70%) rename engine/lib/{generic_printer/generic_printer_base.ml => deprecated_generic_printer/deprecated_generic_printer_base.ml} (100%) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 983cbae39..bcbd3f258 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -142,9 +142,9 @@ end module Make (Options : OPTS) : MAKE = struct module Print = struct module GenericPrint = - Generic_printer.Make (InputLanguage) (U.Concrete_ident_view) + Deprecated_generic_printer.Make (InputLanguage) (U.Concrete_ident_view) - open Generic_printer_base.Make (InputLanguage) + open Deprecated_generic_printer_base.Make (InputLanguage) open PPrint let iblock f = group >> jump 2 0 >> terminate (break 0) >> f >> group @@ -264,7 +264,8 @@ module Make (Options : OPTS) : MAKE = struct method typed_wildcard = print#wildcard ^^ string ": bitstring" - method tuple_elem_pat' : Generic_printer_base.par_state -> pat' fn = + method tuple_elem_pat' + : Deprecated_generic_printer_base.par_state -> pat' fn = fun ctx -> let wrap_parens = group @@ -277,14 +278,15 @@ module Make (Options : OPTS) : MAKE = struct p ^^ colon ^^ space ^^ print#ty ctx typ | p -> print#pat' ctx p - method tuple_elem_pat : Generic_printer_base.par_state -> pat fn = + method tuple_elem_pat + : Deprecated_generic_printer_base.par_state -> pat fn = fun ctx { p; span; _ } -> print#with_span ~span (fun _ -> print#tuple_elem_pat' ctx p) method tuple_elem_pat_at = print#par_state >> print#tuple_elem_pat (* Overridden methods *) - method! pat' : Generic_printer_base.par_state -> pat' fn = + method! pat' : Deprecated_generic_printer_base.par_state -> pat' fn = fun ctx -> let wrap_parens = group @@ -344,7 +346,8 @@ module Make (Options : OPTS) : MAKE = struct method! ty_bool = string "bool" method! ty_int _ = string "nat" - method! pat_at : Generic_printer_base.ast_position -> pat fn = + method! pat_at : Deprecated_generic_printer_base.ast_position -> pat fn + = fun pos pat -> match pat with | { p = PWild } -> ( @@ -374,7 +377,7 @@ module Make (Options : OPTS) : MAKE = struct in f ^^ iblock parens args - method! expr' : Generic_printer_base.par_state -> expr' fn = + method! expr' : Deprecated_generic_printer_base.par_state -> expr' fn = fun ctx e -> let wrap_parens = group @@ -720,7 +723,7 @@ module Make (Options : OPTS) : MAKE = struct | _ -> super#expr ctx e (*This cannot happen*)) | _ -> super#expr ctx e) - method! ty : Generic_printer_base.par_state -> ty fn = + method! ty : Deprecated_generic_printer_base.par_state -> ty fn = fun ctx ty -> match ty with | TBool -> print#ty_bool diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml similarity index 99% rename from engine/lib/generic_printer/generic_printer.ml rename to engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml index 8094d83b3..aec4440ab 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml @@ -2,8 +2,8 @@ open! Prelude open! Ast module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct - open Generic_printer_base - open Generic_printer_base.Make (F) + open Deprecated_generic_printer_base + open Deprecated_generic_printer_base.Make (F) module Class = struct module U = Ast_utils.Make (F) diff --git a/engine/lib/generic_printer/generic_printer.mli b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.mli similarity index 70% rename from engine/lib/generic_printer/generic_printer.mli rename to engine/lib/deprecated_generic_printer/deprecated_generic_printer.mli index ccd471cc3..3eb3904f6 100644 --- a/engine/lib/generic_printer/generic_printer.mli +++ b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.mli @@ -1,5 +1,5 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) : sig - open Generic_printer_base.Make(F) + open Deprecated_generic_printer_base.Make(F) include API class print : print_class diff --git a/engine/lib/generic_printer/generic_printer_base.ml b/engine/lib/deprecated_generic_printer/deprecated_generic_printer_base.ml similarity index 100% rename from engine/lib/generic_printer/generic_printer_base.ml rename to engine/lib/deprecated_generic_printer/deprecated_generic_printer_base.ml From 80334538010349b4efd622dcf9dbed631de3310e Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 30 Sep 2024 14:43:50 +0200 Subject: [PATCH 005/253] refactor: rename `New_generic_printer` to `Generic_printer` --- engine/backends/fstar/fstar_backend.ml | 4 ++-- .../generic_printer_api.ml} | 2 +- .../generic_printer_base.ml} | 4 ++-- .../generic_printer_base.mli} | 4 ++-- .../generic_printer_base_sig.ml} | 0 .../generic_printer_template.ml} | 4 ++-- .../generic_rust_printer.ml} | 6 ++--- .../generic_rust_printer.mli} | 2 +- engine/lib/print_rust.ml | 23 ++++++++----------- 9 files changed, 23 insertions(+), 26 deletions(-) rename engine/lib/{new_generic_printer/new_generic_printer_api.ml => generic_printer/generic_printer_api.ml} (98%) rename engine/lib/{new_generic_printer/new_generic_printer_base.ml => generic_printer/generic_printer_base.ml} (98%) rename engine/lib/{new_generic_printer/new_generic_printer_base.mli => generic_printer/generic_printer_base.mli} (80%) rename engine/lib/{new_generic_printer/new_generic_printer_base_sig.ml => generic_printer/generic_printer_base_sig.ml} (100%) rename engine/lib/{new_generic_printer/new_generic_printer_template.ml => generic_printer/generic_printer_template.ml} (95%) rename engine/lib/{new_generic_printer/new_rust_printer.ml => generic_printer/generic_rust_printer.ml} (97%) rename engine/lib/{new_generic_printer/new_rust_printer.mli => generic_printer/generic_rust_printer.mli} (66%) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 76e9005c5..bfd29f20a 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1663,8 +1663,8 @@ let translate_as_experimental_rust m (bo : BackendOptions.t) in let string_of_items _ _ items = let r = NewGenericPrinter.items () items in - let str = New_generic_printer_api.AnnotatedString.to_string r in - let sm = New_generic_printer_api.AnnotatedString.to_sourcemap r in + let str = Generic_printer_api.AnnotatedString.to_string r in + let sm = Generic_printer_api.AnnotatedString.to_sourcemap r in let r = (str, sm) in (r, r) in diff --git a/engine/lib/new_generic_printer/new_generic_printer_api.ml b/engine/lib/generic_printer/generic_printer_api.ml similarity index 98% rename from engine/lib/new_generic_printer/new_generic_printer_api.ml rename to engine/lib/generic_printer/generic_printer_api.ml index a537015d1..83f575ca8 100644 --- a/engine/lib/new_generic_printer/new_generic_printer_api.ml +++ b/engine/lib/generic_printer/generic_printer_api.ml @@ -1,5 +1,5 @@ open! Prelude -open New_generic_printer_base +open Generic_printer_base module AnnotatedString = struct type t = string * Annotation.t list [@@deriving show, yojson, eq] diff --git a/engine/lib/new_generic_printer/new_generic_printer_base.ml b/engine/lib/generic_printer/generic_printer_base.ml similarity index 98% rename from engine/lib/new_generic_printer/new_generic_printer_base.ml rename to engine/lib/generic_printer/generic_printer_base.ml index 63755f5f0..423e4f8d1 100644 --- a/engine/lib/new_generic_printer/new_generic_printer_base.ml +++ b/engine/lib/generic_printer/generic_printer_base.ml @@ -9,12 +9,12 @@ end let ( !: ) (type a) (f : a SecretTypes.no_override) : a = f -include New_generic_printer_base_sig.Types +include Generic_printer_base_sig.Types module Make (F : Features.T) = struct module AST = Ast.Make (F) open Ast.Make (F) - open New_generic_printer_base_sig.Make (F) (SecretTypes) + open Generic_printer_base_sig.Make (F) (SecretTypes) class virtual base : print_base_type = object (print) diff --git a/engine/lib/new_generic_printer/new_generic_printer_base.mli b/engine/lib/generic_printer/generic_printer_base.mli similarity index 80% rename from engine/lib/new_generic_printer/new_generic_printer_base.mli rename to engine/lib/generic_printer/generic_printer_base.mli index 052b29cb1..fb97d5f63 100644 --- a/engine/lib/new_generic_printer/new_generic_printer_base.mli +++ b/engine/lib/generic_printer/generic_printer_base.mli @@ -11,13 +11,13 @@ include module type of struct (** Hello *) end - include New_generic_printer_base_sig.Types + include Generic_printer_base_sig.Types end val ( !: ) : 'a. 'a SecretTypes.no_override -> 'a module Make (F : Features.T) : sig - open New_generic_printer_base_sig.Make(F)(SecretTypes) + open Generic_printer_base_sig.Make(F)(SecretTypes) class virtual base : print_base_type end diff --git a/engine/lib/new_generic_printer/new_generic_printer_base_sig.ml b/engine/lib/generic_printer/generic_printer_base_sig.ml similarity index 100% rename from engine/lib/new_generic_printer/new_generic_printer_base_sig.ml rename to engine/lib/generic_printer/generic_printer_base_sig.ml diff --git a/engine/lib/new_generic_printer/new_generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml similarity index 95% rename from engine/lib/new_generic_printer/new_generic_printer_template.ml rename to engine/lib/generic_printer/generic_printer_template.ml index b2f25df42..86582c455 100644 --- a/engine/lib/new_generic_printer/new_generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -1,7 +1,7 @@ module Make (F : Features.T) = struct module AST = Ast.Make (F) open Ast.Make (F) - module P = New_generic_printer_base.Make (F) + module P = Generic_printer_base.Make (F) open PPrint let unimplemented s = string ("unimplemented: " ^ s) @@ -54,7 +54,7 @@ module Make (F : Features.T) = struct unimplemented "concrete_ident_" end - open New_generic_printer_api.Make (F) + open Generic_printer_api.Make (F) include Api (struct type aux_info = unit diff --git a/engine/lib/new_generic_printer/new_rust_printer.ml b/engine/lib/generic_printer/generic_rust_printer.ml similarity index 97% rename from engine/lib/new_generic_printer/new_rust_printer.ml rename to engine/lib/generic_printer/generic_rust_printer.ml index eb1e42425..8ff0804bb 100644 --- a/engine/lib/new_generic_printer/new_rust_printer.ml +++ b/engine/lib/generic_printer/generic_rust_printer.ml @@ -3,8 +3,8 @@ open Prelude module Make (F : Features.T) = struct module AST = Ast.Make (F) open Ast.Make (F) - open New_generic_printer_base - module P = New_generic_printer_base.Make (F) + open Generic_printer_base + module P = Generic_printer_base.Make (F) open PPrint let unimplemented s = string ("unimplemented: " ^ s) @@ -159,7 +159,7 @@ module Make (F : Features.T) = struct separate_map (colon ^^ colon) utf8string chunks end - open New_generic_printer_api.Make (F) + open Generic_printer_api.Make (F) include Api (struct type aux_info = unit diff --git a/engine/lib/new_generic_printer/new_rust_printer.mli b/engine/lib/generic_printer/generic_rust_printer.mli similarity index 66% rename from engine/lib/new_generic_printer/new_rust_printer.mli rename to engine/lib/generic_printer/generic_rust_printer.mli index 52178d3fa..6a277bb7f 100644 --- a/engine/lib/new_generic_printer/new_rust_printer.mli +++ b/engine/lib/generic_printer/generic_rust_printer.mli @@ -1,4 +1,4 @@ module Make (F : Features.T) : sig - open New_generic_printer_api.Make(F) + open Generic_printer_api.Make(F) include API with type aux_info = unit end diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index d40c94595..1a13df86c 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -708,34 +708,31 @@ module Traditional : T = struct end module Experimental : T = struct - module NewRustGenericPrinter = New_rust_printer.Make (Features.Full) + module GenericRustPrinter = Generic_rust_printer.Make (Features.Full) let pitem : item -> AnnotatedString.Output.t = - NewRustGenericPrinter.item () - >> New_generic_printer_api.AnnotatedString.to_spanned_strings + GenericRustPrinter.item () + >> Generic_printer_api.AnnotatedString.to_spanned_strings >> AnnotatedString.Output.convert let pitems : item list -> AnnotatedString.Output.t = - NewRustGenericPrinter.items () - >> New_generic_printer_api.AnnotatedString.to_spanned_strings + GenericRustPrinter.items () + >> Generic_printer_api.AnnotatedString.to_spanned_strings >> AnnotatedString.Output.convert let pexpr : expr -> AnnotatedString.Output.t = - NewRustGenericPrinter.expr () - >> New_generic_printer_api.AnnotatedString.to_spanned_strings + GenericRustPrinter.expr () + >> Generic_printer_api.AnnotatedString.to_spanned_strings >> AnnotatedString.Output.convert let pitem_str : item -> string = - NewRustGenericPrinter.item () - >> New_generic_printer_api.AnnotatedString.to_string + GenericRustPrinter.item () >> Generic_printer_api.AnnotatedString.to_string let pexpr_str : expr -> string = - NewRustGenericPrinter.expr () - >> New_generic_printer_api.AnnotatedString.to_string + GenericRustPrinter.expr () >> Generic_printer_api.AnnotatedString.to_string let pty_str : ty -> string = - NewRustGenericPrinter.ty () - >> New_generic_printer_api.AnnotatedString.to_string + GenericRustPrinter.ty () >> Generic_printer_api.AnnotatedString.to_string end let experimental = From c9726061b83d8a033c000effdf330dacfa2c2f04 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 30 Sep 2024 15:38:43 +0200 Subject: [PATCH 006/253] refactor: inline `github:W95psp/ocaml-sourcemaps` in the repo --- engine/backends/fstar/fstar_backend.ml | 4 +- engine/default.nix | 2 - engine/utils/sourcemaps/base64.ml | 10 ++ engine/utils/sourcemaps/dune | 9 ++ engine/utils/sourcemaps/location.ml | 22 ++++ engine/utils/sourcemaps/mappings/dual.ml | 10 ++ .../utils/sourcemaps/mappings/instruction.ml | 104 ++++++++++++++++++ engine/utils/sourcemaps/mappings/mappings.ml | 41 +++++++ engine/utils/sourcemaps/mappings/mappings.mli | 13 +++ engine/utils/sourcemaps/mappings/spanned.ml | 44 ++++++++ engine/utils/sourcemaps/mappings/types.ml | 4 + engine/utils/sourcemaps/prelude.ml | 4 + engine/utils/sourcemaps/source_maps.ml | 53 +++++++++ engine/utils/sourcemaps/source_maps.mli | 33 ++++++ engine/utils/sourcemaps/vql.ml | 48 ++++++++ flake.lock | 24 ---- flake.nix | 11 +- 17 files changed, 398 insertions(+), 38 deletions(-) create mode 100644 engine/utils/sourcemaps/base64.ml create mode 100644 engine/utils/sourcemaps/dune create mode 100644 engine/utils/sourcemaps/location.ml create mode 100644 engine/utils/sourcemaps/mappings/dual.ml create mode 100644 engine/utils/sourcemaps/mappings/instruction.ml create mode 100644 engine/utils/sourcemaps/mappings/mappings.ml create mode 100644 engine/utils/sourcemaps/mappings/mappings.mli create mode 100644 engine/utils/sourcemaps/mappings/spanned.ml create mode 100644 engine/utils/sourcemaps/mappings/types.ml create mode 100644 engine/utils/sourcemaps/prelude.ml create mode 100644 engine/utils/sourcemaps/source_maps.ml create mode 100644 engine/utils/sourcemaps/source_maps.mli create mode 100644 engine/utils/sourcemaps/vql.ml diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index bfd29f20a..a84c1c931 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1641,7 +1641,7 @@ let fstar_headers (bo : BackendOptions.t) = in [ opts; "open Core"; "open FStar.Mul" ] |> String.concat ~sep:"\n" -module NewGenericPrinter = New_rust_printer.Make (InputLanguage) +module GenericPrinter = Generic_rust_printer.Make (InputLanguage) (** Use the generic printer instead of the F* printer. For now, there is no generic printer for F*, that's why we currently just use the @@ -1662,7 +1662,7 @@ let translate_as_experimental_rust m (bo : BackendOptions.t) (fst ns :: snd ns)) in let string_of_items _ _ items = - let r = NewGenericPrinter.items () items in + let r = GenericPrinter.items () items in let str = Generic_printer_api.AnnotatedString.to_string r in let sm = Generic_printer_api.AnnotatedString.to_sourcemap r in let r = (str, sm) in diff --git a/engine/default.nix b/engine/default.nix index 5f5202a0e..1a676c743 100644 --- a/engine/default.nix +++ b/engine/default.nix @@ -10,7 +10,6 @@ gnused, lib, removeReferencesTo, - ocaml-sourcemaps, }: let non_empty_list = ocamlPackages.buildDunePackage rec { pname = "non_empty_list"; @@ -67,7 +66,6 @@ re js_of_ocaml ocamlgraph - ocaml-sourcemaps ] ++ # F* dependencies diff --git a/engine/utils/sourcemaps/base64.ml b/engine/utils/sourcemaps/base64.ml new file mode 100644 index 000000000..064b85a61 --- /dev/null +++ b/engine/utils/sourcemaps/base64.ml @@ -0,0 +1,10 @@ +open Prelude + +let alphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +let encode (n : int) : char = + assert (n >= 0 && n < 64); + String.get alphabet n + +let decode (c : char) : int = String.index alphabet c |> Option.value_exn diff --git a/engine/utils/sourcemaps/dune b/engine/utils/sourcemaps/dune new file mode 100644 index 000000000..cf4e7dc83 --- /dev/null +++ b/engine/utils/sourcemaps/dune @@ -0,0 +1,9 @@ +(library + (name sourcemaps) + (package hax-engine) + (inline_tests) + (preprocess + (pps ppx_inline_test ppx_yojson_conv ppx_deriving.show ppx_deriving.eq)) + (libraries base)) + +(include_subdirs unqualified) diff --git a/engine/utils/sourcemaps/location.ml b/engine/utils/sourcemaps/location.ml new file mode 100644 index 000000000..cf2bda904 --- /dev/null +++ b/engine/utils/sourcemaps/location.ml @@ -0,0 +1,22 @@ +open Prelude + +type t = { line : int; col : int } [@@deriving eq] + +let show { line; col } = + "(" ^ Int.to_string line ^ ":" ^ Int.to_string col ^ ")" + +let pp (fmt : Stdlib.Format.formatter) (s : t) : unit = + Stdlib.Format.pp_print_string fmt @@ show s + +let default = { line = 0; col = 0 } +let plus_cols x cols = { x with col = x.col + cols } +let op ( + ) x y = { line = x.line + y.line; col = x.col + y.col } +let ( + ) = op ( + ) +let ( - ) = op ( - ) + +let compare (x : t) (y : t) : int = + let open Int in + if x.line > y.line then 1 + else if x.line = y.line then + if x.col > y.col then 1 else if x.col = y.col then 0 else -1 + else -1 diff --git a/engine/utils/sourcemaps/mappings/dual.ml b/engine/utils/sourcemaps/mappings/dual.ml new file mode 100644 index 000000000..09548fd9f --- /dev/null +++ b/engine/utils/sourcemaps/mappings/dual.ml @@ -0,0 +1,10 @@ +type 'a t = { gen : 'a; src : 'a } [@@deriving show, eq] + +let transpose ~(default : 'a t) ({ gen; src } : 'a option t) : 'a t option = + match (gen, src) with + | Some gen, None -> Some { gen; src = default.src } + | None, Some src -> Some { gen = default.gen; src } + | Some gen, Some src -> Some { gen; src } + | _ -> None + +let default (type a) (default : a) : a t = { gen = default; src = default } diff --git a/engine/utils/sourcemaps/mappings/instruction.ml b/engine/utils/sourcemaps/mappings/instruction.ml new file mode 100644 index 000000000..922e1593a --- /dev/null +++ b/engine/utils/sourcemaps/mappings/instruction.ml @@ -0,0 +1,104 @@ +open Prelude +open Types + +type t = + | ShiftGenLinesResetGenCols of { lines : int } + | ShiftGenCols of int + | Full of { shift_gen_col : int; shift_src : Location.t; meta : meta } +[@@deriving show { with_path = false }, eq] + +let encode_one : t -> string * [ `Sep | `NeedsSep ] = function + | ShiftGenLinesResetGenCols { lines } -> + Stdlib.prerr_endline ("lines:::" ^ Int.to_string lines); + (String.make lines ';', `Sep) + | ShiftGenCols n -> (Vql.encode_base64 [ n ], `NeedsSep) + | Full { shift_gen_col; shift_src; meta = { file_offset; name } } -> + ( Vql.encode_base64 + ([ shift_gen_col; file_offset; shift_src.line; shift_src.col ] + @ match name with Some name -> [ name ] | None -> []), + `NeedsSep ) + +let encode : t list -> string = + List.map ~f:encode_one + >> List.fold_left + ~f:(fun (acc, sep) (str, sep') -> + let acc = + acc + ^ + match (sep, sep') with `NeedsSep, `NeedsSep -> "," ^ str | _ -> str + in + (acc, sep')) + ~init:("", `Sep) + >> fst + +let decode_one (s : string) : t = + match Vql.decode_base64 s with + | [ cols ] -> ShiftGenCols cols + | shift_gen_col :: file_offset :: line :: col :: rest -> + let name = match rest with [ name ] -> Some name | _ -> None in + let meta = { file_offset; name } in + let shift_src : Location.t = { line; col } in + Full { shift_gen_col; shift_src; meta } + | _ -> failwith "??" + +let rec decode' (s : string) : t option list = + if String.is_empty s then [] + else + let n = + String.lfindi ~f:(fun _ -> function ';' | ',' -> true | _ -> false) s + |> Option.value ~default:(String.length s) + in + (if n > 0 then Some (decode_one (String.prefix s n)) + else + match String.get s 0 with + | ';' -> Some (ShiftGenLinesResetGenCols { lines = 1 }) + | ',' -> None + | _ -> failwith "should not be possible") + :: decode' (String.drop_prefix s (Int.max 1 n)) + +let decode : string -> t list = decode' >> List.filter_map ~f:Fn.id + +let eval_one (s : Location.t Dual.t) (i : t) : Location.t Dual.t * meta option = + match i with + | ShiftGenLinesResetGenCols { lines } -> + ({ s with gen = { line = s.gen.line + lines; col = 0 } }, None) + | ShiftGenCols i -> ({ s with gen = Location.plus_cols s.gen i }, None) + | Full { shift_gen_col; shift_src; meta } -> + let gen = Location.plus_cols s.gen shift_gen_col in + let src = Location.(s.src + shift_src) in + ({ gen; src }, Some meta) + +let to_points ?(init = Dual.default Location.default) : t list -> point list = + List.fold_left ~init:(init, []) ~f:(fun (s, acc) i -> + let s, r = eval_one s i in + (s, (s, r) :: acc)) + >> snd >> List.rev + +let from_points : point list -> t list = + List.folding_map ~init:(Dual.default Location.default) + ~f:(fun { src; gen } (x, m) -> + let d = + Location.(Dual.{ Dual.src = x.src - src; Dual.gen = x.gen - gen }) + in + let shift_gen_col = (if Int.(d.gen.line = 0) then d else x).gen.col in + let output = + (if Int.(d.gen.line = 0) then [] + else [ ShiftGenLinesResetGenCols { lines = d.gen.line } ]) + @ + match m with + | Some meta -> [ Full { shift_gen_col; shift_src = d.src; meta } ] + | None when Int.(shift_gen_col = 0) -> [] + | _ -> [ ShiftGenCols shift_gen_col ] + in + let x = match m with Some _ -> x | None -> { x with src } in + (x, output)) + >> List.concat + +let%test _ = + let f = decode >> to_points >> from_points >> encode in + [ + ";AAAA,SAAS,KAAAA,GAAG,YAAAC,GAAU,UAAAC,SAAc;;;ACApC,SAAS,KAAAC,GAAG,aAAAC,SAAiB;AAC7B,SAAS,YAAAC,SAAgB;AAWlB,IAAMC,IAAN,cAA2BF,EAAsC;AAAA,EAGtE,YAAYG,GAAqB;AAC/B,UAAMA,CAAK;AAIb,SAAAC,IAAa,MAAM,KAAK,SAAS,EAAEC,GAAQ,KAAK,MAAMA,IAAS,EAAE,CAAC;AAClE,SAAAC,IAAa,MAAM,KAAK,SAAS,EAAED,GAAQ,KAAK,MAAMA,IAAS,EAAE,CAAC;AAJhE,SAAK,MAAMA,IAASF,EAAMI;AAAA,EAC5B;AAAA,EAKA,SAAS;AACP,WAAOR,EAAC;AAAA,MAAI,OAAM;AAAA,OAChBA,EAAC,YAAI,KAAK,MAAM,KAAM,GACtBA,EAAC,WACCA,EAAC;AAAA,MAAO,SAAS,KAAKO;AAAA,OAAY,GAAC,GAClC,KACA,KAAK,MAAMD,GACX,KACDN,EAAC;AAAA,MAAO,SAAS,KAAKK;AAAA,OAAY,GAAC,CACrC,CACF;AAAA,EACF;AACF,GAEWI,IAAkB,CAACL,MAAwB;AACpD,MAAI,CAACM,GAAOC,CAAQ,IAAIT,EAASE,EAAMI,CAAa;AACpD,SAAOR,EAAC;AAAA,IAAI,OAAM;AAAA,KAChBA,EAAC,YAAII,EAAMQ,CAAO,GAClBZ,EAAC,WACCA,EAAC;AAAA,IAAO,SAAS,MAAMW,EAASD,IAAQ,CAAC;AAAA,KAAG,GAAC,GAC5C,KACAA,GACA,KACDV,EAAC;AAAA,IAAO,SAAS,MAAMW,EAASD,IAAQ,CAAC;AAAA,KAAG,GAAC,CAC/C,CACF;AACF;;;AD9CAG;AAAA,EACEC,EAAAC,GAAA,MACED,EAACE,GAAA;AAAA,IAAaC,GAAO;AAAA,IAAYC,GAAe;AAAA,GAAK,GACrDJ,EAACK,GAAA;AAAA,IAAgBF,GAAO;AAAA,IAAYC,GAAe;AAAA,GAAK,CAC1D;AAAA,EACA,SAAS,eAAe,MAAM;AAChC;"; + ] + |> List.for_all ~f:(fun s -> String.equal s (f s)) + +let from_spanned : Spanned.t list -> t list = Spanned.to_points >> from_points diff --git a/engine/utils/sourcemaps/mappings/mappings.ml b/engine/utils/sourcemaps/mappings/mappings.ml new file mode 100644 index 000000000..67fb40347 --- /dev/null +++ b/engine/utils/sourcemaps/mappings/mappings.ml @@ -0,0 +1,41 @@ +open Prelude +include Types + +type range = { start : Location.t; end_ : Location.t option } +[@@deriving show, eq] + +module Chunk = struct + type t = { gen : range; src : range; meta : meta } [@@deriving show, eq] + + let compare (x : t) (y : t) = Location.compare x.gen.start y.gen.start + + let from_spanned ((start, end_, meta) : Spanned.t) : t = + let gen = { start = start.gen; end_ = end_.gen } in + let src = { start = start.src; end_ = end_.src } in + { gen; src; meta } + + let to_spanned ({ gen; src; meta } : t) : Spanned.t = + ( { gen = gen.start; src = src.start }, + { gen = gen.end_; src = src.end_ }, + meta ) + + let%test _ = + let x = ";AAAA,SAAS,KAAAA,GAAG,YAAAC,GAAU" in + let s = Instruction.(decode x |> to_points) |> Spanned.from_points in + [%eq: Spanned.t list] (List.map ~f:(from_spanned >> to_spanned) s) s + + let decode : string -> t list = + Instruction.(decode >> to_points >> Spanned.from_points) + >> List.map ~f:from_spanned + + let encode : t list -> string = + List.map ~f:to_spanned >> Instruction.from_spanned >> Instruction.encode + + let%test _ = + let x = + ";AAAA,SAAS,KAAAA,GAAG,YAAAC,GAAU,UAAAC,SAAc;;;ACApC,SAAS,KAAAC,GAAG,aAAAC,SAAiB;AAC7B,SAAS,YAAAC,SAAgB;AAWlB,IAAMC,IAAN,cAA2BF,EAAsC" + in + decode x |> encode |> [%eq: string] x +end + +include Chunk diff --git a/engine/utils/sourcemaps/mappings/mappings.mli b/engine/utils/sourcemaps/mappings/mappings.mli new file mode 100644 index 000000000..7bc0e9d55 --- /dev/null +++ b/engine/utils/sourcemaps/mappings/mappings.mli @@ -0,0 +1,13 @@ +type meta = { file_offset : int; name : int option } [@@deriving show, eq] +type range = { start : Location.t; end_ : Location.t option } + +module Chunk : sig + type t = { gen : range; src : range; meta : meta } [@@deriving show, eq] + + val compare : t -> t -> int +end + +open Chunk + +val decode : string -> t list +val encode : t list -> string diff --git a/engine/utils/sourcemaps/mappings/spanned.ml b/engine/utils/sourcemaps/mappings/spanned.ml new file mode 100644 index 000000000..965485025 --- /dev/null +++ b/engine/utils/sourcemaps/mappings/spanned.ml @@ -0,0 +1,44 @@ +open Prelude +open Types + +type t = Location.t Dual.t * Location.t option Dual.t * meta +[@@deriving show, eq] + +let to_points (pts : t list) : point list = + List.map pts ~f:Option.some + |> Fn.flip List.append [ None ] + |> List.folding_map ~init:None ~f:(fun acc x -> + let prev_end = + match (acc, x) with + | Some end_, Some (start, _, _) + when [%eq: Location.t] start.Dual.gen end_.Dual.gen |> not -> + Some end_ + | Some end_, None -> Some end_ + | _ -> None + in + let out, end_ = + match x with + | Some (start, end_, meta) -> + ([ (start, Some meta) ], Dual.transpose ~default:start end_) + | None -> ([], None) + in + ( end_, + (prev_end |> Option.map ~f:(fun e -> (e, None)) |> Option.to_list) + @ out )) + |> List.concat + +let from_points : point list -> t list = + List.rev + >> List.folding_map + ~init:(None, Map.empty (module Int)) + ~f:(fun (gen_loc_0, src_locs) ((loc_start : _ Dual.t), meta) -> + match meta with + | Some meta -> + let src_loc_0 = Map.find src_locs meta.file_offset in + let src_locs = + Map.set src_locs ~key:meta.file_offset ~data:loc_start.src + in + let loc_end = Dual.{ gen = gen_loc_0; src = src_loc_0 } in + ((Some loc_start.gen, src_locs), Some (loc_start, loc_end, meta)) + | None -> ((Some loc_start.gen, src_locs), None)) + >> List.filter_map ~f:Fn.id >> List.rev diff --git a/engine/utils/sourcemaps/mappings/types.ml b/engine/utils/sourcemaps/mappings/types.ml new file mode 100644 index 000000000..be2cd146e --- /dev/null +++ b/engine/utils/sourcemaps/mappings/types.ml @@ -0,0 +1,4 @@ +open Prelude + +type meta = { file_offset : int; name : int option } [@@deriving show, eq] +type point = Location.t Dual.t * meta option [@@deriving show, eq] diff --git a/engine/utils/sourcemaps/prelude.ml b/engine/utils/sourcemaps/prelude.ml new file mode 100644 index 000000000..c68769180 --- /dev/null +++ b/engine/utils/sourcemaps/prelude.ml @@ -0,0 +1,4 @@ +include Base + +let ( << ) f g x = f (g x) +let ( >> ) f g x = g (f x) diff --git a/engine/utils/sourcemaps/source_maps.ml b/engine/utils/sourcemaps/source_maps.ml new file mode 100644 index 000000000..6da383baa --- /dev/null +++ b/engine/utils/sourcemaps/source_maps.ml @@ -0,0 +1,53 @@ +open Prelude +module Location = Location +include Mappings + +type mapping = { + gen : range; + src : range; + source : string; + name : string option; +} + +type t = { + mappings : string; + sourceRoot : string; + sources : string list; + sourcesContent : string option list; + names : string list; + version : int; + file : string; +} +[@@deriving yojson] + +let dedup_freq (l : string list) : string list = + let hashtbl : (string, int) Hashtbl.t = Hashtbl.create (module String) in + List.iter ~f:(Hashtbl.incr hashtbl) l; + Hashtbl.to_alist hashtbl + |> List.sort ~compare:(fun (_, x) (_, y) -> Int.(y - x)) + |> List.map ~f:fst + +let mk ?(file = "") ?(sourceRoot = "") ?(sourcesContent = fun _ -> None) + (mappings : mapping list) : t = + let sources = List.map ~f:(fun x -> x.source) mappings |> dedup_freq in + let names = List.filter_map ~f:(fun x -> x.name) mappings |> dedup_freq in + let f { gen; src; source; name } = + let file_offset, _ = + List.findi_exn ~f:(fun _ -> String.equal source) sources + in + let name = + Option.map + ~f:(fun name -> + List.findi_exn ~f:(fun _ -> String.equal name) names |> fst) + name + in + let meta = { file_offset; name } in + Chunk.{ gen; src; meta } + in + let mappings = List.map mappings ~f |> List.sort ~compare:Chunk.compare in + Stdlib.prerr_endline @@ [%show: Chunk.t list] mappings; + let mappings = Mappings.encode mappings in + let sourcesContent = List.map ~f:sourcesContent sources in + { mappings; sourceRoot; sourcesContent; sources; names; version = 3; file } + +let to_json = [%yojson_of: t] >> Yojson.Safe.pretty_to_string diff --git a/engine/utils/sourcemaps/source_maps.mli b/engine/utils/sourcemaps/source_maps.mli new file mode 100644 index 000000000..73105053b --- /dev/null +++ b/engine/utils/sourcemaps/source_maps.mli @@ -0,0 +1,33 @@ +type range = { start : Location.t; end_ : Location.t option } + +module Location : sig + type t = { line : int; col : int } [@@deriving eq] +end + +type mapping = { + gen : range; + src : range; + source : string; + name : string option; +} +(** A source file to generated file mapping *) + +type t = { + mappings : string; + sourceRoot : string; + sources : string list; + sourcesContent : string option list; + names : string list; + version : int; + file : string; +} +[@@deriving yojson] + +val mk : + ?file:string -> + ?sourceRoot:string -> + ?sourcesContent:(string -> string option) -> + mapping list -> + t + +val to_json : t -> string diff --git a/engine/utils/sourcemaps/vql.ml b/engine/utils/sourcemaps/vql.ml new file mode 100644 index 000000000..50bc07a45 --- /dev/null +++ b/engine/utils/sourcemaps/vql.ml @@ -0,0 +1,48 @@ +open Prelude + +let rec encode_one ?(first = true) (n : int) : int list = + let n = if first then (Int.abs n lsl 1) + if n < 0 then 1 else 0 else n in + let lhs, rhs = (n lsr 5, n land 0b11111) in + let last = Int.equal lhs 0 in + let output = (if last then 0b000000 else 0b100000) lor rhs in + output :: (if last then [] else encode_one ~first:false lhs) + +let encode : int list -> int list = List.concat_map ~f:encode_one + +let encode_base64 : int list -> string = + encode >> List.map ~f:Base64.encode >> String.of_char_list + +let rec decode_one' (first : bool) (l : int list) : int * int list = + match l with + | [] -> (0, []) + | hd :: tl -> + assert (hd < 64); + let c = Int.shift_right hd 5 |> Int.bit_and 0b1 in + let last = Int.equal c 0 in + if first then + let sign = match Int.bit_and hd 0b1 with 1 -> -1 | _ -> 1 in + let hd = Int.shift_right hd 1 |> Int.bit_and 0b1111 in + if last then (sign * hd, tl) + else + let next, tl = decode_one' false tl in + let value = hd + Int.shift_left next 4 in + (sign * value, tl) + else + let hd = Int.bit_and hd 0b11111 in + if last then (hd, tl) + else + let next, tl = decode_one' false tl in + (hd + Int.shift_left next 5, tl) + +let rec decode (l : int list) : int list = + match decode_one' true l with n, [] -> [ n ] | n, tl -> n :: decode tl + +let decode_base64 : string -> int list = + String.to_list >> List.map ~f:Base64.decode >> decode + +let%test _ = + let tests = + [ [ 132; 6; 2323; 64; 32; 63; 31; 65; 33 ]; [ 133123232 ]; [ 0; 0; 0 ] ] + in + let tests = tests @ List.map ~f:(List.map ~f:(fun x -> -x)) tests in + List.for_all ~f:(fun x -> [%eq: int list] x (encode x |> decode)) tests diff --git a/flake.lock b/flake.lock index 65baec36d..ba2824fa7 100644 --- a/flake.lock +++ b/flake.lock @@ -93,29 +93,6 @@ "type": "github" } }, - "ocaml-sourcemaps": { - "inputs": { - "flake-utils": [ - "flake-utils" - ], - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709059830, - "narHash": "sha256-K+g/h6xhE5uOBri1oCaOier3jeIwZrMGOSx79mz5FrU=", - "owner": "W95Psp", - "repo": "ocaml-sourcemaps", - "rev": "391ef51d2fad9884f7535e003b9c9f1a53536fbb", - "type": "github" - }, - "original": { - "owner": "W95Psp", - "repo": "ocaml-sourcemaps", - "type": "github" - } - }, "root": { "inputs": { "crane": "crane", @@ -123,7 +100,6 @@ "fstar": "fstar", "hacl-star": "hacl-star", "nixpkgs": "nixpkgs", - "ocaml-sourcemaps": "ocaml-sourcemaps", "rust-overlay": "rust-overlay" } }, diff --git a/flake.nix b/flake.nix index a93b93e94..a29793609 100644 --- a/flake.nix +++ b/flake.nix @@ -23,14 +23,6 @@ url = "github:hacl-star/hacl-star"; flake = false; }; - ocaml-sourcemaps = { - url = "github:W95Psp/ocaml-sourcemaps"; - flake = true; - inputs = { - nixpkgs.follows = "nixpkgs"; - flake-utils.follows = "flake-utils"; - }; - }; }; outputs = { @@ -64,7 +56,6 @@ cat "${hax-env-file}" | xargs -I{} echo "export {}" fi ''; - ocaml-sourcemaps = inputs.ocaml-sourcemaps.packages.${system}.default; ocamlPackages = pkgs.ocamlPackages; in rec { packages = { @@ -83,7 +74,7 @@ #!${pkgs.stdenv.shell} ${packages.hax-rust-frontend.hax-engine-names-extract}/bin/hax-engine-names-extract | sed 's|/nix/store/\(.\{6\}\)|/nix_store/\1-|g' ''; - inherit rustc ocaml-sourcemaps ocamlPackages; + inherit rustc ocamlPackages; }; hax-rust-frontend = pkgs.callPackage ./cli { inherit rustc craneLib; From 794be5b53df7c574434f2fbce5ec6d5d86377ea6 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 2 Oct 2024 05:49:42 +0200 Subject: [PATCH 007/253] refactor(engine/ast): move witness on the RHS of the tuple --- engine/lib/ast.ml | 2 +- engine/lib/print_rust.ml | 2 +- engine/lib/side_effect_utils.ml | 6 +++--- engine/lib/subtype.ml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 5fca55c87..5ed316077 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -273,7 +273,7 @@ functor coercion is applied on the (potential) error payload of `e`. Coercion should be made explicit within `e`. *) | Continue of { - e : (F.state_passing_loop * expr) option; + e : (expr * F.state_passing_loop) option; label : string option; witness : F.continue * F.loop; } diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 1a13df86c..9792ffaa6 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -344,7 +344,7 @@ module Raw = struct | None -> main) | Break { e; _ } -> !"(break (" & pexpr e & !"))" | Continue { e = None; _ } -> !"continue" - | Continue { e = Some (_, e); _ } -> + | Continue { e = Some (e, _); _ } -> !"state_passing_continue!(" & pexpr e & !")" | Return { e; _ } -> !"(return " & pexpr e & !")" | QuestionMark { e; _ } -> !"(" & pexpr e & !")?" diff --git a/engine/lib/side_effect_utils.ml b/engine/lib/side_effect_utils.ml index 79f66fb0e..820ce0d7f 100644 --- a/engine/lib/side_effect_utils.ml +++ b/engine/lib/side_effect_utils.ml @@ -271,16 +271,16 @@ struct no_lbs { SideEffects.zero with - continue = Some (Option.map ~f:(fun (_, e) -> e.typ) e'); + continue = Some (Option.map ~f:(fun (e, _) -> e.typ) e'); } in match e' with - | Some (witness', e') -> + | Some (e', witness') -> HoistSeq.one env (self#visit_expr env e') (fun e' effects -> ( { e with e = - Continue { e = Some (witness', e'); label; witness }; + Continue { e = Some (e', witness'); label; witness }; }, m#plus ceffect effects )) | None -> (e, ceffect)) diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index 65daa8ac0..eb893d35f 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -264,7 +264,7 @@ struct | Continue { e; label; witness = w1, w2 } -> Continue { - e = Option.map ~f:(S.state_passing_loop span *** dexpr) e; + e = Option.map ~f:(dexpr *** S.state_passing_loop span) e; label; witness = (S.continue span w1, S.loop span w2); } From 06a0ded2a61159be35fc7f04cd4480404665aaf9 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 3 Oct 2024 13:40:18 +0200 Subject: [PATCH 008/253] misc: generic printer --- engine/backends/fstar/fstar_backend.ml | 4 +- engine/lib/ast.ml | 2 +- engine/lib/dune | 13 +- engine/lib/generic_printer/generic_printer.ml | 509 ++++++++++++++++++ .../generic_printer/generic_printer_api.ml | 92 ---- .../generic_printer/generic_printer_base.ml | 175 ------ .../generic_printer/generic_printer_base.mli | 23 - .../generic_printer_base_sig.ml | 373 ------------- .../generic_printer_template.generate.js | 46 ++ .../generic_printer_template.ml | 379 +++++++++++-- .../generic_printer/generic_rust_printer.ml | 169 ------ .../generic_printer/generic_rust_printer.mli | 4 - engine/lib/print_rust.ml | 44 +- .../generate_visitors/codegen_printer.ml | 402 ++++++++++++++ .../generate_visitors/generate_visitors.ml | 9 +- .../utils/sourcemaps/mappings/instruction.ml | 12 +- 16 files changed, 1345 insertions(+), 911 deletions(-) create mode 100644 engine/lib/generic_printer/generic_printer.ml delete mode 100644 engine/lib/generic_printer/generic_printer_api.ml delete mode 100644 engine/lib/generic_printer/generic_printer_base.ml delete mode 100644 engine/lib/generic_printer/generic_printer_base.mli delete mode 100644 engine/lib/generic_printer/generic_printer_base_sig.ml create mode 100755 engine/lib/generic_printer/generic_printer_template.generate.js delete mode 100644 engine/lib/generic_printer/generic_rust_printer.ml delete mode 100644 engine/lib/generic_printer/generic_rust_printer.mli create mode 100644 engine/utils/generate_visitors/codegen_printer.ml diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index a84c1c931..57d298333 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1641,6 +1641,7 @@ let fstar_headers (bo : BackendOptions.t) = in [ opts; "open Core"; "open FStar.Mul" ] |> String.concat ~sep:"\n" +(* module GenericPrinter = Generic_rust_printer.Make (InputLanguage) (** Use the generic printer instead of the F* printer. For now, there @@ -1681,6 +1682,7 @@ let translate_as_experimental_rust m (bo : BackendOptions.t) } in List.filter_map ~f:Fn.id [ make ~ext:"rs" impl ]) +*) (** Translate as F* (the "legacy" printer) *) let translate_as_fstar m (bo : BackendOptions.t) (items : AST.item list) : @@ -1725,7 +1727,7 @@ let translate = if Sys.getenv "HAX_ENGINE_EXPERIMENTAL_RUST_PRINTER_INSTEAD_OF_FSTAR" |> Option.is_some - then translate_as_experimental_rust + then failwith "todo" else translate_as_fstar open Phase_utils diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 5ed316077..7eb48dc09 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -197,9 +197,9 @@ functor | PAscription of { typ : ty; typ_span : span; pat : pat } | PConstruct of { name : global_ident; - args : field_pat list; is_record : bool; (* are fields named? *) is_struct : bool; (* a struct has one constructor *) + args : field_pat list; } (* An or-pattern, e.g. `p | q`. Invariant: `List.length subpats >= 2`. *) diff --git a/engine/lib/dune b/engine/lib/dune index 91d5acc2e..418198f46 100644 --- a/engine/lib/dune +++ b/engine/lib/dune @@ -56,7 +56,18 @@ ast_visitors.ml (with-stdin-from %{ast} - (run generate_visitors))))) + (run generate_visitors visitors))))) + +(rule + (target generated_generic_printer_base.ml) + (deps + (:ast ast.ml)) + (action + (with-stdout-to + generated_generic_printer_base.ml + (with-stdin-from + %{ast} + (run generate_visitors printer))))) (rule (target concrete_ident_generated.ml) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml new file mode 100644 index 000000000..6cce72c72 --- /dev/null +++ b/engine/lib/generic_printer/generic_printer.ml @@ -0,0 +1,509 @@ +(** + The generic printer if +*) + +open! Prelude +open! Ast +open! PPrint +module LazyDoc = Generated_generic_printer_base.LazyDoc +open LazyDoc + +module Annotation = struct + type loc = { line : int; col : int } [@@deriving show, yojson, eq] + type t = loc * span [@@deriving show, yojson, eq] + + let compare ((a, _) : t) ((b, _) : t) : int = + let line = Int.compare a.line b.line in + if Int.equal line 0 then Int.compare a.col b.col else line + + (** Converts a list of annotation and a string to a list of annotated string *) + let split_with_string (s : string) (annots : t list) = + let lines_position = + String.to_list s + |> List.filter_mapi ~f:(fun i ch -> + match ch with '\n' -> Some i | _ -> None) + |> List.to_array |> Array.get + in + let annots = List.sort ~compare annots in + let init = ({ line = 0; col = 0 }, None) in + let slices = + List.folding_map + ~f:(fun (start, start_span) (end_, end_span) -> + let span = Option.value ~default:end_span start_span in + ((end_, Some end_span), (span, start, end_))) + ~init annots + in + List.map slices ~f:(fun (span, start, end_) -> + let pos = lines_position start.line + start.col in + let len = lines_position end_.line + end_.col - pos in + (span, String.sub s ~pos ~len)) + + let to_mapping ((loc, span) : t) : Sourcemaps.Source_maps.mapping option = + let real_path (x : Types.file_name) = + match x with + | Real (LocalPath p) | Real (Remapped { local_path = Some p; _ }) -> + Some p + | _ -> None + in + let loc_to_loc ({ line; col } : loc) : Sourcemaps.Location.t = + { line; col } + in + let to_loc ({ col; line } : Types.loc) : loc = + { col = Int.of_string col; line = Int.of_string line - 1 } + in + let* span = + Span.to_thir span + |> List.find ~f:(fun (s : Types.span) -> + real_path s.filename |> Option.is_some) + in + let* src_filename = real_path span.filename in + let src_start = to_loc span.lo |> loc_to_loc in + let src_end = to_loc span.hi |> loc_to_loc in + let dst_start = loc_to_loc loc in + Some + Sourcemaps.Source_maps. + { + src = { start = src_start; end_ = Some src_end }; + gen = { start = dst_start; end_ = None }; + source = src_filename; + name = None; + } +end + +module AnnotatedString = struct + type t = string * Annotation.t list [@@deriving show, yojson, eq] + + let to_string = fst + + let to_spanned_strings ((s, annots) : t) : (Ast.span * string) list = + Annotation.split_with_string s annots + + let to_sourcemap : t -> Types.source_map = + snd >> List.filter_map ~f:Annotation.to_mapping >> Sourcemaps.Source_maps.mk + >> fun ({ + mappings; + sourceRoot; + sources; + sourcesContent; + names; + version; + file; + } : + Sourcemaps.Source_maps.t) -> + Types. + { mappings; sourceRoot; sources; sourcesContent; names; version; file } +end + +(** Helper class that brings imperative span *) +class span_helper : + object + method span_data : Annotation.t list + (** Get the span annotation accumulated while printing *) + + method with_span : span:span -> (unit -> document) -> document + (** Runs the printer `f` under a node of span `span` *) + + method current_span : span + (** Get the current span *) + end = + object (self) + val mutable current_span = Span.default + val mutable span_data : Annotation.t list = [] + method span_data = span_data + method current_span = current_span + + method with_span ~(span : span) (f : unit -> document) : document = + let prev_span = current_span in + current_span <- span; + let doc = f () |> self#spanned_doc |> custom in + current_span <- prev_span; + doc + + method private spanned_doc (doc : document) : custom = + let span = current_span in + object + method requirement : requirement = requirement doc + + method pretty : output -> state -> int -> bool -> unit = + fun o s i b -> + span_data <- ({ line = s.line; col = s.column }, span) :: span_data; + pretty o s i b doc + + method compact : output -> unit = fun o -> compact o doc + end + end + +module Make (F : Features.T) = struct + module AST = Ast.Make (F) + open Ast.Make (F) + module Gen = Generated_generic_printer_base.Make (F) + + type printer = (unit -> Annotation.t list, PPrint.document) Gen.object_type + type finalized_printer = (unit, string * Annotation.t list) Gen.object_type + + let finalize (new_printer : unit -> printer) : finalized_printer = + Gen.map (fun apply -> + let printer = new_printer () in + let doc = apply printer in + let buf = Buffer.create 0 in + PPrint.ToBuffer.pretty 1.0 80 buf doc; + (Buffer.contents buf, printer#get_span_data ())) + + class virtual base = + object (self) + inherit Gen.base as super + inherit span_helper + val mutable current_namespace : (string * string list) option = None + + method private catch_exn (handle : string -> document) + (f : unit -> document) : document = + self#catch_exn' + (fun context kind -> + Diagnostics.pretty_print_context_kind context kind |> handle) + f + + method private catch_exn' + (handle : Diagnostics.Context.t -> Diagnostics.kind -> document) + (f : unit -> document) : document = + try f () + with Diagnostics.SpanFreeError.Exn (Data (context, kind)) -> + handle context kind + + method assertion_failure : 'any. string -> 'any = + fun details -> + let span = Span.to_thir self#current_span in + let kind = Types.AssertionFailure { details } in + let ctx = Diagnostics.Context.GenericPrinter self#printer_name in + Diagnostics.SpanFreeError.raise ~span ctx kind + + method unreachable : 'any. unit -> 'any = failwith "Unreachable!" + method virtual printer_name : string + + (** {2:specialize-expr Specialized printers for [expr]} *) + + method virtual expr'_App_constant + : super:expr -> + constant:concrete_ident lazy_doc -> + generics:generic_value lazy_doc list -> + document + (** [expr'_App_constant ~super ~constant ~generics] prints the + constant [e] with generics [generics]. [super] is the + unspecialized [expr]. *) + + method virtual expr'_App_application + : super:expr -> + f:expr lazy_doc -> + args:expr lazy_doc list -> + generics:generic_value lazy_doc list -> + document + (** [expr'_App_application ~super ~f ~args ~generics] prints the + function application [e<...generics>(...args)]. [super] is the + unspecialized [expr]. *) + + method virtual expr'_App_tuple_projection + : super:expr -> size:int -> nth:int -> e:expr lazy_doc -> document + (** [expr'_App_tuple_projection ~super ~size ~nth ~e] prints + the projection of the [nth] component of the tuple [e] of + size [size]. [super] is the unspecialized [expr]. *) + + method virtual expr'_App_field_projection + : super:expr -> + field:concrete_ident lazy_doc -> + e:expr lazy_doc -> + document + (** [expr'_App_field_projection ~super ~field ~e] prints the + projection of the field [field] in the expression [e]. [super] + is the unspecialized [expr]. *) + + method virtual expr'_Construct_inductive + : super:expr -> + constructor:concrete_ident lazy_doc -> + is_record:bool -> + is_struct:bool -> + fields:(concrete_ident lazy_doc * expr lazy_doc) list -> + base:(expr lazy_doc * F.construct_base) lazy_doc option -> + document + (** [expr'_Construct_inductive ~super ~is_record ~is_struct + ~constructor ~base ~fields] prints the construction of an + inductive with base [base] and fields [fields]. [super] is the + unspecialized [expr]. TODO doc is_record is_struct *) + + method virtual expr'_Construct_tuple + : super:expr -> components:expr lazy_doc list -> document + + (** {2:specialize-pat Specialized printers for [pat]} *) + + method virtual pat'_PConstruct_inductive + : super:pat -> + constructor:concrete_ident lazy_doc -> + is_record:bool -> + is_struct:bool -> + fields:(concrete_ident lazy_doc * pat lazy_doc) list -> + document + + method virtual pat'_PConstruct_tuple + : super:pat -> components:pat lazy_doc list -> document + + (** {2:specialize-lhs Specialized printers for [lhs]} *) + + method virtual lhs_LhsFieldAccessor_field + : e:lhs lazy_doc -> + typ:ty lazy_doc -> + field:concrete_ident lazy_doc -> + witness:F.nontrivial_lhs -> + document + + method virtual lhs_LhsFieldAccessor_tuple + : e:lhs lazy_doc -> + typ:ty lazy_doc -> + nth:int -> + size:int -> + witness:F.nontrivial_lhs -> + document + + (** {2:specialize-ty Specialized printers for [ty]} *) + + method virtual ty_TApp_tuple : types:ty list -> document + (** [ty_TApp_tuple ~types] prints a tuple type with + compounds types [types]. *) + + method virtual ty_TApp_application + : typ:concrete_ident lazy_doc -> + generics:generic_value lazy_doc list -> + document + (** [ty_TApp_application ~typ ~generics] prints the type + [typ<...generics>]. *) + + (** {2:common-nodes Printers for common nodes} *) + + method virtual common_array : document list -> document + (** [common_array values] is a default for printing array-like nodes: array patterns, array expressions. *) + + method _do_not_override_lhs_LhsFieldAccessor ~e ~typ ~field ~witness = + let field = + match field with + | `Projector field -> field + | _ -> + self#assertion_failure + @@ "LhsFieldAccessor: field not a [`Projector] " + in + match field with + | `TupleField (nth, size) -> + self#lhs_LhsFieldAccessor_tuple ~e ~typ ~nth ~size ~witness + | `Concrete field -> + let field : concrete_ident lazy_doc = + self#_do_not_override_lazy_of_concrete_ident + AstPos_lhs_LhsFieldAccessor_field field + in + self#lhs_LhsFieldAccessor_field ~e ~typ ~field ~witness + + method _do_not_override_expr'_App ~super ~f ~args ~generic_args + ~bounds_impls ~trait = + let _ = (super, f, args, generic_args, bounds_impls, trait) in + match f#v with + | { e = GlobalVar i; _ } -> ( + let expect_one_arg where = + match args with + | [ arg ] -> arg + | _ -> self#assertion_failure @@ "Expected one arg at " ^ where + in + match i with + | `Concrete _ | `Primitive _ -> ( + match (args, i) with + | [], `Concrete i -> + let constant = + self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_App_f i + in + self#expr'_App_constant ~super ~constant + ~generics:generic_args + | [], _ -> self#assertion_failure "Primitive app of arity 0" + | _ -> + self#expr'_App_application ~super ~f ~args + ~generics:generic_args) + | `TupleType _ | `TupleCons _ | `TupleField _ -> + self#assertion_failure "App: unexpected tuple" + | `Projector (`TupleField (nth, size)) -> + let e = expect_one_arg "projector tuple field" in + self#expr'_App_tuple_projection ~super ~size ~nth ~e + | `Projector (`Concrete field) -> + let e = expect_one_arg "projector concrete" in + let field = + self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_App_f field + in + self#expr'_App_field_projection ~super ~field ~e) + | _ -> self#assertion_failure "Primitive app of arity 0" + + method _do_not_override_expr'_Construct ~super ~constructor ~is_record + ~is_struct ~fields ~base = + match constructor with + | `Concrete constructor -> + let constructor = + self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_Construct_constructor constructor + in + let fields = + List.map + ~f:(fun field -> + let name, expr = field#v in + let name = + match name with + | `Concrete name -> name + | _ -> + self#assertion_failure + "expr'.Construct: field: non-`Concrete" + in + ( self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_Construct_fields name, + expr )) + fields + in + self#expr'_Construct_inductive ~super ~constructor ~is_record + ~is_struct ~fields ~base + | `TupleCons _ -> + let components = List.map ~f:(fun field -> snd field#v) fields in + self#expr'_Construct_tuple ~super ~components + | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> + self#assertion_failure "Construct unexpected constructors" + + method _do_not_override_pat'_PConstruct ~super ~constructor ~is_record + ~is_struct ~fields = + match constructor with + | `Concrete constructor -> + let constructor = + self#_do_not_override_lazy_of_concrete_ident + AstPos_pat'_PConstruct_constructor constructor + in + let fields = + List.map + ~f:(fun field -> + let { field; pat } = field#v in + let field = + match field with + | `Concrete field -> field + | _ -> + self#assertion_failure + "expr'.Construct: field: non-`Concrete" + in + let pat = + self#_do_not_override_lazy_of_pat AstPos_field_pat__pat pat + in + ( self#_do_not_override_lazy_of_concrete_ident + AstPos_pat'_PConstruct_fields field, + pat )) + fields + in + self#pat'_PConstruct_inductive ~super ~constructor ~is_record + ~is_struct ~fields + | `TupleCons _ -> + let components = + List.map + ~f:(fun field -> + self#_do_not_override_lazy_of_pat AstPos_field_pat__pat + field#v.pat) + fields + in + self#pat'_PConstruct_tuple ~super ~components + | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> + self#assertion_failure "Construct unexpected constructors" + + method _do_not_override_ty_TApp ~ident ~args = + match ident with + | `Concrete ident -> + let typ = + self#_do_not_override_lazy_of_concrete_ident AstPos_ty_TApp_args + ident + in + self#ty_TApp_application ~typ ~generics:args |> group + | `Primitive _ | `TupleCons _ | `TupleField _ | `Projector _ -> + self#assertion_failure "TApp not concrete" + | `TupleType size -> + let types = + List.filter_map + ~f:(fun garg -> + match garg#v with GType t -> Some t | _ -> None) + args + in + if [%equal: int] (List.length args) size |> not then + self#assertion_failure "malformed [ty.TApp] tuple"; + self#ty_TApp_tuple ~types + + method pat'_PArray ~super:_ ~args = + List.map ~f:(fun arg -> arg#p) args |> self#common_array + + method expr'_Array ~super:_ args = + List.map ~f:(fun arg -> arg#p) args |> self#common_array + + val concrete_ident_view : (module Concrete_ident.VIEW_API) = + (module Concrete_ident.DefaultViewAPI) + (** The concrete ident view to be used *) + + method local_ident (id : local_ident) : document = + let module View = (val concrete_ident_view) in + View.local_ident + (match String.chop_prefix ~prefix:"impl " id.name with + | Some _ -> + let name = "impl_" ^ Int.to_string ([%hash: string] id.name) in + { id with name } + | _ -> id) + |> string + + method _do_not_override_lazy_of_local_ident ast_position + (id : local_ident) = + lazy_doc (fun (id : local_ident) -> self#local_ident id) ast_position id + + method _do_not_override_lazy_of_concrete_ident ast_position + (id : concrete_ident) : concrete_ident lazy_doc = + lazy_doc + (fun (id : concrete_ident) -> + let module View = (val concrete_ident_view) in + let id = View.to_view id in + let ns_crate, ns_path = + Option.value ~default:("", []) current_namespace + in + let local = + String.(ns_crate = id.crate) && [%eq: string list] ns_path id.path + in + self#concrete_ident ~local id) + ast_position id + + method module_path_separator = "::" + (** [module_path_separator] is the default separator for + paths. `::` by default *) + + method concrete_ident ~local id : document = + string + (if local then id.definition + else + String.concat ~sep:self#module_path_separator + (id.crate :: (id.path @ [ id.definition ]))) + (** [concrete_ident ~local id] prints a name without path if + [local] is true, otherwise it prints the full path, separated by + `module_path_separator`. *) + + method pat'_POr ~super:_ ~subpats = + List.map ~f:(fun subpat -> subpat#p) subpats + |> separate (break 1 ^^ char '|' ^^ space) + + method quote (quote : quote) : document = + List.map + ~f:(function + | `Verbatim code -> string code + | `Expr e -> self#print_expr AstPosition_Quote e + | `Pat p -> self#print_pat AstPosition_Quote p + | `Typ p -> self#print_ty AstPosition_Quote p) + quote.contents + |> concat + + method _do_not_override_lazy_of_quote ast_position (value : quote) + : quote lazy_doc = + lazy_doc (fun (value : quote) -> self#quote value) ast_position value + + method! _do_not_override_lazy_of_item ast_position (value : item) + : item lazy_doc = + let module View = (val concrete_ident_view) in + current_namespace <- View.to_namespace value.ident |> Option.some; + super#_do_not_override_lazy_of_item ast_position value + end +end diff --git a/engine/lib/generic_printer/generic_printer_api.ml b/engine/lib/generic_printer/generic_printer_api.ml deleted file mode 100644 index 83f575ca8..000000000 --- a/engine/lib/generic_printer/generic_printer_api.ml +++ /dev/null @@ -1,92 +0,0 @@ -open! Prelude -open Generic_printer_base - -module AnnotatedString = struct - type t = string * Annotation.t list [@@deriving show, yojson, eq] - - let to_string = fst - - let to_spanned_strings ((s, annots) : t) : (Ast.span * string) list = - Annotation.split_with_string s annots - - let to_sourcemap : t -> Types.source_map = - snd >> List.filter_map ~f:Annotation.to_mapping >> Sourcemaps.Source_maps.mk - >> fun ({ - mappings; - sourceRoot; - sources; - sourcesContent; - names; - version; - file; - } : - Sourcemaps.Source_maps.t) -> - Types. - { mappings; sourceRoot; sources; sourcesContent; names; version; file } -end - -module Make (F : Features.T) = struct - module AST = Ast.Make (F) - open Ast.Make (F) - open SecretTypes - - type print_object = - < printer_name : string - ; get_span_data : unit -> Annotation.t list - ; ty : (par_state -> ty fn) no_override - ; pat : (par_state -> pat fn) no_override - ; arm : arm fn no_override - ; expr : (par_state -> expr fn) no_override - ; item : item fn no_override - ; items : item list fn > - (** In the end, an printer *object* should be of the type {!print_object}. *) - - module type API = sig - type aux_info - - val items : aux_info -> item list -> AnnotatedString.t - val item : aux_info -> item -> AnnotatedString.t - val expr : aux_info -> expr -> AnnotatedString.t - val pat : aux_info -> pat -> AnnotatedString.t - val ty : aux_info -> ty -> AnnotatedString.t - end - - module Api (NewPrint : sig - type aux_info - - val new_print : aux_info -> print_object - end) = - struct - open NewPrint - - let mk' (f : print_object -> 'a -> PPrint.document) (aux : aux_info) - (x : 'a) : AnnotatedString.t = - let printer = new_print aux in - let doc = f printer x in - let buf = Buffer.create 0 in - PPrint.ToBuffer.pretty 1.0 80 buf doc; - (Buffer.contents buf, printer#get_span_data ()) - - let mk (f : print_object -> 'a fn no_override) = - mk' (fun (po : print_object) -> - let f : 'a fn no_override = f po in - let f = !:f in - f) - - type aux_info = NewPrint.aux_info - - let items : aux_info -> item list -> AnnotatedString.t = - mk' (fun p -> p#items) - - let item : aux_info -> item -> AnnotatedString.t = mk (fun p -> p#item) - - let expr : aux_info -> expr -> AnnotatedString.t = - mk' (fun p -> !:(p#expr) AlreadyPar) - - let pat : aux_info -> pat -> AnnotatedString.t = - mk' (fun p -> !:(p#pat) AlreadyPar) - - let ty : aux_info -> ty -> AnnotatedString.t = - mk' (fun p -> !:(p#ty) AlreadyPar) - end -end diff --git a/engine/lib/generic_printer/generic_printer_base.ml b/engine/lib/generic_printer/generic_printer_base.ml deleted file mode 100644 index 423e4f8d1..000000000 --- a/engine/lib/generic_printer/generic_printer_base.ml +++ /dev/null @@ -1,175 +0,0 @@ -open! Prelude -open! Ast -open PPrint - -module SecretTypes = struct - type 't no_override = 't - type 'location no_direct_call = unit -end - -let ( !: ) (type a) (f : a SecretTypes.no_override) : a = f - -include Generic_printer_base_sig.Types - -module Make (F : Features.T) = struct - module AST = Ast.Make (F) - open Ast.Make (F) - open Generic_printer_base_sig.Make (F) (SecretTypes) - - class virtual base : print_base_type = - object (print) - val mutable current_span = Span.default - val mutable span_data : Annotation.t list = [] - val mutable current_namespace : (string * string list) option = None - method get_span_data () = span_data - - method with_span ~(span : span) (f : unit -> document) : document = - let prev_span = current_span in - current_span <- span; - let doc = f () |> print#spanned_doc |> custom in - current_span <- prev_span; - doc - - method spanned_doc (doc : document) : custom = - let span = current_span in - object - method requirement : requirement = requirement doc - - method pretty : output -> state -> int -> bool -> unit = - fun o s i b -> - span_data <- - ({ line = s.line; col = s.column }, span) :: span_data; - pretty o s i b doc - - method compact : output -> unit = fun o -> compact o doc - end - - method expr_at = print#par_state >> print#expr - method ty_at = print#par_state >> print#ty - method pat_at = print#par_state >> print#pat - - method expr ctx (e : expr) = - let span = e.span in - print#with_span ~span (fun _ -> - try print#__expr ctx e - with Diagnostics.SpanFreeError.Exn (Data (_context, _kind)) -> - failwith "todo") - - method ty ctx full = - match full with - | TApp { ident = `Concrete ident; args } -> - print#ty_TApp_application ~full ident args |> group - | TApp - { - ident = `Primitive _ | `TupleCons _ | `TupleField _ | `Projector _; - _; - } -> - print#assertion_failure "TApp not concrete" - | TApp { ident = `TupleType size; args } -> - let args = - List.filter_map ~f:(function GType t -> Some t | _ -> None) args - in - if [%equal: int] (List.length args) size |> not then - print#assertion_failure "malformed [ty.TApp] tuple"; - print#ty_TApp_tuple ~full args - | TApp _ -> . - | _ -> print#ty_ () ctx full - - method pat ctx (full : pat) = - print#with_span ~span:full.span (fun _ -> print#pat_ () ctx full) - - method item i = - print#set_current_namespace - (print#namespace_of_concrete_ident i.ident |> Option.some); - print#with_span ~span:i.span (fun _ -> - try print#item_ () i - with Diagnostics.SpanFreeError.Exn (Data (context, kind)) -> - let error = Diagnostics.pretty_print_context_kind context kind in - (* let cast_item : item -> Ast.Full.item = Stdlib.Obj.magic in *) - (* let ast = cast_item i |> Print_rust.pitem_str in *) - let msg = - error ^ "\nLast available AST for this item:\n\n" ^ "ast" - in - (* TODO: if the printer is extremely broken, this results in a stack overflow *) - make_hax_error_item i.span i.ident msg |> print#item) - - method private __expr ctx full = - match full.e with - | App { f = { e = GlobalVar i; _ } as f; args; generic_args; _ } -> ( - let expect_one_arg where = - match args with - | [ arg ] -> arg - | _ -> print#assertion_failure @@ "Expected one arg at " ^ where - in - match i with - | `Concrete _ | `Primitive _ -> ( - match (args, i) with - | [], `Concrete i -> - print#expr_App_constant ~full i generic_args - | [], _ -> print#assertion_failure "Primitive app of arity 0" - | _ -> print#expr_App_application ~full f args generic_args) - | `TupleType _ | `TupleCons _ | `TupleField _ -> - print#assertion_failure "App: unexpected tuple" - | `Projector (`TupleField (nth, size)) -> - let arg = expect_one_arg "projector tuple field" in - print#expr_App_tuple_projection ~full ~size ~nth arg - | `Projector (`Concrete i) -> - let arg = expect_one_arg "projector concrete" in - print#expr_App_field_projection ~full i arg) - | App { f; args; generic_args; _ } -> - print#expr_App_application ~full f args generic_args - | Construct { constructor; fields; base; is_record; is_struct } -> ( - match constructor with - | `Concrete constructor -> - print#expr_Construct_inductive ~full ~is_record ~is_struct - ~constructor ~base fields - | `TupleCons _ -> - List.map ~f:snd fields |> print#expr_Construct_tuple ~full - | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> - print#assertion_failure "Construct unexpected constructors") - | App _ | Construct _ -> . - | _ -> print#expr_ () ctx full - - method arm (full : arm) = - print#with_span ~span:full.span (fun _ -> print#arm_ () full) - - method generic_param (full : generic_param) = - print#with_span ~span:full.span (fun _ -> print#generic_param_ () full) - - method param_ty (full : param) = - match full.typ_span with - | Some span -> print#with_span ~span (fun _ -> print#param_ty_ () full) - | None -> print#param_ty_ () full - - method impl_item (full : impl_item) = - print#with_span ~span:full.ii_span (fun _ -> print#impl_item_ () full) - - method trait_item (full : trait_item) = - print#with_span ~span:full.ti_span (fun _ -> print#trait_item_ () full) - - method attr (full : attr) = - print#with_span ~span:full.span (fun _ -> print#attr_ () full) - - method concrete_ident id = - let current_ns = print#get_current_namespace () in - let id_ns = print#namespace_of_concrete_ident id in - print#concrete_ident_ () - ~under_current_ns: - ([%equal: (string * string list) option] current_ns (Some id_ns)) - id - - method items = separate_map (twice hardline) print#item - method attrs = separate_map hardline print#attr - - method assertion_failure : 'any. string -> 'any = - fun details -> - let span = Span.to_thir current_span in - let kind = Types.AssertionFailure { details } in - let ctx = Diagnostics.Context.GenericPrinter print#printer_name in - Diagnostics.SpanFreeError.raise ~span ctx kind - - method set_current_namespace ns = current_namespace <- ns - method get_current_namespace () = current_namespace - method unreachable : 'any. unit -> 'any = failwith "Unreachable!" - end -end diff --git a/engine/lib/generic_printer/generic_printer_base.mli b/engine/lib/generic_printer/generic_printer_base.mli deleted file mode 100644 index fb97d5f63..000000000 --- a/engine/lib/generic_printer/generic_printer_base.mli +++ /dev/null @@ -1,23 +0,0 @@ -open! Prelude -open! Ast - -include module type of struct - (** Protects some methods from being called or overrided. *) - module SecretTypes = struct - type 't no_override = private 't - (** Hello *) - - type 'location no_direct_call = private unit - (** Hello *) - end - - include Generic_printer_base_sig.Types -end - -val ( !: ) : 'a. 'a SecretTypes.no_override -> 'a - -module Make (F : Features.T) : sig - open Generic_printer_base_sig.Make(F)(SecretTypes) - - class virtual base : print_base_type -end diff --git a/engine/lib/generic_printer/generic_printer_base_sig.ml b/engine/lib/generic_printer/generic_printer_base_sig.ml deleted file mode 100644 index f786df7f2..000000000 --- a/engine/lib/generic_printer/generic_printer_base_sig.ml +++ /dev/null @@ -1,373 +0,0 @@ -[@@@warning "-37-34-27"] - -open! Prelude -open! Ast -open PPrint - -module Types = struct - (** Generic printer for the {!module:Ast} ASTs. It uses the [PPrint] -library, and additionaly computes {!Annotation.t}. *) - - (** Identifies a position in the AST. This is useful for figuring out -wether we should wrap a chunk of AST in parenthesis. or not *) - type ast_position = - | GenericValue_GType - | GenericValue_GConst - | Lhs_LhsArbitraryExpr - | Lhs_LhsArrayAccessor - | Ty_TArrow - | Ty_TRef - | Ty_Tuple - | Ty_TSlice - | Ty_TArray_typ - | Ty_TArray_length - | Expr_If_cond - | Expr_If_then - | Expr_If_else - | Expr_Array - | Expr_Assign - | Expr_Closure_param - | Expr_Closure_body - | Expr_Ascription_e - | Expr_Ascription_typ - | Expr_Let_lhs - | Expr_Let_rhs - | Expr_Let_body - | Expr_Match_scrutinee - | Expr_QuestionMark - | Expr_Borrow - | Expr_TupleProjection - | Expr_ConstructTuple - | Expr_FieldProjection - | Expr_App_f - | Expr_App_arg - | Expr_ConcreteInductive_base - | Expr_ConcreteInductive_field - | Pat_PBinding_subpat - | Pat_PDeref - | Pat_PArray - | Pat_ConstructTuple - | Pat_ConcreteInductive - | Pat_Ascription_pat - | Pat_Ascription_typ - | Pat_Or - | Param_pat - | Param_typ - | GenericParam_GPType - | GenericParam_GPConst - | Arm_pat - | Arm_body - | Item_Fn_body - [@@warning "-37"] - - module Annotation = struct - type loc = { line : int; col : int } [@@deriving show, yojson, eq] - type t = loc * span [@@deriving show, yojson, eq] - - let compare ((a, _) : t) ((b, _) : t) : int = - let line = Int.compare a.line b.line in - if Int.equal line 0 then Int.compare a.col b.col else line - - (** Converts a list of annotation and a string to a list of annotated string *) - let split_with_string (s : string) (annots : t list) = - let lines_position = - String.to_list s - |> List.filter_mapi ~f:(fun i ch -> - match ch with '\n' -> Some i | _ -> None) - |> List.to_array |> Array.get - in - let annots = List.sort ~compare annots in - let init = ({ line = 0; col = 0 }, None) in - let slices = - List.folding_map - ~f:(fun (start, start_span) (end_, end_span) -> - let span = Option.value ~default:end_span start_span in - ((end_, Some end_span), (span, start, end_))) - ~init annots - in - List.map slices ~f:(fun (span, start, end_) -> - let pos = lines_position start.line + start.col in - let len = lines_position end_.line + end_.col - pos in - (span, String.sub s ~pos ~len)) - - let to_mapping ((loc, span) : t) : Sourcemaps.Source_maps.mapping option = - let real_path (x : Types.file_name) = - match x with - | Real (LocalPath p) | Real (Remapped { local_path = Some p; _ }) -> - Some p - | _ -> None - in - let loc_to_loc ({ line; col } : loc) : Sourcemaps.Location.t = - { line; col } - in - let to_loc ({ col; line } : Types.loc) : loc = - { col = Int.of_string col; line = Int.of_string line - 1 } - in - let* span = - Span.to_thir span - |> List.find ~f:(fun (s : Types.span) -> - real_path s.filename |> Option.is_some) - in - let* src_filename = real_path span.filename in - let src_start = to_loc span.lo |> loc_to_loc in - let src_end = to_loc span.hi |> loc_to_loc in - let dst_start = loc_to_loc loc in - Some - Sourcemaps.Source_maps. - { - src = { start = src_start; end_ = Some src_end }; - gen = { start = dst_start; end_ = None }; - source = src_filename; - name = None; - } - end - - type annot_str = string * Annotation.t list [@@deriving show, yojson, eq] - - (** When printing a chunk of AST, should we wrap parenthesis -({!NeedsPar}) or not ({!AlreadyPar})? *) - type par_state = NeedsPar | AlreadyPar - - type 't fn = 't -> document -end - -open Types - -module Make - (F : Features.T) (SecretTypes : sig - type 't no_override - type 'location no_direct_call - end) = -struct - module AST = Ast.Make (F) - open Ast.Make (F) - open SecretTypes - - (** Raw generic printers base class. Those are useful for building a - printer, not for consuming printers. Consumers should use - the {!module:Api} functor. *) - class type virtual print_base_type = - object - - (** {1 Span handling} *) - - (** Every piece of string rendered is contextualized with span information automatically. *) - - method get_span_data : unit -> Annotation.t list - (** Retreive the mapping between locations in the rendered - string and Rust locations. *) - - method with_span : span:span -> (unit -> document) -> document - (** [with_span ~span f] runs `f` in the context of [span]. *) - - method spanned_doc : document -> custom - (** [spanned_doc doc] constructs a custom wrapping document for - [doc]. Rendering this document in [pretty] mode has a - side-effect: we push a [Annotation.t] to internal state. An - annotation maps a location within the rendered string to a Rust - span (that is, a location in the original Rust source code). *) - - (** {1 [*_at] methods} *) - - (** Always use [_at] methods rather than [] - ones. The former takes an [ast_position], that contextualizes - from where we are printing something. Printing the body of a - [let .. = ..;] expression (position [Expr_Let_body]) and - printing a function argument (position [Expr_App_arg]) will - probably require different parenthesizing: [ast_position] gives - contextual information upon which such parenthesizing decisions - can be taken. *) - - method expr_at : ast_position -> expr fn - (** Renders an [expr] at some [ast_position]. *) - - method ty_at : ast_position -> ty fn - (** Renders a [ty] at some [ast_position]. *) - - method pat_at : ast_position -> pat fn - (** Renders a [pat] at some [ast_position]. *) - - (** {1 Driver methods} *) - - (** The methods in this section are defined in two flavors: - `` and `_`. `` methods are not - overridable. Indeed, they take care of various things for - you: - - {ul {- catch exceptions and translate them as - pretty-printed errors with the original Rust AST;} - {- set contextual span information in a systematic way;} - {- disambiguate certain variant of the AST (see {!section-"specialized-printers"}).}} - - Your can override `_` methods. - *) - - (** {2 Expressions} *) - method expr : (par_state -> expr fn) no_override - (** Prints an expression. Pre-handles the variants [App] and - [Construct]: see {!section-"specialize-expr"}. *) - - method virtual expr_ : [ `Expr ] no_direct_call -> par_state -> expr fn - (** Overridable printer for expressions. Please mark the cases - [App] and [Construct] as unreachable. *) - - (** {2 Types} *) - method ty : (par_state -> ty fn) no_override - (** Prints a type. Pre-handles [TApp]. *) - - method virtual ty_ : [ `Ty ] no_direct_call -> par_state -> ty fn - (** Overridable printer for types. Please mark the case [TApp] - as unreachable. *) - - (** {2 Patterns} *) - method pat : (par_state -> pat fn) no_override - (** Prints a pattern. *) - - method virtual pat_ : [ `Pat ] no_direct_call -> par_state -> pat fn - (** Overridable printer for patterns. *) - - (** {2 Items} *) - method item : item fn no_override - (** Prints a item. *) - - method virtual item_ : [ `Item ] no_direct_call -> item fn - (** Overridable printer for items. *) - - (** {2 Arms} *) - method arm : arm fn no_override - (** Prints an arm (in a match). *) - - method virtual arm_ : [ `Arm ] no_direct_call -> arm fn - (** Overridable printer for arms (in matches).*) - - (** {2 Generic parameters} *) - method generic_param : generic_param fn no_override - (** Prints a generic parameter. *) - - method virtual generic_param_ : [ `GP ] no_direct_call -> generic_param fn - (** Overridable printer for generic parameters. *) - - (** {2 Parameters} *) - method param_ty : param fn no_override - (** Prints the type of a parameter. This is special because of `typ_span`. *) - - method virtual param_ty_ : [ `Param ] no_direct_call -> param fn - (** Overridable printer for parameter types. *) - - (** {2 Impl items} *) - method impl_item : impl_item fn no_override - (** Prints an impl item. *) - - method virtual impl_item_ : [ `II ] no_direct_call -> impl_item fn - (** Overridable printer for impl items. *) - - (** {2 Trait items} *) - method trait_item : trait_item fn no_override - (** Prints an trait item. *) - - method virtual trait_item_ : [ `TI ] no_direct_call -> trait_item fn - (** Overridable printer for trait items. *) - - (** {2 Attributes} *) - - method attr : attr fn no_override - (** Prints an attribute. *) - - method virtual attr_ : [ `Attr ] no_direct_call -> attr fn - (** Overridable printer for attributes. *) - - (** {2 Concrete idents} *) - - method concrete_ident : concrete_ident fn no_override - (** Prints a concrete ident. *) - - method virtual concrete_ident_ : - [ `CIdent ] no_direct_call -> under_current_ns:bool -> concrete_ident fn - (** Overridable printer for concrete idents. *) - - (** {1:specialized-printers Specialized printers} *) - - (** Some nodes in the AST are ambiguous as they encode multiple - language constructs: the `App` constructor of `expr` for - instance encodes (1) function applications, (2) fields - projectors, (3) constants... This is the same for `Construct`, - `TApp`, and some other. - - This section defines specialized methods for those language - constructs. When the variant `` of a type `` in - the AST is encoding various language constructs, we defined - various methods named `__`. *) - - (** {2:specialize-expr Specialized printers for [expr]} *) - - method virtual expr_App_constant : - full:expr -> concrete_ident -> generic_value list fn - (** [expr_App_constant ~full e generics] prints the constant - [e] with generics [generics]. [full] is the unspecialized [expr]. *) - - method virtual expr_App_application : - full:expr -> expr -> expr list -> generic_value list fn - (** [expr_App_application ~full e args generics] prints the - function application [e<...generics>(...args)]. [full] is the unspecialized [expr]. *) - - method virtual expr_App_tuple_projection : - full:expr -> size:int -> nth:int -> expr fn - (** [expr_App_tuple_projection ~full ~size ~nth expr] prints - the projection of the [nth] component of the tuple [expr] of - size [size]. [full] is the unspecialized [expr]. *) - - method virtual expr_App_field_projection : - full:expr -> concrete_ident -> expr fn - (** [expr_App_field_projection ~full field expr] prints the - projection of the field [field] in the expression [expr]. [full] - is the unspecialized [expr]. *) - - method virtual expr_Construct_inductive : - full:expr -> - is_record:bool -> - is_struct:bool -> - constructor:concrete_ident -> - base:(expr * F.construct_base) option -> - (global_ident * expr) list fn - (** [expr_Construct_inductive ~full ~is_record ~is_struct - ~constructor ~base fields] prints the construction of an - inductive with base [base] and fields [fields]. [full] is the - unspecialized [expr]. TODO doc is_record is_struct *) - - method virtual expr_Construct_tuple : full:expr -> expr list fn - - (** {2:specialize-expr Specialized printers for [ty]} *) - - method virtual ty_TApp_tuple : full:ty -> ty list fn - (** [ty_TApp_tuple ~full types] prints a tuple type with - compounds types [types]. [full] is the unspecialized [ty]. *) - - method virtual ty_TApp_application : - full:ty -> concrete_ident -> generic_value list fn - (** [ty_TApp_application ~full typ generic_args] prints the type - [typ<...generic_args>]. [full] is the unspecialized [ty]. *) - - method items : item list fn - - (** {1 Misc methods} *) - - (** {1 Convenience methods} *) - - method attrs : attrs fn - - method assertion_failure : 'any. string -> 'any - (** Helper that throws and reports an [Types.AssertionFailure] error. *) - - method set_current_namespace : (string * string list) option -> unit - method get_current_namespace : unit -> (string * string list) option - - method virtual namespace_of_concrete_ident : - concrete_ident -> string * string list - - method virtual printer_name : string - method virtual par_state : ast_position -> par_state - - method unreachable : 'any. unit -> 'any - (** Mark an unreachable place in the printer. *) - end -end diff --git a/engine/lib/generic_printer/generic_printer_template.generate.js b/engine/lib/generic_printer/generic_printer_template.generate.js new file mode 100755 index 000000000..2521256c0 --- /dev/null +++ b/engine/lib/generic_printer/generic_printer_template.generate.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node + +// This script regenerates `generic_printer_template.ml` + +const {readFileSync, writeFileSync} = require('fs'); +const {execSync} = require('child_process'); + +const GENERIC_PRINTER_DIR = `lib/generic_printer`; +const GENERIC_PRINTER = `${GENERIC_PRINTER_DIR}/generic_printer.ml`; +const TEMPLATE = `${GENERIC_PRINTER_DIR}/generic_printer_template.ml`; + +// Utility function to format an OCaml module +let fmt = path => execSync(`ocamlformat -i ${path}`); + +// Go to the root of the engine +require('process').chdir(`${execSync('git rev-parse --show-toplevel').toString().trim()}/engine`); + +// Prints the signature of module `Generic_printer` (using `ocaml-print-intf`) +let mli = execSync(`dune exec -- ocaml-print-intf ${GENERIC_PRINTER}`).toString(); + +// Parses all +let virtual_methods = [...mli.matchAll(/^( +)method (private )?virtual +(?.*) +:(?.*(\n \1.*)*)/gm)]; + +let output = []; +for(let v of virtual_methods) { + let {name, sig} = v.groups; + let out = sig.trim().split('->').slice(-1)[0].trim().split('.').slice(-1)[0]; + let args = sig.trim().split('->').map((s, i) => { + let chunks = s.trim().split(':').reverse(); + if(chunks.length > 2 || chunks.length == 0) { + throw "Chunks: bad length"; + } + let [type, name] = chunks; + name = name ? '~'+name+':_' : '_x'+(i + 1); + return {type, name}; + }).map(n => n.name).slice(0, -1).join(' '); + + output.push(`method ${name} ${args} = default_${out}_for "${name}"`); +} + +{ + let [before, _, after] = readFileSync(TEMPLATE).toString().split(/(?=\(\* (?:BEGIN|END) GENERATED \*\))/); + writeFileSync(TEMPLATE, before + '\n(* BEGIN GENERATED *)\n' + output.join('\n') + '\n' + after); +} + +fmt(TEMPLATE); diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 86582c455..be7ccb88b 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -1,64 +1,357 @@ -module Make (F : Features.T) = struct +open! Prelude +open! Ast +open! PPrint + +module Make + (F : Features.T) (Default : sig + val default : string -> string + end) = +struct module AST = Ast.Make (F) open Ast.Make (F) - module P = Generic_printer_base.Make (F) + module Base = Generic_printer.Make (F) open PPrint - let unimplemented s = string ("unimplemented: " ^ s) + let default_string_for s = "TODO: please implement the method `" ^ s ^ "`" + let default_document_for = default_string_for >> string - class print = + class printer = object - inherit P.base as _super - method ty_TApp_tuple ~full:_ _args = unimplemented "ty_TApp_tuple" + inherit Base.base - method ty_TApp_application ~full:_ _f _args = - unimplemented "ty_TApp_application" + (* BEGIN GENERATED *) + method arm ~arm:_ ~span:_ = default_document_for "arm" - method expr_App_constant ~full:_ _ident _generic_values = - unimplemented "expr_App_constant" + method arm' ~super:_ ~arm_pat:_ ~body:_ ~guard:_ = + default_document_for "arm'" - method expr_App_application ~full:_ _f _args _generics = - unimplemented "expr_App_application" + method attrs _x1 = default_document_for "attrs" - method expr_App_tuple_projection ~full:_ ~size:_ ~nth:_ _tuple = - unimplemented "expr_App_tuple_projection" + method binding_mode_ByRef _x1 _x2 = + default_document_for "binding_mode_ByRef" - method expr_App_field_projection ~full:_ _ident _data = - unimplemented "expr_App_field_projection" + method binding_mode_ByValue = default_document_for "binding_mode_ByValue" + method borrow_kind_Mut _x1 = default_document_for "borrow_kind_Mut" + method borrow_kind_Shared = default_document_for "borrow_kind_Shared" + method borrow_kind_Unique = default_document_for "borrow_kind_Unique" + method common_array _x1 = default_document_for "common_array" - method expr_Construct_inductive ~full:_ ~is_record:_ ~is_struct:_ - ~constructor:_ ~base:_ _fields = - unimplemented "expr_Construct_inductive" + method dyn_trait_goal ~trait:_ ~non_self_args:_ = + default_document_for "dyn_trait_goal" - method expr_Construct_tuple ~full:_ _components = - unimplemented "expr_Construct_tuple" + method error_expr _x1 = default_document_for "error_expr" + method error_item _x1 = default_document_for "error_item" + method error_pat _x1 = default_document_for "error_pat" + method expr ~e:_ ~span:_ ~typ:_ = default_document_for "expr" - method expr_ _ _ctx _expr = unimplemented "expr_" - method ty_ _ _ctx _typ = unimplemented "ty_" - method pat_ _ _ctx _pat = unimplemented "pat_" - method item_ _ _item = unimplemented "item_" - method arm_ _ _arm = unimplemented "arm_" - method generic_param_ _ _gp = unimplemented "generic_param_" - method param_ty_ _ _param_ty = unimplemented "param_ty_" - method impl_item_ _ _ii = unimplemented "impl_item_" - method trait_item_ _ _ti = unimplemented "trait_item_" - method attr_ _ _attr = unimplemented "attr_" + method expr'_AddressOf ~super:_ ~mut:_ ~e:_ ~witness:_ = + default_document_for "expr'_AddressOf" - method namespace_of_concrete_ident = - Concrete_ident.DefaultViewAPI.to_namespace + method expr'_App_application ~super:_ ~f:_ ~args:_ ~generics:_ = + default_document_for "expr'_App_application" - method printer_name = "blank-template" - method par_state _ = AlreadyPar + method expr'_App_constant ~super:_ ~constant:_ ~generics:_ = + default_document_for "expr'_App_constant" - method concrete_ident_ _ ~under_current_ns:_ _ident = - unimplemented "concrete_ident_" - end + method expr'_App_field_projection ~super:_ ~field:_ ~e:_ = + default_document_for "expr'_App_field_projection" + + method expr'_App_tuple_projection ~super:_ ~size:_ ~nth:_ ~e:_ = + default_document_for "expr'_App_tuple_projection" + + method expr'_Ascription ~super:_ ~e:_ ~typ:_ = + default_document_for "expr'_Ascription" + + method expr'_Assign ~super:_ ~lhs:_ ~e:_ ~witness:_ = + default_document_for "expr'_Assign" + + method expr'_Block ~super:_ ~e:_ ~safety_mode:_ ~witness:_ = + default_document_for "expr'_Block" + + method expr'_Borrow ~super:_ ~kind:_ ~e:_ ~witness:_ = + default_document_for "expr'_Borrow" + + method expr'_Break ~super:_ ~e:_ ~label:_ ~witness:_ = + default_document_for "expr'_Break" + + method expr'_Closure ~super:_ ~params:_ ~body:_ ~captures:_ = + default_document_for "expr'_Closure" + + method expr'_Construct_inductive ~super:_ ~constructor:_ ~is_record:_ + ~is_struct:_ ~fields:_ ~base:_ = + default_document_for "expr'_Construct_inductive" + + method expr'_Construct_tuple ~super:_ ~components:_ = + default_document_for "expr'_Construct_tuple" + + method expr'_Continue ~super:_ ~e:_ ~label:_ ~witness:_ = + default_document_for "expr'_Continue" + + method expr'_EffectAction ~super:_ ~action:_ ~argument:_ = + default_document_for "expr'_EffectAction" + + method expr'_GlobalVar ~super:_ _x2 = + default_document_for "expr'_GlobalVar" + + method expr'_If ~super:_ ~cond:_ ~then_:_ ~else_:_ = + default_document_for "expr'_If" + + method expr'_Let ~super:_ ~monadic:_ ~lhs:_ ~rhs:_ ~body:_ = + default_document_for "expr'_Let" + + method expr'_Literal ~super:_ _x2 = default_document_for "expr'_Literal" + method expr'_LocalVar ~super:_ _x2 = default_document_for "expr'_LocalVar" + + method expr'_Loop ~super:_ ~body:_ ~kind:_ ~state:_ ~label:_ ~witness:_ = + default_document_for "expr'_Loop" + + method expr'_MacroInvokation ~super:_ ~macro:_ ~args:_ ~witness:_ = + default_document_for "expr'_MacroInvokation" + + method expr'_Match ~super:_ ~scrutinee:_ ~arms:_ = + default_document_for "expr'_Match" + + method expr'_QuestionMark ~super:_ ~e:_ ~return_typ:_ ~witness:_ = + default_document_for "expr'_QuestionMark" + + method expr'_Quote ~super:_ _x2 = default_document_for "expr'_Quote" + + method expr'_Return ~super:_ ~e:_ ~witness:_ = + default_document_for "expr'_Return" + + method field_pat ~field:_ ~pat:_ = default_document_for "field_pat" + + method generic_constraint_GCLifetime _x1 _x2 = + default_document_for "generic_constraint_GCLifetime" + + method generic_constraint_GCProjection _x1 = + default_document_for "generic_constraint_GCProjection" + + method generic_constraint_GCType _x1 = + default_document_for "generic_constraint_GCType" + + method generic_param ~ident:_ ~span:_ ~attrs:_ ~kind:_ = + default_document_for "generic_param" + + method generic_param_kind_GPConst ~typ:_ = + default_document_for "generic_param_kind_GPConst" + + method generic_param_kind_GPLifetime ~witness:_ = + default_document_for "generic_param_kind_GPLifetime" + + method generic_param_kind_GPType ~default:_ = + default_document_for "generic_param_kind_GPType" + + method generic_value_GConst _x1 = + default_document_for "generic_value_GConst" + + method generic_value_GLifetime ~lt:_ ~witness:_ = + default_document_for "generic_value_GLifetime" + + method generic_value_GType _x1 = + default_document_for "generic_value_GType" + + method generics ~params:_ ~constraints:_ = default_document_for "generics" + method guard ~guard:_ ~span:_ = default_document_for "guard" + + method guard'_IfLet ~super:_ ~lhs:_ ~rhs:_ ~witness:_ = + default_document_for "guard'_IfLet" + + method impl_expr ~kind:_ ~goal:_ = default_document_for "impl_expr" + + method impl_expr_kind_Builtin _x1 = + default_document_for "impl_expr_kind_Builtin" + + method impl_expr_kind_Concrete _x1 = + default_document_for "impl_expr_kind_Concrete" + + method impl_expr_kind_Dyn = default_document_for "impl_expr_kind_Dyn" + + method impl_expr_kind_ImplApp ~impl:_ ~args:_ = + default_document_for "impl_expr_kind_ImplApp" + + method impl_expr_kind_LocalBound ~id:_ = + default_document_for "impl_expr_kind_LocalBound" + + method impl_expr_kind_Parent ~impl:_ ~ident:_ = + default_document_for "impl_expr_kind_Parent" + + method impl_expr_kind_Projection ~impl:_ ~item:_ ~ident:_ = + default_document_for "impl_expr_kind_Projection" + + method impl_expr_kind_Self = default_document_for "impl_expr_kind_Self" + method impl_ident ~goal:_ ~name:_ = default_document_for "impl_ident" + + method impl_item ~ii_span:_ ~ii_generics:_ ~ii_v:_ ~ii_ident:_ ~ii_attrs:_ + = + default_document_for "impl_item" + + method impl_item'_IIFn ~body:_ ~params:_ = + default_document_for "impl_item'_IIFn" + + method impl_item'_IIType ~typ:_ ~parent_bounds:_ = + default_document_for "impl_item'_IIType" + + method item ~v:_ ~span:_ ~ident:_ ~attrs:_ = default_document_for "item" - open Generic_printer_api.Make (F) + method item'_Alias ~super:_ ~name:_ ~item:_ = + default_document_for "item'_Alias" - include Api (struct - type aux_info = unit + method item'_Fn ~super:_ ~name:_ ~generics:_ ~body:_ ~params:_ ~safety:_ = + default_document_for "item'_Fn" - let new_print _ = (new print :> print_object) - end) + method item'_HaxError ~super:_ _x2 = default_document_for "item'_HaxError" + + method item'_IMacroInvokation ~super:_ ~macro:_ ~argument:_ ~span:_ + ~witness:_ = + default_document_for "item'_IMacroInvokation" + + method item'_Impl ~super:_ ~generics:_ ~self_ty:_ ~of_trait:_ ~items:_ + ~parent_bounds:_ ~safety:_ = + default_document_for "item'_Impl" + + method item'_NotImplementedYet = + default_document_for "item'_NotImplementedYet" + + method item'_Quote ~super:_ _x2 = default_document_for "item'_Quote" + + method item'_Trait ~super:_ ~name:_ ~generics:_ ~items:_ ~safety:_ = + default_document_for "item'_Trait" + + method item'_TyAlias ~super:_ ~name:_ ~generics:_ ~ty:_ = + default_document_for "item'_TyAlias" + + method item'_Type ~super:_ ~name:_ ~generics:_ ~variants:_ ~is_struct:_ = + default_document_for "item'_Type" + + method item'_Use ~super:_ ~path:_ ~is_external:_ ~rename:_ = + default_document_for "item'_Use" + + method lhs_LhsArbitraryExpr ~e:_ ~witness:_ = + default_document_for "lhs_LhsArbitraryExpr" + + method lhs_LhsArrayAccessor ~e:_ ~typ:_ ~index:_ ~witness:_ = + default_document_for "lhs_LhsArrayAccessor" + + method lhs_LhsFieldAccessor_field ~e:_ ~typ:_ ~field:_ ~witness:_ = + default_document_for "lhs_LhsFieldAccessor_field" + + method lhs_LhsFieldAccessor_tuple ~e:_ ~typ:_ ~nth:_ ~size:_ ~witness:_ = + default_document_for "lhs_LhsFieldAccessor_tuple" + + method lhs_LhsLocalVar ~var:_ ~typ:_ = + default_document_for "lhs_LhsLocalVar" + + method literal_Bool _x1 = default_document_for "literal_Bool" + method literal_Char _x1 = default_document_for "literal_Char" + + method literal_Float ~value:_ ~negative:_ ~kind:_ = + default_document_for "literal_Float" + + method literal_Int ~value:_ ~negative:_ ~kind:_ = + default_document_for "literal_Int" + + method literal_String _x1 = default_document_for "literal_String" + + method loop_kind_ForIndexLoop ~start:_ ~end_:_ ~var:_ ~var_typ:_ + ~witness:_ = + default_document_for "loop_kind_ForIndexLoop" + + method loop_kind_ForLoop ~pat:_ ~it:_ ~witness:_ = + default_document_for "loop_kind_ForLoop" + + method loop_kind_UnconditionalLoop = + default_document_for "loop_kind_UnconditionalLoop" + + method loop_kind_WhileLoop ~condition:_ ~witness:_ = + default_document_for "loop_kind_WhileLoop" + + method loop_state ~init:_ ~bpat:_ ~witness:_ = + default_document_for "loop_state" + + method modul _x1 = default_document_for "modul" + + method param ~pat:_ ~typ:_ ~typ_span:_ ~attrs:_ = + default_document_for "param" + + method pat ~p:_ ~span:_ ~typ:_ = default_document_for "pat" + + method pat'_PAscription ~super:_ ~typ:_ ~typ_span:_ ~pat:_ = + default_document_for "pat'_PAscription" + + method pat'_PBinding ~super:_ ~mut:_ ~mode:_ ~var:_ ~typ:_ ~subpat:_ = + default_document_for "pat'_PBinding" + + method pat'_PConstant ~super:_ ~lit:_ = + default_document_for "pat'_PConstant" + + method pat'_PConstruct_inductive ~super:_ ~constructor:_ ~is_record:_ + ~is_struct:_ ~fields:_ = + default_document_for "pat'_PConstruct_inductive" + + method pat'_PConstruct_tuple ~super:_ ~components:_ = + default_document_for "pat'_PConstruct_tuple" + + method pat'_PDeref ~super:_ ~subpat:_ ~witness:_ = + default_document_for "pat'_PDeref" + + method pat'_PWild = default_document_for "pat'_PWild" + method printer_name = default_string_for "printer_name" + + method projection_predicate ~impl:_ ~assoc_item:_ ~typ:_ = + default_document_for "projection_predicate" + + method safety_kind_Safe = default_document_for "safety_kind_Safe" + method safety_kind_Unsafe _x1 = default_document_for "safety_kind_Unsafe" + + method supported_monads_MException _x1 = + default_document_for "supported_monads_MException" + + method supported_monads_MOption = + default_document_for "supported_monads_MOption" + + method supported_monads_MResult _x1 = + default_document_for "supported_monads_MResult" + + method trait_goal ~trait:_ ~args:_ = default_document_for "trait_goal" + + method trait_item ~ti_span:_ ~ti_generics:_ ~ti_v:_ ~ti_ident:_ + ~ti_attrs:_ = + default_document_for "trait_item" + + method trait_item'_TIDefault ~params:_ ~body:_ ~witness:_ = + default_document_for "trait_item'_TIDefault" + + method trait_item'_TIFn _x1 = default_document_for "trait_item'_TIFn" + method trait_item'_TIType _x1 = default_document_for "trait_item'_TIType" + + method ty_TApp_application ~typ:_ ~generics:_ = + default_document_for "ty_TApp_application" + + method ty_TApp_tuple ~types:_ = default_document_for "ty_TApp_tuple" + method ty_TArray ~typ:_ ~length:_ = default_document_for "ty_TArray" + method ty_TArrow _x1 _x2 = default_document_for "ty_TArrow" + + method ty_TAssociatedType ~impl:_ ~item:_ = + default_document_for "ty_TAssociatedType" + + method ty_TBool = default_document_for "ty_TBool" + method ty_TChar = default_document_for "ty_TChar" + method ty_TDyn ~witness:_ ~goals:_ = default_document_for "ty_TDyn" + method ty_TFloat _x1 = default_document_for "ty_TFloat" + method ty_TInt _x1 = default_document_for "ty_TInt" + method ty_TOpaque _x1 = default_document_for "ty_TOpaque" + method ty_TParam _x1 = default_document_for "ty_TParam" + method ty_TRawPointer ~witness:_ = default_document_for "ty_TRawPointer" + + method ty_TRef ~witness:_ ~region:_ ~typ:_ ~mut:_ = + default_document_for "ty_TRef" + + method ty_TSlice ~witness:_ ~ty:_ = default_document_for "ty_TSlice" + method ty_TStr = default_document_for "ty_TStr" + + method variant ~name:_ ~arguments:_ ~is_record:_ ~attrs:_ = + default_document_for "variant" + (* END GENERATED *) + end end diff --git a/engine/lib/generic_printer/generic_rust_printer.ml b/engine/lib/generic_printer/generic_rust_printer.ml deleted file mode 100644 index 8ff0804bb..000000000 --- a/engine/lib/generic_printer/generic_rust_printer.ml +++ /dev/null @@ -1,169 +0,0 @@ -open Prelude - -module Make (F : Features.T) = struct - module AST = Ast.Make (F) - open Ast.Make (F) - open Generic_printer_base - module P = Generic_printer_base.Make (F) - open PPrint - - let unimplemented s = string ("unimplemented: " ^ s) - - module View = Concrete_ident.DefaultViewAPI - - let iblock f = group >> jump 2 0 >> terminate (break 0) >> f >> group - let call = ( !: ) - - class print = - object (print) - inherit P.base as _super - method ty_TApp_tuple ~full:_ _args = unimplemented "ty_TApp_tuple" - - method ty_TApp_application ~full:_ _f _args = - unimplemented "ty_TApp_application" - - method expr_App_constant ~full:_ _ident _generic_values = - unimplemented "expr_App_constant" - - method expr_App_application ~full:_ f _args _generics = - print#expr_at Expr_App_f f - (* print#expr_at Expr_App_f f ^/^ separate_map space (print#expr_at Expr_App_arg) args *) - (* unimplemented "expr_App_application" *) - - method expr_App_tuple_projection ~full:_ ~size:_ ~nth:_ _tuple = - unimplemented "expr_App_tuple_projection" - - method expr_App_field_projection ~full:_ _ident _data = - unimplemented "expr_App_field_projection" - - method expr_Construct_inductive ~full:_ ~is_record:_ ~is_struct:_ - ~constructor:_ ~base:_ _fields = - unimplemented "expr_Construct_inductive" - - method expr_Construct_tuple ~full:_ _components = - unimplemented "expr_Construct_tuple" - - method expr_ _ ctx expr = - let wrap_parens = - group - >> match ctx with AlreadyPar -> Fn.id | NeedsPar -> iblock braces - in - match expr.e with - | If { cond; then_; else_ } -> - let if_then = - (string "if" ^//^ nest 2 (print#expr_at Expr_If_cond cond)) - ^/^ string "then" - ^//^ (print#expr_at Expr_If_then then_ |> braces |> nest 1) - in - (match else_ with - | None -> if_then - | Some else_ -> - if_then ^^ break 1 ^^ string "else" ^^ space - ^^ (print#expr_at Expr_If_else else_ |> iblock braces)) - |> wrap_parens - | Match { scrutinee; arms } -> - let header = - string "match" ^^ space - ^^ (print#expr_at Expr_Match_scrutinee scrutinee - |> terminate space |> iblock Fn.id) - |> group - in - let arms = - separate_map hardline - (call print#arm >> group >> nest 2 - >> precede (bar ^^ space) - >> group) - arms - in - header ^^ iblock braces arms - | Let { monadic; lhs; rhs; body } -> - (Option.map ~f:(fun monad -> print#expr_monadic_let ~monad) monadic - |> Option.value ~default:print#expr_let) - ~lhs ~rhs body - |> wrap_parens - | Literal l -> print#literal l - | Block { e; _ } -> call print#expr ctx e - | _ -> unimplemented "expr_todo" - - method expr_monadic_let - : monad:supported_monads * F.monadic_binding -> - lhs:pat -> - rhs:expr -> - expr fn = - fun ~monad:_ ~lhs ~rhs body -> print#expr_let ~lhs ~rhs body - - method expr_let : lhs:pat -> rhs:expr -> expr fn = - fun ~lhs ~rhs body -> - string "let" - ^/^ iblock Fn.id (print#pat_at Expr_Let_lhs lhs) - ^/^ equals - ^/^ iblock Fn.id (print#expr_at Expr_Let_rhs rhs) - ^^ semi - ^/^ (print#expr_at Expr_Let_body body |> group) - - method literal = - function - | String s -> utf8string s |> dquotes - | Char c -> char c |> bquotes - | Int { value; negative; _ } -> - string value |> precede (if negative then minus else empty) - | Float { value; kind; negative } -> - string value - |> precede (if negative then minus else empty) - |> terminate (string (Ast.show_float_kind kind)) - | Bool b -> OCaml.bool b - - method ty_ _ _ctx _typ = unimplemented "ty_" - method pat_ _ _ctx _pat = unimplemented "pat_" - - method item_ _ item = - match item.v with - | Fn { name; generics; body; params; _ } -> - let params = - iblock parens (separate_map (comma ^^ break 1) print#param params) - in - let generics = - separate_map comma (call print#generic_param) generics.params - in - string "fn" ^^ space - ^^ call print#concrete_ident name - ^^ generics ^^ params - ^^ iblock braces (print#expr_at Item_Fn_body body) - | _ -> string "item not implemented" - - method param_ty_ _ _param_ty = unimplemented "param_ty_" - - method param (param : param) = - let { pat; typ = _; typ_span = _; attrs } = param in - print#attrs attrs ^^ print#pat_at Param_pat pat ^^ space ^^ colon - ^^ space ^^ !:(print#param_ty) param - - method arm_ _ _arm = unimplemented "arm_" - method generic_param_ _ _gp = unimplemented "generic_param_" - method impl_item_ _ _ii = unimplemented "impl_item_" - method trait_item_ _ _ti = unimplemented "trait_item_" - method attr_ _ _attr = unimplemented "attr_" - - method namespace_of_concrete_ident = - Concrete_ident.DefaultViewAPI.to_namespace - - method printer_name = "blank-template" - method par_state _ = AlreadyPar - - method concrete_ident_ _ ~under_current_ns id = - let id = View.to_view id in - let chunks = - if under_current_ns then [ id.definition ] - else id.crate :: (id.path @ [ id.definition ]) - in - separate_map (colon ^^ colon) utf8string chunks - end - - open Generic_printer_api.Make (F) - - include Api (struct - type aux_info = unit - - let new_print _ = (new print :> print_object) - end) -end diff --git a/engine/lib/generic_printer/generic_rust_printer.mli b/engine/lib/generic_printer/generic_rust_printer.mli deleted file mode 100644 index 6a277bb7f..000000000 --- a/engine/lib/generic_printer/generic_rust_printer.mli +++ /dev/null @@ -1,4 +0,0 @@ -module Make (F : Features.T) : sig - open Generic_printer_api.Make(F) - include API with type aux_info = unit -end diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 9792ffaa6..1f437f17f 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -707,37 +707,37 @@ module Traditional : T = struct |> Stdlib.String.trim end -module Experimental : T = struct - module GenericRustPrinter = Generic_rust_printer.Make (Features.Full) +(* module Experimental : T = struct *) +(* module GenericRustPrinter = Generic_rust_printer.Make (Features.Full) *) - let pitem : item -> AnnotatedString.Output.t = - GenericRustPrinter.item () - >> Generic_printer_api.AnnotatedString.to_spanned_strings - >> AnnotatedString.Output.convert +(* let pitem : item -> AnnotatedString.Output.t = *) +(* GenericRustPrinter.item () *) +(* >> Generic_printer_api.AnnotatedString.to_spanned_strings *) +(* >> AnnotatedString.Output.convert *) - let pitems : item list -> AnnotatedString.Output.t = - GenericRustPrinter.items () - >> Generic_printer_api.AnnotatedString.to_spanned_strings - >> AnnotatedString.Output.convert +(* let pitems : item list -> AnnotatedString.Output.t = *) +(* GenericRustPrinter.items () *) +(* >> Generic_printer_api.AnnotatedString.to_spanned_strings *) +(* >> AnnotatedString.Output.convert *) - let pexpr : expr -> AnnotatedString.Output.t = - GenericRustPrinter.expr () - >> Generic_printer_api.AnnotatedString.to_spanned_strings - >> AnnotatedString.Output.convert +(* let pexpr : expr -> AnnotatedString.Output.t = *) +(* GenericRustPrinter.expr () *) +(* >> Generic_printer_api.AnnotatedString.to_spanned_strings *) +(* >> AnnotatedString.Output.convert *) - let pitem_str : item -> string = - GenericRustPrinter.item () >> Generic_printer_api.AnnotatedString.to_string +(* let pitem_str : item -> string = *) +(* GenericRustPrinter.item () >> Generic_printer_api.AnnotatedString.to_string *) - let pexpr_str : expr -> string = - GenericRustPrinter.expr () >> Generic_printer_api.AnnotatedString.to_string +(* let pexpr_str : expr -> string = *) +(* GenericRustPrinter.expr () >> Generic_printer_api.AnnotatedString.to_string *) - let pty_str : ty -> string = - GenericRustPrinter.ty () >> Generic_printer_api.AnnotatedString.to_string -end +(* let pty_str : ty -> string = *) +(* GenericRustPrinter.ty () >> Generic_printer_api.AnnotatedString.to_string *) +(* end *) let experimental = Sys.getenv "HAX_ENGINE_EXPERIMENTAL_RUST_PRINTER" |> Option.is_some include - (val if experimental then (module Experimental : T) + (val if experimental then failwith "todo" (*module Experimental : T*) else (module Traditional : T)) diff --git a/engine/utils/generate_visitors/codegen_printer.ml b/engine/utils/generate_visitors/codegen_printer.ml new file mode 100644 index 000000000..75b692d56 --- /dev/null +++ b/engine/utils/generate_visitors/codegen_printer.ml @@ -0,0 +1,402 @@ +open Base +open Utils +open Types + +type state = { names_with_doc : string list } + +let ( let* ) x f = Option.bind ~f x +let super_types_list = [ "expr"; "pat"; "guard"; "arm"; "item" ] + +let get_super_type ty = + List.find ~f:(fun s -> String.equal (s ^ "'") ty) super_types_list + +let get_child_type ty = + if List.mem ~equal:String.equal super_types_list ty then Some (ty ^ "'") + else None + +let do_not_override_prefix = "_do_not_override_" + +let is_hidden_method = + let list = + [ + "expr'_App"; + "expr'_Construct"; + "ty_TApp"; + "lhs_LhsFieldAccessor"; + "local_ident"; + "pat'_PConstruct"; + ] + in + List.mem ~equal:[%eq: string] list + +let rec of_ty (state : state) (call_method : string -> ty:string -> string) + (t : Type.t) : ((unit -> string) -> string -> string) option = + let* args = + List.fold t.args ~init:(Some []) ~f:(fun acc x -> + let* acc = acc in + let* x = of_ty state call_method x in + Some (x :: acc)) + |> Option.map ~f:List.rev + in + match (t.typ, args) with + | "option", [ inner ] -> + Some + (fun pos value -> + "(match " ^ value ^ " with | None -> None | Some value -> Some (" + ^ inner pos "value" ^ "))") + | "list", [ inner ] -> + Some + (fun pos value -> + "(List.map ~f:(fun x -> " ^ inner pos "x" ^ ") " ^ value ^ ")") + | "prim___tuple_2", [ fst; snd ] -> + Some + (fun pos value -> + let base = + "(" + ^ fst pos ("(fst " ^ value ^ ")") + ^ "," + ^ snd pos ("(snd " ^ value ^ ")") + ^ ")" + in + let mk proj = + "(let x = " ^ base ^ "in lazy_doc (fun tuple -> (" ^ proj + ^ " tuple)#p) " ^ pos () ^ " x)" + in + match List.map ~f:(is_lazy_doc_typ state) t.args with + | [ false; true ] -> mk "snd" + | [ true; false ] -> mk "fst" + | _ -> base) + (* if String.is_prefix ~prefix:"F." (List.nth t.args 1 |> Option.value ~default:"") then "(let x = " ^ base ^ "in lazy_doc x)" else base) *) + | "prim___tuple_3", [ fst; snd; thd ] -> + Some + (fun pos value -> + "(let (value1, value2, value3) = " ^ value ^ " in (" + ^ fst pos "value1" ^ "," ^ snd pos "value2" ^ "," ^ thd pos "value3" + ^ "))") + | _ when List.mem ~equal:[%eq: string] state.names_with_doc t.typ -> + Some + (fun pos value -> + "(print#" ^ do_not_override_prefix ^ "lazy_of_" ^ t.typ + ^ (if Option.is_some (get_super_type t.typ) then " ~super" else "") + ^ " " ^ pos () ^ " " ^ value ^ ")") + | _ -> Some (fun pos value -> "(" ^ value ^ ")") + +and string_ty_of_ty (state : state) (t : Type.t) = + if String.is_prefix t.typ ~prefix:"prim___tuple_" then + let args = List.map t.args ~f:(string_ty_of_ty state) in + let n = List.count args ~f:(String.is_suffix ~suffix:"lazy_doc)") in + let base = + "(" + ^ String.concat ~sep:" * " (List.map t.args ~f:(string_ty_of_ty state)) + ^ ")" + in + if [%eq: int] n 1 then "(" ^ base ^ " lazy_doc)" else base + else + "(" + ^ (if List.is_empty t.args then "" + else + "(" + ^ String.concat ~sep:", " (List.map t.args ~f:(string_ty_of_ty state)) + ^ ") ") + ^ t.typ + ^ (if List.mem ~equal:[%eq: string] state.names_with_doc t.typ then + " lazy_doc" + else "") + ^ ")" + +and is_lazy_doc_typ (state : state) = string_ty_of_ty state >> is_lazy_doc_typ' +and is_lazy_doc_typ' = String.is_suffix ~suffix:"lazy_doc)" + +let meth_name' typ_name variant_name = + typ_name ^ if String.is_empty variant_name then "" else "_" ^ variant_name + +let meth_name typ_name variant_name = + let meth = meth_name' typ_name variant_name in + (if is_hidden_method meth then do_not_override_prefix else "") ^ meth + +let print_variant state (call_method : string -> ty:string -> string) + (register_position : string option -> string) (super_type : string option) + (register_signature : string -> unit) (t_name : string) (v : Variant.t) : + string = + let meth_name = meth_name t_name v.name in + let meth = "print#" ^ meth_name in + let mk named fields = + let head = + v.name + ^ (if named then " { " else " ( ") + ^ String.concat ~sep:(if named then ";" else ",") (List.map ~f:fst fields) + ^ (if named then " } " else ")") + ^ " -> " + in + let args = + List.map + ~f:(fun (field_name, ty) -> + let value = + match of_ty state call_method ty with + | Some f -> + let pos = register_position (Some field_name) in + f (fun _ -> pos) field_name + | None -> field_name + in + let name = "~" ^ field_name ^ ":" in + (if named then name else "") ^ "(" ^ value ^ ")") + fields + in + let call = + String.concat ~sep:" " + (meth + :: ((if Option.is_some super_type then [ "~super" ] else []) @ args)) + in + let signature = + let ty = + List.map + ~f:(fun (name, ty) -> + let name = if named then name ^ ":" else "" in + name ^ string_ty_of_ty state ty) + fields + |> String.concat ~sep:" -> " + in + let super = + match super_type with + | Some super_type -> " super:(" ^ super_type ^ ") -> " + | None -> "" + in + register_signature + ("method virtual " ^ meth_name ^ " : " ^ super ^ ty ^ " -> document") + in + head ^ call + in + "\n | " + ^ + match v.payload with + | Record fields -> mk true fields + | None -> v.name ^ " -> " ^ meth + | Tuple types -> + mk false (List.mapi ~f:(fun i ty -> ("x" ^ Int.to_string i, ty)) types) + +let catch_errors_for = [ "expr"; "item"; "pat" ] + +let print_datatype state (dt : Datatype.t) + (register_entrypoint : string -> unit) + (register_position : string -> string -> string option -> string) = + let super_type = get_super_type dt.name in + let sigs = ref [] in + let method_name = do_not_override_prefix ^ "lazy_of_" ^ dt.name in + let print_variants variants wrapper = + let head = + "(**/**) method " ^ method_name + ^ (match super_type with Some t -> " ~(super: " ^ t ^ ")" | _ -> "") + ^ " ast_position (value: " ^ dt.name ^ "): " ^ dt.name ^ " lazy_doc =" + in + let body = + (if Option.is_some (get_child_type dt.name) then + "\n let super = value in" + else "") + ^ "\n match value with" + ^ String.concat ~sep:"" + (List.map + ~f:(fun variant -> + print_variant state + (fun name ~ty:_ -> name) + (register_position dt.name variant.Variant.name) + super_type + (fun s -> sigs := s :: !sigs) + dt.name variant) + variants) + in + let body = + "(print#wrap_" ^ dt.name ^ " ast_position value (" ^ body ^ "))" + in + let body = wrapper body in + sigs := + ("method wrap_" ^ dt.name ^ " _pos (_value: " ^ dt.name + ^ ") (doc: document): document = doc") + :: !sigs; + head ^ "lazy_doc (fun (value: " ^ dt.name ^ ") -> " ^ body + ^ ") ast_position value" ^ "(**/**)" + in + let main = + match dt.kind with + | Variant variants -> print_variants variants Fn.id + | Record record -> + let wrapper = + if List.exists ~f:(fst >> [%eq: string] "span") record then + fun body -> + "print#with_span ~span:value.span (fun _ -> " ^ body ^ ")" + else Fn.id + in + let wrapper = + if List.mem ~equal:[%eq: string] catch_errors_for dt.name then + fun body -> + "print#catch_exn print#error_" ^ dt.name ^ " (fun () -> " + ^ wrapper body ^ ")" + else wrapper + in + print_variants [ { name = ""; payload = Record record } ] wrapper + | TypeSynonym ty -> + print_variants [ { name = ""; payload = Tuple [ ty ] } ] (fun x -> x) + | _ -> "(* Not translating " ^ dt.name ^ " *)" + in + let print = + let name = "print_" ^ dt.name in + let ty = "ast_position -> " ^ dt.name ^ " -> " in + let body = + "fun ast_position x -> (print#" ^ method_name ^ " ast_position x)#p" + in + if Option.is_none super_type then + "method " ^ name ^ ": " ^ ty ^ " document = " ^ body + else "" + in + let entrypoint = + let name = "entrypoint_" ^ dt.name in + let ty = dt.name ^ " -> " in + let body = "print#print_" ^ dt.name ^ " AstPos_Entrypoint" in + if Option.is_none super_type then ( + register_entrypoint (name ^ " : " ^ ty ^ " 'a"); + "method " ^ name ^ ": " ^ ty ^ " document = " ^ body) + else "" + in + String.concat ~sep:"\n\n" (main :: print :: entrypoint :: !sigs) + +let hardcoded = + {| +module LazyDoc = struct + type 'a lazy_doc = + < compact : output -> unit + ; pretty : output -> state -> int -> bool -> unit + ; requirement : int + ; p : document + ; v : 'a + ; ast_position : ast_position > + let lazy_doc : 'a. ('a -> document) -> ast_position -> 'a -> 'a lazy_doc = + fun to_document pos value -> + let lazy_doc = ref None in + let doc () = + match !lazy_doc with + | None -> + let doc = to_document value in + lazy_doc := Some doc; + doc + | Some doc -> doc + in + object (self) + method requirement : requirement = requirement (doc ()) + method pretty : output -> state -> int -> bool -> unit = + fun o s i b -> pretty o s i b (doc ()) + method compact : output -> unit = fun o -> compact o (doc ()) + method p = custom (self :> custom) + method v = value + method ast_position = pos + end +end +open LazyDoc +|} + +let class_prelude = + {| + method virtual with_span: span:span -> (unit -> document) -> document + method virtual catch_exn : (string -> document) -> (unit -> document) -> document + + method virtual _do_not_override_lazy_of_local_ident: _ + method virtual _do_not_override_lazy_of_concrete_ident: _ +|} + +let mk datatypes = + let datatypes = + List.filter + ~f:(fun dt -> not ([%eq: string] dt.Datatype.name "mutability")) + datatypes + in + let state = + let names_with_doc = List.map ~f:(fun dt -> dt.name) datatypes in + let names_with_doc = + "quote" :: "concrete_ident" :: "local_ident" :: names_with_doc + in + { names_with_doc } + in + let positions = ref [ "AstPos_Entrypoint"; "AstPos_NotApplicable" ] in + let entrypoint_types = ref [] in + let class_body = + List.map + ~f:(fun dt -> + print_datatype state dt + (fun x -> entrypoint_types := x :: !entrypoint_types) + (fun ty variant field -> + let pos = + "AstPos_" ^ ty ^ "_" ^ variant + ^ match field with Some field -> "_" ^ field | _ -> "" + in + positions := pos :: !positions; + pos)) + datatypes + |> String.concat ~sep:"\n\n" + in + let object_poly = String.concat ~sep:";\n " !entrypoint_types in + let object_span_data_map = + String.concat ~sep:"\n" + (List.map + ~f:(fun s -> + let n = fst (String.lsplit2_exn ~on:':' s) in + "method " ^ n ^ " = obj#" ^ n) + !entrypoint_types) + in + let object_map = + String.concat ~sep:"\n" + (List.map + ~f:(fun s -> + let n = fst (String.lsplit2_exn ~on:':' s) in + "method " ^ n ^ " x = f (fun obj -> obj#" ^ n ^ " x)") + !entrypoint_types) + in + Printf.sprintf + {| +open! Prelude +open! Ast +open PPrint +type ast_position = %s | AstPosition_Quote + +%s + +module Make (F : Features.T) = struct + module AST = Ast.Make (F) + open Ast.Make (F) + + (* module DoNotOverride: sig + type 'a t + val __force (type a) (f: a t): a + end = struct + (** Marks a method that should not be overriden by a printer. *) + type 'a t = 'a + let __force (f: 'a) = 'a + end *) + + class virtual base = object (print) + %s + end + + type ('get_span_data, 'a) object_type = < + get_span_data : 'get_span_data; + %s + > + + let map (type get_span_data) (type a) (type b) + (f: ((get_span_data, a) object_type -> a) -> b) + : (unit, b) object_type = object + method get_span_data: unit = () + %s + end + + let map_get_span_data (type a) (type b) (type t) + (obj: (a, t) object_type) + (get_span_data: b) + : (b, t) object_type = object + method get_span_data: b = get_span_data + %s + end +end +|} + (String.concat ~sep:" | " + (List.dedup_and_sort ~compare:String.compare !positions)) + hardcoded + (class_prelude ^ class_body) + object_poly object_map object_span_data_map diff --git a/engine/utils/generate_visitors/generate_visitors.ml b/engine/utils/generate_visitors/generate_visitors.ml index 21f303d9e..4ec018807 100644 --- a/engine/utils/generate_visitors/generate_visitors.ml +++ b/engine/utils/generate_visitors/generate_visitors.ml @@ -27,4 +27,11 @@ let _main = | Result.Ok v -> Some Datatype.{ v with name = path } | _ -> None) in - datatypes |> Codegen_visitor.mk |> Stdio.print_endline + + datatypes + |> (match Sys.argv.(1) with + | "visitors" -> Codegen_visitor.mk + | "printer" -> Codegen_printer.mk + | "json" -> [%yojson_of: Datatype.t list] >> Yojson.Safe.pretty_to_string + | verb -> failwith ("Unknown action `" ^ verb ^ "`")) + |> Stdio.print_endline diff --git a/engine/utils/sourcemaps/mappings/instruction.ml b/engine/utils/sourcemaps/mappings/instruction.ml index 922e1593a..966e4cba3 100644 --- a/engine/utils/sourcemaps/mappings/instruction.ml +++ b/engine/utils/sourcemaps/mappings/instruction.ml @@ -49,11 +49,11 @@ let rec decode' (s : string) : t option list = |> Option.value ~default:(String.length s) in (if n > 0 then Some (decode_one (String.prefix s n)) - else - match String.get s 0 with - | ';' -> Some (ShiftGenLinesResetGenCols { lines = 1 }) - | ',' -> None - | _ -> failwith "should not be possible") + else + match String.get s 0 with + | ';' -> Some (ShiftGenLinesResetGenCols { lines = 1 }) + | ',' -> None + | _ -> failwith "should not be possible") :: decode' (String.drop_prefix s (Int.max 1 n)) let decode : string -> t list = decode' >> List.filter_map ~f:Fn.id @@ -83,7 +83,7 @@ let from_points : point list -> t list = let shift_gen_col = (if Int.(d.gen.line = 0) then d else x).gen.col in let output = (if Int.(d.gen.line = 0) then [] - else [ ShiftGenLinesResetGenCols { lines = d.gen.line } ]) + else [ ShiftGenLinesResetGenCols { lines = d.gen.line } ]) @ match m with | Some meta -> [ Full { shift_gen_col; shift_src = d.src; meta } ] From bf6a12b5e9b06fb6987b3e42855dc5a51463476e Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Sun, 6 Oct 2024 07:55:08 +0200 Subject: [PATCH 009/253] refactor(engine): rename `pat'.PConstruct` fields similarly to `expr'.Construct` This commits makes the node for constructors on patterns and expressions use the same names. --- engine/backends/coq/coq/coq_backend.ml | 16 +++--- .../backends/coq/ssprove/ssprove_backend.ml | 54 ++++++++++--------- engine/backends/fstar/fstar_backend.ml | 19 ++++--- engine/backends/proverif/proverif_backend.ml | 30 ++++++----- engine/lib/ast.ml | 4 +- engine/lib/ast_utils.ml | 8 +-- .../deprecated_generic_printer_base.ml | 8 +-- engine/lib/import_thir.ml | 12 ++--- engine/lib/phases/phase_drop_match_guards.ml | 6 +-- .../phase_hoist_disjunctive_patterns.ml | 16 +++--- .../lib/phases/phase_reconstruct_for_loops.ml | 8 +-- .../phase_reconstruct_question_marks.ml | 6 +-- .../phases/phase_simplify_question_marks.ml | 10 ++-- .../phases/phase_transform_hax_lib_inline.ml | 2 +- engine/lib/print_rust.ml | 10 ++-- engine/lib/subtype.ml | 6 +-- 16 files changed, 114 insertions(+), 101 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 1f46b05fd..11f29348f 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -215,16 +215,16 @@ struct C.AST.Ident var.name | POr { subpats } -> C.AST.DisjunctivePat (List.map ~f:ppat subpats) | PArray _ -> __TODO_pat__ p.span "Parray?" - | PConstruct { name = `TupleCons 0; args = []; _ } -> C.AST.UnitPat - | PConstruct { name = `TupleCons 1; args = [ _ ]; _ } -> + | PConstruct { constructor = `TupleCons 0; fields = []; _ } -> C.AST.UnitPat + | PConstruct { constructor = `TupleCons 1; fields = [ _ ]; _ } -> __TODO_pat__ p.span "tuple 1" - | PConstruct { name = `TupleCons _n; args; _ } -> - C.AST.TuplePat (List.map ~f:(fun { pat; _ } -> ppat pat) args) - | PConstruct { name; args; is_record = true; _ } -> - C.AST.RecordPat (pglobal_ident name, pfield_pats args) - | PConstruct { name; args; is_record = false; _ } -> + | PConstruct { constructor = `TupleCons _n; fields; _ } -> + C.AST.TuplePat (List.map ~f:(fun { pat; _ } -> ppat pat) fields) + | PConstruct { constructor; fields; is_record = true; _ } -> + C.AST.RecordPat (pglobal_ident constructor, pfield_pats fields) + | PConstruct { constructor; fields; is_record = false; _ } -> C.AST.ConstructorPat - (pglobal_ident name, List.map ~f:(fun p -> ppat p.pat) args) + (pglobal_ident constructor, List.map ~f:(fun p -> ppat p.pat) fields) | PConstant { lit } -> C.AST.Lit (pliteral p.span lit) | _ -> . diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index 8c37530ba..fbcb594eb 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -792,25 +792,26 @@ struct SSP.AST.Ident (plocal_ident var) (* TODO Mutable binding ! *) | POr { subpats } -> SSP.AST.DisjunctivePat (List.map ~f:ppat subpats) | PArray _ -> __TODO_pat__ p.span "Parray?" - | PConstruct { name = `TupleCons 0; args = []; _ } -> + | PConstruct { constructor = `TupleCons 0; fields = []; _ } -> SSP.AST.WildPat (* UnitPat *) - | PConstruct { name = `TupleCons 1; args = [ _ ]; _ } -> + | PConstruct { constructor = `TupleCons 1; fields = [ _ ]; _ } -> __TODO_pat__ p.span "tuple 1" - | PConstruct { name = `TupleCons _n; args; _ } -> - SSP.AST.TuplePat (List.map ~f:(fun { pat; _ } -> ppat pat) args) + | PConstruct { constructor = `TupleCons _n; fields; _ } -> + SSP.AST.TuplePat (List.map ~f:(fun { pat; _ } -> ppat pat) fields) (* Record *) | PConstruct { is_record = true; _ } -> __TODO_pat__ p.span "record pattern" - (* (\* SSP.AST.Ident (pglobal_ident name) *\) *) - (* SSP.AST.RecordPat (pglobal_ident name, List.map ~f:(fun {field; pat} -> (pglobal_ident field, ppat pat)) args) *) - (* (\* SSP.AST.ConstructorPat (pglobal_ident name ^ "_case", [SSP.AST.Ident "temp"]) *\) *) - (* (\* List.map ~f:(fun {field; pat} -> (pat, SSP.AST.App (SSP.AST.Var (pglobal_ident field), [SSP.AST.Var "temp"]))) args *\) *) + (* (\* SSP.AST.Ident (pglobal_ident constructor) *\) *) + (* SSP.AST.RecordPat (pglobal_ident constructor, List.map ~f:(fun {field; pat} -> (pglobal_ident field, ppat pat)) fields) *) + (* (\* SSP.AST.ConstructorPat (pglobal_ident constructor ^ "_case", [SSP.AST.Ident "temp"]) *\) *) + (* (\* List.map ~f:(fun {field; pat} -> (pat, SSP.AST.App (SSP.AST.Var (pglobal_ident field), [SSP.AST.Var "temp"]))) fields *\) *) (* Enum *) - | PConstruct { name; args; is_record = false; _ } -> + | PConstruct { constructor; fields; is_record = false; _ } -> SSP.AST.ConstructorPat - ( pglobal_ident name, - match args with + ( pglobal_ident constructor, + match fields with | [] -> [] - | _ -> [ SSP.AST.TuplePat (List.map ~f:(fun p -> ppat p.pat) args) ] + | _ -> + [ SSP.AST.TuplePat (List.map ~f:(fun p -> ppat p.pat) fields) ] ) | PConstant { lit } -> SSP.AST.Lit (pliteral lit) | _ -> . @@ -959,7 +960,7 @@ struct p = PConstruct { - args = [ { pat; _ } ]; + fields = [ { pat; _ } ]; is_record = false; is_struct = true; _; @@ -990,16 +991,21 @@ struct ~f:(fun { arm = { arm_pat; body }; _ } -> match arm_pat.p with | PConstruct - { name; args; is_record = false; is_struct = false } -> ( + { + constructor; + fields; + is_record = false; + is_struct = false; + } -> ( let arg_tuple = SSP.AST.TuplePat - (List.map ~f:(fun p -> ppat p.pat) args) + (List.map ~f:(fun p -> ppat p.pat) fields) in ( SSP.AST.ConstructorPat - ( pglobal_ident name ^ "_case", - match args with [] -> [] | _ -> [ arg_tuple ] ), + ( pglobal_ident constructor ^ "_case", + match fields with [] -> [] | _ -> [ arg_tuple ] ), match - (args, SSPExtraDefinitions.pat_as_expr arg_tuple) + (fields, SSPExtraDefinitions.pat_as_expr arg_tuple) with | _ :: _, Some (redefine_pat, redefine_expr) -> SSPExtraDefinitions.letb @@ -1016,14 +1022,14 @@ struct (List.map ~f:(fun x -> pty arm_pat.span x.pat.typ) - args) ); + fields) ); ] ); body = (pexpr env true) body; value_typ = SSP.AST.Product (List.map ~f:(fun x -> pty arm_pat.span x.pat.typ) - args); + fields); monad_typ = None; } | _, _ -> (pexpr env true) body )) @@ -1103,8 +1109,8 @@ struct p = PConstruct { - name = `TupleCons 0; - args = []; + constructor = `TupleCons 0; + fields = []; is_record = false; is_struct = false; }; @@ -1299,9 +1305,9 @@ struct match pat.p with | PWild -> false | PAscription { pat; _ } -> is_mutable_pat pat - | PConstruct { name = `TupleCons _; args; _ } -> + | PConstruct { constructor = `TupleCons _; fields; _ } -> List.fold ~init:false ~f:( || ) - (List.map ~f:(fun p -> is_mutable_pat p.pat) args) + (List.map ~f:(fun p -> is_mutable_pat p.pat) fields) | PConstruct _ -> false | PArray _ -> (* List.fold ~init:false ~f:(||) (List.map ~f:(fun p -> is_mutable_pat p) args) *) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 57d298333..6ab7744b1 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -401,23 +401,26 @@ struct Error.unimplemented p.span ~issue_id:463 ~details:"The F* backend doesn't support nested disjuntive patterns" | PArray { args } -> F.pat @@ F.AST.PatList (List.map ~f:ppat args) - | PConstruct { name = `TupleCons 0; args = [] } -> + | PConstruct { constructor = `TupleCons 0; fields = [] } -> F.pat @@ F.AST.PatConst F.Const.Const_unit - | PConstruct { name = `TupleCons 1; args = [ { pat } ] } -> ppat pat - | PConstruct { name = `TupleCons n; args } -> + | PConstruct { constructor = `TupleCons 1; fields = [ { pat } ] } -> + ppat pat + | PConstruct { constructor = `TupleCons n; fields } -> F.pat - @@ F.AST.PatTuple (List.map ~f:(fun { pat } -> ppat pat) args, false) - | PConstruct { name; args; is_record; is_struct } -> + @@ F.AST.PatTuple (List.map ~f:(fun { pat } -> ppat pat) fields, false) + | PConstruct { constructor; fields; is_record; is_struct } -> let pat_rec () = - F.pat @@ F.AST.PatRecord (List.map ~f:pfield_pat args) + F.pat @@ F.AST.PatRecord (List.map ~f:pfield_pat fields) in if is_struct && is_record then pat_rec () else - let pat_name = F.pat @@ F.AST.PatName (pglobal_ident p.span name) in + let pat_name = + F.pat @@ F.AST.PatName (pglobal_ident p.span constructor) + in F.pat_app pat_name @@ if is_record then [ pat_rec () ] - else List.map ~f:(fun { field; pat } -> ppat pat) args + else List.map ~f:(fun { field; pat } -> ppat pat) fields | PConstant { lit } -> F.pat @@ F.AST.PatConst (pliteral p.span lit) | _ -> . diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index bcbd3f258..cc6da6f8b 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -242,8 +242,8 @@ module Make (Options : OPTS) : MAKE = struct let body = print#expr_at Arm_body body in match arm_pat with | { p = PWild; _ } -> body - | { p = PConstruct { name; _ } } - when Global_ident.eq_name Core__result__Result__Err name -> + | { p = PConstruct { constructor; _ } } + when Global_ident.eq_name Core__result__Result__Err constructor -> print#pv_letfun_call (print#error_letfun_name body_typ) [] | _ -> let pat = @@ -296,16 +296,18 @@ module Make (Options : OPTS) : MAKE = struct fun pat -> match pat with | PConstant { lit } -> string "=" ^^ print#literal Pat lit - | PConstruct { name; args } - when Global_ident.eq_name Core__option__Option__None name -> + | PConstruct { constructor; fields } + when Global_ident.eq_name Core__option__Option__None constructor + -> string "None()" - | PConstruct { name; args } + | PConstruct { constructor; fields } (* The `Some` constructor in ProVerif expects a bitstring argument, so we use the appropriate `_to_bitstring` type converter on the inner expression. *) - when Global_ident.eq_name Core__option__Option__Some name -> - let inner_field = List.hd_exn args in + when Global_ident.eq_name Core__option__Option__Some constructor + -> + let inner_field = List.hd_exn fields in let inner_field_type_doc = print#ty AlreadyPar inner_field.pat.typ in @@ -322,21 +324,23 @@ module Make (Options : OPTS) : MAKE = struct ^^ iblock parens inner_field_doc) in string "Some" ^^ inner_block - | PConstruct { name; args } + | PConstruct { constructor; fields } (* We replace applications of the `Ok` constructor with their contents. *) - when Global_ident.eq_name Core__result__Result__Ok name -> - let inner_field = List.hd_exn args in + when Global_ident.eq_name Core__result__Result__Ok constructor + -> + let inner_field = List.hd_exn fields in let inner_field_type_doc = print#ty AlreadyPar inner_field.pat.typ in let inner_field_doc = print#pat ctx inner_field.pat in inner_field_doc - | PConstruct { name; args } -> ( + | PConstruct { constructor; fields } -> ( match - translate_known_name name ~dict:library_constructor_patterns + translate_known_name constructor + ~dict:library_constructor_patterns with - | Some (_, translation) -> translation args + | Some (_, translation) -> translation fields | None -> super#pat' ctx pat) | PWild -> print#typed_wildcard diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 7eb48dc09..d84584e18 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -196,10 +196,10 @@ functor | PWild | PAscription of { typ : ty; typ_span : span; pat : pat } | PConstruct of { - name : global_ident; + constructor : global_ident; is_record : bool; (* are fields named? *) is_struct : bool; (* a struct has one constructor *) - args : field_pat list; + fields : field_pat list; } (* An or-pattern, e.g. `p | q`. Invariant: `List.length subpats >= 2`. *) diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 8e064d761..7fe2f75e8 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -704,7 +704,7 @@ module Make (F : Features.T) = struct (* TODO: Those tuple1 things are wrong! Tuples of size one exists in Rust! e.g. `(123,)` *) let rec remove_tuple1_pat (p : pat) : pat = match p.p with - | PConstruct { name = `TupleType 1; args = [ { pat; _ } ]; _ } -> + | PConstruct { constructor = `TupleType 1; fields = [ { pat; _ } ]; _ } -> remove_tuple1_pat pat | _ -> p @@ -745,7 +745,7 @@ module Make (F : Features.T) = struct pat_is_expr p e | PBinding { subpat = None; var = pv; _ }, LocalVar ev -> [%eq: local_ident] pv ev - | ( PConstruct { name = pn; args = pargs; _ }, + | ( PConstruct { constructor = pn; fields = pargs; _ }, Construct { constructor = en; fields = eargs; base = None; _ } ) when [%eq: global_ident] pn en -> ( match List.zip pargs eargs with @@ -827,10 +827,10 @@ module Make (F : Features.T) = struct p = PConstruct { - name = `TupleCons len; - args = tuple; + constructor = `TupleCons len; is_record = false; is_struct = true; + fields = tuple; }; typ = make_tuple_typ @@ List.map ~f:(fun { pat; _ } -> pat.typ) tuple; span; diff --git a/engine/lib/deprecated_generic_printer/deprecated_generic_printer_base.ml b/engine/lib/deprecated_generic_printer/deprecated_generic_printer_base.ml index 3e61a44fd..c887ecdf1 100644 --- a/engine/lib/deprecated_generic_printer/deprecated_generic_printer_base.ml +++ b/engine/lib/deprecated_generic_printer/deprecated_generic_printer_base.ml @@ -216,17 +216,17 @@ module Make (F : Features.T) = struct method pat' : par_state -> pat' fn = fun _ -> function | PConstant { lit } -> print#literal Pat lit - | PConstruct { name; args; is_record; is_struct } -> ( - match name with + | PConstruct { constructor; is_record; is_struct; fields } -> ( + match constructor with | `Concrete constructor -> print#doc_construct_inductive ~is_record ~is_struct ~constructor ~base:None (List.map ~f:(fun fp -> (fp.field, print#pat_at Pat_ConcreteInductive fp.pat)) - args) + fields) | `TupleCons _ -> - List.map ~f:(fun fp -> fp.pat) args + List.map ~f:(fun fp -> fp.pat) fields |> print#pat_construct_tuple | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> print#assertion_failure "todo err") diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index f0ce1fe7d..3883adb53 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -866,14 +866,14 @@ end) : EXPR = struct let var = local_ident Expr var in PBinding { mut; mode; var; typ; subpat } | Variant { info; subpatterns; _ } -> - let name = + let constructor = def_id (Constructor { is_struct = info.typ_is_struct }) info.variant in - let args = List.map ~f:(c_field_pat info) subpatterns in + let fields = List.map ~f:(c_field_pat info) subpatterns in PConstruct { - name; - args; + constructor; + fields; is_record = info.variant_is_record; is_struct = info.typ_is_struct; } @@ -1375,12 +1375,12 @@ let cast_of_enum typ_name generics typ thir_span { is_record = variant.is_record; is_struct = false; - args = + fields = List.map ~f:(fun (cid, typ, _) -> { field = `Concrete cid; pat = { p = PWild; typ; span } }) variant.arguments; - name = `Concrete variant.name; + constructor = `Concrete variant.name; } in let pat = { p = pat; typ = self; span } in diff --git a/engine/lib/phases/phase_drop_match_guards.ml b/engine/lib/phases/phase_drop_match_guards.ml index a193b8e7a..1facd7f18 100644 --- a/engine/lib/phases/phase_drop_match_guards.ml +++ b/engine/lib/phases/phase_drop_match_guards.ml @@ -119,7 +119,7 @@ module%inlined_contents Make (F : Features.T) = struct in let mk_opt_pattern (binding : B.pat option) : B.pat = - let (name : Concrete_ident.name), (args : B.field_pat list) = + let (name : Concrete_ident.name), (fields : B.field_pat list) = match binding with | Some b -> ( Core__option__Option__Some, @@ -130,11 +130,11 @@ module%inlined_contents Make (F : Features.T) = struct p = PConstruct { - name = + constructor = Global_ident.of_name (Constructor { is_struct = false }) name; - args; + fields; is_record = false; is_struct = false; }; diff --git a/engine/lib/phases/phase_hoist_disjunctive_patterns.ml b/engine/lib/phases/phase_hoist_disjunctive_patterns.ml index 332a094d8..cdec91d08 100644 --- a/engine/lib/phases/phase_hoist_disjunctive_patterns.ml +++ b/engine/lib/phases/phase_hoist_disjunctive_patterns.ml @@ -64,18 +64,18 @@ module Make (F : Features.T) = in match p.p with - | PConstruct { name; args; is_record; is_struct } -> - let args_as_pat = - List.rev_map args ~f:(fun arg -> self#visit_pat () arg.pat) + | PConstruct { constructor; fields; is_record; is_struct } -> + let fields_as_pat = + List.rev_map fields ~f:(fun arg -> self#visit_pat () arg.pat) in let subpats = - List.map (treat_args [ [] ] args_as_pat) - ~f:(fun args_as_pat -> - let args = - List.map2_exn args_as_pat args + List.map (treat_args [ [] ] fields_as_pat) + ~f:(fun fields_as_pat -> + let fields = + List.map2_exn fields_as_pat fields ~f:(fun pat { field; _ } -> { field; pat }) in - PConstruct { name; args; is_record; is_struct } + PConstruct { constructor; fields; is_record; is_struct } |> return_pat) in diff --git a/engine/lib/phases/phase_reconstruct_for_loops.ml b/engine/lib/phases/phase_reconstruct_for_loops.ml index a6b3c48b5..19e992497 100644 --- a/engine/lib/phases/phase_reconstruct_for_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_loops.ml @@ -131,10 +131,10 @@ struct p = PConstruct { - name = + constructor = `Concrete none_ctor; - args = + fields = []; _; }; @@ -180,10 +180,10 @@ struct p = PConstruct { - name = + constructor = `Concrete some_ctor; - args = + fields = [ { pat; diff --git a/engine/lib/phases/phase_reconstruct_question_marks.ml b/engine/lib/phases/phase_reconstruct_question_marks.ml index 1a4735b90..c7f88fd91 100644 --- a/engine/lib/phases/phase_reconstruct_question_marks.ml +++ b/engine/lib/phases/phase_reconstruct_question_marks.ml @@ -130,8 +130,8 @@ module%inlined_contents Make (FA : Features.T) = struct match p.p with | PConstruct { - name; - args = + constructor; + fields = [ { pat = @@ -145,7 +145,7 @@ module%inlined_contents Make (FA : Features.T) = struct ]; _; } -> - Some (name, var) + Some (constructor, var) | _ -> None in match e.e with diff --git a/engine/lib/phases/phase_simplify_question_marks.ml b/engine/lib/phases/phase_simplify_question_marks.ml index 4567ec48a..67ab9dfe0 100644 --- a/engine/lib/phases/phase_simplify_question_marks.ml +++ b/engine/lib/phases/phase_simplify_question_marks.ml @@ -111,17 +111,17 @@ module%inlined_contents Make (FA : Features.T) = struct let mk_pconstruct ~is_struct ~is_record ~span ~typ (constructor : Concrete_ident_generated.t) (fields : (Concrete_ident_generated.t * pat) list) = - let name = + let constructor = Global_ident.of_name (Constructor { is_struct }) constructor in - let args = + let fields = List.map ~f:(fun (field, pat) -> let field = Global_ident.of_name Field field in { field; pat }) fields in - let p = PConstruct { name; args; is_record; is_struct } in + let p = PConstruct { constructor; fields; is_record; is_struct } in { p; span; typ } (** [extract e] returns [Some (x, ty)] if [e] was a `y?` @@ -153,8 +153,8 @@ module%inlined_contents Make (FA : Features.T) = struct match p.p with | PConstruct { - name; - args = + constructor = name; + fields = [ { pat = diff --git a/engine/lib/phases/phase_transform_hax_lib_inline.ml b/engine/lib/phases/phase_transform_hax_lib_inline.ml index d2b2a4527..3005fddaa 100644 --- a/engine/lib/phases/phase_transform_hax_lib_inline.ml +++ b/engine/lib/phases/phase_transform_hax_lib_inline.ml @@ -52,7 +52,7 @@ module%inlined_contents Make (F : Features.T) = struct arm = { arm_pat = - { p = PConstruct { args = [ arg ]; _ }; _ }; + { p = PConstruct { fields = [ arg ]; _ }; _ }; _; }; _; diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 1f437f17f..7ff34f777 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -195,21 +195,21 @@ module Raw = struct | PWild -> !"_" | PAscription { typ; pat; _ } -> !"pat_ascription!(" & ppat pat & !" as " & pty e.span typ & !")" - | PConstruct { name; args; is_record; _ } -> - pglobal_ident e.span name + | PConstruct { constructor; fields; is_record; _ } -> + pglobal_ident e.span constructor & - if List.is_empty args then !"" + if List.is_empty fields then !"" else if is_record then !"{" & concat ~sep:!", " (List.map ~f:(fun { field; pat } -> !(last_of_global_ident field e.span) & !":" & ppat pat) - args) + fields) & !"}" else !"(" - & concat ~sep:!", " (List.map ~f:(fun { pat; _ } -> ppat pat) args) + & concat ~sep:!", " (List.map ~f:(fun { pat; _ } -> ppat pat) fields) & !")" | POr { subpats } -> concat ~sep:!" | " (List.map ~f:ppat subpats) | PArray { args } -> !"[" & concat ~sep:!"," (List.map ~f:ppat args) & !"]" diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index eb893d35f..79f1106a7 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -121,13 +121,13 @@ struct | PWild -> PWild | PAscription { typ; typ_span; pat } -> PAscription { typ = dty span typ; pat = dpat pat; typ_span } - | PConstruct { name; args; is_record; is_struct } -> + | PConstruct { constructor; is_record; is_struct; fields } -> PConstruct { - name; - args = List.map ~f:(dfield_pat span) args; + constructor; is_record; is_struct; + fields = List.map ~f:(dfield_pat span) fields; } | POr { subpats } -> POr { subpats = List.map ~f:dpat subpats } | PArray { args } -> PArray { args = List.map ~f:dpat args } From a8c1867557838e8746fd32938163151394773914 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 10 Oct 2024 16:57:44 +0200 Subject: [PATCH 010/253] fix(engine): make consts fun. calls of arity 0 when there is an impl expr The engine was dropping trait information when importing constants: now, if a constant `T::CONST` is an associated item of a non-inherent trait, we represent it `T::CONST` as a call to `CONST()` with the implementation expression for `T`. Note that, in the engine, constants are already represented as functions of arity zero. Rust functions of arity zero are represented as function that take exactly one `unit` input. Fixes #840. --- engine/lib/import_thir.ml | 10 ++++++++-- .../src/snapshots/toolchain__naming into-fstar.snap | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 7c3f35c95..df70997fc 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -716,11 +716,17 @@ end) : EXPR = struct typ = TInt { size = S8; signedness = Unsigned }; }) l)) - | NamedConst { def_id = id; impl; _ } -> + | NamedConst { def_id = id; impl; _ } -> ( let kind : Concrete_ident.Kind.t = match impl with Some _ -> AssociatedItem Value | _ -> Value in - GlobalVar (def_id kind id) + let f = GlobalVar (def_id kind id) in + match impl with + | Some impl -> + let trait = Some (c_impl_expr e.span impl, []) in + let f = { e = f; span; typ = TArrow ([], typ) } in + App { f; trait; args = []; generic_args = []; bounds_impls = [] } + | _ -> f) | Closure { body; params; upvars; _ } -> let params = List.filter_map ~f:(fun p -> Option.map ~f:c_pat p.pat) params diff --git a/test-harness/src/snapshots/toolchain__naming into-fstar.snap b/test-harness/src/snapshots/toolchain__naming into-fstar.snap index 585900c82..bc7a1661d 100644 --- a/test-harness/src/snapshots/toolchain__naming into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__naming into-fstar.snap @@ -127,7 +127,8 @@ let constants (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_FooTrait v_T) (_: Prims.unit) - : usize = f_ASSOCIATED_CONSTANT +! v_INHERENT_CONSTANT + : usize = + (f_ASSOCIATED_CONSTANT #FStar.Tactics.Typeclasses.solve <: usize) +! v_INHERENT_CONSTANT let ff__g (_: Prims.unit) : Prims.unit = () From 7307809a7593e4a4562fbde0c1a0018535b3ed12 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 16:34:23 +0200 Subject: [PATCH 011/253] Remove workaround in trait resolution for associated items --- frontend/exporter/src/traits.rs | 2 +- frontend/exporter/src/types/copied.rs | 34 ++++++++++++++------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index a04b6fafa..4c31e6b63 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -257,7 +257,7 @@ pub mod rustc { } // Lifetimes are irrelevant when resolving instances. - pub(super) fn erase_and_norm<'tcx, T>( + pub(crate) fn erase_and_norm<'tcx, T>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, x: T, diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 80a5359be..250498de5 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1775,7 +1775,7 @@ pub enum AliasKind { #[cfg(feature = "rustc")] impl Alias { #[tracing::instrument(level = "trace", skip(s))] - fn from<'tcx, S: BaseState<'tcx> + HasOwnerId>( + fn from<'tcx, S: UnderOwnerState<'tcx>>( s: &S, alias_kind: &rustc_type_ir::AliasTyKind, alias_ty: &rustc_middle::ty::AliasTy<'tcx>, @@ -1783,23 +1783,25 @@ impl Alias { use rustc_type_ir::AliasTyKind as RustAliasKind; let kind = match alias_kind { RustAliasKind::Projection => { - use rustc_middle::ty::{Binder, TypeVisitableExt}; let tcx = s.base().tcx; let trait_ref = alias_ty.trait_ref(tcx); - // We don't have a clear handling of binders here; this is causing a number of - // problems in Charon. In the meantime we return something well-formed when we - // can't trait-solve. See also https://github.com/hacspec/hax/issues/495. - if trait_ref.has_escaping_bound_vars() { - warning!( - s, - "Hax frontend found a projected type with escaping bound vars. Please report https://github.com/hacspec/hax/issues/495" - ); - AliasKind::Opaque - } else { - AliasKind::Projection { - assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), - impl_expr: solve_trait(s, Binder::dummy(trait_ref)), - } + // In a case like: + // ``` + // impl Trait for Result + // where + // for<'a> &'a Result: IntoIterator, + // for<'a> <&'a Result as IntoIterator>::Item: Copy, + // {} + // ``` + // the `&'a Result as IntoIterator` trait ref has escaping bound variables + // yet we dont have a binder around (could even be several). Binding this correctly + // is therefore difficult. Since our trait resolution ignores lifetimes anyway, we + // just erase them. See also https://github.com/hacspec/hax/issues/747. + let trait_ref = + traits::rustc::search_clause::erase_and_norm(tcx, s.param_env(), trait_ref); + AliasKind::Projection { + assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), + impl_expr: solve_trait(s, ty::Binder::dummy(trait_ref)), } } RustAliasKind::Inherent => AliasKind::Inherent, From 44447e57029df61d2df13a544f6e6ed4a2f27b47 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 14 Oct 2024 09:14:30 +0200 Subject: [PATCH 012/253] fix: DEV.md debug engine Fixes #346 --- engine/DEV.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/engine/DEV.md b/engine/DEV.md index a0d2ef381..37f96217a 100644 --- a/engine/DEV.md +++ b/engine/DEV.md @@ -52,7 +52,8 @@ To see the implementation of the `Ast_visitors` module, run `dune describe pp li You can enable a debug mode that prints a Rustish AST at each phase, that you can browse interactively along with the actual AST. -Just add the flag `--debug-engine` (or `-d`) to the `into` subcommand. -At the end of the translation, `cargo hax` will spawn a webserver that -lets you browse the debug information. Note, you can change to port by -setting the environment variable `HAX_DEBUGGER_PORT`. +Just add the flag `--debug-engine i` (or `-d i`, `i` stands for +**i**nteractive) to the `into` subcommand. At the end of the +translation, `cargo hax` will spawn a webserver that lets you browse +the debug information. Note, you can change to port by setting the +environment variable `HAX_DEBUGGER_PORT`. From 6fcf4e9c076cbf6b98b34b58737873c9f0aec142 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 10 Oct 2024 12:13:59 +0200 Subject: [PATCH 013/253] feat: use `just` This PR introduces a `justfile`, for the `just` command runner (https://github.com/casey/just). Now we can `just ` with recipie one of the following: ``` Available recipes: build # Build everyting and install in PATH expand *FLAGS # This is useful to debug hax macros. fmt # Format all the code list-names # declared in the `./engine/names` crate. list-types # Show the Rust to OCaml generated types available to the engine. ocaml # Build the OCaml parts of hax, and install OCaml binaries in PATH rust # Build the Rust parts of hax, and install Rust binaries in PATH ``` --- .utils/expand.sh | 8 ----- .utils/list-names.sh | 11 ------- README.md | 15 ++++++--- flake.nix | 21 +------------ justfile | 72 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 43 deletions(-) delete mode 100755 .utils/expand.sh delete mode 100755 .utils/list-names.sh create mode 100644 justfile diff --git a/.utils/expand.sh b/.utils/expand.sh deleted file mode 100755 index 6f0e5ea96..000000000 --- a/.utils/expand.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -# This script expands a crate so that one can inspect macro expansion -# by hax. It is a wrapper around `cargo expand` that inject the -# required rustc flags. - -RUSTFLAGS='-Zcrate-attr=register_tool(_hax) -Zcrate-attr=feature(register_tool) --cfg hax_compilation --cfg _hax --cfg hax --cfg hax_backend_fstar --cfg hax' cargo expand "$@" - diff --git a/.utils/list-names.sh b/.utils/list-names.sh deleted file mode 100755 index e0c99c586..000000000 --- a/.utils/list-names.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -function pager() { - if command -v bat &> /dev/null; then - bat -l ml - else - less - fi -} - -hax-engine-names-extract | sed '/include .val/,$d' | pager diff --git a/README.md b/README.md index 65eb569f5..3adf2858d 100644 --- a/README.md +++ b/README.md @@ -138,10 +138,17 @@ You can also just use [direnv](https://github.com/nix-community/nix-direnv), wit programs from the Rust language to various backends (see `engine/backends/`). - `cli/`: the `hax` subcommand for Cargo. -### Recompiling -You can use the [`.utils/rebuild.sh`](./.utils/rebuild.sh) script (which is available automatically as the command `rebuild` when using the Nix devshell): - - `rebuild`: rebuild the Rust then the OCaml part; - - `rebuild TARGET`: rebuild the `TARGET` part (`TARGET` is either `rust` or `ocaml`). +### Compiling, formatting, and more +We use the [`just` command runner](https://just.systems/). If you use +Nix, the dev shell provides it automatically, if you don't use Nix, +please [install `just`](https://just.systems/man/en/packages.html) on +your system. + +Anywhere within the repository, you can build and install in PATH (1) +the Rust parts with `just rust`, (2) the OCaml parts with `just ocaml` +or (3) both with `just build`. More commands (e.g. `just fmt` to +format) are available, please run `just` or `just --list` to get all +the commands. ## Publications & Other material diff --git a/flake.nix b/flake.nix index 4fd03ee02..778ab9967 100644 --- a/flake.nix +++ b/flake.nix @@ -131,24 +131,6 @@ ${pkgs.python3}/bin/python -m http.server "$@" ''}"; }; - # Check the coherency between issues labeled - # `marked-unimplemented` on GitHub and issues mentionned in - # the engine in the `Unimplemented {issue_id: ...}` errors. - check-unimlemented-issue-coherency = { - type = "app"; - program = "${pkgs.writeScript "check-unimlemented-issue-coherency" '' - RG=${pkgs.ripgrep}/bin/rg - SD=${pkgs.sd}/bin/sd - - diff -U0 \ - <(${pkgs.gh}/bin/gh issue -R hacspec/hax list --label 'marked-unimplemented' --json number,closed -L 200 \ - | ${pkgs.jq}/bin/jq '.[] | select(.closed | not) | .number' | sort -u) \ - <($RG 'issue_id:(\d+)' -Ior '$1' | sort -u) \ - | $RG '^[+-]\d' \ - | $SD '[-](\d+)' '#$1\t is labeled `marked-unimplemented`, but was not found in the code' \ - | $SD '[+](\d+)' '#$1\t is *not* labeled `marked-unimplemented` or is closed' - ''}"; - }; serve-book = { type = "app"; program = "${pkgs.writeScript "serve-book" '' @@ -176,8 +158,6 @@ installPhase = '' mkdir -p $out/bin cp ${./.utils/rebuild.sh} $out/bin/rebuild - cp ${./.utils/list-names.sh} $out/bin/list-names - cp ${./.utils/expand.sh} $out/bin/expand-hax-macros ''; }; packages = [ @@ -188,6 +168,7 @@ pkgs.ocamlPackages.odoc pkgs.ocamlPackages.utop + pkgs.just pkgs.cargo-expand pkgs.cargo-release pkgs.cargo-insta diff --git a/justfile b/justfile new file mode 100644 index 000000000..1f3478f9d --- /dev/null +++ b/justfile @@ -0,0 +1,72 @@ +@_default: + just --list + +# Build Rust and OCaml parts and install binaries in PATH. To build +# only OCaml parts or only Rust parts, set target to `rust` or +# `ocaml`. +@build target='rust ocaml': + ./.utils/rebuild.sh {{target}} + +alias b := build + +# alias for `build rust` +@rust: + just build rust + +# alias for `build ocaml` +@ocaml: + just build ocaml + +# `cargo expand` a crate, but sets flags and crate attributes so that the expansion is exactly what hax receives. This is useful to debug hax macros. +[no-cd] +expand *FLAGS: + RUSTFLAGS='-Zcrate-attr=register_tool(_hax) -Zcrate-attr=feature(register_tool) --cfg hax_compilation --cfg _hax --cfg hax --cfg hax_backend_fstar --cfg hax' cargo expand {{FLAGS}} + +# Show the generated module `concrete_ident_generated.ml`, that contains all the Rust names the engine knows about. Those names are declared in the `./engine/names` crate. +@list-names: + hax-engine-names-extract | sed '/include .val/,$d' | just _pager + +# Show the Rust to OCaml generated types available to the engine. +@list-types: + just _ensure_binary_availability ocamlformat ocamlformat + cd engine && dune describe pp lib/types.ml \ + | sed -e '1,/open ParseError/ d' \ + | sed '/let rec pp_/,$d' \ + | ocamlformat --impl - \ + | just _pager + +# Format all the code +fmt: + cargo fmt + cd engine && dune fmt + +# Check the coherency between issues labeled `marked-unimplemented` on GitHub and issues mentionned in the engine in the `Unimplemented {issue_id: ...}` errors. +@check-issues: + just _ensure_command_in_path jq "jq (https://jqlang.github.io/jq/)" + just _ensure_command_in_path gh "GitHub CLI (https://cli.github.com/)" + just _ensure_command_in_path rg "ripgrep (https://github.com/BurntSushi/ripgrep)" + just _ensure_command_in_path sd "sd (https://github.com/chmln/sd)" + diff -U0 \ + <(gh issue -R hacspec/hax list --label 'marked-unimplemented' --json number,closed -L 200 \ + | jq '.[] | select(.closed | not) | .number' | sort -u) \ + <(rg 'issue_id:(\d+)' -Ior '$1' | sort -u) \ + | rg '^[+-]\d' \ + | sd '[-](\d+)' '#$1\t is labeled `marked-unimplemented`, but was not found in the code' \ + | sd '[+](\d+)' '#$1\t is *not* labeled `marked-unimplemented` or is closed' + +_ensure_command_in_path BINARY NAME: + #!/usr/bin/env bash + command -v {{BINARY}} &> /dev/null || { + >&2 echo -e "\033[0;31mSorry, the binary \033[1m{{BINARY}}\033[0m\033[0;31m is required for this command.\033[0m" + >&2 echo -e " \033[0;31m→ please install \033[1m{{NAME}}\033[0m" + >&2 echo "" + exit 1 + } + +_pager: + #!/usr/bin/env bash + if command -v bat &> /dev/null; then + bat -l ml + else + less + fi From 893e6d036a20373fb5daf7f3d75ad87cc832911d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 17:44:13 +0200 Subject: [PATCH 014/253] Nested obligations inherit the parent param_env --- frontend/exporter/src/traits.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 4c31e6b63..3460ea1f9 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -505,6 +505,7 @@ pub mod rustc { fn impl_exprs<'tcx>( tcx: TyCtxt<'tcx>, owner_id: DefId, + param_env: rustc_middle::ty::ParamEnv<'tcx>, obligations: &[rustc_trait_selection::traits::Obligation< 'tcx, rustc_middle::ty::Predicate<'tcx>, @@ -520,7 +521,7 @@ pub mod rustc { impl_expr( tcx, owner_id, - obligation.param_env, + param_env, &trait_ref.map_bound(|p| p.trait_ref), warn, ) @@ -600,7 +601,7 @@ pub mod rustc { Ok(ImplSource::Builtin(_, _ignored)) => &[], Err(_) => &[], }; - let nested = impl_exprs(tcx, owner_id, nested, warn)?; + let nested = impl_exprs(tcx, owner_id, param_env, nested, warn)?; Ok(ImplExpr { r#impl: atom, From 05544d13189f8785ad56e686a6ba24370715ddd8 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:00:37 +0200 Subject: [PATCH 015/253] Move trait resolution to its own module --- frontend/exporter/src/traits.rs | 626 +-------------------- frontend/exporter/src/traits/resolution.rs | 472 ++++++++++++++++ frontend/exporter/src/traits/utils.rs | 128 +++++ frontend/exporter/src/types/copied.rs | 3 +- 4 files changed, 612 insertions(+), 617 deletions(-) create mode 100644 frontend/exporter/src/traits/resolution.rs create mode 100644 frontend/exporter/src/traits/utils.rs diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 3460ea1f9..f952018c0 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -1,7 +1,14 @@ use crate::prelude::*; +#[cfg(feature = "rustc")] +mod resolution; +#[cfg(feature = "rustc")] +mod utils; +#[cfg(feature = "rustc")] +pub use utils::erase_and_norm; + #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc::PathChunk<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::PathChunk<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub enum ImplExprPathChunk { @@ -25,7 +32,7 @@ pub enum ImplExprPathChunk { /// The source of a particular trait implementation. Most often this is either `Concrete` for a /// concrete `impl Trait for Type {}` item, or `LocalBound` for a context-bound `where T: Trait`. #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc::ImplExprAtom<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExprAtom<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub enum ImplExprAtom { @@ -75,7 +82,7 @@ pub enum ImplExprAtom { /// concrete implementations for `u8` and `&str`, represented as a tree. #[derive_group(Serializers)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema, AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc::ImplExpr<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExpr<'tcx>, state: S as s)] pub struct ImplExpr { /// The trait this is an impl for. pub r#trait: Binder, @@ -85,617 +92,6 @@ pub struct ImplExpr { pub args: Vec, } -#[cfg(feature = "rustc")] -pub mod rustc { - use rustc_hir::def::DefKind; - use rustc_hir::def_id::DefId; - use rustc_middle::ty::*; - - /// Items have various predicates in scope. `path_to` uses them as a starting point for trait - /// resolution. This tracks where each of them comes from. - #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] - pub enum BoundPredicateOrigin { - /// The `Self: Trait` predicate implicitly present within trait declarations (note: we - /// don't add it for trait implementations, should we?). - SelfPred, - /// The nth (non-self) predicate found for this item. We use predicates from - /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an opaque - /// type, we also append the predicates from `explicit_item_bounds` to this list. - Item(usize), - } - - #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] - pub struct AnnotatedTraitPred<'tcx> { - pub origin: BoundPredicateOrigin, - pub clause: PolyTraitPredicate<'tcx>, - } - - /// Just like `TyCtxt::predicates_of`, but in the case of a trait or impl item or closures, - /// also includes the predicates defined on the parents. Also this returns the special - /// `Self` clause separately. - fn predicates_of_or_above<'tcx>( - tcx: TyCtxt<'tcx>, - did: rustc_span::def_id::DefId, - ) -> ( - Vec>, - Option>, - ) { - use DefKind::*; - let def_kind = tcx.def_kind(did); - - let (mut predicates, mut self_pred) = match def_kind { - // These inherit some predicates from their parent. - AssocTy | AssocFn | AssocConst | Closure => { - let parent = tcx.parent(did); - predicates_of_or_above(tcx, parent) - } - _ => (vec![], None), - }; - - match def_kind { - // Don't list the predicates of traits, we already list the `Self` clause from - // which we can resolve anything needed. - Trait => {} - AssocConst - | AssocFn - | AssocTy - | Const - | Enum - | Fn - | ForeignTy - | Impl { .. } - | OpaqueTy - | Static { .. } - | Struct - | TraitAlias - | TyAlias - | Union => { - // Only these kinds may reasonably have predicates; we have to filter - // otherwise calling `predicates_defined_on` may ICE. - predicates.extend( - tcx.predicates_defined_on(did) - .predicates - .iter() - .filter_map(|(clause, _span)| clause.as_trait_clause()), - ); - } - _ => {} - } - - // Add some extra predicates that aren't in `predicates_defined_on`. - match def_kind { - OpaqueTy => { - // An opaque type (e.g. `impl Trait`) provides predicates by itself: we need to - // account for them. - // TODO: is this still useful? The test that used to require this doesn't anymore. - predicates.extend( - tcx.explicit_item_bounds(did) - .skip_binder() // Skips an `EarlyBinder`, likely for GATs - .iter() - .filter_map(|(clause, _span)| clause.as_trait_clause()), - ) - } - Trait => { - // Add the special `Self: Trait` clause. - // Copied from the code of `tcx.predicates_of()`. - let self_clause: Clause<'_> = TraitRef::identity(tcx, did).upcast(tcx); - self_pred = Some(self_clause.as_trait_clause().unwrap()); - } - _ => {} - } - - (predicates, self_pred) - } - - /// The predicates to use as a starting point for resolving trait references within this - /// item. This is just like `TyCtxt::predicates_of`, but in the case of a trait or impl - /// item or closures, also includes the predicates defined on the parents. - fn initial_search_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - did: rustc_span::def_id::DefId, - ) -> Vec> { - let (predicates, self_pred) = predicates_of_or_above(tcx, did); - let predicates = predicates - .into_iter() - .enumerate() - .map(|(i, clause)| AnnotatedTraitPred { - origin: BoundPredicateOrigin::Item(i), - clause, - }); - let self_pred = self_pred.map(|clause| AnnotatedTraitPred { - origin: BoundPredicateOrigin::SelfPred, - clause, - }); - - self_pred.into_iter().chain(predicates).collect() - } - - // FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 - pub(crate) mod search_clause { - use super::{AnnotatedTraitPred, Path, PathChunk}; - use itertools::Itertools; - use rustc_hir::def_id::DefId; - use rustc_middle::ty::*; - use std::collections::{hash_map::Entry, HashMap}; - - /// Erase all regions. Largely copied from `tcx.erase_regions`. - fn erase_all_regions<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> T - where - T: TypeFoldable>, - { - use rustc_middle::ty; - struct RegionEraserVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeFolder> for RegionEraserVisitor<'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - ty.super_fold_with(self) - } - - fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> - where - T: TypeFoldable>, - { - // Empty the binder - Binder::dummy(t.skip_binder().fold_with(self)) - } - - fn fold_region(&mut self, _r: ty::Region<'tcx>) -> ty::Region<'tcx> { - // We erase bound regions despite it being possibly incorrect. `for<'a> fn(&'a - // ())` and `fn(&'free ())` are different types: they may implement different - // traits and have a different `TypeId`. It's unclear whether this can cause us - // to select the wrong trait reference. - self.tcx.lifetimes.re_erased - } - } - value.fold_with(&mut RegionEraserVisitor { tcx }) - } - - // Lifetimes are irrelevant when resolving instances. - pub(crate) fn erase_and_norm<'tcx, T>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - x: T, - ) -> T - where - T: TypeFoldable> + Copy, - { - erase_all_regions( - tcx, - tcx.try_normalize_erasing_regions(param_env, x).unwrap_or(x), - ) - } - - #[tracing::instrument(level = "trace", skip(tcx))] - fn parents_trait_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - pred: PolyTraitPredicate<'tcx>, - ) -> Vec> { - let self_trait_ref = pred.to_poly_trait_ref(); - tcx.predicates_of(pred.def_id()) - .predicates - .iter() - // Substitute with the `self` args so that the clause makes sense in the - // outside context. - .map(|(clause, _span)| clause.instantiate_supertrait(tcx, self_trait_ref)) - .filter_map(|pred| pred.as_trait_clause()) - .collect() - } - - /// A candidate projects `self` along a path reaching some predicate. A candidate is - /// selected when its predicate is the one expected, aka `target`. - #[derive(Debug, Clone)] - struct Candidate<'tcx> { - path: Path<'tcx>, - pred: PolyTraitPredicate<'tcx>, - origin: AnnotatedTraitPred<'tcx>, - } - - /// Stores a set of predicates along with where they came from. - struct PredicateSearcher<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - candidates: HashMap, Candidate<'tcx>>, - } - - impl<'tcx> PredicateSearcher<'tcx> { - /// Initialize the elaborator with the predicates accessible within this item. - fn new_for_owner( - tcx: TyCtxt<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - owner_id: DefId, - ) -> Self { - let mut out = Self { - tcx, - param_env, - candidates: Default::default(), - }; - out.extend( - super::initial_search_predicates(tcx, owner_id) - .into_iter() - .map(|clause| Candidate { - path: vec![], - pred: clause.clause, - origin: clause, - }), - ); - out - } - - /// Insert new candidates and all their parent predicates. This deduplicates predicates - /// to avoid divergence. - fn extend(&mut self, candidates: impl IntoIterator>) { - let tcx = self.tcx; - // Filter out duplicated candidates. - let mut new_candidates = Vec::new(); - for mut candidate in candidates { - // Normalize and erase all lifetimes. - candidate.pred = erase_and_norm(tcx, self.param_env, candidate.pred); - if let Entry::Vacant(entry) = self.candidates.entry(candidate.pred) { - entry.insert(candidate.clone()); - new_candidates.push(candidate); - } - } - if !new_candidates.is_empty() { - self.extend_parents(new_candidates); - } - } - - /// Add the parents of these candidates. This is a separate function to avoid - /// polymorphic recursion due to the closures capturing the type parameters of this - /// function. - fn extend_parents(&mut self, new_candidates: Vec>) { - let tcx = self.tcx; - // Then recursively add their parents. This way ensures a breadth-first order, - // which means we select the shortest path when looking up predicates. - self.extend(new_candidates.into_iter().flat_map(|candidate| { - parents_trait_predicates(tcx, candidate.pred) - .into_iter() - .enumerate() - .map(move |(index, parent_pred)| { - let mut parent_candidate = Candidate { - pred: parent_pred, - path: candidate.path.clone(), - origin: candidate.origin, - }; - parent_candidate.path.push(PathChunk::Parent { - predicate: parent_pred, - index, - }); - parent_candidate - }) - })); - } - - /// Lookup a predicate in this set. If the predicate applies to an associated type, we - /// add the relevant implied associated type bounds to the set as well. - fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option<&Candidate<'tcx>> { - let tcx = self.tcx; - let target: PolyTraitPredicate = - erase_and_norm(tcx, self.param_env, target).upcast(tcx); - - // The predicate is `::Type: OtherTrait`. We look up `T as Trait` in - // the current context and add all the bounds on `Trait::Type` to our context. - // Note: We skip a binder but rebind it just after. - if let TyKind::Alias(AliasTyKind::Projection, alias_ty) = - target.self_ty().skip_binder().kind() - { - let trait_ref = target.rebind(alias_ty.trait_ref(tcx)); - // Recursively look up the trait ref inside `self`. - let trait_candidate = self.lookup(trait_ref)?.clone(); - let item_bounds = tcx - // TODO: `item_bounds` can contain parent traits, we don't want them - .item_bounds(alias_ty.def_id) - .instantiate(tcx, alias_ty.args) - .iter() - .filter_map(|pred| pred.as_trait_clause()) - .enumerate(); - // Add all the bounds on the corresponding associated item. - self.extend(item_bounds.map(|(index, pred)| { - let mut candidate = Candidate { - path: trait_candidate.path.clone(), - pred, - origin: trait_candidate.origin, - }; - candidate.path.push(PathChunk::AssocItem { - item: tcx.associated_item(alias_ty.def_id), - predicate: pred, - index, - }); - candidate - })); - } - - tracing::trace!("Looking for {target:?}"); - let ret = self.candidates.get(&target); - if ret.is_none() { - tracing::trace!( - "Couldn't find {target:?} in: [\n{}]", - self.candidates - .iter() - .map(|(_, c)| format!(" - {:?}\n", c.pred)) - .join("") - ); - } - ret - } - } - - #[tracing::instrument(level = "trace", skip(tcx, param_env))] - pub(super) fn path_to<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - target: PolyTraitRef<'tcx>, - ) -> Option<(Path<'tcx>, AnnotatedTraitPred<'tcx>)> { - let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); - let candidate = searcher.lookup(target)?; - Some((candidate.path.clone(), candidate.origin)) - } - } - - #[derive(Debug, Clone)] - pub enum PathChunk<'tcx> { - AssocItem { - item: AssocItem, - predicate: PolyTraitPredicate<'tcx>, - /// The nth predicate returned by `tcx.item_bounds`. - index: usize, - }, - Parent { - predicate: PolyTraitPredicate<'tcx>, - /// The nth predicate returned by `tcx.predicates_of`. - index: usize, - }, - } - pub type Path<'tcx> = Vec>; - - #[derive(Debug, Clone)] - pub enum ImplExprAtom<'tcx> { - /// A concrete `impl Trait for Type {}` item. - Concrete { - def_id: DefId, - generics: GenericArgsRef<'tcx>, - }, - /// A context-bound clause like `where T: Trait`. - LocalBound { - predicate: Predicate<'tcx>, - /// The nth (non-self) predicate found for this item. We use predicates from - /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an - /// opaque type, we also append the predicates from `explicit_item_bounds` to this - /// list. - index: usize, - r#trait: PolyTraitRef<'tcx>, - path: Path<'tcx>, - }, - /// The automatic clause `Self: Trait` present inside a `impl Trait for Type {}` item. - SelfImpl { - r#trait: PolyTraitRef<'tcx>, - path: Path<'tcx>, - }, - /// `dyn Trait` is a wrapped value with a virtual table for trait - /// `Trait`. In other words, a value `dyn Trait` is a dependent - /// triple that gathers a type τ, a value of type τ and an - /// instance of type `Trait`. - /// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that - /// built-in implementation. - Dyn, - /// A built-in trait whose implementation is computed by the compiler, such as `Sync`. - Builtin { r#trait: PolyTraitRef<'tcx> }, - /// An error happened while resolving traits. - Error(String), - } - - #[derive(Clone, Debug)] - pub struct ImplExpr<'tcx> { - /// The trait this is an impl for. - pub r#trait: PolyTraitRef<'tcx>, - /// The kind of implemention of the root of the tree. - pub r#impl: ImplExprAtom<'tcx>, - /// A list of `ImplExpr`s required to fully specify the trait references in `impl`. - pub args: Vec, - } - - #[tracing::instrument(level = "trace", skip(tcx, warn))] - fn impl_exprs<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - obligations: &[rustc_trait_selection::traits::Obligation< - 'tcx, - rustc_middle::ty::Predicate<'tcx>, - >], - warn: &impl Fn(&str), - ) -> Result>, String> { - obligations - .iter() - // Only keep depth-1 obligations to avoid duplicate impl exprs. - .filter(|obligation| obligation.recursion_depth == 1) - .filter_map(|obligation| { - obligation.predicate.as_trait_clause().map(|trait_ref| { - impl_expr( - tcx, - owner_id, - param_env, - &trait_ref.map_bound(|p| p.trait_ref), - warn, - ) - }) - }) - .collect() - } - - #[tracing::instrument(level = "trace", skip(tcx, param_env, warn))] - pub(super) fn impl_expr<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - tref: &rustc_middle::ty::PolyTraitRef<'tcx>, - // Call back into hax-related code to display a nice warning. - warn: &impl Fn(&str), - ) -> Result, String> { - use rustc_trait_selection::traits::{ - BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, - }; - - let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, *tref)); - let atom = match impl_source { - Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { - impl_def_id, - args: generics, - .. - })) => ImplExprAtom::Concrete { - def_id: impl_def_id, - generics, - }, - Ok(ImplSource::Param(_)) => { - match search_clause::path_to(tcx, owner_id, param_env, *tref) { - Some((path, apred)) => { - let r#trait = apred.clause.to_poly_trait_ref(); - match apred.origin { - BoundPredicateOrigin::SelfPred => { - ImplExprAtom::SelfImpl { r#trait, path } - } - BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound { - predicate: apred.clause.upcast(tcx), - index, - r#trait, - path, - }, - } - } - None => { - let msg = format!( - "Could not find a clause for `{tref:?}` in the item parameters" - ); - warn(&msg); - ImplExprAtom::Error(msg) - } - } - } - Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn, - Ok(ImplSource::Builtin(_, _)) => ImplExprAtom::Builtin { r#trait: *tref }, - Err(e) => { - let msg = format!( - "Could not find a clause for `{tref:?}` in the current context: `{e:?}`" - ); - warn(&msg); - ImplExprAtom::Error(msg) - } - }; - - let nested = match &impl_source { - Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { nested, .. })) => { - nested.as_slice() - } - Ok(ImplSource::Param(nested)) => nested.as_slice(), - // We ignore the contained obligations here. For example for `(): Send`, the - // obligations contained would be `[(): Send]`, which leads to an infinite loop. There - // might be important obligations here in other cases; we'll have to see if that comes - // up. - Ok(ImplSource::Builtin(_, _ignored)) => &[], - Err(_) => &[], - }; - let nested = impl_exprs(tcx, owner_id, param_env, nested, warn)?; - - Ok(ImplExpr { - r#impl: atom, - args: nested, - r#trait: *tref, - }) - } - - mod copy_paste_from_rustc { - use rustc_infer::infer::TyCtxtInferExt; - use rustc_middle::traits::CodegenObligationError; - use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; - use rustc_trait_selection::error_reporting::InferCtxtErrorExt; - use rustc_trait_selection::traits::{ - Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, - Unimplemented, - }; - - /// Attempts to resolve an obligation to an `ImplSource`. The result is - /// a shallow `ImplSource` resolution, meaning that we do not - /// (necessarily) resolve all nested obligations on the impl. Note - /// that type check should guarantee to us that all nested - /// obligations *could be* resolved if we wanted to. - /// - /// This also expects that `trait_ref` is fully normalized. - pub fn codegen_select_candidate<'tcx>( - tcx: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), - ) -> Result, CodegenObligationError> - { - let trait_ref = super::search_clause::erase_and_norm(tcx, param_env, trait_ref); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); - - let selection = match selcx.poly_select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => return Err(CodegenObligationError::Ambiguity), - Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), - Err(e) => { - panic!( - "Encountered error `{:?}` selecting `{:?}` during codegen", - e, trait_ref - ) - } - }; - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. - let ocx = ObligationCtxt::new(&infcx); - let impl_source = selection.map(|obligation| { - ocx.register_obligation(obligation.clone()); - obligation - }); - - // In principle, we only need to do this so long as `impl_source` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - // `rustc_monomorphize::collector` assumes there are no type errors. - // Cycle errors are the only post-monomorphization errors possible; emit them now so - // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. - for err in errors { - if let ScrubbedTraitError::Cycle(cycle) = err { - infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); - } - } - return Err(CodegenObligationError::FulfillmentError); - } - - let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = infcx.tcx.erase_regions(impl_source); - - if impl_source.has_infer() { - // Unused lifetimes on an impl get replaced with inference vars, but never resolved, - // causing the return value of a query to contain inference vars. We do not have a concept - // for this and will in fact ICE in stable hashing of the return value. So bail out instead. - infcx.tcx.dcx().has_errors().unwrap(); - return Err(CodegenObligationError::FulfillmentError); - } - - Ok(impl_source) - } - } -} - /// Given a clause `clause` in the context of some impl block `impl_did`, susbts correctly `Self` /// from `clause` and (1) derive a `Clause` and (2) resolve an `ImplExpr`. #[cfg(feature = "rustc")] @@ -742,7 +138,7 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - match rustc::impl_expr(s.base().tcx, s.owner_id(), s.param_env(), &trait_ref, &warn) { + match resolution::impl_expr(s.base().tcx, s.owner_id(), s.param_env(), &trait_ref, &warn) { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), } diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs new file mode 100644 index 000000000..b05d2f645 --- /dev/null +++ b/frontend/exporter/src/traits/resolution.rs @@ -0,0 +1,472 @@ +//! Trait resolution: given a trait reference, we track which local clause caused it to be true. +//! This module is independent from the rest of hax, in particular it doesn't use its +//! state-tracking machinery. + +use rustc_hir::def_id::DefId; +use rustc_middle::ty::*; + +/// Items have various predicates in scope. `path_to` uses them as a starting point for trait +/// resolution. This tracks where each of them comes from. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum BoundPredicateOrigin { + /// The `Self: Trait` predicate implicitly present within trait declarations (note: we + /// don't add it for trait implementations, should we?). + SelfPred, + /// The nth (non-self) predicate found for this item. We use predicates from + /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an opaque + /// type, we also append the predicates from `explicit_item_bounds` to this list. + Item(usize), +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct AnnotatedTraitPred<'tcx> { + pub origin: BoundPredicateOrigin, + pub clause: PolyTraitPredicate<'tcx>, +} + +/// The predicates to use as a starting point for resolving trait references within this +/// item. This is just like `TyCtxt::predicates_of`, but in the case of a trait or impl +/// item or closures, also includes the predicates defined on the parents. +fn initial_search_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + did: rustc_span::def_id::DefId, +) -> Vec> { + let (predicates, self_pred) = super::utils::predicates_of_or_above(tcx, did); + let predicates = predicates + .into_iter() + .enumerate() + .map(|(i, clause)| AnnotatedTraitPred { + origin: BoundPredicateOrigin::Item(i), + clause, + }); + let self_pred = self_pred.map(|clause| AnnotatedTraitPred { + origin: BoundPredicateOrigin::SelfPred, + clause, + }); + + self_pred.into_iter().chain(predicates).collect() +} + +// FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 +pub(crate) mod search_clause { + use crate::traits::utils::erase_and_norm; + + use super::{AnnotatedTraitPred, Path, PathChunk}; + use itertools::Itertools; + use rustc_hir::def_id::DefId; + use rustc_middle::ty::*; + use std::collections::{hash_map::Entry, HashMap}; + + #[tracing::instrument(level = "trace", skip(tcx))] + fn parents_trait_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + pred: PolyTraitPredicate<'tcx>, + ) -> Vec> { + let self_trait_ref = pred.to_poly_trait_ref(); + tcx.predicates_of(pred.def_id()) + .predicates + .iter() + // Substitute with the `self` args so that the clause makes sense in the + // outside context. + .map(|(clause, _span)| clause.instantiate_supertrait(tcx, self_trait_ref)) + .filter_map(|pred| pred.as_trait_clause()) + .collect() + } + + /// A candidate projects `self` along a path reaching some predicate. A candidate is + /// selected when its predicate is the one expected, aka `target`. + #[derive(Debug, Clone)] + struct Candidate<'tcx> { + path: Path<'tcx>, + pred: PolyTraitPredicate<'tcx>, + origin: AnnotatedTraitPred<'tcx>, + } + + /// Stores a set of predicates along with where they came from. + struct PredicateSearcher<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + candidates: HashMap, Candidate<'tcx>>, + } + + impl<'tcx> PredicateSearcher<'tcx> { + /// Initialize the elaborator with the predicates accessible within this item. + fn new_for_owner( + tcx: TyCtxt<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + owner_id: DefId, + ) -> Self { + let mut out = Self { + tcx, + param_env, + candidates: Default::default(), + }; + out.extend( + super::initial_search_predicates(tcx, owner_id) + .into_iter() + .map(|clause| Candidate { + path: vec![], + pred: clause.clause, + origin: clause, + }), + ); + out + } + + /// Insert new candidates and all their parent predicates. This deduplicates predicates + /// to avoid divergence. + fn extend(&mut self, candidates: impl IntoIterator>) { + let tcx = self.tcx; + // Filter out duplicated candidates. + let mut new_candidates = Vec::new(); + for mut candidate in candidates { + // Normalize and erase all lifetimes. + candidate.pred = erase_and_norm(tcx, self.param_env, candidate.pred); + if let Entry::Vacant(entry) = self.candidates.entry(candidate.pred) { + entry.insert(candidate.clone()); + new_candidates.push(candidate); + } + } + if !new_candidates.is_empty() { + self.extend_parents(new_candidates); + } + } + + /// Add the parents of these candidates. This is a separate function to avoid + /// polymorphic recursion due to the closures capturing the type parameters of this + /// function. + fn extend_parents(&mut self, new_candidates: Vec>) { + let tcx = self.tcx; + // Then recursively add their parents. This way ensures a breadth-first order, + // which means we select the shortest path when looking up predicates. + self.extend(new_candidates.into_iter().flat_map(|candidate| { + parents_trait_predicates(tcx, candidate.pred) + .into_iter() + .enumerate() + .map(move |(index, parent_pred)| { + let mut parent_candidate = Candidate { + pred: parent_pred, + path: candidate.path.clone(), + origin: candidate.origin, + }; + parent_candidate.path.push(PathChunk::Parent { + predicate: parent_pred, + index, + }); + parent_candidate + }) + })); + } + + /// Lookup a predicate in this set. If the predicate applies to an associated type, we + /// add the relevant implied associated type bounds to the set as well. + fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option<&Candidate<'tcx>> { + let tcx = self.tcx; + let target: PolyTraitPredicate = + erase_and_norm(tcx, self.param_env, target).upcast(tcx); + + // The predicate is `::Type: OtherTrait`. We look up `T as Trait` in + // the current context and add all the bounds on `Trait::Type` to our context. + // Note: We skip a binder but rebind it just after. + if let TyKind::Alias(AliasTyKind::Projection, alias_ty) = + target.self_ty().skip_binder().kind() + { + let trait_ref = target.rebind(alias_ty.trait_ref(tcx)); + // Recursively look up the trait ref inside `self`. + let trait_candidate = self.lookup(trait_ref)?.clone(); + let item_bounds = tcx + // TODO: `item_bounds` can contain parent traits, we don't want them + .item_bounds(alias_ty.def_id) + .instantiate(tcx, alias_ty.args) + .iter() + .filter_map(|pred| pred.as_trait_clause()) + .enumerate(); + // Add all the bounds on the corresponding associated item. + self.extend(item_bounds.map(|(index, pred)| { + let mut candidate = Candidate { + path: trait_candidate.path.clone(), + pred, + origin: trait_candidate.origin, + }; + candidate.path.push(PathChunk::AssocItem { + item: tcx.associated_item(alias_ty.def_id), + predicate: pred, + index, + }); + candidate + })); + } + + tracing::trace!("Looking for {target:?}"); + let ret = self.candidates.get(&target); + if ret.is_none() { + tracing::trace!( + "Couldn't find {target:?} in: [\n{}]", + self.candidates + .iter() + .map(|(_, c)| format!(" - {:?}\n", c.pred)) + .join("") + ); + } + ret + } + } + + #[tracing::instrument(level = "trace", skip(tcx, param_env))] + pub(super) fn path_to<'tcx>( + tcx: TyCtxt<'tcx>, + owner_id: DefId, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + target: PolyTraitRef<'tcx>, + ) -> Option<(Path<'tcx>, AnnotatedTraitPred<'tcx>)> { + let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); + let candidate = searcher.lookup(target)?; + Some((candidate.path.clone(), candidate.origin)) + } +} + +#[derive(Debug, Clone)] +pub enum PathChunk<'tcx> { + AssocItem { + item: AssocItem, + predicate: PolyTraitPredicate<'tcx>, + /// The nth predicate returned by `tcx.item_bounds`. + index: usize, + }, + Parent { + predicate: PolyTraitPredicate<'tcx>, + /// The nth predicate returned by `tcx.predicates_of`. + index: usize, + }, +} +pub type Path<'tcx> = Vec>; + +#[derive(Debug, Clone)] +pub enum ImplExprAtom<'tcx> { + /// A concrete `impl Trait for Type {}` item. + Concrete { + def_id: DefId, + generics: GenericArgsRef<'tcx>, + }, + /// A context-bound clause like `where T: Trait`. + LocalBound { + predicate: Predicate<'tcx>, + /// The nth (non-self) predicate found for this item. We use predicates from + /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an + /// opaque type, we also append the predicates from `explicit_item_bounds` to this + /// list. + index: usize, + r#trait: PolyTraitRef<'tcx>, + path: Path<'tcx>, + }, + /// The automatic clause `Self: Trait` present inside a `impl Trait for Type {}` item. + SelfImpl { + r#trait: PolyTraitRef<'tcx>, + path: Path<'tcx>, + }, + /// `dyn Trait` is a wrapped value with a virtual table for trait + /// `Trait`. In other words, a value `dyn Trait` is a dependent + /// triple that gathers a type τ, a value of type τ and an + /// instance of type `Trait`. + /// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that + /// built-in implementation. + Dyn, + /// A built-in trait whose implementation is computed by the compiler, such as `Sync`. + Builtin { r#trait: PolyTraitRef<'tcx> }, + /// An error happened while resolving traits. + Error(String), +} + +#[derive(Clone, Debug)] +pub struct ImplExpr<'tcx> { + /// The trait this is an impl for. + pub r#trait: PolyTraitRef<'tcx>, + /// The kind of implemention of the root of the tree. + pub r#impl: ImplExprAtom<'tcx>, + /// A list of `ImplExpr`s required to fully specify the trait references in `impl`. + pub args: Vec, +} + +#[tracing::instrument(level = "trace", skip(tcx, warn))] +fn impl_exprs<'tcx>( + tcx: TyCtxt<'tcx>, + owner_id: DefId, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + obligations: &[rustc_trait_selection::traits::Obligation< + 'tcx, + rustc_middle::ty::Predicate<'tcx>, + >], + warn: &impl Fn(&str), +) -> Result>, String> { + obligations + .iter() + // Only keep depth-1 obligations to avoid duplicate impl exprs. + .filter(|obligation| obligation.recursion_depth == 1) + .filter_map(|obligation| { + obligation.predicate.as_trait_clause().map(|trait_ref| { + impl_expr( + tcx, + owner_id, + param_env, + &trait_ref.map_bound(|p| p.trait_ref), + warn, + ) + }) + }) + .collect() +} + +#[tracing::instrument(level = "trace", skip(tcx, param_env, warn))] +pub(super) fn impl_expr<'tcx>( + tcx: TyCtxt<'tcx>, + owner_id: DefId, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + tref: &rustc_middle::ty::PolyTraitRef<'tcx>, + // Call back into hax-related code to display a nice warning. + warn: &impl Fn(&str), +) -> Result, String> { + use rustc_trait_selection::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; + + let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, *tref)); + let atom = match impl_source { + Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, + args: generics, + .. + })) => ImplExprAtom::Concrete { + def_id: impl_def_id, + generics, + }, + Ok(ImplSource::Param(_)) => match search_clause::path_to(tcx, owner_id, param_env, *tref) { + Some((path, apred)) => { + let r#trait = apred.clause.to_poly_trait_ref(); + match apred.origin { + BoundPredicateOrigin::SelfPred => ImplExprAtom::SelfImpl { r#trait, path }, + BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound { + predicate: apred.clause.upcast(tcx), + index, + r#trait, + path, + }, + } + } + None => { + let msg = format!("Could not find a clause for `{tref:?}` in the item parameters"); + warn(&msg); + ImplExprAtom::Error(msg) + } + }, + Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn, + Ok(ImplSource::Builtin(_, _)) => ImplExprAtom::Builtin { r#trait: *tref }, + Err(e) => { + let msg = + format!("Could not find a clause for `{tref:?}` in the current context: `{e:?}`"); + warn(&msg); + ImplExprAtom::Error(msg) + } + }; + + let nested = match &impl_source { + Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { nested, .. })) => nested.as_slice(), + Ok(ImplSource::Param(nested)) => nested.as_slice(), + // We ignore the contained obligations here. For example for `(): Send`, the + // obligations contained would be `[(): Send]`, which leads to an infinite loop. There + // might be important obligations here in other cases; we'll have to see if that comes + // up. + Ok(ImplSource::Builtin(_, _ignored)) => &[], + Err(_) => &[], + }; + let nested = impl_exprs(tcx, owner_id, param_env, nested, warn)?; + + Ok(ImplExpr { + r#impl: atom, + args: nested, + r#trait: *tref, + }) +} + +mod copy_paste_from_rustc { + use rustc_infer::infer::TyCtxtInferExt; + use rustc_middle::traits::CodegenObligationError; + use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; + use rustc_trait_selection::error_reporting::InferCtxtErrorExt; + use rustc_trait_selection::traits::{ + Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, + Unimplemented, + }; + + use crate::traits::utils::erase_and_norm; + + /// Attempts to resolve an obligation to an `ImplSource`. The result is + /// a shallow `ImplSource` resolution, meaning that we do not + /// (necessarily) resolve all nested obligations on the impl. Note + /// that type check should guarantee to us that all nested + /// obligations *could be* resolved if we wanted to. + /// + /// This also expects that `trait_ref` is fully normalized. + pub fn codegen_select_candidate<'tcx>( + tcx: TyCtxt<'tcx>, + (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), + ) -> Result, CodegenObligationError> { + let trait_ref = erase_and_norm(tcx, param_env, trait_ref); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); + + let selection = match selcx.poly_select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(e) => { + panic!( + "Encountered error `{:?}` selecting `{:?}` during codegen", + e, trait_ref + ) + } + }; + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. + let ocx = ObligationCtxt::new(&infcx); + let impl_source = selection.map(|obligation| { + ocx.register_obligation(obligation.clone()); + obligation + }); + + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + // `rustc_monomorphize::collector` assumes there are no type errors. + // Cycle errors are the only post-monomorphization errors possible; emit them now so + // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. + for err in errors { + if let ScrubbedTraitError::Cycle(cycle) = err { + infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); + } + } + return Err(CodegenObligationError::FulfillmentError); + } + + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); + + if impl_source.has_infer() { + // Unused lifetimes on an impl get replaced with inference vars, but never resolved, + // causing the return value of a query to contain inference vars. We do not have a concept + // for this and will in fact ICE in stable hashing of the return value. So bail out instead. + infcx.tcx.dcx().has_errors().unwrap(); + return Err(CodegenObligationError::FulfillmentError); + } + + Ok(impl_source) + } +} diff --git a/frontend/exporter/src/traits/utils.rs b/frontend/exporter/src/traits/utils.rs new file mode 100644 index 000000000..92c11fd2f --- /dev/null +++ b/frontend/exporter/src/traits/utils.rs @@ -0,0 +1,128 @@ +use rustc_hir::def::DefKind; +use rustc_middle::ty::*; + +/// Just like `TyCtxt::predicates_of`, but in the case of a trait or impl item or closures, +/// also includes the predicates defined on the parents. Also this returns the special +/// `Self` clause separately. +pub fn predicates_of_or_above<'tcx>( + tcx: TyCtxt<'tcx>, + did: rustc_span::def_id::DefId, +) -> ( + Vec>, + Option>, +) { + use DefKind::*; + let def_kind = tcx.def_kind(did); + + let (mut predicates, mut self_pred) = match def_kind { + // These inherit some predicates from their parent. + AssocTy | AssocFn | AssocConst | Closure => { + let parent = tcx.parent(did); + predicates_of_or_above(tcx, parent) + } + _ => (vec![], None), + }; + + match def_kind { + // Don't list the predicates of traits, we already list the `Self` clause from + // which we can resolve anything needed. + Trait => {} + AssocConst + | AssocFn + | AssocTy + | Const + | Enum + | Fn + | ForeignTy + | Impl { .. } + | OpaqueTy + | Static { .. } + | Struct + | TraitAlias + | TyAlias + | Union => { + // Only these kinds may reasonably have predicates; we have to filter + // otherwise calling `predicates_defined_on` may ICE. + predicates.extend( + tcx.predicates_defined_on(did) + .predicates + .iter() + .filter_map(|(clause, _span)| clause.as_trait_clause()), + ); + } + _ => {} + } + + // Add some extra predicates that aren't in `predicates_defined_on`. + match def_kind { + OpaqueTy => { + // An opaque type (e.g. `impl Trait`) provides predicates by itself: we need to + // account for them. + // TODO: is this still useful? The test that used to require this doesn't anymore. + predicates.extend( + tcx.explicit_item_bounds(did) + .skip_binder() // Skips an `EarlyBinder`, likely for GATs + .iter() + .filter_map(|(clause, _span)| clause.as_trait_clause()), + ) + } + Trait => { + // Add the special `Self: Trait` clause. + // Copied from the code of `tcx.predicates_of()`. + let self_clause: Clause<'_> = TraitRef::identity(tcx, did).upcast(tcx); + self_pred = Some(self_clause.as_trait_clause().unwrap()); + } + _ => {} + } + + (predicates, self_pred) +} + +/// Erase all regions. Largely copied from `tcx.erase_regions`. +pub fn erase_all_regions<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> T +where + T: TypeFoldable>, +{ + use rustc_middle::ty; + struct RegionEraserVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> TypeFolder> for RegionEraserVisitor<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + ty.super_fold_with(self) + } + + fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> + where + T: TypeFoldable>, + { + // Empty the binder + Binder::dummy(t.skip_binder().fold_with(self)) + } + + fn fold_region(&mut self, _r: ty::Region<'tcx>) -> ty::Region<'tcx> { + // We erase bound regions despite it being possibly incorrect. `for<'a> fn(&'a + // ())` and `fn(&'free ())` are different types: they may implement different + // traits and have a different `TypeId`. It's unclear whether this can cause us + // to select the wrong trait reference. + self.tcx.lifetimes.re_erased + } + } + value.fold_with(&mut RegionEraserVisitor { tcx }) +} + +// Lifetimes are irrelevant when resolving instances. +pub fn erase_and_norm<'tcx, T>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, x: T) -> T +where + T: TypeFoldable> + Copy, +{ + erase_all_regions( + tcx, + tcx.try_normalize_erasing_regions(param_env, x).unwrap_or(x), + ) +} diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 250498de5..eee73b8d5 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1797,8 +1797,7 @@ impl Alias { // yet we dont have a binder around (could even be several). Binding this correctly // is therefore difficult. Since our trait resolution ignores lifetimes anyway, we // just erase them. See also https://github.com/hacspec/hax/issues/747. - let trait_ref = - traits::rustc::search_clause::erase_and_norm(tcx, s.param_env(), trait_ref); + let trait_ref = crate::traits::erase_and_norm(tcx, s.param_env(), trait_ref); AliasKind::Projection { assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), impl_expr: solve_trait(s, ty::Binder::dummy(trait_ref)), From 780a6798abe7685c5b3544f452b509a43d8467bb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:07:23 +0200 Subject: [PATCH 016/253] Reorganize a little --- frontend/exporter/src/traits/resolution.rs | 431 ++++++++++----------- 1 file changed, 212 insertions(+), 219 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index b05d2f645..ffa5eea8e 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -2,9 +2,76 @@ //! This module is independent from the rest of hax, in particular it doesn't use its //! state-tracking machinery. +use itertools::Itertools; +use std::collections::{hash_map::Entry, HashMap}; + use rustc_hir::def_id::DefId; use rustc_middle::ty::*; +use crate::traits::utils::erase_and_norm; + +#[derive(Debug, Clone)] +pub enum PathChunk<'tcx> { + AssocItem { + item: AssocItem, + predicate: PolyTraitPredicate<'tcx>, + /// The nth predicate returned by `tcx.item_bounds`. + index: usize, + }, + Parent { + predicate: PolyTraitPredicate<'tcx>, + /// The nth predicate returned by `tcx.predicates_of`. + index: usize, + }, +} +pub type Path<'tcx> = Vec>; + +#[derive(Debug, Clone)] +pub enum ImplExprAtom<'tcx> { + /// A concrete `impl Trait for Type {}` item. + Concrete { + def_id: DefId, + generics: GenericArgsRef<'tcx>, + }, + /// A context-bound clause like `where T: Trait`. + LocalBound { + predicate: Predicate<'tcx>, + /// The nth (non-self) predicate found for this item. We use predicates from + /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an + /// opaque type, we also append the predicates from `explicit_item_bounds` to this + /// list. + index: usize, + r#trait: PolyTraitRef<'tcx>, + path: Path<'tcx>, + }, + /// The automatic clause `Self: Trait` present inside a `impl Trait for Type {}` item. + SelfImpl { + r#trait: PolyTraitRef<'tcx>, + path: Path<'tcx>, + }, + /// `dyn Trait` is a wrapped value with a virtual table for trait + /// `Trait`. In other words, a value `dyn Trait` is a dependent + /// triple that gathers a type τ, a value of type τ and an + /// instance of type `Trait`. + /// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that + /// built-in implementation. + Dyn, + /// A built-in trait whose implementation is computed by the compiler, such as `Sync`. + Builtin { r#trait: PolyTraitRef<'tcx> }, + /// An error happened while resolving traits. + Error(String), +} + +#[derive(Clone, Debug)] +pub struct ImplExpr<'tcx> { + /// The trait this is an impl for. + pub r#trait: PolyTraitRef<'tcx>, + /// The kind of implemention of the root of the tree. + pub r#impl: ImplExprAtom<'tcx>, + /// A list of `ImplExpr`s required to fully specify the trait references in `impl`. + pub args: Vec, +} + /// Items have various predicates in scope. `path_to` uses them as a starting point for trait /// resolution. This tracks where each of them comes from. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] @@ -47,244 +114,170 @@ fn initial_search_predicates<'tcx>( self_pred.into_iter().chain(predicates).collect() } -// FIXME: this has visibility `pub(crate)` only because of https://github.com/rust-lang/rust/issues/83049 -pub(crate) mod search_clause { - use crate::traits::utils::erase_and_norm; - - use super::{AnnotatedTraitPred, Path, PathChunk}; - use itertools::Itertools; - use rustc_hir::def_id::DefId; - use rustc_middle::ty::*; - use std::collections::{hash_map::Entry, HashMap}; +#[tracing::instrument(level = "trace", skip(tcx))] +fn parents_trait_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + pred: PolyTraitPredicate<'tcx>, +) -> Vec> { + let self_trait_ref = pred.to_poly_trait_ref(); + tcx.predicates_of(pred.def_id()) + .predicates + .iter() + // Substitute with the `self` args so that the clause makes sense in the + // outside context. + .map(|(clause, _span)| clause.instantiate_supertrait(tcx, self_trait_ref)) + .filter_map(|pred| pred.as_trait_clause()) + .collect() +} - #[tracing::instrument(level = "trace", skip(tcx))] - fn parents_trait_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - pred: PolyTraitPredicate<'tcx>, - ) -> Vec> { - let self_trait_ref = pred.to_poly_trait_ref(); - tcx.predicates_of(pred.def_id()) - .predicates - .iter() - // Substitute with the `self` args so that the clause makes sense in the - // outside context. - .map(|(clause, _span)| clause.instantiate_supertrait(tcx, self_trait_ref)) - .filter_map(|pred| pred.as_trait_clause()) - .collect() - } +/// A candidate projects `self` along a path reaching some predicate. A candidate is +/// selected when its predicate is the one expected, aka `target`. +#[derive(Debug, Clone)] +struct Candidate<'tcx> { + path: Path<'tcx>, + pred: PolyTraitPredicate<'tcx>, + origin: AnnotatedTraitPred<'tcx>, +} - /// A candidate projects `self` along a path reaching some predicate. A candidate is - /// selected when its predicate is the one expected, aka `target`. - #[derive(Debug, Clone)] - struct Candidate<'tcx> { - path: Path<'tcx>, - pred: PolyTraitPredicate<'tcx>, - origin: AnnotatedTraitPred<'tcx>, - } +/// Stores a set of predicates along with where they came from. +struct PredicateSearcher<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + candidates: HashMap, Candidate<'tcx>>, +} - /// Stores a set of predicates along with where they came from. - struct PredicateSearcher<'tcx> { +impl<'tcx> PredicateSearcher<'tcx> { + /// Initialize the elaborator with the predicates accessible within this item. + fn new_for_owner( tcx: TyCtxt<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, - candidates: HashMap, Candidate<'tcx>>, + owner_id: DefId, + ) -> Self { + let mut out = Self { + tcx, + param_env, + candidates: Default::default(), + }; + out.extend( + initial_search_predicates(tcx, owner_id) + .into_iter() + .map(|clause| Candidate { + path: vec![], + pred: clause.clause, + origin: clause, + }), + ); + out } - impl<'tcx> PredicateSearcher<'tcx> { - /// Initialize the elaborator with the predicates accessible within this item. - fn new_for_owner( - tcx: TyCtxt<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - owner_id: DefId, - ) -> Self { - let mut out = Self { - tcx, - param_env, - candidates: Default::default(), - }; - out.extend( - super::initial_search_predicates(tcx, owner_id) - .into_iter() - .map(|clause| Candidate { - path: vec![], - pred: clause.clause, - origin: clause, - }), - ); - out - } - - /// Insert new candidates and all their parent predicates. This deduplicates predicates - /// to avoid divergence. - fn extend(&mut self, candidates: impl IntoIterator>) { - let tcx = self.tcx; - // Filter out duplicated candidates. - let mut new_candidates = Vec::new(); - for mut candidate in candidates { - // Normalize and erase all lifetimes. - candidate.pred = erase_and_norm(tcx, self.param_env, candidate.pred); - if let Entry::Vacant(entry) = self.candidates.entry(candidate.pred) { - entry.insert(candidate.clone()); - new_candidates.push(candidate); - } - } - if !new_candidates.is_empty() { - self.extend_parents(new_candidates); + /// Insert new candidates and all their parent predicates. This deduplicates predicates + /// to avoid divergence. + fn extend(&mut self, candidates: impl IntoIterator>) { + let tcx = self.tcx; + // Filter out duplicated candidates. + let mut new_candidates = Vec::new(); + for mut candidate in candidates { + // Normalize and erase all lifetimes. + candidate.pred = erase_and_norm(tcx, self.param_env, candidate.pred); + if let Entry::Vacant(entry) = self.candidates.entry(candidate.pred) { + entry.insert(candidate.clone()); + new_candidates.push(candidate); } } - - /// Add the parents of these candidates. This is a separate function to avoid - /// polymorphic recursion due to the closures capturing the type parameters of this - /// function. - fn extend_parents(&mut self, new_candidates: Vec>) { - let tcx = self.tcx; - // Then recursively add their parents. This way ensures a breadth-first order, - // which means we select the shortest path when looking up predicates. - self.extend(new_candidates.into_iter().flat_map(|candidate| { - parents_trait_predicates(tcx, candidate.pred) - .into_iter() - .enumerate() - .map(move |(index, parent_pred)| { - let mut parent_candidate = Candidate { - pred: parent_pred, - path: candidate.path.clone(), - origin: candidate.origin, - }; - parent_candidate.path.push(PathChunk::Parent { - predicate: parent_pred, - index, - }); - parent_candidate - }) - })); + if !new_candidates.is_empty() { + self.extend_parents(new_candidates); } + } - /// Lookup a predicate in this set. If the predicate applies to an associated type, we - /// add the relevant implied associated type bounds to the set as well. - fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option<&Candidate<'tcx>> { - let tcx = self.tcx; - let target: PolyTraitPredicate = - erase_and_norm(tcx, self.param_env, target).upcast(tcx); - - // The predicate is `::Type: OtherTrait`. We look up `T as Trait` in - // the current context and add all the bounds on `Trait::Type` to our context. - // Note: We skip a binder but rebind it just after. - if let TyKind::Alias(AliasTyKind::Projection, alias_ty) = - target.self_ty().skip_binder().kind() - { - let trait_ref = target.rebind(alias_ty.trait_ref(tcx)); - // Recursively look up the trait ref inside `self`. - let trait_candidate = self.lookup(trait_ref)?.clone(); - let item_bounds = tcx - // TODO: `item_bounds` can contain parent traits, we don't want them - .item_bounds(alias_ty.def_id) - .instantiate(tcx, alias_ty.args) - .iter() - .filter_map(|pred| pred.as_trait_clause()) - .enumerate(); - // Add all the bounds on the corresponding associated item. - self.extend(item_bounds.map(|(index, pred)| { - let mut candidate = Candidate { - path: trait_candidate.path.clone(), - pred, - origin: trait_candidate.origin, + /// Add the parents of these candidates. This is a separate function to avoid + /// polymorphic recursion due to the closures capturing the type parameters of this + /// function. + fn extend_parents(&mut self, new_candidates: Vec>) { + let tcx = self.tcx; + // Then recursively add their parents. This way ensures a breadth-first order, + // which means we select the shortest path when looking up predicates. + self.extend(new_candidates.into_iter().flat_map(|candidate| { + parents_trait_predicates(tcx, candidate.pred) + .into_iter() + .enumerate() + .map(move |(index, parent_pred)| { + let mut parent_candidate = Candidate { + pred: parent_pred, + path: candidate.path.clone(), + origin: candidate.origin, }; - candidate.path.push(PathChunk::AssocItem { - item: tcx.associated_item(alias_ty.def_id), - predicate: pred, + parent_candidate.path.push(PathChunk::Parent { + predicate: parent_pred, index, }); - candidate - })); - } + parent_candidate + }) + })); + } - tracing::trace!("Looking for {target:?}"); - let ret = self.candidates.get(&target); - if ret.is_none() { - tracing::trace!( - "Couldn't find {target:?} in: [\n{}]", - self.candidates - .iter() - .map(|(_, c)| format!(" - {:?}\n", c.pred)) - .join("") - ); - } - ret + /// Lookup a predicate in this set. If the predicate applies to an associated type, we + /// add the relevant implied associated type bounds to the set as well. + fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option<&Candidate<'tcx>> { + let tcx = self.tcx; + let target: PolyTraitPredicate = erase_and_norm(tcx, self.param_env, target).upcast(tcx); + + // The predicate is `::Type: OtherTrait`. We look up `T as Trait` in + // the current context and add all the bounds on `Trait::Type` to our context. + // Note: We skip a binder but rebind it just after. + if let TyKind::Alias(AliasTyKind::Projection, alias_ty) = + target.self_ty().skip_binder().kind() + { + let trait_ref = target.rebind(alias_ty.trait_ref(tcx)); + // Recursively look up the trait ref inside `self`. + let trait_candidate = self.lookup(trait_ref)?.clone(); + let item_bounds = tcx + // TODO: `item_bounds` can contain parent traits, we don't want them + .item_bounds(alias_ty.def_id) + .instantiate(tcx, alias_ty.args) + .iter() + .filter_map(|pred| pred.as_trait_clause()) + .enumerate(); + // Add all the bounds on the corresponding associated item. + self.extend(item_bounds.map(|(index, pred)| { + let mut candidate = Candidate { + path: trait_candidate.path.clone(), + pred, + origin: trait_candidate.origin, + }; + candidate.path.push(PathChunk::AssocItem { + item: tcx.associated_item(alias_ty.def_id), + predicate: pred, + index, + }); + candidate + })); } - } - #[tracing::instrument(level = "trace", skip(tcx, param_env))] - pub(super) fn path_to<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - target: PolyTraitRef<'tcx>, - ) -> Option<(Path<'tcx>, AnnotatedTraitPred<'tcx>)> { - let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); - let candidate = searcher.lookup(target)?; - Some((candidate.path.clone(), candidate.origin)) + tracing::trace!("Looking for {target:?}"); + let ret = self.candidates.get(&target); + if ret.is_none() { + tracing::trace!( + "Couldn't find {target:?} in: [\n{}]", + self.candidates + .iter() + .map(|(_, c)| format!(" - {:?}\n", c.pred)) + .join("") + ); + } + ret } } -#[derive(Debug, Clone)] -pub enum PathChunk<'tcx> { - AssocItem { - item: AssocItem, - predicate: PolyTraitPredicate<'tcx>, - /// The nth predicate returned by `tcx.item_bounds`. - index: usize, - }, - Parent { - predicate: PolyTraitPredicate<'tcx>, - /// The nth predicate returned by `tcx.predicates_of`. - index: usize, - }, -} -pub type Path<'tcx> = Vec>; - -#[derive(Debug, Clone)] -pub enum ImplExprAtom<'tcx> { - /// A concrete `impl Trait for Type {}` item. - Concrete { - def_id: DefId, - generics: GenericArgsRef<'tcx>, - }, - /// A context-bound clause like `where T: Trait`. - LocalBound { - predicate: Predicate<'tcx>, - /// The nth (non-self) predicate found for this item. We use predicates from - /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an - /// opaque type, we also append the predicates from `explicit_item_bounds` to this - /// list. - index: usize, - r#trait: PolyTraitRef<'tcx>, - path: Path<'tcx>, - }, - /// The automatic clause `Self: Trait` present inside a `impl Trait for Type {}` item. - SelfImpl { - r#trait: PolyTraitRef<'tcx>, - path: Path<'tcx>, - }, - /// `dyn Trait` is a wrapped value with a virtual table for trait - /// `Trait`. In other words, a value `dyn Trait` is a dependent - /// triple that gathers a type τ, a value of type τ and an - /// instance of type `Trait`. - /// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that - /// built-in implementation. - Dyn, - /// A built-in trait whose implementation is computed by the compiler, such as `Sync`. - Builtin { r#trait: PolyTraitRef<'tcx> }, - /// An error happened while resolving traits. - Error(String), -} - -#[derive(Clone, Debug)] -pub struct ImplExpr<'tcx> { - /// The trait this is an impl for. - pub r#trait: PolyTraitRef<'tcx>, - /// The kind of implemention of the root of the tree. - pub r#impl: ImplExprAtom<'tcx>, - /// A list of `ImplExpr`s required to fully specify the trait references in `impl`. - pub args: Vec, +#[tracing::instrument(level = "trace", skip(tcx, param_env))] +pub(super) fn path_to<'tcx>( + tcx: TyCtxt<'tcx>, + owner_id: DefId, + param_env: rustc_middle::ty::ParamEnv<'tcx>, + target: PolyTraitRef<'tcx>, +) -> Option<(Path<'tcx>, AnnotatedTraitPred<'tcx>)> { + let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); + let candidate = searcher.lookup(target)?; + Some((candidate.path.clone(), candidate.origin)) } #[tracing::instrument(level = "trace", skip(tcx, warn))] @@ -337,7 +330,7 @@ pub(super) fn impl_expr<'tcx>( def_id: impl_def_id, generics, }, - Ok(ImplSource::Param(_)) => match search_clause::path_to(tcx, owner_id, param_env, *tref) { + Ok(ImplSource::Param(_)) => match path_to(tcx, owner_id, param_env, *tref) { Some((path, apred)) => { let r#trait = apred.clause.to_poly_trait_ref(); match apred.origin { From d04d36a12f0b72a3627ae9323b9f5e127c7f40ce Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:20:13 +0200 Subject: [PATCH 017/253] Inline two functions --- frontend/exporter/src/traits/resolution.rs | 97 +++++++++------------- 1 file changed, 38 insertions(+), 59 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index ffa5eea8e..b7b3715fb 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -268,47 +268,6 @@ impl<'tcx> PredicateSearcher<'tcx> { } } -#[tracing::instrument(level = "trace", skip(tcx, param_env))] -pub(super) fn path_to<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - target: PolyTraitRef<'tcx>, -) -> Option<(Path<'tcx>, AnnotatedTraitPred<'tcx>)> { - let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); - let candidate = searcher.lookup(target)?; - Some((candidate.path.clone(), candidate.origin)) -} - -#[tracing::instrument(level = "trace", skip(tcx, warn))] -fn impl_exprs<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - obligations: &[rustc_trait_selection::traits::Obligation< - 'tcx, - rustc_middle::ty::Predicate<'tcx>, - >], - warn: &impl Fn(&str), -) -> Result>, String> { - obligations - .iter() - // Only keep depth-1 obligations to avoid duplicate impl exprs. - .filter(|obligation| obligation.recursion_depth == 1) - .filter_map(|obligation| { - obligation.predicate.as_trait_clause().map(|trait_ref| { - impl_expr( - tcx, - owner_id, - param_env, - &trait_ref.map_bound(|p| p.trait_ref), - warn, - ) - }) - }) - .collect() -} - #[tracing::instrument(level = "trace", skip(tcx, param_env, warn))] pub(super) fn impl_expr<'tcx>( tcx: TyCtxt<'tcx>, @@ -330,25 +289,30 @@ pub(super) fn impl_expr<'tcx>( def_id: impl_def_id, generics, }, - Ok(ImplSource::Param(_)) => match path_to(tcx, owner_id, param_env, *tref) { - Some((path, apred)) => { - let r#trait = apred.clause.to_poly_trait_ref(); - match apred.origin { - BoundPredicateOrigin::SelfPred => ImplExprAtom::SelfImpl { r#trait, path }, - BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound { - predicate: apred.clause.upcast(tcx), - index, - r#trait, - path, - }, + Ok(ImplSource::Param(_)) => { + let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); + match searcher.lookup(*tref) { + Some(candidate) => { + let path = candidate.path.clone(); + let r#trait = candidate.origin.clause.to_poly_trait_ref(); + match candidate.origin.origin { + BoundPredicateOrigin::SelfPred => ImplExprAtom::SelfImpl { r#trait, path }, + BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound { + predicate: candidate.origin.clause.upcast(tcx), + index, + r#trait, + path, + }, + } + } + None => { + let msg = + format!("Could not find a clause for `{tref:?}` in the item parameters"); + warn(&msg); + ImplExprAtom::Error(msg) } } - None => { - let msg = format!("Could not find a clause for `{tref:?}` in the item parameters"); - warn(&msg); - ImplExprAtom::Error(msg) - } - }, + } Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn, Ok(ImplSource::Builtin(_, _)) => ImplExprAtom::Builtin { r#trait: *tref }, Err(e) => { @@ -369,7 +333,22 @@ pub(super) fn impl_expr<'tcx>( Ok(ImplSource::Builtin(_, _ignored)) => &[], Err(_) => &[], }; - let nested = impl_exprs(tcx, owner_id, param_env, nested, warn)?; + let nested = nested + .iter() + // Only keep depth-1 obligations to avoid duplicate impl exprs. + .filter(|obligation| obligation.recursion_depth == 1) + .filter_map(|obligation| { + obligation.predicate.as_trait_clause().map(|trait_ref| { + impl_expr( + tcx, + owner_id, + param_env, + &trait_ref.map_bound(|p| p.trait_ref), + warn, + ) + }) + }) + .collect::>()?; Ok(ImplExpr { r#impl: atom, From dd9c077ad7f17e229b99be18a45f5bd805b87b61 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:24:11 +0200 Subject: [PATCH 018/253] Keep the same `PredicateSearcher` when resolving nested obligations --- frontend/exporter/src/traits.rs | 5 +- frontend/exporter/src/traits/resolution.rs | 132 ++++++++++----------- 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index f952018c0..dd5448904 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -138,7 +138,10 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - match resolution::impl_expr(s.base().tcx, s.owner_id(), s.param_env(), &trait_ref, &warn) { + let tcx = s.base().tcx; + let mut searcher = + resolution::PredicateSearcher::new_for_owner(tcx, s.param_env(), s.owner_id()); + match searcher.resolve(&trait_ref, &warn) { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), } diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index b7b3715fb..7ae06b771 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -140,7 +140,7 @@ struct Candidate<'tcx> { } /// Stores a set of predicates along with where they came from. -struct PredicateSearcher<'tcx> { +pub(super) struct PredicateSearcher<'tcx> { tcx: TyCtxt<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, candidates: HashMap, Candidate<'tcx>>, @@ -148,7 +148,7 @@ struct PredicateSearcher<'tcx> { impl<'tcx> PredicateSearcher<'tcx> { /// Initialize the elaborator with the predicates accessible within this item. - fn new_for_owner( + pub(super) fn new_for_owner( tcx: TyCtxt<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, owner_id: DefId, @@ -266,32 +266,32 @@ impl<'tcx> PredicateSearcher<'tcx> { } ret } -} -#[tracing::instrument(level = "trace", skip(tcx, param_env, warn))] -pub(super) fn impl_expr<'tcx>( - tcx: TyCtxt<'tcx>, - owner_id: DefId, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - tref: &rustc_middle::ty::PolyTraitRef<'tcx>, - // Call back into hax-related code to display a nice warning. - warn: &impl Fn(&str), -) -> Result, String> { - use rustc_trait_selection::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; - - let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, *tref)); - let atom = match impl_source { - Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { - impl_def_id, - args: generics, - .. - })) => ImplExprAtom::Concrete { - def_id: impl_def_id, - generics, - }, - Ok(ImplSource::Param(_)) => { - let mut searcher = PredicateSearcher::new_for_owner(tcx, param_env, owner_id); - match searcher.lookup(*tref) { + /// Resolve the given trait reference in the local context. + #[tracing::instrument(level = "trace", skip(self, warn))] + pub(super) fn resolve( + &mut self, + tref: &rustc_middle::ty::PolyTraitRef<'tcx>, + // Call back into hax-related code to display a nice warning. + warn: &impl Fn(&str), + ) -> Result, String> { + use rustc_trait_selection::traits::{ + BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, + }; + + let tcx = self.tcx; + let impl_source = + copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, *tref)); + let atom = match impl_source { + Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, + args: generics, + .. + })) => ImplExprAtom::Concrete { + def_id: impl_def_id, + generics, + }, + Ok(ImplSource::Param(_)) => match self.lookup(*tref) { Some(candidate) => { let path = candidate.path.clone(); let r#trait = candidate.origin.clause.to_poly_trait_ref(); @@ -311,50 +311,48 @@ pub(super) fn impl_expr<'tcx>( warn(&msg); ImplExprAtom::Error(msg) } + }, + Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn, + Ok(ImplSource::Builtin(_, _)) => ImplExprAtom::Builtin { r#trait: *tref }, + Err(e) => { + let msg = format!( + "Could not find a clause for `{tref:?}` in the current context: `{e:?}`" + ); + warn(&msg); + ImplExprAtom::Error(msg) } - } - Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn, - Ok(ImplSource::Builtin(_, _)) => ImplExprAtom::Builtin { r#trait: *tref }, - Err(e) => { - let msg = - format!("Could not find a clause for `{tref:?}` in the current context: `{e:?}`"); - warn(&msg); - ImplExprAtom::Error(msg) - } - }; + }; - let nested = match &impl_source { - Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { nested, .. })) => nested.as_slice(), - Ok(ImplSource::Param(nested)) => nested.as_slice(), - // We ignore the contained obligations here. For example for `(): Send`, the - // obligations contained would be `[(): Send]`, which leads to an infinite loop. There - // might be important obligations here in other cases; we'll have to see if that comes - // up. - Ok(ImplSource::Builtin(_, _ignored)) => &[], - Err(_) => &[], - }; - let nested = nested - .iter() - // Only keep depth-1 obligations to avoid duplicate impl exprs. - .filter(|obligation| obligation.recursion_depth == 1) - .filter_map(|obligation| { - obligation.predicate.as_trait_clause().map(|trait_ref| { - impl_expr( - tcx, - owner_id, - param_env, - &trait_ref.map_bound(|p| p.trait_ref), - warn, - ) + let nested = match &impl_source { + Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { nested, .. })) => { + nested.as_slice() + } + Ok(ImplSource::Param(nested)) => nested.as_slice(), + // We ignore the contained obligations here. For example for `(): Send`, the + // obligations contained would be `[(): Send]`, which leads to an infinite loop. There + // might be important obligations here in other cases; we'll have to see if that comes + // up. + Ok(ImplSource::Builtin(_, _ignored)) => &[], + Err(_) => &[], + }; + let nested = nested + .iter() + // Only keep depth-1 obligations to avoid duplicate impl exprs. + .filter(|obligation| obligation.recursion_depth == 1) + .filter_map(|obligation| { + obligation + .predicate + .as_trait_clause() + .map(|trait_ref| self.resolve(&trait_ref.map_bound(|p| p.trait_ref), warn)) }) - }) - .collect::>()?; + .collect::>()?; - Ok(ImplExpr { - r#impl: atom, - args: nested, - r#trait: *tref, - }) + Ok(ImplExpr { + r#impl: atom, + args: nested, + r#trait: *tref, + }) + } } mod copy_paste_from_rustc { From a417b9cad05eb9657b2a0f85f82bb74207c1ba63 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:31:46 +0200 Subject: [PATCH 019/253] Factor out a function --- frontend/exporter/src/traits/resolution.rs | 72 ++++++++++++---------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 7ae06b771..7f111ce18 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -215,43 +215,53 @@ impl<'tcx> PredicateSearcher<'tcx> { })); } + /// If the type is a trait associated type, we add any relevant bounds to our context. + fn add_associated_type_refs(&mut self, ty: Binder<'tcx, Ty<'tcx>>) { + let tcx = self.tcx; + // Note: We skip a binder but rebind it just after. + let TyKind::Alias(AliasTyKind::Projection, alias_ty) = ty.skip_binder().kind() else { + return; + }; + let trait_ref = ty.rebind(alias_ty.trait_ref(tcx)); + + // The predicate we're looking for is is `::Type: OtherTrait`. We look up `T as + // Trait` in the current context and add all the bounds on `Trait::Type` to our context. + let Some(trait_candidate) = self.lookup(trait_ref).cloned() else { + return; + }; + + let item_bounds = tcx + // TODO: `item_bounds` can contain parent traits, we don't want them + .item_bounds(alias_ty.def_id) + .instantiate(tcx, alias_ty.args) + .iter() + .filter_map(|pred| pred.as_trait_clause()) + .enumerate(); + + // Add all the bounds on the corresponding associated item. + self.extend(item_bounds.map(|(index, pred)| { + let mut candidate = Candidate { + path: trait_candidate.path.clone(), + pred, + origin: trait_candidate.origin, + }; + candidate.path.push(PathChunk::AssocItem { + item: tcx.associated_item(alias_ty.def_id), + predicate: pred, + index, + }); + candidate + })); + } + /// Lookup a predicate in this set. If the predicate applies to an associated type, we /// add the relevant implied associated type bounds to the set as well. fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option<&Candidate<'tcx>> { let tcx = self.tcx; let target: PolyTraitPredicate = erase_and_norm(tcx, self.param_env, target).upcast(tcx); - // The predicate is `::Type: OtherTrait`. We look up `T as Trait` in - // the current context and add all the bounds on `Trait::Type` to our context. - // Note: We skip a binder but rebind it just after. - if let TyKind::Alias(AliasTyKind::Projection, alias_ty) = - target.self_ty().skip_binder().kind() - { - let trait_ref = target.rebind(alias_ty.trait_ref(tcx)); - // Recursively look up the trait ref inside `self`. - let trait_candidate = self.lookup(trait_ref)?.clone(); - let item_bounds = tcx - // TODO: `item_bounds` can contain parent traits, we don't want them - .item_bounds(alias_ty.def_id) - .instantiate(tcx, alias_ty.args) - .iter() - .filter_map(|pred| pred.as_trait_clause()) - .enumerate(); - // Add all the bounds on the corresponding associated item. - self.extend(item_bounds.map(|(index, pred)| { - let mut candidate = Candidate { - path: trait_candidate.path.clone(), - pred, - origin: trait_candidate.origin, - }; - candidate.path.push(PathChunk::AssocItem { - item: tcx.associated_item(alias_ty.def_id), - predicate: pred, - index, - }); - candidate - })); - } + // Add clauses related to associated type in the `Self` type of the predicate. + self.add_associated_type_refs(target.self_ty()); tracing::trace!("Looking for {target:?}"); let ret = self.candidates.get(&target); From 8cc2a8e56f178e0cd0ceee86c659fd1824c22781 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:34:50 +0200 Subject: [PATCH 020/253] Only explore associated types if we couldn't find the target --- frontend/exporter/src/traits/resolution.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 7f111ce18..954270f20 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -226,7 +226,7 @@ impl<'tcx> PredicateSearcher<'tcx> { // The predicate we're looking for is is `::Type: OtherTrait`. We look up `T as // Trait` in the current context and add all the bounds on `Trait::Type` to our context. - let Some(trait_candidate) = self.lookup(trait_ref).cloned() else { + let Some(trait_candidate) = self.lookup(trait_ref) else { return; }; @@ -256,15 +256,21 @@ impl<'tcx> PredicateSearcher<'tcx> { /// Lookup a predicate in this set. If the predicate applies to an associated type, we /// add the relevant implied associated type bounds to the set as well. - fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option<&Candidate<'tcx>> { + fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option> { let tcx = self.tcx; let target: PolyTraitPredicate = erase_and_norm(tcx, self.param_env, target).upcast(tcx); + tracing::trace!("Looking for {target:?}"); + + // Look up the predicate + let ret = self.candidates.get(&target).cloned(); + if ret.is_some() { + return ret; + } // Add clauses related to associated type in the `Self` type of the predicate. self.add_associated_type_refs(target.self_ty()); - tracing::trace!("Looking for {target:?}"); - let ret = self.candidates.get(&target); + let ret = self.candidates.get(&target).cloned(); if ret.is_none() { tracing::trace!( "Couldn't find {target:?} in: [\n{}]", @@ -303,7 +309,7 @@ impl<'tcx> PredicateSearcher<'tcx> { }, Ok(ImplSource::Param(_)) => match self.lookup(*tref) { Some(candidate) => { - let path = candidate.path.clone(); + let path = candidate.path; let r#trait = candidate.origin.clause.to_poly_trait_ref(); match candidate.origin.origin { BoundPredicateOrigin::SelfPred => ImplExprAtom::SelfImpl { r#trait, path }, From 8e0177c915b0efa3497999fe4e3c74bf95f2fb20 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 9 Oct 2024 18:38:30 +0200 Subject: [PATCH 021/253] Cache `ImplExpr` resolutions inside `PredicateSearcher` --- frontend/exporter/src/traits/resolution.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 954270f20..8423b6c34 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -143,7 +143,10 @@ struct Candidate<'tcx> { pub(super) struct PredicateSearcher<'tcx> { tcx: TyCtxt<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, + /// Local clauses available in the current context. candidates: HashMap, Candidate<'tcx>>, + /// Cache of trait refs to resolved impl expressions. + resolution_cache: HashMap, ImplExpr<'tcx>>, } impl<'tcx> PredicateSearcher<'tcx> { @@ -157,6 +160,7 @@ impl<'tcx> PredicateSearcher<'tcx> { tcx, param_env, candidates: Default::default(), + resolution_cache: Default::default(), }; out.extend( initial_search_predicates(tcx, owner_id) @@ -287,7 +291,7 @@ impl<'tcx> PredicateSearcher<'tcx> { #[tracing::instrument(level = "trace", skip(self, warn))] pub(super) fn resolve( &mut self, - tref: &rustc_middle::ty::PolyTraitRef<'tcx>, + tref: &PolyTraitRef<'tcx>, // Call back into hax-related code to display a nice warning. warn: &impl Fn(&str), ) -> Result, String> { @@ -295,6 +299,10 @@ impl<'tcx> PredicateSearcher<'tcx> { BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, }; + if let Some(impl_expr) = self.resolution_cache.get(tref) { + return Ok(impl_expr.clone()); + } + let tcx = self.tcx; let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, *tref)); @@ -363,11 +371,13 @@ impl<'tcx> PredicateSearcher<'tcx> { }) .collect::>()?; - Ok(ImplExpr { + let impl_expr = ImplExpr { r#impl: atom, args: nested, r#trait: *tref, - }) + }; + self.resolution_cache.insert(*tref, impl_expr.clone()); + Ok(impl_expr) } } From f3fe2ea197b268ed2943642664af461bd48f44cb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 10 Oct 2024 14:51:20 +0200 Subject: [PATCH 022/253] Trait resolution always uses the `param_env` of the `owner_id` --- frontend/exporter/src/traits.rs | 4 +--- frontend/exporter/src/traits/resolution.rs | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index dd5448904..add6aa2c8 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -132,15 +132,13 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( s: &S, trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>, ) -> ImplExpr { - use crate::ParamEnv; let warn = |msg: &str| { if !s.base().ty_alias_mode { crate::warning!(s, "{}", msg) } }; let tcx = s.base().tcx; - let mut searcher = - resolution::PredicateSearcher::new_for_owner(tcx, s.param_env(), s.owner_id()); + let mut searcher = resolution::PredicateSearcher::new_for_owner(tcx, s.owner_id()); match searcher.resolve(&trait_ref, &warn) { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 8423b6c34..c3fef4e04 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -151,14 +151,10 @@ pub(super) struct PredicateSearcher<'tcx> { impl<'tcx> PredicateSearcher<'tcx> { /// Initialize the elaborator with the predicates accessible within this item. - pub(super) fn new_for_owner( - tcx: TyCtxt<'tcx>, - param_env: rustc_middle::ty::ParamEnv<'tcx>, - owner_id: DefId, - ) -> Self { + pub(super) fn new_for_owner(tcx: TyCtxt<'tcx>, owner_id: DefId) -> Self { let mut out = Self { tcx, - param_env, + param_env: tcx.param_env(owner_id), candidates: Default::default(), resolution_cache: Default::default(), }; From 8a1413c66130bab6667aba7f990d01940a1e2e99 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 10 Oct 2024 15:22:23 +0200 Subject: [PATCH 023/253] Keep the same `PredicateSearcher` for a given `DefId` --- frontend/exporter/src/state.rs | 7 +++++++ frontend/exporter/src/traits.rs | 19 ++++++++++++++++--- frontend/exporter/src/traits/resolution.rs | 6 +++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index f94d04fe1..8c8dfa732 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -119,6 +119,11 @@ mod types { } } + #[derive(Default)] + pub struct Caches<'tcx> { + pub predicate_searcher: HashMap>, + } + #[derive(Clone)] pub struct Base<'tcx> { pub options: Rc, @@ -136,6 +141,7 @@ mod types { ), >, >, + pub caches: Rc>>, pub tcx: rustc_middle::ty::TyCtxt<'tcx>, /// Rust doesn't enforce bounds on generic parameters in type /// aliases. Thus, when translating type aliases, we need to @@ -154,6 +160,7 @@ mod types { tcx, macro_infos: Rc::new(HashMap::new()), cached_thirs: Rc::new(HashMap::new()), + caches: Default::default(), options: Rc::new(options), // Always prefer `s.owner_id()` to `s.base().opt_def_id`. // `opt_def_id` is used in `utils` for error reporting diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index add6aa2c8..9127dcfda 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -7,6 +7,9 @@ mod utils; #[cfg(feature = "rustc")] pub use utils::erase_and_norm; +#[cfg(feature = "rustc")] +pub use resolution::PredicateSearcher; + #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::PathChunk<'tcx>, state: S as s)] #[derive_group(Serializers)] @@ -137,9 +140,19 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - let tcx = s.base().tcx; - let mut searcher = resolution::PredicateSearcher::new_for_owner(tcx, s.owner_id()); - match searcher.resolve(&trait_ref, &warn) { + let base = s.base(); + let resolved = { + // Important: drop this borrow before calling `sinto(s)` again. + let mut caches = base.caches.borrow_mut(); + let searcher = caches + .predicate_searcher + .entry(s.owner_id()) + .or_insert_with(|| { + resolution::PredicateSearcher::new_for_owner(base.tcx, s.owner_id()) + }); + searcher.resolve(&trait_ref, &warn) + }; + match resolved { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), } diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index c3fef4e04..86d5b40c5 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -140,7 +140,7 @@ struct Candidate<'tcx> { } /// Stores a set of predicates along with where they came from. -pub(super) struct PredicateSearcher<'tcx> { +pub struct PredicateSearcher<'tcx> { tcx: TyCtxt<'tcx>, param_env: rustc_middle::ty::ParamEnv<'tcx>, /// Local clauses available in the current context. @@ -151,7 +151,7 @@ pub(super) struct PredicateSearcher<'tcx> { impl<'tcx> PredicateSearcher<'tcx> { /// Initialize the elaborator with the predicates accessible within this item. - pub(super) fn new_for_owner(tcx: TyCtxt<'tcx>, owner_id: DefId) -> Self { + pub fn new_for_owner(tcx: TyCtxt<'tcx>, owner_id: DefId) -> Self { let mut out = Self { tcx, param_env: tcx.param_env(owner_id), @@ -285,7 +285,7 @@ impl<'tcx> PredicateSearcher<'tcx> { /// Resolve the given trait reference in the local context. #[tracing::instrument(level = "trace", skip(self, warn))] - pub(super) fn resolve( + pub fn resolve( &mut self, tref: &PolyTraitRef<'tcx>, // Call back into hax-related code to display a nice warning. From 2d5b47a78dd6ff6b14d89524ab9f0fabbe33ee01 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 10 Oct 2024 15:31:00 +0200 Subject: [PATCH 024/253] Improve caching by normalizing earlier --- frontend/exporter/src/traits/resolution.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 86d5b40c5..9cc739c5b 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -222,7 +222,7 @@ impl<'tcx> PredicateSearcher<'tcx> { let TyKind::Alias(AliasTyKind::Projection, alias_ty) = ty.skip_binder().kind() else { return; }; - let trait_ref = ty.rebind(alias_ty.trait_ref(tcx)); + let trait_ref = ty.rebind(alias_ty.trait_ref(tcx)).upcast(tcx); // The predicate we're looking for is is `::Type: OtherTrait`. We look up `T as // Trait` in the current context and add all the bounds on `Trait::Type` to our context. @@ -256,9 +256,7 @@ impl<'tcx> PredicateSearcher<'tcx> { /// Lookup a predicate in this set. If the predicate applies to an associated type, we /// add the relevant implied associated type bounds to the set as well. - fn lookup(&mut self, target: PolyTraitRef<'tcx>) -> Option> { - let tcx = self.tcx; - let target: PolyTraitPredicate = erase_and_norm(tcx, self.param_env, target).upcast(tcx); + fn lookup(&mut self, target: PolyTraitPredicate<'tcx>) -> Option> { tracing::trace!("Looking for {target:?}"); // Look up the predicate @@ -295,13 +293,15 @@ impl<'tcx> PredicateSearcher<'tcx> { BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, }; - if let Some(impl_expr) = self.resolution_cache.get(tref) { + let erased_tref = erase_and_norm(self.tcx, self.param_env, *tref); + + if let Some(impl_expr) = self.resolution_cache.get(&erased_tref) { return Ok(impl_expr.clone()); } let tcx = self.tcx; let impl_source = - copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, *tref)); + copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, erased_tref)); let atom = match impl_source { Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, @@ -311,7 +311,7 @@ impl<'tcx> PredicateSearcher<'tcx> { def_id: impl_def_id, generics, }, - Ok(ImplSource::Param(_)) => match self.lookup(*tref) { + Ok(ImplSource::Param(_)) => match self.lookup(erased_tref.upcast(self.tcx)) { Some(candidate) => { let path = candidate.path; let r#trait = candidate.origin.clause.to_poly_trait_ref(); @@ -372,7 +372,7 @@ impl<'tcx> PredicateSearcher<'tcx> { args: nested, r#trait: *tref, }; - self.resolution_cache.insert(*tref, impl_expr.clone()); + self.resolution_cache.insert(erased_tref, impl_expr.clone()); Ok(impl_expr) } } @@ -387,8 +387,6 @@ mod copy_paste_from_rustc { Unimplemented, }; - use crate::traits::utils::erase_and_norm; - /// Attempts to resolve an obligation to an `ImplSource`. The result is /// a shallow `ImplSource` resolution, meaning that we do not /// (necessarily) resolve all nested obligations on the impl. Note @@ -400,8 +398,6 @@ mod copy_paste_from_rustc { tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result, CodegenObligationError> { - let trait_ref = erase_and_norm(tcx, param_env, trait_ref); - // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. let infcx = tcx.infer_ctxt().ignoring_regions().build(); From 3f2d9cc76914f651a815f895c13edc82c724af7e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 10 Oct 2024 15:48:42 +0200 Subject: [PATCH 025/253] Cache `ImplExpr`s after `sinto` instead of before --- frontend/exporter/src/state.rs | 11 +++++++++ frontend/exporter/src/traits.rs | 26 +++++++++++++++------- frontend/exporter/src/traits/resolution.rs | 13 ++--------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 8c8dfa732..21247b8f2 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -121,7 +121,11 @@ mod types { #[derive(Default)] pub struct Caches<'tcx> { + /// Cache the trait resolution engine for each item. pub predicate_searcher: HashMap>, + /// Cache of trait refs to resolved impl expressions. + pub resolution_cache: + HashMap<(RDefId, rustc_middle::ty::PolyTraitRef<'tcx>), crate::traits::ImplExpr>, } #[derive(Clone)] @@ -171,6 +175,13 @@ mod types { ty_alias_mode: false, } } + + /// Access the shared caches. You must not call `sinto` within this function as this will + /// likely result in `BorrowMut` panics. + pub fn with_caches(&self, f: impl FnOnce(&mut Caches<'tcx>) -> T) -> T { + let mut caches = self.caches.borrow_mut(); + f(&mut *caches) + } } pub type MacroCalls = Rc>; diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 9127dcfda..fc69ae991 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -140,22 +140,32 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - let base = s.base(); - let resolved = { - // Important: drop this borrow before calling `sinto(s)` again. - let mut caches = base.caches.borrow_mut(); + let owner_id = s.owner_id(); + if let Some(impl_expr) = s + .base() + .with_caches(|caches| caches.resolution_cache.get(&(owner_id, trait_ref)).cloned()) + { + return impl_expr; + } + let resolved = s.base().with_caches(|caches| { let searcher = caches .predicate_searcher .entry(s.owner_id()) .or_insert_with(|| { - resolution::PredicateSearcher::new_for_owner(base.tcx, s.owner_id()) + resolution::PredicateSearcher::new_for_owner(s.base().tcx, owner_id) }); searcher.resolve(&trait_ref, &warn) - }; - match resolved { + }); + let impl_expr = match resolved { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), - } + }; + s.base().with_caches(|caches| { + caches + .resolution_cache + .insert((owner_id, trait_ref), impl_expr.clone()) + }); + impl_expr } /// Solve the trait obligations for a specific item use (for example, a method call, an ADT, etc.). diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 9cc739c5b..342025f6f 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -145,8 +145,6 @@ pub struct PredicateSearcher<'tcx> { param_env: rustc_middle::ty::ParamEnv<'tcx>, /// Local clauses available in the current context. candidates: HashMap, Candidate<'tcx>>, - /// Cache of trait refs to resolved impl expressions. - resolution_cache: HashMap, ImplExpr<'tcx>>, } impl<'tcx> PredicateSearcher<'tcx> { @@ -156,7 +154,6 @@ impl<'tcx> PredicateSearcher<'tcx> { tcx, param_env: tcx.param_env(owner_id), candidates: Default::default(), - resolution_cache: Default::default(), }; out.extend( initial_search_predicates(tcx, owner_id) @@ -295,10 +292,6 @@ impl<'tcx> PredicateSearcher<'tcx> { let erased_tref = erase_and_norm(self.tcx, self.param_env, *tref); - if let Some(impl_expr) = self.resolution_cache.get(&erased_tref) { - return Ok(impl_expr.clone()); - } - let tcx = self.tcx; let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, erased_tref)); @@ -367,13 +360,11 @@ impl<'tcx> PredicateSearcher<'tcx> { }) .collect::>()?; - let impl_expr = ImplExpr { + Ok(ImplExpr { r#impl: atom, args: nested, r#trait: *tref, - }; - self.resolution_cache.insert(erased_tref, impl_expr.clone()); - Ok(impl_expr) + }) } } From e27075993026abfadd690977709fd908f8fc24a8 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 11:17:49 +0200 Subject: [PATCH 026/253] Make the caches per-item --- frontend/exporter/src/state.rs | 29 +++++++++++++++++++++-------- frontend/exporter/src/traits.rs | 23 +++++++---------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 21247b8f2..56b2687c0 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -98,6 +98,7 @@ macro_rules! mk { mod types { use crate::prelude::*; + use rustc_middle::ty; use std::cell::RefCell; use std::collections::HashSet; @@ -119,13 +120,21 @@ mod types { } } - #[derive(Default)] + /// Per-item cache pub struct Caches<'tcx> { /// Cache the trait resolution engine for each item. - pub predicate_searcher: HashMap>, + pub predicate_searcher: crate::traits::PredicateSearcher<'tcx>, /// Cache of trait refs to resolved impl expressions. - pub resolution_cache: - HashMap<(RDefId, rustc_middle::ty::PolyTraitRef<'tcx>), crate::traits::ImplExpr>, + pub resolution_cache: HashMap, crate::traits::ImplExpr>, + } + + impl<'tcx> Caches<'tcx> { + pub fn new(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Self { + Self { + predicate_searcher: crate::traits::PredicateSearcher::new_for_owner(tcx, def_id), + resolution_cache: Default::default(), + } + } } #[derive(Clone)] @@ -145,8 +154,9 @@ mod types { ), >, >, - pub caches: Rc>>, - pub tcx: rustc_middle::ty::TyCtxt<'tcx>, + /// Per-item caches. + pub caches: Rc>>>, + pub tcx: ty::TyCtxt<'tcx>, /// Rust doesn't enforce bounds on generic parameters in type /// aliases. Thus, when translating type aliases, we need to /// disable the resolution of implementation expressions. For @@ -178,9 +188,12 @@ mod types { /// Access the shared caches. You must not call `sinto` within this function as this will /// likely result in `BorrowMut` panics. - pub fn with_caches(&self, f: impl FnOnce(&mut Caches<'tcx>) -> T) -> T { + pub fn with_caches(&self, def_id: RDefId, f: impl FnOnce(&mut Caches<'tcx>) -> T) -> T { let mut caches = self.caches.borrow_mut(); - f(&mut *caches) + let caches_for_def_id = caches + .entry(def_id) + .or_insert_with(|| Caches::new(self.tcx, def_id)); + f(caches_for_def_id) } } diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index fc69ae991..34d01d236 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -141,29 +141,20 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( } }; let owner_id = s.owner_id(); - if let Some(impl_expr) = s - .base() - .with_caches(|caches| caches.resolution_cache.get(&(owner_id, trait_ref)).cloned()) - { + if let Some(impl_expr) = s.base().with_caches(owner_id, |caches| { + caches.resolution_cache.get(&trait_ref).cloned() + }) { return impl_expr; } - let resolved = s.base().with_caches(|caches| { - let searcher = caches - .predicate_searcher - .entry(s.owner_id()) - .or_insert_with(|| { - resolution::PredicateSearcher::new_for_owner(s.base().tcx, owner_id) - }); - searcher.resolve(&trait_ref, &warn) + let resolved = s.base().with_caches(owner_id, |caches| { + caches.predicate_searcher.resolve(&trait_ref, &warn) }); let impl_expr = match resolved { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), }; - s.base().with_caches(|caches| { - caches - .resolution_cache - .insert((owner_id, trait_ref), impl_expr.clone()) + s.base().with_caches(owner_id, |caches| { + caches.resolution_cache.insert(trait_ref, impl_expr.clone()) }); impl_expr } From ad7d84ff3d4441b420f76c90f7ad64d19c6a45b0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 11:38:49 +0200 Subject: [PATCH 027/253] Move existing thir cache to the new caching struct --- cli/driver/src/exporter.rs | 19 +++++++++++-------- frontend/exporter/src/body.rs | 6 ++++-- frontend/exporter/src/state.rs | 16 ++++++---------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index 91151aa5d..3a005bbf3 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -46,8 +46,7 @@ fn dummy_thir_body( /// stealing issues (theoretically...) fn precompute_local_thir_bodies( tcx: TyCtxt<'_>, -) -> std::collections::HashMap> { - let hir = tcx.hir(); +) -> impl Iterator)> { use rustc_hir::def::DefKind::*; use rustc_hir::*; @@ -74,7 +73,7 @@ fn precompute_local_thir_bodies( } use itertools::Itertools; - hir.body_owners() + tcx.hir().body_owners() .filter(|ldid| { match tcx.def_kind(ldid.to_def_id()) { InlineConst | AnonConst => { @@ -91,10 +90,10 @@ fn precompute_local_thir_bodies( } }) .sorted_by_key(|ldid| const_level_of(tcx, *ldid)) - .filter(|ldid| hir.maybe_body_owned_by(*ldid).is_some()) - .map(|ldid| { + .filter(move |ldid| tcx.hir().maybe_body_owned_by(*ldid).is_some()) + .map(move |ldid| { tracing::debug!("⏳ Type-checking THIR body for {:#?}", ldid); - let span = hir.span(tcx.local_def_id_to_hir_id(ldid)); + let span = tcx.hir().span(tcx.local_def_id_to_hir_id(ldid)); let (thir, expr) = match tcx.thir_body(ldid) { Ok(x) => x, Err(e) => { @@ -117,7 +116,7 @@ fn precompute_local_thir_bodies( tracing::debug!("✅ Type-checked THIR body for {:#?}", ldid); (ldid, (Rc::new(thir), expr)) }) - .collect() + .map(|(ldid, bundle)| (ldid.to_def_id(), bundle)) } /// Browse a crate and translate every item from HIR+THIR to "THIR'" @@ -138,7 +137,11 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( ) { let mut state = hax_frontend_exporter::state::State::new(tcx, options.clone()); state.base.macro_infos = Rc::new(macro_calls); - state.base.cached_thirs = Rc::new(precompute_local_thir_bodies(tcx)); + for (def_id, thir) in precompute_local_thir_bodies(tcx) { + state + .base + .with_caches(def_id, |caches| caches.thir = Some(thir)); + } let result = hax_frontend_exporter::inline_macro_invocations(tcx.hir().items(), &state); let impl_infos = hax_frontend_exporter::impl_def_ids_to_impled_types_and_bounds(&state) diff --git a/frontend/exporter/src/body.rs b/frontend/exporter/src/body.rs index 8d47409cd..671c6fccd 100644 --- a/frontend/exporter/src/body.rs +++ b/frontend/exporter/src/body.rs @@ -22,8 +22,10 @@ mod module { rustc_middle::thir::ExprId, ) { let base = s.base(); - let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); - base.cached_thirs.get(&did).unwrap_or_else(msg).clone() + base.with_caches(did.to_def_id(), |caches| { + let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); + caches.thir.as_ref().unwrap_or_else(msg).clone() + }) } pub trait IsBody: Sized + Clone + 'static { diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 56b2687c0..2f5026ac5 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -126,6 +126,11 @@ mod types { pub predicate_searcher: crate::traits::PredicateSearcher<'tcx>, /// Cache of trait refs to resolved impl expressions. pub resolution_cache: HashMap, crate::traits::ImplExpr>, + /// Cache thir bodies. + pub thir: Option<( + Rc>, + rustc_middle::thir::ExprId, + )>, } impl<'tcx> Caches<'tcx> { @@ -133,6 +138,7 @@ mod types { Self { predicate_searcher: crate::traits::PredicateSearcher::new_for_owner(tcx, def_id), resolution_cache: Default::default(), + thir: Default::default(), } } } @@ -145,15 +151,6 @@ mod types { pub opt_def_id: Option, pub exported_spans: ExportedSpans, pub exported_def_ids: ExportedDefIds, - pub cached_thirs: Rc< - HashMap< - rustc_span::def_id::LocalDefId, - ( - Rc>, - rustc_middle::thir::ExprId, - ), - >, - >, /// Per-item caches. pub caches: Rc>>>, pub tcx: ty::TyCtxt<'tcx>, @@ -173,7 +170,6 @@ mod types { Self { tcx, macro_infos: Rc::new(HashMap::new()), - cached_thirs: Rc::new(HashMap::new()), caches: Default::default(), options: Rc::new(options), // Always prefer `s.owner_id()` to `s.base().opt_def_id`. From 3d98ad6ea0a4bcc90157bafe3244836bf3cb083f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 13:15:28 +0200 Subject: [PATCH 028/253] Make `Ty` reference-counted --- Cargo.toml | 2 +- engine/lib/concrete_ident/concrete_ident.ml | 12 +++-- engine/lib/import_thir.ml | 4 +- frontend/exporter/src/constant_utils.rs | 14 +++--- frontend/exporter/src/rustc_utils.rs | 7 ++- frontend/exporter/src/types/copied.rs | 52 ++++++++++++++------- frontend/exporter/src/types/mir.rs | 12 ++--- 7 files changed, 62 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f64e16d76..90ca24953 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ readme = "README.md" itertools = "0.11.0" schemars = "0.8" which = "4.4" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" clap = { version = "4.0", features = ["derive"] } syn = { version = "1.0.107", features = [ diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index c8a1a49ec..96562978d 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -284,8 +284,8 @@ module View = struct last.data |> Imported.of_def_path_item |> string_of_def_path_item |> Option.map ~f:escape in - let arity0 = - Option.map ~f:escape << function + let arity0 ty = + match ty.Types.kind with | Types.Bool -> Some "bool" | Char -> Some "char" | Str -> Some "str" @@ -305,11 +305,13 @@ module View = struct | Float F32 -> Some "f32" | Float F64 -> Some "f64" | Tuple [] -> Some "unit" - | Adt { def_id; generic_args = []; _ } -> adt def_id + | Adt { def_id; generic_args = []; _ } -> + Option.map ~f:escape (adt def_id) | _ -> None in let apply left right = left ^ "_of_" ^ right in - let rec arity1 = function + let rec arity1 ty = + match ty.Types.kind with | Types.Slice sub -> arity1 sub |> Option.map ~f:(apply "slice") | Ref (_, sub, _) -> arity1 sub |> Option.map ~f:(apply "ref") | Adt { def_id; generic_args = [ Type arg ]; _ } -> @@ -319,7 +321,7 @@ module View = struct | Tuple l -> let* l = List.map ~f:arity0 l |> Option.all in Some ("tuple_" ^ String.concat ~sep:"_" l) - | otherwise -> arity0 otherwise + | _ -> arity0 ty in arity1 diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index df70997fc..60aae64cc 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -385,7 +385,7 @@ end) : EXPR = struct in (* if there is no expression & the last expression is ⊥, just use that *) let lift_last_statement_as_expr_if_possible expr stmts (ty : Thir.ty) = - match (ty, expr, List.drop_last stmts, List.last stmts) with + match (ty.kind, expr, List.drop_last stmts, List.last stmts) with | ( Thir.Never, None, Some stmts, @@ -981,7 +981,7 @@ end) : EXPR = struct ("Pointer, with [cast] being " ^ [%show: Thir.pointer_coercion] cast) and c_ty (span : Thir.span) (ty : Thir.ty) : ty = - match ty with + match ty.kind with | Bool -> TBool | Char -> TChar | Int k -> TInt (c_int_ty k) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index cf91501dd..7005b7eb8 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -584,9 +584,9 @@ mod rustc { assert!(dc.variant.is_none()); // The type should be tuple - let hax_ty = ty.sinto(s); - match &hax_ty { - Ty::Tuple(_) => (), + let hax_ty: Ty = ty.sinto(s); + match hax_ty.kind() { + TyKind::Tuple(_) => (), _ => { fatal!(s[span], "Expected the type to be tuple: {:?}", val) } @@ -632,12 +632,12 @@ mod rustc { } ConstValue::ZeroSized { .. } => { // Should be unit - let hty = ty.sinto(s); - let cv = match &hty { - Ty::Tuple(tys) if tys.is_empty() => { + let hty: Ty = ty.sinto(s); + let cv = match hty.kind() { + TyKind::Tuple(tys) if tys.is_empty() => { ConstantExprKind::Tuple { fields: Vec::new() } } - Ty::Arrow(_) => match ty.kind() { + TyKind::Arrow(_) => match ty.kind() { rustc_middle::ty::TyKind::FnDef(def_id, args) => { let (def_id, generics, generics_impls, method_impl) = get_function_from_def_id_and_generics(s, *def_id, args); diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index 2e8601b86..241216b84 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -13,8 +13,11 @@ impl<'tcx, T: ty::TypeFoldable>> ty::Binder<'tcx, T> { } #[tracing::instrument(skip(s))] -pub(crate) fn arrow_of_sig<'tcx, S: UnderOwnerState<'tcx>>(sig: &ty::PolyFnSig<'tcx>, s: &S) -> Ty { - Ty::Arrow(Box::new(sig.sinto(s))) +pub(crate) fn arrow_of_sig<'tcx, S: UnderOwnerState<'tcx>>( + sig: &ty::PolyFnSig<'tcx>, + s: &S, +) -> TyKind { + TyKind::Arrow(Box::new(sig.sinto(s))) } #[tracing::instrument(skip(s))] diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index eee73b8d5..c3251ae6f 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use std::sync::Arc; #[cfg(feature = "rustc")] use rustc_middle::ty; @@ -262,20 +263,6 @@ impl SInto for rustc_middle::mir::interpret::AllocId { } } -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { - fn sinto(&self, s: &S) -> Box { - Box::new(self.sinto(s)) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { - fn sinto(&self, s: &S) -> Ty { - self.kind().sinto(s) - } -} - /// Reflects [`rustc_hir::hir_id::HirId`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -1815,12 +1802,41 @@ impl Alias { } } +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { + fn sinto(&self, s: &S) -> Box { + Box::new(self.sinto(s)) + } +} + +/// Reflects [`rustc_middle::ty::Ty`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Ty { + pub kind: Arc, +} + +impl Ty { + pub fn kind(&self) -> &TyKind { + self.kind.as_ref() + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { + fn sinto(&self, s: &S) -> Ty { + Ty { + kind: Arc::new(self.kind().sinto(s)), + } + } +} + /// Reflects [`rustc_middle::ty::TyKind`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TyKind<'tcx>, state: S as state)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Ty { +pub enum TyKind { Bool, Char, Int(IntTy), @@ -1847,7 +1863,7 @@ pub enum Ty { let def_id = adt_def.did().sinto(state); let generic_args: Vec = generics.sinto(state); let trait_refs = solve_item_traits(state, adt_def.did(), generics, None); - Ty::Adt { def_id, generic_args, trait_refs } + TyKind::Adt { def_id, generic_args, trait_refs } }, )] Adt { @@ -1870,7 +1886,7 @@ pub enum Ty { Tuple(Vec), #[custom_arm( rustc_middle::ty::TyKind::Alias(alias_kind, alias_ty) => { - Ty::Alias(Alias::from(state, alias_kind, alias_ty)) + TyKind::Alias(Alias::from(state, alias_kind, alias_ty)) }, )] Alias(Alias), @@ -1878,7 +1894,7 @@ pub enum Ty { Bound(DebruijnIndex, BoundTy), Placeholder(PlaceholderType), Infer(InferTy), - #[custom_arm(rustc_middle::ty::TyKind::Error(..) => Ty::Error,)] + #[custom_arm(rustc_middle::ty::TyKind::Error(..) => TyKind::Error,)] Error, #[todo] Todo(String), diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 8e85f8f51..8bb408eec 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -540,8 +540,8 @@ fn translate_switch_targets<'tcx, S: UnderOwnerState<'tcx>>( let targets_vec: Vec<(u128, BasicBlock)> = targets.iter().map(|(v, b)| (v, b.sinto(s))).collect(); - match switch_ty { - Ty::Bool => { + match switch_ty.kind() { + TyKind::Bool => { // This is an: `if ... then ... else ...` assert!(targets_vec.len() == 1); // It seems the block targets are inverted @@ -554,10 +554,10 @@ fn translate_switch_targets<'tcx, S: UnderOwnerState<'tcx>>( SwitchTargets::If(if_block, otherwise_block) } - Ty::Int(_) | Ty::Uint(_) => { - let int_ty = match switch_ty { - Ty::Int(ty) => IntUintTy::Int(*ty), - Ty::Uint(ty) => IntUintTy::Uint(*ty), + TyKind::Int(_) | TyKind::Uint(_) => { + let int_ty = match switch_ty.kind() { + TyKind::Int(ty) => IntUintTy::Int(*ty), + TyKind::Uint(ty) => IntUintTy::Uint(*ty), _ => unreachable!(), }; From e18475800a73d769635e9b890c6ca914f4aa6647 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 13:42:59 +0200 Subject: [PATCH 029/253] Cache `Ty` translation --- frontend/exporter/src/state.rs | 3 +++ frontend/exporter/src/types/copied.rs | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 2f5026ac5..1b515ebe4 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -122,6 +122,8 @@ mod types { /// Per-item cache pub struct Caches<'tcx> { + /// Cache the `Ty` translations. + pub ty: HashMap, Ty>, /// Cache the trait resolution engine for each item. pub predicate_searcher: crate::traits::PredicateSearcher<'tcx>, /// Cache of trait refs to resolved impl expressions. @@ -136,6 +138,7 @@ mod types { impl<'tcx> Caches<'tcx> { pub fn new(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Self { Self { + ty: Default::default(), predicate_searcher: crate::traits::PredicateSearcher::new_for_owner(tcx, def_id), resolution_cache: Default::default(), thir: Default::default(), diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index c3251ae6f..f97376b1b 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1825,9 +1825,19 @@ impl Ty { #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { - Ty { - kind: Arc::new(self.kind().sinto(s)), + let owner_id = s.owner_id(); + if let Some(ty) = s + .base() + .with_caches(owner_id, |caches| caches.ty.get(self).cloned()) + { + return ty; } + let ty = Ty { + kind: Arc::new(self.kind().sinto(s)), + }; + s.base() + .with_caches(owner_id, |caches| caches.ty.insert(*self, ty.clone())); + ty } } From eac51a9d0c39d73b3d79e8d42e98907c54e4d9e6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 13:52:01 +0200 Subject: [PATCH 030/253] Prepare for non-per-item caching --- cli/driver/src/exporter.rs | 5 +-- frontend/exporter/src/body.rs | 6 +-- frontend/exporter/src/state.rs | 65 +++++++++++++++++++-------- frontend/exporter/src/traits.rs | 13 ++---- frontend/exporter/src/types/copied.rs | 9 +--- 5 files changed, 56 insertions(+), 42 deletions(-) diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index 3a005bbf3..2dc13204b 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -135,12 +135,11 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( )>, Vec>, ) { + use hax_frontend_exporter::WithGlobalCacheExt; let mut state = hax_frontend_exporter::state::State::new(tcx, options.clone()); state.base.macro_infos = Rc::new(macro_calls); for (def_id, thir) in precompute_local_thir_bodies(tcx) { - state - .base - .with_caches(def_id, |caches| caches.thir = Some(thir)); + state.with_item_cache(def_id, |caches| caches.thir = Some(thir)); } let result = hax_frontend_exporter::inline_macro_invocations(tcx.hir().items(), &state); diff --git a/frontend/exporter/src/body.rs b/frontend/exporter/src/body.rs index 671c6fccd..77c27e0c1 100644 --- a/frontend/exporter/src/body.rs +++ b/frontend/exporter/src/body.rs @@ -21,9 +21,9 @@ mod module { Rc>, rustc_middle::thir::ExprId, ) { - let base = s.base(); - base.with_caches(did.to_def_id(), |caches| { - let msg = || fatal!(s[base.tcx.def_span(did)], "THIR not found for {:?}", did); + let tcx = s.base().tcx; + s.with_item_cache(did.to_def_id(), |caches| { + let msg = || fatal!(s[tcx.def_span(did)], "THIR not found for {:?}", did); caches.thir.as_ref().unwrap_or_else(msg).clone() }) } diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 1b515ebe4..7f321474c 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -120,14 +120,21 @@ mod types { } } + /// Global caches + #[derive(Default)] + pub struct GlobalCache<'tcx> { + /// Per-item cache. + pub per_item: HashMap>, + } + /// Per-item cache - pub struct Caches<'tcx> { + pub struct ItemCache<'tcx> { /// Cache the `Ty` translations. - pub ty: HashMap, Ty>, + pub tys: HashMap, Ty>, /// Cache the trait resolution engine for each item. pub predicate_searcher: crate::traits::PredicateSearcher<'tcx>, /// Cache of trait refs to resolved impl expressions. - pub resolution_cache: HashMap, crate::traits::ImplExpr>, + pub impl_exprs: HashMap, crate::traits::ImplExpr>, /// Cache thir bodies. pub thir: Option<( Rc>, @@ -135,12 +142,12 @@ mod types { )>, } - impl<'tcx> Caches<'tcx> { + impl<'tcx> ItemCache<'tcx> { pub fn new(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Self { Self { - ty: Default::default(), + tys: Default::default(), predicate_searcher: crate::traits::PredicateSearcher::new_for_owner(tcx, def_id), - resolution_cache: Default::default(), + impl_exprs: Default::default(), thir: Default::default(), } } @@ -154,8 +161,7 @@ mod types { pub opt_def_id: Option, pub exported_spans: ExportedSpans, pub exported_def_ids: ExportedDefIds, - /// Per-item caches. - pub caches: Rc>>>, + pub cache: Rc>>, pub tcx: ty::TyCtxt<'tcx>, /// Rust doesn't enforce bounds on generic parameters in type /// aliases. Thus, when translating type aliases, we need to @@ -173,7 +179,7 @@ mod types { Self { tcx, macro_infos: Rc::new(HashMap::new()), - caches: Default::default(), + cache: Default::default(), options: Rc::new(options), // Always prefer `s.owner_id()` to `s.base().opt_def_id`. // `opt_def_id` is used in `utils` for error reporting @@ -184,16 +190,6 @@ mod types { ty_alias_mode: false, } } - - /// Access the shared caches. You must not call `sinto` within this function as this will - /// likely result in `BorrowMut` panics. - pub fn with_caches(&self, def_id: RDefId, f: impl FnOnce(&mut Caches<'tcx>) -> T) -> T { - let mut caches = self.caches.borrow_mut(); - let caches_for_def_id = caches - .entry(def_id) - .or_insert_with(|| Caches::new(self.tcx, def_id)); - f(caches_for_def_id) - } } pub type MacroCalls = Rc>; @@ -324,6 +320,37 @@ pub trait UnderBinderState<'tcx> = UnderOwnerState<'tcx> + HasBinder<'tcx>; /// body and an `owner_id` in the state pub trait ExprState<'tcx> = UnderOwnerState<'tcx> + HasThir<'tcx>; +pub trait WithGlobalCacheExt<'tcx>: BaseState<'tcx> { + /// Access the global cache. You must not call `sinto` within this function as this will likely + /// result in `BorrowMut` panics. + fn with_global_cache(&self, f: impl FnOnce(&mut GlobalCache<'tcx>) -> T) -> T { + let base = self.base(); + let mut cache = base.cache.borrow_mut(); + f(&mut *cache) + } + /// Access the cache for a given item. You must not call `sinto` within this function as this + /// will likely result in `BorrowMut` panics. + fn with_item_cache(&self, def_id: RDefId, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { + self.with_global_cache(|cache| { + let cache_for_item = cache + .per_item + .entry(def_id) + .or_insert_with(|| ItemCache::new(self.base().tcx, def_id)); + f(cache_for_item) + }) + } +} +impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {} + +pub trait WithItemCacheExt<'tcx>: UnderOwnerState<'tcx> { + /// Access the cache for the current item. You must not call `sinto` within this function as + /// this will likely result in `BorrowMut` panics. + fn with_cache(&self, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { + self.with_item_cache(self.owner_id(), f) + } +} +impl<'tcx, S: UnderOwnerState<'tcx>> WithItemCacheExt<'tcx> for S {} + impl ImplInfos { fn from(base: Base<'_>, did: rustc_hir::def_id::DefId) -> Self { let tcx = base.tcx; diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 34d01d236..6ce83e8f3 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -140,22 +140,15 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - let owner_id = s.owner_id(); - if let Some(impl_expr) = s.base().with_caches(owner_id, |caches| { - caches.resolution_cache.get(&trait_ref).cloned() - }) { + if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) { return impl_expr; } - let resolved = s.base().with_caches(owner_id, |caches| { - caches.predicate_searcher.resolve(&trait_ref, &warn) - }); + let resolved = s.with_cache(|cache| cache.predicate_searcher.resolve(&trait_ref, &warn)); let impl_expr = match resolved { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), }; - s.base().with_caches(owner_id, |caches| { - caches.resolution_cache.insert(trait_ref, impl_expr.clone()) - }); + s.with_cache(|cache| cache.impl_exprs.insert(trait_ref, impl_expr.clone())); impl_expr } diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index f97376b1b..38db59745 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1825,18 +1825,13 @@ impl Ty { #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { - let owner_id = s.owner_id(); - if let Some(ty) = s - .base() - .with_caches(owner_id, |caches| caches.ty.get(self).cloned()) - { + if let Some(ty) = s.with_cache(|cache| cache.tys.get(self).cloned()) { return ty; } let ty = Ty { kind: Arc::new(self.kind().sinto(s)), }; - s.base() - .with_caches(owner_id, |caches| caches.ty.insert(*self, ty.clone())); + s.with_cache(|cache| cache.tys.insert(*self, ty.clone())); ty } } From 6c6843784eb1601af49d2d9828ed8974915970a5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 15:14:28 +0200 Subject: [PATCH 031/253] Lazily initialize the cached predicate searcher --- frontend/exporter/src/state.rs | 22 +++------------------- frontend/exporter/src/traits.rs | 7 ++++++- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 7f321474c..bef9ab833 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -128,11 +128,12 @@ mod types { } /// Per-item cache + #[derive(Default)] pub struct ItemCache<'tcx> { /// Cache the `Ty` translations. pub tys: HashMap, Ty>, /// Cache the trait resolution engine for each item. - pub predicate_searcher: crate::traits::PredicateSearcher<'tcx>, + pub predicate_searcher: Option>, /// Cache of trait refs to resolved impl expressions. pub impl_exprs: HashMap, crate::traits::ImplExpr>, /// Cache thir bodies. @@ -142,17 +143,6 @@ mod types { )>, } - impl<'tcx> ItemCache<'tcx> { - pub fn new(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Self { - Self { - tys: Default::default(), - predicate_searcher: crate::traits::PredicateSearcher::new_for_owner(tcx, def_id), - impl_exprs: Default::default(), - thir: Default::default(), - } - } - } - #[derive(Clone)] pub struct Base<'tcx> { pub options: Rc, @@ -331,13 +321,7 @@ pub trait WithGlobalCacheExt<'tcx>: BaseState<'tcx> { /// Access the cache for a given item. You must not call `sinto` within this function as this /// will likely result in `BorrowMut` panics. fn with_item_cache(&self, def_id: RDefId, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { - self.with_global_cache(|cache| { - let cache_for_item = cache - .per_item - .entry(def_id) - .or_insert_with(|| ItemCache::new(self.base().tcx, def_id)); - f(cache_for_item) - }) + self.with_global_cache(|cache| f(cache.per_item.entry(def_id).or_default())) } } impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {} diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 6ce83e8f3..80ceb27fb 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -143,7 +143,12 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) { return impl_expr; } - let resolved = s.with_cache(|cache| cache.predicate_searcher.resolve(&trait_ref, &warn)); + let resolved = s.with_cache(|cache| { + cache + .predicate_searcher + .get_or_insert_with(|| PredicateSearcher::new_for_owner(s.base().tcx, s.owner_id())) + .resolve(&trait_ref, &warn) + }); let impl_expr = match resolved { Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), From 3b67709f3f81951a4de52fef6977e8237d67ee62 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 14:01:04 +0200 Subject: [PATCH 032/253] Cache `Span` translation --- cli/driver/src/exporter.rs | 11 +++-------- frontend/exporter/src/state.rs | 5 ++--- frontend/exporter/src/types/copied.rs | 9 ++++++--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index 2dc13204b..a4226fe82 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -1,4 +1,4 @@ -use hax_frontend_exporter::state::{ExportedSpans, LocalContextS}; +use hax_frontend_exporter::state::LocalContextS; use hax_frontend_exporter::SInto; use hax_types::cli_options::{Backend, PathOrDash, ENV_VAR_OPTIONS_FRONTEND}; use rustc_driver::{Callbacks, Compilation}; @@ -146,19 +146,14 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( let impl_infos = hax_frontend_exporter::impl_def_ids_to_impled_types_and_bounds(&state) .into_iter() .collect(); - let exported_spans = state.base.exported_spans.borrow().clone(); + let exported_spans = state.base.cache.borrow().spans.keys().copied().collect(); let exported_def_ids = { let def_ids = state.base.exported_def_ids.borrow(); let state = hax_frontend_exporter::state::State::new(tcx, options.clone()); def_ids.iter().map(|did| did.sinto(&state)).collect() }; - ( - exported_spans.into_iter().collect(), - exported_def_ids, - impl_infos, - result, - ) + (exported_spans, exported_def_ids, impl_infos, result) } /// Collect a map from spans to macro calls diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index bef9ab833..5c31b0647 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -123,6 +123,8 @@ mod types { /// Global caches #[derive(Default)] pub struct GlobalCache<'tcx> { + /// Cache the `Span` translations. + pub spans: HashMap, /// Per-item cache. pub per_item: HashMap>, } @@ -149,7 +151,6 @@ mod types { pub macro_infos: MacroCalls, pub local_ctx: Rc>, pub opt_def_id: Option, - pub exported_spans: ExportedSpans, pub exported_def_ids: ExportedDefIds, pub cache: Rc>>, pub tcx: ty::TyCtxt<'tcx>, @@ -175,7 +176,6 @@ mod types { // `opt_def_id` is used in `utils` for error reporting opt_def_id: None, local_ctx: Rc::new(RefCell::new(LocalContextS::new())), - exported_spans: Rc::new(RefCell::new(HashSet::new())), exported_def_ids: Rc::new(RefCell::new(HashSet::new())), ty_alias_mode: false, } @@ -183,7 +183,6 @@ mod types { } pub type MacroCalls = Rc>; - pub type ExportedSpans = Rc>>; pub type ExportedDefIds = Rc>>; pub type RcThir<'tcx> = Rc>; pub type RcMir<'tcx> = Rc>; diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 38db59745..8c4f36dd7 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -987,9 +987,12 @@ impl From for Loc { #[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>> SInto for rustc_span::Span { fn sinto(&self, s: &S) -> Span { - let set: crate::state::ExportedSpans = s.base().exported_spans; - set.borrow_mut().insert(*self); - translate_span(*self, s.base().tcx.sess) + if let Some(span) = s.with_global_cache(|cache| cache.spans.get(self).cloned()) { + return span; + } + let span = translate_span(*self, s.base().tcx.sess); + s.with_global_cache(|cache| cache.spans.insert(*self, span.clone())); + span } } From 936ed5a49ccbd1f25113bfd824f720bcc563aae1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 15:07:20 +0200 Subject: [PATCH 033/253] Cache exported `DefId`s --- cli/driver/src/exporter.rs | 14 +++++++----- frontend/exporter/src/state.rs | 17 ++++---------- frontend/exporter/src/types/copied.rs | 33 +++++++++++++++++---------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index a4226fe82..d9e767530 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -146,13 +146,15 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( let impl_infos = hax_frontend_exporter::impl_def_ids_to_impled_types_and_bounds(&state) .into_iter() .collect(); - let exported_spans = state.base.cache.borrow().spans.keys().copied().collect(); + let exported_spans = state.with_global_cache(|cache| cache.spans.keys().copied().collect()); + let exported_def_ids = state.with_global_cache(|cache| { + cache + .per_item + .values() + .filter_map(|per_item_cache| per_item_cache.def_id.clone()) + .collect() + }); - let exported_def_ids = { - let def_ids = state.base.exported_def_ids.borrow(); - let state = hax_frontend_exporter::state::State::new(tcx, options.clone()); - def_ids.iter().map(|did| did.sinto(&state)).collect() - }; (exported_spans, exported_def_ids, impl_infos, result) } diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 5c31b0647..f6a2a053a 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -100,7 +100,6 @@ mod types { use crate::prelude::*; use rustc_middle::ty; use std::cell::RefCell; - use std::collections::HashSet; pub struct LocalContextS { pub vars: HashMap, @@ -132,6 +131,8 @@ mod types { /// Per-item cache #[derive(Default)] pub struct ItemCache<'tcx> { + /// The translated `DefId`. + pub def_id: Option, /// Cache the `Ty` translations. pub tys: HashMap, Ty>, /// Cache the trait resolution engine for each item. @@ -151,7 +152,6 @@ mod types { pub macro_infos: MacroCalls, pub local_ctx: Rc>, pub opt_def_id: Option, - pub exported_def_ids: ExportedDefIds, pub cache: Rc>>, pub tcx: ty::TyCtxt<'tcx>, /// Rust doesn't enforce bounds on generic parameters in type @@ -176,14 +176,12 @@ mod types { // `opt_def_id` is used in `utils` for error reporting opt_def_id: None, local_ctx: Rc::new(RefCell::new(LocalContextS::new())), - exported_def_ids: Rc::new(RefCell::new(HashSet::new())), ty_alias_mode: false, } } } pub type MacroCalls = Rc>; - pub type ExportedDefIds = Rc>>; pub type RcThir<'tcx> = Rc>; pub type RcMir<'tcx> = Rc>; pub type Binder<'tcx> = rustc_middle::ty::Binder<'tcx, ()>; @@ -353,13 +351,9 @@ impl ImplInfos { pub fn impl_def_ids_to_impled_types_and_bounds<'tcx, S: BaseState<'tcx>>( s: &S, ) -> HashMap { - let Base { - tcx, - exported_def_ids, - .. - } = s.base(); + let tcx = s.base().tcx; - let def_ids = exported_def_ids.as_ref().borrow().clone(); + let def_ids: Vec<_> = s.with_global_cache(|cache| cache.per_item.keys().copied().collect()); let with_parents = |mut did: rustc_hir::def_id::DefId| { let mut acc = vec![did]; while let Some(parent) = tcx.opt_parent(did) { @@ -370,8 +364,7 @@ pub fn impl_def_ids_to_impled_types_and_bounds<'tcx, S: BaseState<'tcx>>( }; use itertools::Itertools; def_ids - .iter() - .cloned() + .into_iter() .flat_map(with_parents) .unique() .filter(|&did| { diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 8c4f36dd7..f52897b03 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -19,22 +19,31 @@ impl std::hash::Hash for DefId { } } +#[cfg(feature = "rustc")] +pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> DefId { + let tcx = s.base().tcx; + let def_path = tcx.def_path(def_id); + let krate = tcx.crate_name(def_path.krate); + DefId { + path: def_path.data.iter().map(|x| x.sinto(s)).collect(), + krate: format!("{}", krate), + index: ( + rustc_hir::def_id::CrateNum::as_u32(def_id.krate), + rustc_hir::def_id::DefIndex::as_u32(def_id.index), + ), + is_local: def_id.is_local(), + } +} + #[cfg(feature = "rustc")] impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { fn sinto(&self, s: &S) -> DefId { - s.base().exported_def_ids.borrow_mut().insert(*self); - let tcx = s.base().tcx; - let def_path = tcx.def_path(*self); - let krate = tcx.crate_name(def_path.krate); - DefId { - path: def_path.data.iter().map(|x| x.sinto(s)).collect(), - krate: format!("{}", krate), - index: ( - rustc_hir::def_id::CrateNum::as_u32(self.krate), - rustc_hir::def_id::DefIndex::as_u32(self.index), - ), - is_local: self.is_local(), + if let Some(def_id) = s.with_item_cache(*self, |cache| cache.def_id.clone()) { + return def_id; } + let def_id = translate_def_id(s, *self); + s.with_item_cache(*self, |cache| cache.def_id = Some(def_id.clone())); + def_id } } From 3575efceddc32ed90a0cd1ad9b7b3588d0a3be8d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 11 Oct 2024 16:13:37 +0200 Subject: [PATCH 034/253] `tracing_subscriber::fmt` does not mix with `tracing_tree` It resulted in duplicated log lines that contain the whole history of a given line, rendering complex logs entirely unusable. --- cli/driver/src/driver.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cli/driver/src/driver.rs b/cli/driver/src/driver.rs index bccfe3a96..3a6a92823 100644 --- a/cli/driver/src/driver.rs +++ b/cli/driver/src/driver.rs @@ -60,11 +60,6 @@ fn setup_logging() { }; let subscriber = tracing_subscriber::Registry::default() .with(tracing_subscriber::EnvFilter::from_default_env()) - .with( - tracing_subscriber::fmt::layer() - .with_file(true) - .with_line_number(true), - ) .with( tracing_tree::HierarchicalLayer::new(2) .with_ansi(enable_colors) From c547a6badd7dc37f87dcd6bbed0f5a7ab1d9eddc Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 14 Oct 2024 14:03:09 +0200 Subject: [PATCH 035/253] fix(exporter): `get_variant_information`: works fine on unions The helper function `get_variant_information` had an assertion about the ADT being anything but an union. This function works fine on unions, though. A union is just like a struct: the difference is the semantics of its only variant. This is unrelated to `VariantInformations`. --- frontend/exporter/src/rustc_utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index 241216b84..f260f1468 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -26,7 +26,6 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( variant_index: rustc_target::abi::VariantIdx, s: &S, ) -> VariantInformations { - s_assert!(s, !adt_def.is_union() || *CORE_EXTRACTION_MODE); fn is_record<'s, I: std::iter::Iterator + Clone>(it: I) -> bool { it.clone() .any(|field| field.name.to_ident_string().parse::().is_err()) From 33d45a839515ee59d681a4da240755b2512faa70 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 14 Oct 2024 15:39:42 +0200 Subject: [PATCH 036/253] Implement `FullDef: SInto` by hand --- frontend/exporter/src/types/new/full_def.rs | 44 ++++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 784de0a67..c664967a8 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -6,36 +6,51 @@ use rustc_middle::ty; use rustc_span::def_id::DefId as RDefId; /// Gathers a lot of definition information about a [`rustc_hir::def_id::DefId`]. -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::def_id::DefId, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct FullDef { - #[value(self.sinto(s))] pub def_id: DefId, - #[value(s.base().tcx.opt_parent(*self).sinto(s))] + /// The enclosing item. pub parent: Option, - #[value(s.base().tcx.def_span(*self).sinto(s))] pub span: Span, - #[value(s.base().tcx.get_attrs_unchecked(*self).sinto(s))] /// Attributes on this definition, if applicable. pub attributes: Vec, - #[value(get_def_visibility(s, *self))] /// Visibility of the definition, for definitions where this makes sense. pub visibility: Option, - #[value(s.base().tcx.as_lang_item(*self).map(|litem| litem.name()).sinto(s))] /// If this definition is a lang item, we store the identifier, e.g. `sized`. pub lang_item: Option, - #[value(s.base().tcx.get_diagnostic_name(*self).sinto(s))] /// If this definition is a diagnostic item, we store the identifier, e.g. `box_new`. pub diagnostic_item: Option, - #[value({ - let state_with_id = State { thir: (), mir: (), owner_id: *self, binder: (), base: s.base() }; - s.base().tcx.def_kind(*self).sinto(&state_with_id) - })] pub kind: FullDefKind, } +#[cfg(feature = "rustc")] +impl<'tcx, S: BaseState<'tcx>> SInto for RDefId { + fn sinto(&self, s: &S) -> FullDef { + let tcx = s.base().tcx; + let def_id = *self; + let kind = { + let state_with_id = with_owner_id(s.base(), (), (), def_id); + tcx.def_kind(def_id).sinto(&state_with_id) + }; + FullDef { + def_id: self.sinto(s), + parent: tcx.opt_parent(def_id).sinto(s), + span: tcx.def_span(def_id).sinto(s), + attributes: tcx.get_attrs_unchecked(def_id).sinto(s), + visibility: get_def_visibility(tcx, def_id), + lang_item: s + .base() + .tcx + .as_lang_item(def_id) + .map(|litem| litem.name()) + .sinto(s), + diagnostic_item: tcx.get_diagnostic_name(def_id).sinto(s), + kind, + } + } +} + /// Imbues [`rustc_hir::def::DefKind`] with a lot of extra information. /// Important: the `owner_id()` must be the id of this definition. #[derive(AdtInto)] @@ -330,9 +345,8 @@ impl FullDef { /// Gets the visibility (`pub` or not) of the definition. Returns `None` for defs that don't have a /// meaningful visibility. #[cfg(feature = "rustc")] -fn get_def_visibility<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> Option { +fn get_def_visibility<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Option { use rustc_hir::def::DefKind::*; - let tcx = s.base().tcx; match tcx.def_kind(def_id) { AssocConst | AssocFn From 9aac819484c93ffbfecee44ba6a3939623ee3f7a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 14 Oct 2024 14:56:45 +0200 Subject: [PATCH 037/253] Cache `FullDef` translation --- frontend/exporter/src/state.rs | 4 +++- frontend/exporter/src/types/new/full_def.rs | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index f6a2a053a..cb3aa5254 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -99,7 +99,7 @@ macro_rules! mk { mod types { use crate::prelude::*; use rustc_middle::ty; - use std::cell::RefCell; + use std::{cell::RefCell, sync::Arc}; pub struct LocalContextS { pub vars: HashMap, @@ -133,6 +133,8 @@ mod types { pub struct ItemCache<'tcx> { /// The translated `DefId`. pub def_id: Option, + /// The translated definition. + pub full_def: Option>, /// Cache the `Ty` translations. pub tys: HashMap, Ty>, /// Cache the trait resolution engine for each item. diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index c664967a8..15861be4c 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -4,6 +4,8 @@ use crate::prelude::*; use rustc_middle::ty; #[cfg(feature = "rustc")] use rustc_span::def_id::DefId as RDefId; +#[cfg(feature = "rustc")] +use std::sync::Arc; /// Gathers a lot of definition information about a [`rustc_hir::def_id::DefId`]. #[derive_group(Serializers)] @@ -25,15 +27,18 @@ pub struct FullDef { } #[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>> SInto for RDefId { - fn sinto(&self, s: &S) -> FullDef { +impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { + fn sinto(&self, s: &S) -> Arc { + if let Some(full_def) = s.with_item_cache(*self, |cache| cache.full_def.clone()) { + return full_def; + } let tcx = s.base().tcx; let def_id = *self; let kind = { let state_with_id = with_owner_id(s.base(), (), (), def_id); tcx.def_kind(def_id).sinto(&state_with_id) }; - FullDef { + let full_def = FullDef { def_id: self.sinto(s), parent: tcx.opt_parent(def_id).sinto(s), span: tcx.def_span(def_id).sinto(s), @@ -47,7 +52,10 @@ impl<'tcx, S: BaseState<'tcx>> SInto for RDefId { .sinto(s), diagnostic_item: tcx.get_diagnostic_name(def_id).sinto(s), kind, - } + }; + let full_def: Arc = Arc::new(full_def); + s.with_item_cache(*self, |cache| cache.full_def = Some(full_def.clone())); + full_def } } From 200fef4981f3d0883aed80ab0544977f7492f5aa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 14 Oct 2024 15:01:18 +0200 Subject: [PATCH 038/253] Include the `FullDef` of associated items in `FullDefKind::Trait/Impl` --- frontend/exporter/src/types/new/full_def.rs | 29 ++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 15861be4c..565c21f32 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -1,11 +1,10 @@ use crate::prelude::*; +use std::sync::Arc; #[cfg(feature = "rustc")] use rustc_middle::ty; #[cfg(feature = "rustc")] use rustc_span::def_id::DefId as RDefId; -#[cfg(feature = "rustc")] -use std::sync::Arc; /// Gathers a lot of definition information about a [`rustc_hir::def_id::DefId`]. #[derive_group(Serializers)] @@ -109,8 +108,17 @@ pub enum FullDefKind { })] self_predicate: TraitPredicate, /// Associated items, in definition order. - #[value(s.base().tcx.associated_items(s.owner_id()).in_definition_order().collect::>().sinto(s))] - items: Vec, + #[value( + s + .base() + .tcx + .associated_items(s.owner_id()) + .in_definition_order() + .map(|assoc| (assoc, assoc.def_id)) + .collect::>() + .sinto(s) + )] + items: Vec<(AssocItem, Arc)>, }, /// Type alias: `type Foo = Bar;` TyAlias { @@ -263,8 +271,17 @@ pub enum FullDefKind { #[value(s.base().tcx.impl_subject(s.owner_id()).instantiate_identity().sinto(s))] impl_subject: ImplSubject, /// Associated items, in definition order. - #[value(s.base().tcx.associated_items(s.owner_id()).in_definition_order().collect::>().sinto(s))] - items: Vec, + #[value( + s + .base() + .tcx + .associated_items(s.owner_id()) + .in_definition_order() + .map(|assoc| (assoc, assoc.def_id)) + .collect::>() + .sinto(s) + )] + items: Vec<(AssocItem, Arc)>, }, /// A field in a struct, enum or union. e.g. /// - `bar` in `struct Foo { bar: u8 }` From 651ae5a7d12cf20dd84d5b3aa0534a810d5e098d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 14 Oct 2024 15:44:57 +0200 Subject: [PATCH 039/253] Add more information to `FullDef` --- frontend/exporter/src/types/copied.rs | 47 +++++++++++++++------ frontend/exporter/src/types/new/full_def.rs | 19 ++++++++- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index f52897b03..453d95d10 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -3879,25 +3879,46 @@ pub enum PredicateKind { } /// Reflects [`rustc_middle::ty::ImplSubject`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ImplSubject<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ImplSubject { - Trait( - // Also record the polarity. - #[map({ - let polarity = s.base().tcx.impl_polarity(s.owner_id()); - TraitPredicate { - trait_ref: x.sinto(s), - is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive), - } - })] - TraitPredicate, - ), + Trait { + /// The trait that is implemented by this impl block. + trait_pred: TraitPredicate, + /// The `ImplExpr`s required to satisfy the predicates on the trait declaration. E.g.: + /// ```ignore + /// trait Foo: Bar {} + /// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`. + /// ``` + required_impl_exprs: Vec, + }, Inherent(Ty), } +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<'tcx> { + fn sinto(&self, s: &S) -> ImplSubject { + let tcx = s.base().tcx; + match self { + ty::ImplSubject::Inherent(ty) => ImplSubject::Inherent(ty.sinto(s)), + ty::ImplSubject::Trait(trait_ref) => { + // Also record the polarity. + let polarity = tcx.impl_polarity(s.owner_id()); + let trait_pred = TraitPredicate { + trait_ref: trait_ref.sinto(s), + is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive), + }; + let required_impl_exprs = + solve_item_traits(s, trait_ref.def_id, trait_ref.args, None); + ImplSubject::Trait { + trait_pred, + required_impl_exprs, + } + } + } + } +} + /// Reflects [`rustc_hir::GenericBounds`] type GenericBounds = Vec; diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 565c21f32..a24e9b357 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -13,7 +13,12 @@ pub struct FullDef { pub def_id: DefId, /// The enclosing item. pub parent: Option, + /// The span of the definition of this item (e.g. for a function this is is signature). pub span: Span, + /// The span of the whole definition (including e.g. the function body). + pub source_span: Option, + /// The text of the whole definition. + pub source_text: Option, /// Attributes on this definition, if applicable. pub attributes: Vec, /// Visibility of the definition, for definitions where this makes sense. @@ -37,10 +42,17 @@ impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { let state_with_id = with_owner_id(s.base(), (), (), def_id); tcx.def_kind(def_id).sinto(&state_with_id) }; + + let source_span = def_id.as_local().map(|ldid| tcx.source_span(ldid)); + let source_text = source_span + .filter(|source_span| source_span.ctxt().is_root()) + .and_then(|source_span| tcx.sess.source_map().span_to_snippet(source_span).ok()); let full_def = FullDef { def_id: self.sinto(s), parent: tcx.opt_parent(def_id).sinto(s), span: tcx.def_span(def_id).sinto(s), + source_span: source_span.sinto(s), + source_text, attributes: tcx.get_attrs_unchecked(def_id).sinto(s), visibility: get_def_visibility(tcx, def_id), lang_item: s @@ -99,7 +111,7 @@ pub enum FullDefKind { generics: TyGenerics, #[value(get_generic_predicates(s, s.owner_id()))] predicates: GenericPredicates, - // `predicates_of` has the special `Self: Trait` clause as its last element. + /// The special `Self: Trait` clause. #[value({ use ty::Upcast; let tcx = s.base().tcx; @@ -294,6 +306,11 @@ pub enum FullDefKind { } impl FullDef { + #[cfg(feature = "rustc")] + pub fn rust_def_id(&self) -> RDefId { + (&self.def_id).into() + } + pub fn kind(&self) -> &FullDefKind { &self.kind } From 8e81a9d1db50ba6d76603df6565132f6731250ac Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 14 Oct 2024 15:19:30 +0200 Subject: [PATCH 040/253] feat(frontend): add support for union types --- engine/lib/concrete_ident/concrete_ident.ml | 10 ++--- engine/lib/import_thir.ml | 44 +++++++++++---------- frontend/exporter/src/rustc_utils.rs | 20 ++++++---- frontend/exporter/src/types/copied.rs | 32 +++++++++------ 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index 96562978d..1508d11a5 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -284,9 +284,9 @@ module View = struct last.data |> Imported.of_def_path_item |> string_of_def_path_item |> Option.map ~f:escape in - let arity0 ty = + let arity0 (ty : Types.ty) = match ty.Types.kind with - | Types.Bool -> Some "bool" + | Bool -> Some "bool" | Char -> Some "char" | Str -> Some "str" | Never -> Some "never" @@ -310,9 +310,9 @@ module View = struct | _ -> None in let apply left right = left ^ "_of_" ^ right in - let rec arity1 ty = - match ty.Types.kind with - | Types.Slice sub -> arity1 sub |> Option.map ~f:(apply "slice") + let rec arity1 (ty : Types.ty) = + match ty.kind with + | Slice sub -> arity1 sub |> Option.map ~f:(apply "slice") | Ref (_, sub, _) -> arity1 sub |> Option.map ~f:(apply "ref") | Adt { def_id; generic_args = [ Type arg ]; _ } -> let* adt = adt def_id in diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 60aae64cc..eb44d8c51 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -679,9 +679,15 @@ end) : EXPR = struct (U.make_tuple_expr' ~span @@ List.map ~f:c_expr fields).e | Array { fields } -> Array (List.map ~f:c_expr fields) | Adt { info; base; fields; _ } -> - let constructor = - def_id (Constructor { is_struct = info.typ_is_struct }) info.variant + let is_struct, is_record = + match info.kind with + | Struct { named } -> (true, named) + | Enum { named; _ } -> (false, named) + | Union -> + unimplemented ~issue_id:998 [ e.span ] + "Construct union types: not supported" in + let constructor = def_id (Constructor { is_struct }) info.variant in let base = Option.map ~f:(fun base -> (c_expr base.base, W.construct_base)) @@ -695,14 +701,7 @@ end) : EXPR = struct (field, value)) fields in - Construct - { - is_record = info.variant_is_record; - is_struct = info.typ_is_struct; - constructor; - fields; - base; - } + Construct { is_record; is_struct; constructor; fields; base } | Literal { lit; neg; _ } -> ( match c_lit e.span neg lit typ with | EL_Lit lit -> Literal lit @@ -873,17 +872,17 @@ end) : EXPR = struct let var = local_ident Expr var in PBinding { mut; mode; var; typ; subpat } | Variant { info; subpatterns; _ } -> - let name = - def_id (Constructor { is_struct = info.typ_is_struct }) info.variant + let is_struct, is_record = + match info.kind with + | Struct { named } -> (true, named) + | Enum { named; _ } -> (false, named) + | Union -> + unimplemented ~issue_id:998 [ pat.span ] + "Pattern match on union types: not supported" in + let name = def_id (Constructor { is_struct }) info.variant in let args = List.map ~f:(c_field_pat info) subpatterns in - PConstruct - { - name; - args; - is_record = info.variant_is_record; - is_struct = info.typ_is_struct; - } + PConstruct { name; args; is_record; is_struct } | Tuple { subpatterns } -> (List.map ~f:c_pat subpatterns |> U.make_tuple_pat').p | Deref { subpattern } -> @@ -1519,7 +1518,8 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = ~f: (fun ({ data; def_id = variant_id; attributes; _ } as original) -> let is_record = - [%matches? Types.Struct { fields = _ :: _; _ }] data + [%matches? (Struct { fields = _ :: _; _ } : Types.variant_data)] + data in let name = Concrete_ident.of_def_id kind variant_id in let arguments = @@ -1757,8 +1757,10 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = } in [ { span; v; ident = Concrete_ident.of_def_id Value def_id; attrs } ] + | Union _ -> + unimplemented ~issue_id:998 [ item.span ] "Union types: not supported" | ExternCrate _ | Static _ | Macro _ | Mod _ | ForeignMod _ | GlobalAsm _ - | OpaqueTy _ | Union _ | TraitAlias _ -> + | OpaqueTy _ | TraitAlias _ -> mk NotImplementedYet let import_item ~drop_body (item : Thir.item) : diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index f260f1468..ce0bd95ba 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -26,22 +26,28 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( variant_index: rustc_target::abi::VariantIdx, s: &S, ) -> VariantInformations { - fn is_record<'s, I: std::iter::Iterator + Clone>(it: I) -> bool { + s_assert!(s, !adt_def.is_union() || *CORE_EXTRACTION_MODE); + fn is_named<'s, I: std::iter::Iterator + Clone>(it: I) -> bool { it.clone() .any(|field| field.name.to_ident_string().parse::().is_err()) } let variant_def = adt_def.variant(variant_index); let variant = variant_def.def_id; let constructs_type: DefId = adt_def.did().sinto(s); + let kind = if adt_def.is_struct() { + let named = is_named(adt_def.all_fields()); + VariantKind::Struct { named } + } else if adt_def.is_union() { + VariantKind::Union + } else { + let named = is_named(variant_def.fields.iter()); + let index = variant_index.into(); + VariantKind::Enum { index, named } + }; VariantInformations { typ: constructs_type.clone(), variant: variant.sinto(s), - variant_index: variant_index.into(), - - typ_is_record: adt_def.is_struct() && is_record(adt_def.all_fields()), - variant_is_record: is_record(variant_def.fields.iter()), - typ_is_struct: adt_def.is_struct(), - + kind, type_namespace: DefId { path: match constructs_type.path.as_slice() { [init @ .., _] => init.to_vec(), diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index f52897b03..68d07d42a 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -2075,6 +2075,26 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtD } } +/// Describe the kind of a variant +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum VariantKind { + /// The variant is the only variant of a `struct` type + Struct { + /// Are the fields on this struct all named? + named: bool, + }, + /// The variant is the only variant of a `union` type + Union, + /// The variant is one of the many variants of a `enum` type + Enum { + /// The index of this variant in the `enum` + index: VariantIdx, + /// Are the fields on this struct all named? + named: bool, + }, +} + /// Describe a variant #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -2083,17 +2103,7 @@ pub struct VariantInformations { pub typ: DefId, pub variant: DefId, - pub variant_index: VariantIdx, - - /// A record type is a type with only one variant which is a - /// record variant. - pub typ_is_record: bool, - /// A record variant is a variant whose fields are named, a record - /// variant always has at least one field. - pub variant_is_record: bool, - /// A struct is a type with exactly one variant. Note that one - /// variant is named exactly as the type. - pub typ_is_struct: bool, + pub kind: VariantKind, } /// Reflects [`rustc_middle::thir::PatKind`] From 39d9fe494d2ceb62d9d43631ea5456766b7f5fbf Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 15 Oct 2024 09:21:49 +0200 Subject: [PATCH 041/253] Avoid a panic when retrieving attributes --- frontend/exporter/src/types/new/full_def.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index a24e9b357..b060de84a 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -53,7 +53,7 @@ impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { span: tcx.def_span(def_id).sinto(s), source_span: source_span.sinto(s), source_text, - attributes: tcx.get_attrs_unchecked(def_id).sinto(s), + attributes: get_def_attrs(tcx, def_id).sinto(s), visibility: get_def_visibility(tcx, def_id), lang_item: s .base() @@ -424,6 +424,17 @@ fn get_def_visibility<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Option(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> &'tcx [rustc_ast::ast::Attribute] { + use rustc_hir::def::DefKind::*; + match tcx.def_kind(def_id) { + // These kinds cause `get_attrs_unchecked` to panic. + ConstParam | LifetimeParam | TyParam => &[], + _ => tcx.get_attrs_unchecked(def_id), + } +} + /// This normalizes trait clauses before calling `sinto` on them. This is a bit of a hack required /// by charon for now. We can't normalize all clauses as this would lose region information in /// outlives clauses. From f7e01ae58a62cf9d2aaa0244cac219d33f40f6f0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 15 Oct 2024 14:29:24 +0200 Subject: [PATCH 042/253] Ignore nested obligations when resolving local clauses --- frontend/exporter/src/traits/resolution.rs | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 342025f6f..4a50a002e 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -338,27 +338,28 @@ impl<'tcx> PredicateSearcher<'tcx> { let nested = match &impl_source { Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { nested, .. })) => { - nested.as_slice() + // The nested obligations of depth 1 correspond (we hope) to the predicates on the + // relevant impl that need to be satisfied. + nested + .iter() + .filter(|obligation| obligation.recursion_depth == 1) + .filter_map(|obligation| { + obligation.predicate.as_trait_clause().map(|trait_ref| { + self.resolve(&trait_ref.map_bound(|p| p.trait_ref), warn) + }) + }) + .collect::>()? } - Ok(ImplSource::Param(nested)) => nested.as_slice(), + // Nested obligations can happen e.g. for GATs. We ignore these as we resolve local + // clauses ourselves. + Ok(ImplSource::Param(_)) => vec![], // We ignore the contained obligations here. For example for `(): Send`, the // obligations contained would be `[(): Send]`, which leads to an infinite loop. There // might be important obligations here in other cases; we'll have to see if that comes // up. - Ok(ImplSource::Builtin(_, _ignored)) => &[], - Err(_) => &[], + Ok(ImplSource::Builtin(..)) => vec![], + Err(_) => vec![], }; - let nested = nested - .iter() - // Only keep depth-1 obligations to avoid duplicate impl exprs. - .filter(|obligation| obligation.recursion_depth == 1) - .filter_map(|obligation| { - obligation - .predicate - .as_trait_clause() - .map(|trait_ref| self.resolve(&trait_ref.map_bound(|p| p.trait_ref), warn)) - }) - .collect::>()?; Ok(ImplExpr { r#impl: atom, From 114519c0574a131df6042fb40919849eef93df87 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 15 Oct 2024 15:29:03 +0200 Subject: [PATCH 043/253] Track GAT information in trait resolution --- frontend/exporter/src/traits.rs | 16 ++++- frontend/exporter/src/traits/resolution.rs | 68 +++++++++++++++++----- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 80ceb27fb..0799cad29 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -17,17 +17,29 @@ pub use resolution::PredicateSearcher; pub enum ImplExprPathChunk { AssocItem { item: AssocItem, + /// The arguments provided to the item (for GATs). + generic_args: Vec, + /// The impl exprs that must be satisfied to apply the given arguments to the item. E.g. + /// `T: Clone` in the following example: + /// ```ignore + /// trait Foo { + /// type Type: Debug; + /// } + /// ``` + impl_exprs: Vec, + /// The implemented predicate. predicate: Binder, #[value(<_ as SInto<_, Clause>>::sinto(predicate, s).id)] predicate_id: PredicateId, - /// The nth predicate returned by `tcx.item_bounds`. + /// The index of this predicate in the list returned by `tcx.item_bounds`. index: usize, }, Parent { + /// The implemented predicate. predicate: Binder, #[value(<_ as SInto<_, Clause>>::sinto(predicate, s).id)] predicate_id: PredicateId, - /// The nth predicate returned by `tcx.predicates_of`. + /// The index of this predicate in the list returned by `tcx.predicates_of`. index: usize, }, } diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 4a50a002e..725044b64 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -14,13 +14,25 @@ use crate::traits::utils::erase_and_norm; pub enum PathChunk<'tcx> { AssocItem { item: AssocItem, + /// The arguments provided to the item (for GATs). + generic_args: &'tcx [GenericArg<'tcx>], + /// The impl exprs that must be satisfied to apply the given arguments to the item. E.g. + /// `T: Clone` in the following example: + /// ```ignore + /// trait Foo { + /// type Type: Debug; + /// } + /// ``` + impl_exprs: Vec>, + /// The implemented predicate. predicate: PolyTraitPredicate<'tcx>, - /// The nth predicate returned by `tcx.item_bounds`. + /// The index of this predicate in the list returned by `tcx.item_bounds`. index: usize, }, Parent { + /// The implemented predicate. predicate: PolyTraitPredicate<'tcx>, - /// The nth predicate returned by `tcx.predicates_of`. + /// The index of this predicate in the list returned by `tcx.predicates_of`. index: usize, }, } @@ -213,20 +225,27 @@ impl<'tcx> PredicateSearcher<'tcx> { } /// If the type is a trait associated type, we add any relevant bounds to our context. - fn add_associated_type_refs(&mut self, ty: Binder<'tcx, Ty<'tcx>>) { + fn add_associated_type_refs( + &mut self, + ty: Binder<'tcx, Ty<'tcx>>, + // Call back into hax-related code to display a nice warning. + warn: &impl Fn(&str), + ) -> Result<(), String> { let tcx = self.tcx; // Note: We skip a binder but rebind it just after. let TyKind::Alias(AliasTyKind::Projection, alias_ty) = ty.skip_binder().kind() else { - return; + return Ok(()); }; - let trait_ref = ty.rebind(alias_ty.trait_ref(tcx)).upcast(tcx); + let (trait_ref, item_args) = alias_ty.trait_ref_and_own_args(tcx); + let trait_ref = ty.rebind(trait_ref).upcast(tcx); // The predicate we're looking for is is `::Type: OtherTrait`. We look up `T as // Trait` in the current context and add all the bounds on `Trait::Type` to our context. - let Some(trait_candidate) = self.lookup(trait_ref) else { - return; + let Some(trait_candidate) = self.resolve_local(trait_ref, warn)? else { + return Ok(()); }; + // The bounds that the associated type must validate. let item_bounds = tcx // TODO: `item_bounds` can contain parent traits, we don't want them .item_bounds(alias_ty.def_id) @@ -235,6 +254,16 @@ impl<'tcx> PredicateSearcher<'tcx> { .filter_map(|pred| pred.as_trait_clause()) .enumerate(); + // Resolve predicates required to mention the item. + let nested_impl_exprs: Vec<_> = tcx + .predicates_defined_on(alias_ty.def_id) + .predicates + .iter() + .filter_map(|(clause, _span)| clause.as_trait_clause()) + .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) + .map(|trait_ref| self.resolve(&trait_ref, warn)) + .collect::>()?; + // Add all the bounds on the corresponding associated item. self.extend(item_bounds.map(|(index, pred)| { let mut candidate = Candidate { @@ -244,26 +273,35 @@ impl<'tcx> PredicateSearcher<'tcx> { }; candidate.path.push(PathChunk::AssocItem { item: tcx.associated_item(alias_ty.def_id), + generic_args: item_args, + impl_exprs: nested_impl_exprs.clone(), predicate: pred, index, }); candidate })); + + Ok(()) } - /// Lookup a predicate in this set. If the predicate applies to an associated type, we - /// add the relevant implied associated type bounds to the set as well. - fn lookup(&mut self, target: PolyTraitPredicate<'tcx>) -> Option> { + /// Resolve a local clause by looking it up in this set. If the predicate applies to an + /// associated type, we add the relevant implied associated type bounds to the set as well. + fn resolve_local( + &mut self, + target: PolyTraitPredicate<'tcx>, + // Call back into hax-related code to display a nice warning. + warn: &impl Fn(&str), + ) -> Result>, String> { tracing::trace!("Looking for {target:?}"); // Look up the predicate let ret = self.candidates.get(&target).cloned(); if ret.is_some() { - return ret; + return Ok(ret); } // Add clauses related to associated type in the `Self` type of the predicate. - self.add_associated_type_refs(target.self_ty()); + self.add_associated_type_refs(target.self_ty(), warn)?; let ret = self.candidates.get(&target).cloned(); if ret.is_none() { @@ -275,7 +313,7 @@ impl<'tcx> PredicateSearcher<'tcx> { .join("") ); } - ret + Ok(ret) } /// Resolve the given trait reference in the local context. @@ -304,7 +342,9 @@ impl<'tcx> PredicateSearcher<'tcx> { def_id: impl_def_id, generics, }, - Ok(ImplSource::Param(_)) => match self.lookup(erased_tref.upcast(self.tcx)) { + Ok(ImplSource::Param(_)) => match self + .resolve_local(erased_tref.upcast(self.tcx), warn)? + { Some(candidate) => { let path = candidate.path; let r#trait = candidate.origin.clause.to_poly_trait_ref(); From 1c87998b12027f5018ea4f8205556f432ea43f71 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 15 Oct 2024 17:24:33 +0200 Subject: [PATCH 044/253] Support non-tuple constant references --- frontend/exporter/src/constant_utils.rs | 46 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 7005b7eb8..99cc977a3 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -581,27 +581,43 @@ mod rustc { .s_unwrap(s); // Iterate over the fields, which should be values - assert!(dc.variant.is_none()); - - // The type should be tuple - let hax_ty: Ty = ty.sinto(s); - match hax_ty.kind() { - TyKind::Tuple(_) => (), - _ => { - fatal!(s[span], "Expected the type to be tuple: {:?}", val) - } - }; - // Below: we are mutually recursive with [const_value_to_constant_expr], // which takes a [Const] as input, but it should be // ok because we call it on a strictly smaller value. - let fields: Vec = dc + let fields = dc .fields .iter() .copied() - .map(|(val, ty)| const_value_to_constant_expr(s, ty, val, span)) - .collect(); - (ConstantExprKind::Tuple { fields }).decorate(hax_ty, span.sinto(s)) + .map(|(val, ty)| const_value_to_constant_expr(s, ty, val, span)); + + // The type should be tuple + let hax_ty: Ty = ty.sinto(s); + match ty.kind() { + ty::TyKind::Tuple(_) => { + assert!(dc.variant.is_none()); + let fields = fields.collect(); + ConstantExprKind::Tuple { fields } + } + ty::TyKind::Adt(adt_def, ..) => { + let variant = dc.variant.unwrap_or(rustc_target::abi::FIRST_VARIANT); + let variants_info = get_variant_information(adt_def, variant, s); + let fields = fields + .zip(&adt_def.variant(variant).fields) + .map(|(value, field)| ConstantFieldExpr { + field: field.did.sinto(s), + value, + }) + .collect(); + ConstantExprKind::Adt { + info: variants_info, + fields, + } + } + _ => { + fatal!(s[span], "Expected the type to be tuple or adt: {:?}", val) + } + } + .decorate(hax_ty, span.sinto(s)) } pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( From 4d5abb0d234b8022f5faea176365958424ffe05f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 15 Oct 2024 17:25:12 +0200 Subject: [PATCH 045/253] Support non-tuple ZSTs --- frontend/exporter/src/constant_utils.rs | 36 ++++++++++++++----------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 99cc977a3..bb1a81463 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -649,26 +649,30 @@ mod rustc { ConstValue::ZeroSized { .. } => { // Should be unit let hty: Ty = ty.sinto(s); - let cv = match hty.kind() { - TyKind::Tuple(tys) if tys.is_empty() => { + let cv = match ty.kind() { + ty::TyKind::Tuple(tys) if tys.is_empty() => { ConstantExprKind::Tuple { fields: Vec::new() } } - TyKind::Arrow(_) => match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def_id, args) => { - let (def_id, generics, generics_impls, method_impl) = - get_function_from_def_id_and_generics(s, *def_id, args); - - ConstantExprKind::FnPtr { - def_id, - generics, - generics_impls, - method_impl, - } + ty::TyKind::FnDef(def_id, args) => { + let (def_id, generics, generics_impls, method_impl) = + get_function_from_def_id_and_generics(s, *def_id, args); + + ConstantExprKind::FnPtr { + def_id, + generics, + generics_impls, + method_impl, } - kind => { - fatal!(s[span], "Unexpected:"; {kind}) + } + ty::TyKind::Adt(adt_def, ..) => { + assert_eq!(adt_def.variants().len(), 1); + let variant = rustc_target::abi::FIRST_VARIANT; + let variants_info = get_variant_information(adt_def, variant, s); + ConstantExprKind::Adt { + info: variants_info, + fields: vec![], } - }, + } _ => { fatal!( s[span], From cb3b260b3d4fb69c2a7d0dacf581a61e06808a1e Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 14 Oct 2024 15:29:37 +0200 Subject: [PATCH 046/253] Fix bug with recursive bundles depending on items from original modules. --- engine/lib/dependencies.ml | 49 ++++++++++++++++--- .../toolchain__cyclic-modules into-fstar.snap | 36 ++++++++++++++ tests/cyclic-modules/src/lib.rs | 15 ++++++ 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index 667426d50..0d7428412 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -197,14 +197,25 @@ module Make (F : Features.T) = struct G.fold_succ (fun dest bundles_graph -> let dest_mod = Namespace.of_concrete_ident dest in - if [%eq: Namespace.t] interm_mod dest_mod then - let g = + if [%eq: Namespace.t] start_mod dest_mod then + let bundles_graph = Bundle.G.add_edge bundles_graph start interm in - let g = Bundle.G.add_edge g interm dest in - g + let bundles_graph = + Bundle.G.add_edge bundles_graph interm dest + in + let bundles_graph = + G.fold_succ + (fun sec_interm bundles_graph -> + if G.mem_edge closure sec_interm dest then + Bundle.G.add_edge bundles_graph interm + sec_interm + else bundles_graph) + closure interm bundles_graph + in + bundles_graph else bundles_graph) - g start bundles_graph + closure interm bundles_graph else bundles_graph) g start bundles_graph in @@ -214,8 +225,32 @@ module Make (F : Features.T) = struct closure Bundle.G.empty in - let bundles = Bundle.cycles bundles_graph in - bundles + let preliminary_bundles = Bundle.cycles bundles_graph in + (* We also need to add to the bundle the dependencies of its items belonging + to the original modules, otherwise we would create a new cycle. + *) + let bundles_graph = + preliminary_bundles + |> List.fold ~init:bundles_graph ~f:(fun bundles_graph bundle -> + let modules = + bundle + |> List.map ~f:Namespace.of_concrete_ident + |> List.dedup_and_sort ~compare:Namespace.compare + in + List.fold bundle ~init:bundles_graph + ~f:(fun bundles_graph item -> + G.fold_succ + (fun dep bundles_graph -> + if + List.mem modules + (Namespace.of_concrete_ident dep) + ~equal:Namespace.equal + then Bundle.G.add_edge bundles_graph item dep + else bundles_graph) + closure item bundles_graph)) + in + let extended_bundles = Bundle.cycles bundles_graph in + extended_bundles let of_graph (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : Bundle.t list = diff --git a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap index 453e0d2a1..1ddcac958 100644 --- a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap @@ -144,6 +144,42 @@ include Cyclic_modules.Enums_b.Rec_bundle_573885887 {U_C as U_C} let f (_: Prims.unit) : t_T = T_A <: t_T ''' +"Cyclic_modules.M1.fst" = ''' +module Cyclic_modules.M1 +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.M2.Rec_bundle_180367580 {a as a} +''' +"Cyclic_modules.M2.Rec_bundle_180367580.fst" = ''' +module Cyclic_modules.M2.Rec_bundle_180367580 +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let c (_: Prims.unit) : Prims.unit = () + +let a (_: Prims.unit) : Prims.unit = c () + +let d (_: Prims.unit) : Prims.unit = () + +let b (_: Prims.unit) : Prims.unit = + let _:Prims.unit = a () in + d () +''' +"Cyclic_modules.M2.fst" = ''' +module Cyclic_modules.M2 +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.M2.Rec_bundle_180367580 {c as c} + +include Cyclic_modules.M2.Rec_bundle_180367580 {d as d} + +include Cyclic_modules.M2.Rec_bundle_180367580 {b as b} +''' "Cyclic_modules.Rec.fst" = ''' module Cyclic_modules.Rec #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" diff --git a/tests/cyclic-modules/src/lib.rs b/tests/cyclic-modules/src/lib.rs index daa7050eb..711bdd47b 100644 --- a/tests/cyclic-modules/src/lib.rs +++ b/tests/cyclic-modules/src/lib.rs @@ -118,3 +118,18 @@ mod enums_b { T::A } } + +mod m1 { + pub fn a() { + super::m2::c() + } +} + +mod m2 { + pub fn d() {} + pub fn b() { + super::m1::a(); + d() + } + pub fn c() {} +} From f99fe4a8e4393fef74048661aaddcc0e0a0cdc6e Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 15 Oct 2024 11:29:42 +0200 Subject: [PATCH 047/253] Simple solution to cyclic dependencies bundling. --- engine/lib/dependencies.ml | 203 ++++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 92 deletions(-) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index 0d7428412..807a107a4 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -155,13 +155,6 @@ module Make (F : Features.T) = struct end module CyclicDep = struct - (* We are looking for dependencies between items that give a cyclic dependency at the module level - (but not necessarily at the item level). All the items belonging to such a cycle should be bundled - together. *) - (* The algorithm is to take the transitive closure of the items dependency graph and look - for paths of length 3 that in terms of modules have the form A -> B -> A (A != B) *) - (* To compute the bundles, we keep a second (undirected graph) where an edge between two items - means they should be in the same bundle. The bundles are the connected components of this graph. *) module Bundle = struct type t = Concrete_ident.t list @@ -171,92 +164,119 @@ module Make (F : Features.T) = struct let cycles g = CC.components_list g end - let of_graph' (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : - Bundle.t list = - let closure = Oper.transitive_closure g in - - let bundles_graph = - G.fold_vertex - (fun start (bundles_graph : Bundle.G.t) -> - let start_mod = Namespace.of_concrete_ident start in - let cycle_modules = - List.filter mod_graph_cycles ~f:(fun cycle -> - Set.mem cycle start_mod) - |> List.reduce ~f:Set.union - in - match cycle_modules with - | Some cycle_modules -> - let bundles_graph = - G.fold_succ - (fun interm bundles_graph -> - let interm_mod = Namespace.of_concrete_ident interm in - if - (not ([%eq: Namespace.t] interm_mod start_mod)) - && Set.mem cycle_modules interm_mod - then + (* This is a solution that bundles together everything that belongs to the same module SCC. + It results in bundles that are much bigger than they could be but is a simple solution + to the problem described in https://github.com/hacspec/hax/issues/995#issuecomment-2411114404 *) + let of_mod_sccs (items : item list) + (mod_graph_cycles : Namespace.Set.t list) : Bundle.t list = + let item_names = List.map items ~f:(fun x -> x.ident) in + let cycles = + List.filter mod_graph_cycles ~f:(fun set -> + Prelude.Set.length set > 1) + in + let bundles = + List.map cycles ~f:(fun set -> + List.filter item_names ~f:(fun item -> + Prelude.Set.mem set (Namespace.of_concrete_ident item))) + in + bundles + + (* + + (* We are looking for dependencies between items that give a cyclic dependency at the module level + (but not necessarily at the item level). All the items belonging to such a cycle should be bundled + together. *) + (* The algorithm is to take the transitive closure of the items dependency graph and look + for paths of length 3 that in terms of modules have the form A -> B -> A (A != B) *) + (* To compute the bundles, we keep a second (undirected graph) where an edge between two items + means they should be in the same bundle. The bundles are the connected components of this graph. *) + + let of_graph' (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : + Bundle.t list = + let closure = Oper.transitive_closure g in + + let bundles_graph = + G.fold_vertex + (fun start (bundles_graph : Bundle.G.t) -> + let start_mod = Namespace.of_concrete_ident start in + let cycle_modules = + List.filter mod_graph_cycles ~f:(fun cycle -> + Set.mem cycle start_mod) + |> List.reduce ~f:Set.union + in + match cycle_modules with + | Some cycle_modules -> + let bundles_graph = G.fold_succ - (fun dest bundles_graph -> - let dest_mod = Namespace.of_concrete_ident dest in - if [%eq: Namespace.t] start_mod dest_mod then - let bundles_graph = - Bundle.G.add_edge bundles_graph start interm - in - let bundles_graph = - Bundle.G.add_edge bundles_graph interm dest - in - let bundles_graph = - G.fold_succ - (fun sec_interm bundles_graph -> - if G.mem_edge closure sec_interm dest then - Bundle.G.add_edge bundles_graph interm - sec_interm - else bundles_graph) - closure interm bundles_graph - in - bundles_graph + (fun interm bundles_graph -> + let interm_mod = Namespace.of_concrete_ident interm in + if + (not ([%eq: Namespace.t] interm_mod start_mod)) + && Set.mem cycle_modules interm_mod + then + G.fold_succ + (fun dest bundles_graph -> + let dest_mod = Namespace.of_concrete_ident dest in + if [%eq: Namespace.t] start_mod dest_mod then + let bundles_graph = + Bundle.G.add_edge bundles_graph start interm + in + let bundles_graph = + Bundle.G.add_edge bundles_graph interm dest + in + let bundles_graph = + G.fold_succ + (fun sec_interm bundles_graph -> + if G.mem_edge closure sec_interm dest then + Bundle.G.add_edge bundles_graph interm + sec_interm + else bundles_graph) + closure interm bundles_graph + in + bundles_graph + else bundles_graph) + closure interm bundles_graph else bundles_graph) - closure interm bundles_graph - else bundles_graph) - g start bundles_graph - in - - bundles_graph - | None -> bundles_graph) - closure Bundle.G.empty - in + g start bundles_graph + in - let preliminary_bundles = Bundle.cycles bundles_graph in - (* We also need to add to the bundle the dependencies of its items belonging - to the original modules, otherwise we would create a new cycle. - *) - let bundles_graph = - preliminary_bundles - |> List.fold ~init:bundles_graph ~f:(fun bundles_graph bundle -> - let modules = - bundle - |> List.map ~f:Namespace.of_concrete_ident - |> List.dedup_and_sort ~compare:Namespace.compare - in - List.fold bundle ~init:bundles_graph - ~f:(fun bundles_graph item -> - G.fold_succ - (fun dep bundles_graph -> - if - List.mem modules - (Namespace.of_concrete_ident dep) - ~equal:Namespace.equal - then Bundle.G.add_edge bundles_graph item dep - else bundles_graph) - closure item bundles_graph)) - in - let extended_bundles = Bundle.cycles bundles_graph in - extended_bundles - - let of_graph (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : - Bundle.t list = - match mod_graph_cycles with - | [] -> [] - | _ -> of_graph' g mod_graph_cycles + bundles_graph + | None -> bundles_graph) + closure Bundle.G.empty + in + + let preliminary_bundles = Bundle.cycles bundles_graph in + (* We also need to add to the bundle the dependencies of its items belonging + to the original modules, otherwise we would create a new cycle. + *) + let bundles_graph = + preliminary_bundles + |> List.fold ~init:bundles_graph ~f:(fun bundles_graph bundle -> + let modules = + bundle + |> List.map ~f:Namespace.of_concrete_ident + |> List.dedup_and_sort ~compare:Namespace.compare + in + List.fold bundle ~init:bundles_graph + ~f:(fun bundles_graph item -> + G.fold_succ + (fun dep bundles_graph -> + if + List.mem modules + (Namespace.of_concrete_ident dep) + ~equal:Namespace.equal + then Bundle.G.add_edge bundles_graph item dep + else bundles_graph) + closure item bundles_graph)) + in + let extended_bundles = Bundle.cycles bundles_graph in + extended_bundles + + let of_graph (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : + Bundle.t list = + match mod_graph_cycles with + | [] -> [] + | _ -> of_graph' g mod_graph_cycles *) end open Graph.Graphviz.Dot (struct @@ -465,13 +485,12 @@ module Make (F : Features.T) = struct item' :: aliases let bundle_cyclic_modules (items : item list) : item list = - let g = ItemGraph.of_items ~original_items:items items in let from_ident ident : item option = List.find ~f:(fun i -> [%equal: Concrete_ident.t] i.ident ident) items in let mut_rec_bundles = let mod_graph_cycles = ModGraph.of_items items |> ModGraph.cycles in - let bundles = ItemGraph.CyclicDep.of_graph g mod_graph_cycles in + let bundles = ItemGraph.CyclicDep.of_mod_sccs items mod_graph_cycles in let f = List.filter_map ~f:from_ident in List.map ~f bundles in From 9f3c5aa04f707126a2dcf6bfd4ae6f109034a22e Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 15 Oct 2024 12:02:03 +0200 Subject: [PATCH 048/253] Fix renaming of struct variants. --- engine/lib/dependencies.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index 807a107a4..d9ee31b1b 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -530,6 +530,12 @@ module Make (F : Features.T) = struct List.map variants ~f:(fun { name; _ } -> ( name, Concrete_ident.Create.move_under ~new_parent:new_name name )) + | Some { v = Type { variants; is_struct = true; _ }; _ } -> + List.concat_map variants ~f:(fun { arguments; _ } -> + List.map arguments ~f:(fun (name, _, _) -> + ( name, + Concrete_ident.Create.move_under ~new_parent:new_name name + ))) | _ -> [] in From 158acf23c7d3e7cde3be8b3385e120be0b09c6bd Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 16 Oct 2024 10:31:27 +0200 Subject: [PATCH 049/253] Give a different name to a struct and its variant. --- engine/lib/import_thir.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index eb44d8c51..4a00c9531 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -1555,6 +1555,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = let v = let kind = Concrete_ident.Kind.Constructor { is_struct } in let name = Concrete_ident.of_def_id kind def_id in + let name = Concrete_ident.Create.move_under name ~new_parent:name in let mk fields is_record = let arguments = List.map From 3aec2cfc1b73ffee36f6a5e4d1ceeb680bd5d59e Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 16 Oct 2024 10:33:40 +0200 Subject: [PATCH 050/253] Remove commented code for cyclic dependencies. --- engine/lib/dependencies.ml | 97 -------------------------------------- 1 file changed, 97 deletions(-) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index d9ee31b1b..b926388d1 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -180,103 +180,6 @@ module Make (F : Features.T) = struct Prelude.Set.mem set (Namespace.of_concrete_ident item))) in bundles - - (* - - (* We are looking for dependencies between items that give a cyclic dependency at the module level - (but not necessarily at the item level). All the items belonging to such a cycle should be bundled - together. *) - (* The algorithm is to take the transitive closure of the items dependency graph and look - for paths of length 3 that in terms of modules have the form A -> B -> A (A != B) *) - (* To compute the bundles, we keep a second (undirected graph) where an edge between two items - means they should be in the same bundle. The bundles are the connected components of this graph. *) - - let of_graph' (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : - Bundle.t list = - let closure = Oper.transitive_closure g in - - let bundles_graph = - G.fold_vertex - (fun start (bundles_graph : Bundle.G.t) -> - let start_mod = Namespace.of_concrete_ident start in - let cycle_modules = - List.filter mod_graph_cycles ~f:(fun cycle -> - Set.mem cycle start_mod) - |> List.reduce ~f:Set.union - in - match cycle_modules with - | Some cycle_modules -> - let bundles_graph = - G.fold_succ - (fun interm bundles_graph -> - let interm_mod = Namespace.of_concrete_ident interm in - if - (not ([%eq: Namespace.t] interm_mod start_mod)) - && Set.mem cycle_modules interm_mod - then - G.fold_succ - (fun dest bundles_graph -> - let dest_mod = Namespace.of_concrete_ident dest in - if [%eq: Namespace.t] start_mod dest_mod then - let bundles_graph = - Bundle.G.add_edge bundles_graph start interm - in - let bundles_graph = - Bundle.G.add_edge bundles_graph interm dest - in - let bundles_graph = - G.fold_succ - (fun sec_interm bundles_graph -> - if G.mem_edge closure sec_interm dest then - Bundle.G.add_edge bundles_graph interm - sec_interm - else bundles_graph) - closure interm bundles_graph - in - bundles_graph - else bundles_graph) - closure interm bundles_graph - else bundles_graph) - g start bundles_graph - in - - bundles_graph - | None -> bundles_graph) - closure Bundle.G.empty - in - - let preliminary_bundles = Bundle.cycles bundles_graph in - (* We also need to add to the bundle the dependencies of its items belonging - to the original modules, otherwise we would create a new cycle. - *) - let bundles_graph = - preliminary_bundles - |> List.fold ~init:bundles_graph ~f:(fun bundles_graph bundle -> - let modules = - bundle - |> List.map ~f:Namespace.of_concrete_ident - |> List.dedup_and_sort ~compare:Namespace.compare - in - List.fold bundle ~init:bundles_graph - ~f:(fun bundles_graph item -> - G.fold_succ - (fun dep bundles_graph -> - if - List.mem modules - (Namespace.of_concrete_ident dep) - ~equal:Namespace.equal - then Bundle.G.add_edge bundles_graph item dep - else bundles_graph) - closure item bundles_graph)) - in - let extended_bundles = Bundle.cycles bundles_graph in - extended_bundles - - let of_graph (g : G.t) (mod_graph_cycles : Namespace.Set.t list) : - Bundle.t list = - match mod_graph_cycles with - | [] -> [] - | _ -> of_graph' g mod_graph_cycles *) end open Graph.Graphviz.Dot (struct From b5b1334a97c204c9539c96b842ffce5f2ba817c4 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 16 Oct 2024 10:38:39 +0200 Subject: [PATCH 051/253] Update test with new handling of cyclic dependencies. --- .../toolchain__cyclic-modules into-fstar.snap | 220 ++++++++++++------ tests/cyclic-modules/src/lib.rs | 13 ++ 2 files changed, 158 insertions(+), 75 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap index 1ddcac958..f0b6e249f 100644 --- a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap @@ -32,7 +32,7 @@ module Cyclic_modules.B open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_507852343 {g as g} +include Cyclic_modules.Rec_bundle_194616565 {g as g} ''' "Cyclic_modules.C.fst" = ''' module Cyclic_modules.C @@ -42,15 +42,29 @@ open FStar.Mul let i (_: Prims.unit) : Prims.unit = () ''' +"Cyclic_modules.D.Rec_bundle_773034964.fst" = ''' +module Cyclic_modules.D.Rec_bundle_773034964 +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let d1 (_: Prims.unit) : Prims.unit = () + +let e1 (_: Prims.unit) : Prims.unit = d1 () + +let de1 (_: Prims.unit) : Prims.unit = e1 () + +let d2 (_: Prims.unit) : Prims.unit = de1 () +''' "Cyclic_modules.D.fst" = ''' module Cyclic_modules.D #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul -include Cyclic_modules.E.Rec_bundle_868781766 {d1 as d1} +include Cyclic_modules.D.Rec_bundle_773034964 {d1 as d1} -include Cyclic_modules.E.Rec_bundle_868781766 {d2 as d2} +include Cyclic_modules.D.Rec_bundle_773034964 {d2 as d2} ''' "Cyclic_modules.De.fst" = ''' module Cyclic_modules.De @@ -58,21 +72,41 @@ module Cyclic_modules.De open Core open FStar.Mul -include Cyclic_modules.E.Rec_bundle_868781766 {de1 as de1} +include Cyclic_modules.D.Rec_bundle_773034964 {de1 as de1} ''' -"Cyclic_modules.E.Rec_bundle_868781766.fst" = ''' -module Cyclic_modules.E.Rec_bundle_868781766 +"Cyclic_modules.Disjoint_cycle_a.Rec_bundle_317759688.fst" = ''' +module Cyclic_modules.Disjoint_cycle_a.Rec_bundle_317759688 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul -let d1 (_: Prims.unit) : Prims.unit = () +let g (_: Prims.unit) : Prims.unit = () -let e1 (_: Prims.unit) : Prims.unit = d1 () +let h (_: Prims.unit) : Prims.unit = () -let de1 (_: Prims.unit) : Prims.unit = e1 () +let f (_: Prims.unit) : Prims.unit = h () -let d2 (_: Prims.unit) : Prims.unit = de1 () +let i (_: Prims.unit) : Prims.unit = g () +''' +"Cyclic_modules.Disjoint_cycle_a.fst" = ''' +module Cyclic_modules.Disjoint_cycle_a +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.Disjoint_cycle_a.Rec_bundle_317759688 {g as g} + +include Cyclic_modules.Disjoint_cycle_a.Rec_bundle_317759688 {f as f} +''' +"Cyclic_modules.Disjoint_cycle_b.fst" = ''' +module Cyclic_modules.Disjoint_cycle_b +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.Disjoint_cycle_a.Rec_bundle_317759688 {h as h} + +include Cyclic_modules.Disjoint_cycle_a.Rec_bundle_317759688 {i as i} ''' "Cyclic_modules.E.fst" = ''' module Cyclic_modules.E @@ -80,7 +114,7 @@ module Cyclic_modules.E open Core open FStar.Mul -include Cyclic_modules.E.Rec_bundle_868781766 {e1 as e1} +include Cyclic_modules.D.Rec_bundle_773034964 {e1 as e1} ''' "Cyclic_modules.Enums_a.fst" = ''' module Cyclic_modules.Enums_a @@ -88,18 +122,18 @@ module Cyclic_modules.Enums_a open Core open FStar.Mul -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {t_T240131830 as t_T} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {t_T240131830 as t_T} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T240131830_A as T_A} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T240131830_A as T_A} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T240131830_B as T_B} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T240131830_B as T_B} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T240131830_C as T_C} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T240131830_C as T_C} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T240131830_D as T_D} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T240131830_D as T_D} ''' -"Cyclic_modules.Enums_b.Rec_bundle_573885887.fst" = ''' -module Cyclic_modules.Enums_b.Rec_bundle_573885887 +"Cyclic_modules.Enums_b.Rec_bundle_994866580.fst" = ''' +module Cyclic_modules.Enums_b.Rec_bundle_994866580 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul @@ -119,6 +153,8 @@ and t_T240131830 = | T240131830_B : t_T240131830 | T240131830_C : Alloc.Vec.t_Vec t_U Alloc.Alloc.t_Global -> t_T240131830 | T240131830_D : Alloc.Vec.t_Vec t_T366415196 Alloc.Alloc.t_Global -> t_T240131830 + +let f (_: Prims.unit) : t_T366415196 = T366415196_A <: t_T366415196 ''' "Cyclic_modules.Enums_b.fst" = ''' module Cyclic_modules.Enums_b @@ -126,23 +162,23 @@ module Cyclic_modules.Enums_b open Core open FStar.Mul -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {t_T366415196 as t_T} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {t_T366415196 as t_T} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T366415196_A as T_A} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T366415196_A as T_A} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T366415196_B as T_B} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T366415196_B as T_B} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {T366415196_C as T_C} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {T366415196_C as T_C} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {t_U as t_U} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {t_U as t_U} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {U_A as U_A} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {U_A as U_A} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {U_B as U_B} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {U_B as U_B} -include Cyclic_modules.Enums_b.Rec_bundle_573885887 {U_C as U_C} +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {U_C as U_C} -let f (_: Prims.unit) : t_T = T_A <: t_T +include Cyclic_modules.Enums_b.Rec_bundle_994866580 {f as f} ''' "Cyclic_modules.M1.fst" = ''' module Cyclic_modules.M1 @@ -150,10 +186,10 @@ module Cyclic_modules.M1 open Core open FStar.Mul -include Cyclic_modules.M2.Rec_bundle_180367580 {a as a} +include Cyclic_modules.M2.Rec_bundle_489499412 {a as a} ''' -"Cyclic_modules.M2.Rec_bundle_180367580.fst" = ''' -module Cyclic_modules.M2.Rec_bundle_180367580 +"Cyclic_modules.M2.Rec_bundle_489499412.fst" = ''' +module Cyclic_modules.M2.Rec_bundle_489499412 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul @@ -174,11 +210,11 @@ module Cyclic_modules.M2 open Core open FStar.Mul -include Cyclic_modules.M2.Rec_bundle_180367580 {c as c} +include Cyclic_modules.M2.Rec_bundle_489499412 {c as c} -include Cyclic_modules.M2.Rec_bundle_180367580 {d as d} +include Cyclic_modules.M2.Rec_bundle_489499412 {d as d} -include Cyclic_modules.M2.Rec_bundle_180367580 {b as b} +include Cyclic_modules.M2.Rec_bundle_489499412 {b as b} ''' "Cyclic_modules.Rec.fst" = ''' module Cyclic_modules.Rec @@ -210,23 +246,23 @@ and g2 (x: t_T) : t_T = | T_t1 -> g1 x | T_t2 -> hf x ''' -"Cyclic_modules.Rec1_same_name.fst" = ''' -module Cyclic_modules.Rec1_same_name +"Cyclic_modules.Rec1_same_name.Rec_bundle_213192514.fst" = ''' +module Cyclic_modules.Rec1_same_name.Rec_bundle_213192514 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul -include Cyclic_modules.Rec2_same_name.Rec_bundle_784146069 {f533409751 as f} +let rec f533409751 (x: i32) : i32 = f91805216 x + +and f91805216 (x: i32) : i32 = if x >. 0l then f533409751 (x -! 1l <: i32) else 0l ''' -"Cyclic_modules.Rec2_same_name.Rec_bundle_784146069.fst" = ''' -module Cyclic_modules.Rec2_same_name.Rec_bundle_784146069 +"Cyclic_modules.Rec1_same_name.fst" = ''' +module Cyclic_modules.Rec1_same_name #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul -let rec f533409751 (x: i32) : i32 = f91805216 x - -and f91805216 (x: i32) : i32 = if x >. 0l then f533409751 (x -! 1l <: i32) else 0l +include Cyclic_modules.Rec1_same_name.Rec_bundle_213192514 {f533409751 as f} ''' "Cyclic_modules.Rec2_same_name.fst" = ''' module Cyclic_modules.Rec2_same_name @@ -234,10 +270,10 @@ module Cyclic_modules.Rec2_same_name open Core open FStar.Mul -include Cyclic_modules.Rec2_same_name.Rec_bundle_784146069 {f91805216 as f} +include Cyclic_modules.Rec1_same_name.Rec_bundle_213192514 {f91805216 as f} ''' -"Cyclic_modules.Rec_bundle_507852343.fst" = ''' -module Cyclic_modules.Rec_bundle_507852343 +"Cyclic_modules.Rec_bundle_194616565.fst" = ''' +module Cyclic_modules.Rec_bundle_194616565 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul @@ -249,6 +285,8 @@ let g (_: Prims.unit) : Prims.unit = f () let h (_: Prims.unit) : Prims.unit = let _:Prims.unit = g () in Cyclic_modules.C.i () + +let h2 (_: Prims.unit) : Prims.unit = Cyclic_modules.C.i () ''' "Cyclic_modules.Typ_a.fst" = ''' module Cyclic_modules.Typ_a @@ -256,22 +294,30 @@ module Cyclic_modules.Typ_a open Core open FStar.Mul -include Cyclic_modules.Typ_b.Rec_bundle_684725220 {t_T as t_T} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T as t_T} -include Cyclic_modules.Typ_b.Rec_bundle_684725220 {T_T as T_T} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {T_T as T_T} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {t_TRec as t_TRec} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_TRec as t_TRec} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {TRec_T as TRec_T} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {TRec_T as TRec_T} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {TRec_Empty as TRec_Empty} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {TRec_Empty as TRec_Empty} ''' -"Cyclic_modules.Typ_b.Rec_bundle_445945170.fst" = ''' -module Cyclic_modules.Typ_b.Rec_bundle_445945170 +"Cyclic_modules.Typ_b.Rec_bundle_546955701.fst" = ''' +module Cyclic_modules.Typ_b.Rec_bundle_546955701 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul +type t_T1 = | T1_T1 : t_T1 + +type t_T = | T_T : t_T1 -> t_T + +let t_T1_cast_to_repr (x: t_T1) : isize = match x with | T1_T1 -> isz 0 + +type t_T2 = | T2_T2 : t_T -> t_T2 + type t_TRec = | TRec_T : t_T1Rec -> t_TRec | TRec_Empty : t_TRec @@ -280,41 +326,29 @@ and t_T1Rec = | T1Rec_T1 : Alloc.Boxed.t_Box t_T2Rec Alloc.Alloc.t_Global -> t_T and t_T2Rec = | T2Rec_T2 : t_TRec -> t_T2Rec ''' -"Cyclic_modules.Typ_b.Rec_bundle_684725220.fst" = ''' -module Cyclic_modules.Typ_b.Rec_bundle_684725220 -#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" -open Core -open FStar.Mul - -type t_T1 = | T1_T1 : t_T1 - -type t_T = | T_T : t_T1 -> t_T - -type t_T2 = | T2_T2 : t_T -> t_T2 -''' "Cyclic_modules.Typ_b.fst" = ''' module Cyclic_modules.Typ_b #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul -include Cyclic_modules.Typ_b.Rec_bundle_684725220 {t_T1 as t_T1} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T1 as t_T1} -include Cyclic_modules.Typ_b.Rec_bundle_684725220 {T1_T1 as T1_T1} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {T1_T1 as T1_T1} -let t_T1_cast_to_repr (x: t_T1) : isize = match x with | T1_T1 -> isz 0 +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T1_cast_to_repr as t_T1_cast_to_repr} -include Cyclic_modules.Typ_b.Rec_bundle_684725220 {t_T2 as t_T2} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T2 as t_T2} -include Cyclic_modules.Typ_b.Rec_bundle_684725220 {T2_T2 as T2_T2} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {T2_T2 as T2_T2} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {t_T1Rec as t_T1Rec} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T1Rec as t_T1Rec} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {T1Rec_T1 as T1Rec_T1} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {T1Rec_T1 as T1Rec_T1} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {t_T2Rec as t_T2Rec} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T2Rec as t_T2Rec} -include Cyclic_modules.Typ_b.Rec_bundle_445945170 {T2Rec_T2 as T2Rec_T2} +include Cyclic_modules.Typ_b.Rec_bundle_546955701 {T2Rec_T2 as T2Rec_T2} ''' "Cyclic_modules.fst" = ''' module Cyclic_modules @@ -322,9 +356,45 @@ module Cyclic_modules open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_507852343 {f as f} +include Cyclic_modules.Rec_bundle_194616565 {v_DUMMY as v_DUMMY} -include Cyclic_modules.Rec_bundle_507852343 {h as h} +include Cyclic_modules.Rec_bundle_194616565 {b as b} -let h2 (_: Prims.unit) : Prims.unit = Cyclic_modules.C.i () +include Cyclic_modules.Rec_bundle_194616565 {c as c} + +include Cyclic_modules.Rec_bundle_194616565 {d as d} + +include Cyclic_modules.Rec_bundle_194616565 {de as de} + +include Cyclic_modules.Rec_bundle_194616565 {disjoint_cycle_a as disjoint_cycle_a} + +include Cyclic_modules.Rec_bundle_194616565 {disjoint_cycle_b as disjoint_cycle_b} + +include Cyclic_modules.Rec_bundle_194616565 {e as e} + +include Cyclic_modules.Rec_bundle_194616565 {enums_a as enums_a} + +include Cyclic_modules.Rec_bundle_194616565 {enums_b as enums_b} + +include Cyclic_modules.Rec_bundle_194616565 {m1 as m1} + +include Cyclic_modules.Rec_bundle_194616565 {m2 as m2} + +include Cyclic_modules.Rec_bundle_194616565 {v_rec as v_rec} + +include Cyclic_modules.Rec_bundle_194616565 {rec1_same_name as rec1_same_name} + +include Cyclic_modules.Rec_bundle_194616565 {rec2_same_name as rec2_same_name} + +include Cyclic_modules.Rec_bundle_194616565 {std as std} + +include Cyclic_modules.Rec_bundle_194616565 {typ_a as typ_a} + +include Cyclic_modules.Rec_bundle_194616565 {typ_b as typ_b} + +include Cyclic_modules.Rec_bundle_194616565 {f as f} + +include Cyclic_modules.Rec_bundle_194616565 {h as h} + +include Cyclic_modules.Rec_bundle_194616565 {h2 as h2} ''' diff --git a/tests/cyclic-modules/src/lib.rs b/tests/cyclic-modules/src/lib.rs index 711bdd47b..781a1e156 100644 --- a/tests/cyclic-modules/src/lib.rs +++ b/tests/cyclic-modules/src/lib.rs @@ -133,3 +133,16 @@ mod m2 { } pub fn c() {} } + +pub mod disjoint_cycle_a { + pub fn f() { + super::disjoint_cycle_b::h() + } + pub fn g() {} +} +pub mod disjoint_cycle_b { + pub fn h() {} + pub fn i() { + super::disjoint_cycle_a::g() + } +} From e0f0bddb021ca0bd919b4b3db2c5966946730141 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 16 Oct 2024 12:01:09 +0200 Subject: [PATCH 052/253] Accept test changes resulting from different ordering of items. --- .../toolchain__attributes into-fstar.snap | 64 ++-- .../toolchain__generics into-fstar.snap | 4 +- .../toolchain__include-flag into-coq.snap | 13 +- .../toolchain__include-flag into-fstar.snap | 10 +- .../toolchain__interface-only into-fstar.snap | 26 +- .../toolchain__literals into-coq.snap | 28 +- .../toolchain__literals into-fstar.snap | 48 +-- ..._mut-ref-functionalization into-fstar.snap | 226 ++++++------- .../toolchain__naming into-fstar.snap | 88 ++--- .../toolchain__reordering into-coq.snap | 14 +- .../toolchain__reordering into-fstar.snap | 8 +- .../toolchain__reordering into-ssprove.snap | 38 +-- .../toolchain__side-effects into-fstar.snap | 312 +++++++++--------- .../toolchain__side-effects into-ssprove.snap | 234 ++++++------- .../toolchain__traits into-fstar.snap | 20 +- 15 files changed, 567 insertions(+), 566 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__attributes into-fstar.snap b/test-harness/src/snapshots/toolchain__attributes into-fstar.snap index 31ac2cfb9..e65784071 100644 --- a/test-harness/src/snapshots/toolchain__attributes into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__attributes into-fstar.snap @@ -118,16 +118,11 @@ module Attributes.Newtype_pattern open Core open FStar.Mul -let v_MAX: usize = sz 10 - type t_SafeIndex = { f_i:f_i: usize{f_i <. v_MAX} } let impl__SafeIndex__as_usize (self: t_SafeIndex) : usize = self.f_i -let impl__SafeIndex__new (i: usize) : Core.Option.t_Option t_SafeIndex = - if i <. v_MAX - then Core.Option.Option_Some ({ f_i = i } <: t_SafeIndex) <: Core.Option.t_Option t_SafeIndex - else Core.Option.Option_None <: Core.Option.t_Option t_SafeIndex +let v_MAX: usize = sz 10 [@@ FStar.Tactics.Typeclasses.tcinstance] let impl_1 (#v_T: Type0) : Core.Ops.Index.t_Index (t_Array v_T (sz 10)) t_SafeIndex = @@ -137,6 +132,11 @@ let impl_1 (#v_T: Type0) : Core.Ops.Index.t_Index (t_Array v_T (sz 10)) t_SafeIn f_index_post = (fun (self: t_Array v_T (sz 10)) (index: t_SafeIndex) (out: v_T) -> true); f_index = fun (self: t_Array v_T (sz 10)) (index: t_SafeIndex) -> self.[ index.f_i ] } + +let impl__SafeIndex__new (i: usize) : Core.Option.t_Option t_SafeIndex = + if i <. v_MAX + then Core.Option.Option_Some ({ f_i = i } <: t_SafeIndex) <: Core.Option.t_Option t_SafeIndex + else Core.Option.Option_None <: Core.Option.t_Option t_SafeIndex ''' "Attributes.Pre_post_on_traits_and_impls.fst" = ''' module Attributes.Pre_post_on_traits_and_impls @@ -169,14 +169,10 @@ class t_TraitWithRequiresAndEnsures (v_Self: Type0) = { -> Prims.Pure u8 (f_method_pre x0 x1) (fun result -> f_method_post x0 x1 result) } -let test - (#v_T: Type0) - (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_TraitWithRequiresAndEnsures v_T) - (x: v_T) - : u8 = (f_method #v_T #FStar.Tactics.Typeclasses.solve x 99uy <: u8) -! 88uy - type t_ViaAdd = | ViaAdd : t_ViaAdd +type t_ViaMul = | ViaMul : t_ViaMul + [@@ FStar.Tactics.Typeclasses.tcinstance] let impl: t_Operation t_ViaAdd = { @@ -194,8 +190,6 @@ let impl: t_Operation t_ViaAdd = f_double = fun (x: u8) -> x +! x } -type t_ViaMul = | ViaMul : t_ViaMul - [@@ FStar.Tactics.Typeclasses.tcinstance] let impl_1: t_Operation t_ViaMul = { @@ -212,6 +206,12 @@ let impl_1: t_Operation t_ViaMul = (Rust_primitives.Hax.Int.from_machine result <: Hax_lib.Int.t_Int)); f_double = fun (x: u8) -> x *! 2uy } + +let test + (#v_T: Type0) + (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_TraitWithRequiresAndEnsures v_T) + (x: v_T) + : u8 = (f_method #v_T #FStar.Tactics.Typeclasses.solve x 99uy <: u8) -! 88uy ''' "Attributes.Refined_arithmetic.fst" = ''' module Attributes.Refined_arithmetic @@ -247,10 +247,10 @@ module Attributes.Refined_indexes open Core open FStar.Mul -let v_MAX: usize = sz 10 - type t_MyArray = | MyArray : t_Array u8 (sz 10) -> t_MyArray +let v_MAX: usize = sz 10 + /// Triple dash comment (** Multiline double star comment Maecenas blandit accumsan feugiat. Done vitae ullamcorper est. @@ -288,18 +288,18 @@ module Attributes.Refinement_types open Core open FStar.Mul -let t_BoundedU8 (v_MIN v_MAX: u8) = x: u8{x >=. v_MIN && x <=. v_MAX} - /// Example of a specific constraint on a value let t_CompressionFactor = x: u8{x =. 4uy || x =. 5uy || x =. 10uy || x =. 11uy} -/// Even `u8` numbers. Constructing pub Even values triggers static -/// proofs in the extraction. -let t_Even = x: u8{(x %! 2uy <: u8) =. 0uy} +let t_BoundedU8 (v_MIN v_MAX: u8) = x: u8{x >=. v_MIN && x <=. v_MAX} /// A field element let t_FieldElement = x: u16{x <=. 2347us} +/// Even `u8` numbers. Constructing pub Even values triggers static +/// proofs in the extraction. +let t_Even = x: u8{(x %! 2uy <: u8) =. 0uy} + /// A modular mutliplicative inverse let t_ModInverse (v_MOD: u32) = n: @@ -330,14 +330,14 @@ let t_NoE = in ~.out } +let double_refine (x: u8) : Prims.Pure t_Even (requires x <. 127uy) (fun _ -> Prims.l_True) = + x +! x <: t_Even + let bounded_u8 (x: t_BoundedU8 12uy 15uy) (y: t_BoundedU8 10uy 11uy) : t_BoundedU8 1uy 23uy = (x <: u8) +! (y <: u8) <: t_BoundedU8 1uy 23uy let double (x: u8) : Prims.Pure t_Even (requires x <. 127uy) (fun _ -> Prims.l_True) = x +! x <: t_Even - -let double_refine (x: u8) : Prims.Pure t_Even (requires x <. 127uy) (fun _ -> Prims.l_True) = - x +! x <: t_Even ''' "Attributes.Requires_mut.fst" = ''' module Attributes.Requires_mut @@ -454,6 +454,12 @@ module Attributes open Core open FStar.Mul +type t_Foo = { + f_x:u32; + f_y:f_y: u32{f_y >. 3ul}; + f_z:f_z: u32{((f_y +! f_x <: u32) +! f_z <: u32) >. 3ul} +} + let inlined_code__V: u8 = 12uy let issue_844_ (v__x: u8) @@ -498,14 +504,6 @@ let add3_lemma (x: u32) x <=. 10ul || x >=. (u32_max /! 3ul <: u32) || (add3 x x x <: u32) =. (x *! 3ul <: u32)) = () -type t_Foo = { - f_x:u32; - f_y:f_y: u32{f_y >. 3ul}; - f_z:f_z: u32{((f_y +! f_x <: u32) +! f_z <: u32) >. 3ul} -} - -unfold let some_function _ = "hello from F*" - let before_inlined_code = "example before" let inlined_code (foo: t_Foo) : Prims.unit = @@ -518,4 +516,6 @@ let inlined_code (foo: t_Foo) : Prims.unit = () let inlined_code_after = "example after" + +unfold let some_function _ = "hello from F*" ''' diff --git a/test-harness/src/snapshots/toolchain__generics into-fstar.snap b/test-harness/src/snapshots/toolchain__generics into-fstar.snap index c875fcfa5..fa558e443 100644 --- a/test-harness/src/snapshots/toolchain__generics into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__generics into-fstar.snap @@ -46,6 +46,8 @@ open FStar.Mul let impl__Bar__inherent_impl_generics (#v_T: Type0) (v_N: usize) (x: t_Array v_T v_N) : Prims.unit = () +type t_Bar = | Bar : t_Bar + class t_Foo (v_Self: Type0) = { f_const_add_pre:v_N: usize -> v_Self -> Type0; f_const_add_post:v_N: usize -> v_Self -> usize -> Type0; @@ -131,6 +133,4 @@ let repeat (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: Core.Marker.t_Copy v_T) (x: v_T) : t_Array v_T v_LEN = Rust_primitives.Hax.repeat x v_LEN - -type t_Bar = | Bar : t_Bar ''' diff --git a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap index 48ac454a6..71c7a484a 100644 --- a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap +++ b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap @@ -18,6 +18,7 @@ info: stderr: false stdout: true include_flag: ~ + backend_options: ~ --- exit = 0 @@ -33,9 +34,15 @@ Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Record t_Foo : Type := { +}. + Class t_Trait (Self : Type) := { }. +#[global] Instance t_Foo_t_t_Trait : t_Trait t_Foo_t := { +}. + (*Not implemented yet? todo(item)*) Definition main_a_a (_ : unit) : unit := @@ -83,12 +90,6 @@ Definition main_c (_ : unit) : unit := let _ := main_c_c tt : unit in tt. -Record t_Foo : Type := { -}. - -#[global] Instance t_Foo_t_t_Trait : t_Trait t_Foo_t := { -}. - Definition main (_ : unit) : unit := let _ := main_a Foot_Foo_t : unit in let _ := main_b tt : unit in diff --git a/test-harness/src/snapshots/toolchain__include-flag into-fstar.snap b/test-harness/src/snapshots/toolchain__include-flag into-fstar.snap index a4ce27894..41cd2ac28 100644 --- a/test-harness/src/snapshots/toolchain__include-flag into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__include-flag into-fstar.snap @@ -32,8 +32,13 @@ module Include_flag open Core open FStar.Mul +type t_Foo = | Foo : t_Foo + class t_Trait (v_Self: Type0) = { __marker_trait_t_Trait:Prims.unit } +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl_Trait_for_Foo: t_Trait t_Foo = { __marker_trait = () } + /// Indirect dependencies let main_a_a (_: Prims.unit) : Prims.unit = () @@ -73,11 +78,6 @@ let main_c (_: Prims.unit) : Prims.unit = let _:Prims.unit = main_c_c () in () -type t_Foo = | Foo : t_Foo - -[@@ FStar.Tactics.Typeclasses.tcinstance] -let impl_Trait_for_Foo: t_Trait t_Foo = { __marker_trait = () } - /// Entrypoint let main (_: Prims.unit) : Prims.unit = let _:Prims.unit = main_a #t_Foo (Foo <: t_Foo) in diff --git a/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap b/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap index cf2674e03..5426ecae4 100644 --- a/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__interface-only into-fstar.snap @@ -33,19 +33,6 @@ module Interface_only open Core open FStar.Mul -/// This item contains unsafe blocks and raw references, two features -/// not supported by hax. Thanks to the `-i` flag and the `+:` -/// modifier, `f` is still extractable as an interface. -/// Expressions within type are still extracted, as well as pre- and -/// post-conditions. -val f (x: u8) - : Prims.Pure (t_Array u8 (sz 4)) - (requires x <. 254uy) - (ensures - fun r -> - let r:t_Array u8 (sz 4) = r in - (r.[ sz 0 ] <: u8) >. x) - type t_Bar = | Bar : t_Bar /// Non-inherent implementations are extracted, their bodies are not @@ -69,4 +56,17 @@ let impl_1: Core.Convert.t_From t_Bar u8 = f_from_post = (fun (x: u8) (out: t_Bar) -> true); f_from = fun (x: u8) -> from__from x } + +/// This item contains unsafe blocks and raw references, two features +/// not supported by hax. Thanks to the `-i` flag and the `+:` +/// modifier, `f` is still extractable as an interface. +/// Expressions within type are still extracted, as well as pre- and +/// post-conditions. +val f (x: u8) + : Prims.Pure (t_Array u8 (sz 4)) + (requires x <. 254uy) + (ensures + fun r -> + let r:t_Array u8 (sz 4) = r in + (r.[ sz 0 ] <: u8) >. x) ''' diff --git a/test-harness/src/snapshots/toolchain__literals into-coq.snap b/test-harness/src/snapshots/toolchain__literals into-coq.snap index c18c543fa..223829d28 100644 --- a/test-harness/src/snapshots/toolchain__literals into-coq.snap +++ b/test-harness/src/snapshots/toolchain__literals into-coq.snap @@ -38,8 +38,15 @@ Open Scope bool_scope. Require Import Hax_lib_Int. Export Hax_lib_Int. +Record t_Foo : Type := { + f_field : int8; +}. + (*Not implemented yet? todo(item)*) +Definition v_CONSTANT : t_Foo_t := + Build_Foo (f_field := (@repr WORDSIZE8 3)). + Definition casts (x8 : int8) (x16 : int16) (x32 : int32) (x64 : int64) (xs : uint_size) : unit := let (_ : int64) := ((((cast x8).+(cast x16)).+(cast x32)).+x64).+(cast xs) : int64 in let (_ : int32) := ((((cast x8).+(cast x16)).+x32).+(cast x64)).+(cast xs) : int32 in @@ -88,20 +95,6 @@ Definition numeric (_ : unit) : unit := let (_ : int128) := (@repr WORDSIZE128 22222222222222222222) : int128 in tt. -Definition panic_with_msg (_ : unit) : unit := - never_to_any (panic_fmt (impl_2__new_const (array_from_list [with msg]))). - -Definition empty_array (_ : unit) : unit := - let (_ : seq int8) := unsize !TODO empty array! : seq int8 in - tt. - -Record t_Foo : Type := { - f_field : int8; -}. - -Definition v_CONSTANT : t_Foo_t := - Build_Foo (f_field := (@repr WORDSIZE8 3)). - Definition patterns (_ : unit) : unit := let _ := match (@repr WORDSIZE8 1) with | (@repr WORDSIZE8 2) => @@ -125,4 +118,11 @@ Definition patterns (_ : unit) : unit := tt end : unit in tt. + +Definition panic_with_msg (_ : unit) : unit := + never_to_any (panic_fmt (impl_2__new_const (array_from_list [with msg]))). + +Definition empty_array (_ : unit) : unit := + let (_ : seq int8) := unsize !TODO empty array! : seq int8 in + tt. ''' diff --git a/test-harness/src/snapshots/toolchain__literals into-fstar.snap b/test-harness/src/snapshots/toolchain__literals into-fstar.snap index be54f22ba..f6c262b10 100644 --- a/test-harness/src/snapshots/toolchain__literals into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__literals into-fstar.snap @@ -33,6 +33,10 @@ module Literals open Core open FStar.Mul +type t_Foo = { f_field:u8 } + +let v_CONSTANT: t_Foo = { f_field = 3uy } <: t_Foo + let casts (x8: u8) (x16: u16) (x32: u32) (x64: u64) (xs: usize) : Prims.unit = let (_: u64):u64 = ((((cast (x8 <: u8) <: u64) +! (cast (x16 <: u16) <: u64) <: u64) +! (cast (x32 <: u32) <: u64) @@ -145,30 +149,6 @@ let numeric (_: Prims.unit) : Prims.unit = let (_: u128):u128 = pub_u128 22222222222222222222 in () -let panic_with_msg (_: Prims.unit) : Prims.unit = - Rust_primitives.Hax.never_to_any (Core.Panicking.panic_fmt (Core.Fmt.impl_2__new_const (sz 1) - (let list = ["with msg"] in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 1); - Rust_primitives.Hax.array_of_list 1 list) - <: - Core.Fmt.t_Arguments) - <: - Rust_primitives.Hax.t_Never) - -let empty_array (_: Prims.unit) : Prims.unit = - let (_: t_Slice u8):t_Slice u8 = - (let list:Prims.list u8 = [] in - FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 0); - Rust_primitives.Hax.array_of_list 0 list) - <: - t_Slice u8 - in - () - -type t_Foo = { f_field:u8 } - -let v_CONSTANT: t_Foo = { f_field = 3uy } <: t_Foo - let patterns (_: Prims.unit) : Prims.unit = let _:Prims.unit = match 1uy with @@ -196,4 +176,24 @@ let patterns (_: Prims.unit) : Prims.unit = | _ -> () <: Prims.unit in () + +let panic_with_msg (_: Prims.unit) : Prims.unit = + Rust_primitives.Hax.never_to_any (Core.Panicking.panic_fmt (Core.Fmt.impl_2__new_const (sz 1) + (let list = ["with msg"] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 1); + Rust_primitives.Hax.array_of_list 1 list) + <: + Core.Fmt.t_Arguments) + <: + Rust_primitives.Hax.t_Never) + +let empty_array (_: Prims.unit) : Prims.unit = + let (_: t_Slice u8):t_Slice u8 = + (let list:Prims.list u8 = [] in + FStar.Pervasives.assert_norm (Prims.eq2 (List.Tot.length list) 0); + Rust_primitives.Hax.array_of_list 0 list) + <: + t_Slice u8 + in + () ''' diff --git a/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap b/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap index 955a69474..d902bca92 100644 --- a/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap @@ -32,12 +32,45 @@ module Mut_ref_functionalization open Core open FStar.Mul +type t_Bar = { + f_a:u8; + f_b:u8 +} + +type t_Foo = { f_field:Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global } + class t_FooTrait (v_Self: Type0) = { f_z_pre:v_Self -> Type0; f_z_post:v_Self -> v_Self -> Type0; f_z:x0: v_Self -> Prims.Pure v_Self (f_z_pre x0) (fun result -> f_z_post x0 result) } +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl_FooTrait_for_Foo: t_FooTrait t_Foo = + { + f_z_pre = (fun (self: t_Foo) -> true); + f_z_post = (fun (self: t_Foo) (out: t_Foo) -> true); + f_z = fun (self: t_Foo) -> self + } + +type t_Pair (v_T: Type0) = { + f_a:v_T; + f_b:t_Foo +} + +type t_S = { f_b:t_Array u8 (sz 5) } + +let impl__S__update (self: t_S) (x: u8) : t_S = + let self:t_S = + { + self with + f_b = Rust_primitives.Hax.Monomorphized_update_at.update_at_usize self.f_b (sz 0) x + } + <: + t_S + in + self + let array (x: t_Array u8 (sz 10)) : t_Array u8 (sz 10) = let x:t_Array u8 (sz 10) = Rust_primitives.Hax.Monomorphized_update_at.update_at_usize x (sz 1) (x.[ sz 2 ] <: u8) @@ -60,6 +93,19 @@ let h (x: u8) : u8 = let x:u8 = x +! 10uy in x +let i (bar: t_Bar) : (t_Bar & u8) = + let bar:t_Bar = { bar with f_b = bar.f_b +! bar.f_a } <: t_Bar in + let bar:t_Bar = { bar with f_a = h bar.f_a } <: t_Bar in + let hax_temp_output:u8 = bar.f_a +! bar.f_b in + bar, hax_temp_output <: (t_Bar & u8) + +let j (x: t_Bar) : (t_Bar & u8) = + let out:u8 = 123uy in + let tmp0, out1:(t_Bar & u8) = i x in + let x:t_Bar = tmp0 in + let hax_temp_output:u8 = out1 +! out in + x, hax_temp_output <: (t_Bar & u8) + let k (vec: Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) (arg_1_wild3: u16) @@ -82,6 +128,73 @@ let k <: (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global & u16 & Prims.unit & u64) +let foo (lhs rhs: t_S) : t_S = + let lhs:t_S = + Rust_primitives.Hax.Folds.fold_range (sz 0) + (sz 1) + (fun lhs temp_1_ -> + let lhs:t_S = lhs in + let _:usize = temp_1_ in + true) + lhs + (fun lhs i -> + let lhs:t_S = lhs in + let i:usize = i in + { + lhs with + f_b + = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize lhs.f_b + i + ((lhs.f_b.[ i ] <: u8) +! (rhs.f_b.[ i ] <: u8) <: u8) + <: + t_Array u8 (sz 5) + } + <: + t_S) + in + lhs + +let g (x: t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) + : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = + Rust_primitives.Hax.Folds.fold_range 1uy + 10uy + (fun x temp_1_ -> + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in + let _:u8 = temp_1_ in + true) + x + (fun x i -> + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in + let i:u8 = i in + { + x with + f_a + = + Alloc.Vec.impl_1__push #u8 #Alloc.Alloc.t_Global x.f_a i + <: + Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global + } + <: + t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) + in + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = + { x with f_a = Core.Slice.impl__swap #u8 x.f_a (sz 0) (sz 1) } + <: + t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) + in + let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = + { + x with + f_b = { x.f_b with f_field = Core.Slice.impl__swap #u8 x.f_b.f_field (sz 0) (sz 1) } <: t_Foo + } + <: + t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) + in + x.f_a + let build_vec (_: Prims.unit) : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = Alloc.Slice.impl__into_vec #u8 #Alloc.Alloc.t_Global @@ -164,117 +277,4 @@ let test_append (_: Prims.unit) : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = (build_vec () <: Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) in vec1 - -type t_Bar = { - f_a:u8; - f_b:u8 -} - -type t_Foo = { f_field:Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global } - -[@@ FStar.Tactics.Typeclasses.tcinstance] -let impl_FooTrait_for_Foo: t_FooTrait t_Foo = - { - f_z_pre = (fun (self: t_Foo) -> true); - f_z_post = (fun (self: t_Foo) (out: t_Foo) -> true); - f_z = fun (self: t_Foo) -> self - } - -type t_S = { f_b:t_Array u8 (sz 5) } - -let impl__S__update (self: t_S) (x: u8) : t_S = - let self:t_S = - { - self with - f_b = Rust_primitives.Hax.Monomorphized_update_at.update_at_usize self.f_b (sz 0) x - } - <: - t_S - in - self - -let foo (lhs rhs: t_S) : t_S = - let lhs:t_S = - Rust_primitives.Hax.Folds.fold_range (sz 0) - (sz 1) - (fun lhs temp_1_ -> - let lhs:t_S = lhs in - let _:usize = temp_1_ in - true) - lhs - (fun lhs i -> - let lhs:t_S = lhs in - let i:usize = i in - { - lhs with - f_b - = - Rust_primitives.Hax.Monomorphized_update_at.update_at_usize lhs.f_b - i - ((lhs.f_b.[ i ] <: u8) +! (rhs.f_b.[ i ] <: u8) <: u8) - <: - t_Array u8 (sz 5) - } - <: - t_S) - in - lhs - -let i (bar: t_Bar) : (t_Bar & u8) = - let bar:t_Bar = { bar with f_b = bar.f_b +! bar.f_a } <: t_Bar in - let bar:t_Bar = { bar with f_a = h bar.f_a } <: t_Bar in - let hax_temp_output:u8 = bar.f_a +! bar.f_b in - bar, hax_temp_output <: (t_Bar & u8) - -let j (x: t_Bar) : (t_Bar & u8) = - let out:u8 = 123uy in - let tmp0, out1:(t_Bar & u8) = i x in - let x:t_Bar = tmp0 in - let hax_temp_output:u8 = out1 +! out in - x, hax_temp_output <: (t_Bar & u8) - -type t_Pair (v_T: Type0) = { - f_a:v_T; - f_b:t_Foo -} - -let g (x: t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) - : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = - let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in - let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = - Rust_primitives.Hax.Folds.fold_range 1uy - 10uy - (fun x temp_1_ -> - let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in - let _:u8 = temp_1_ in - true) - x - (fun x i -> - let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = x in - let i:u8 = i in - { - x with - f_a - = - Alloc.Vec.impl_1__push #u8 #Alloc.Alloc.t_Global x.f_a i - <: - Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global - } - <: - t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) - in - let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = - { x with f_a = Core.Slice.impl__swap #u8 x.f_a (sz 0) (sz 1) } - <: - t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) - in - let x:t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = - { - x with - f_b = { x.f_b with f_field = Core.Slice.impl__swap #u8 x.f_b.f_field (sz 0) (sz 1) } <: t_Foo - } - <: - t_Pair (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) - in - x.f_a ''' diff --git a/test-harness/src/snapshots/toolchain__naming into-fstar.snap b/test-harness/src/snapshots/toolchain__naming into-fstar.snap index bc7a1661d..f25ae1575 100644 --- a/test-harness/src/snapshots/toolchain__naming into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__naming into-fstar.snap @@ -94,6 +94,14 @@ module Naming open Core open FStar.Mul +type t_Arity1 (v_T: Type0) = | Arity1 : v_T -> t_Arity1 v_T + +type t_B = | B : t_B + +let impl__B__f (self: t_B) : t_B = B <: t_B + +type t_C = { f_x:usize } + type t_Foo = | Foo_A : t_Foo | Foo_B { f_x:usize }: t_Foo @@ -106,6 +114,22 @@ type t_Foo2 = class t_FooTrait (v_Self: Type0) = { f_ASSOCIATED_CONSTANT:usize } +type t_Foobar = { f_a:t_Foo } + +type t_StructA = { f_a:usize } + +type t_StructB = { + f_a:usize; + f_b:usize +} + +type t_StructC = { f_a:usize } + +type t_StructD = { + f_a:usize; + f_b:usize +} + class t_T1 (v_Self: Type0) = { __marker_trait_t_T1:Prims.unit } [@@ FStar.Tactics.Typeclasses.tcinstance] @@ -116,11 +140,17 @@ let impl_T1_for_tuple_Foo_u8: t_T1 (t_Foo & u8) = { __marker_trait = () } class t_T2_for_a (v_Self: Type0) = { __marker_trait_t_T2_for_a:Prims.unit } +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl_T2_e_for_a_for_Arity1_of_tuple_Foo_u8: t_T2_for_a (t_Arity1 (t_Foo & u8)) = + { __marker_trait = () } + class t_T3_e_for_a (v_Self: Type0) = { __marker_trait_t_T3_e_for_a:Prims.unit } [@@ FStar.Tactics.Typeclasses.tcinstance] let impl_T3_e_e_for_a_for_Foo: t_T3_e_for_a t_Foo = { __marker_trait = () } +type t_X = | X : t_X + let v_INHERENT_CONSTANT: usize = sz 3 let constants @@ -130,49 +160,6 @@ let constants : usize = (f_ASSOCIATED_CONSTANT #FStar.Tactics.Typeclasses.solve <: usize) +! v_INHERENT_CONSTANT -let ff__g (_: Prims.unit) : Prims.unit = () - -type t_f__g__impl__g__Foo = - | C_f__g__impl__g__Foo_A : t_f__g__impl__g__Foo - | C_f__g__impl__g__Foo_B { f_x:usize }: t_f__g__impl__g__Foo - -let ff__g__impl_1__g (self: t_Foo) : usize = sz 1 - -let reserved_names (v_val v_noeq v_of: u8) : u8 = (v_val +! v_noeq <: u8) +! v_of - -/// From issue https://github.com/hacspec/hax/issues/839 -let string_shadows (v_string n: string) : Prims.unit = () - -type t_Arity1 (v_T: Type0) = | Arity1 : v_T -> t_Arity1 v_T - -[@@ FStar.Tactics.Typeclasses.tcinstance] -let impl_T2_e_for_a_for_Arity1_of_tuple_Foo_u8: t_T2_for_a (t_Arity1 (t_Foo & u8)) = - { __marker_trait = () } - -type t_B = | B : t_B - -let impl__B__f (self: t_B) : t_B = B <: t_B - -type t_C = { f_x:usize } - -type t_Foobar = { f_a:t_Foo } - -type t_StructA = { f_a:usize } - -type t_StructB = { - f_a:usize; - f_b:usize -} - -type t_StructC = { f_a:usize } - -type t_StructD = { - f_a:usize; - f_b:usize -} - -type t_X = | X : t_X - let construct_structs (a b: usize) : Prims.unit = let _:t_StructA = { f_a = a } <: t_StructA in let _:t_StructB = { f_a = a; f_b = b } <: t_StructB in @@ -180,12 +167,25 @@ let construct_structs (a b: usize) : Prims.unit = let _:t_StructD = { f_a = a; f_b = b } <: t_StructD in () -let f (x: t_Foobar) : usize = ff__g__impl_1__g x.f_a +let ff__g (_: Prims.unit) : Prims.unit = () let ff__g__impl__g (self: t_B) : usize = sz 0 +type t_f__g__impl__g__Foo = + | C_f__g__impl__g__Foo_A : t_f__g__impl__g__Foo + | C_f__g__impl__g__Foo_B { f_x:usize }: t_f__g__impl__g__Foo + +let ff__g__impl_1__g (self: t_Foo) : usize = sz 1 + +let f (x: t_Foobar) : usize = ff__g__impl_1__g x.f_a + let mk_c (_: Prims.unit) : t_C = let _:t_Foo = Foo_B ({ Naming.Foo.f_x = sz 3 }) <: t_Foo in let _:t_X = X <: t_X in { f_x = sz 3 } <: t_C + +let reserved_names (v_val v_noeq v_of: u8) : u8 = (v_val +! v_noeq <: u8) +! v_of + +/// From issue https://github.com/hacspec/hax/issues/839 +let string_shadows (v_string n: string) : Prims.unit = () ''' diff --git a/test-harness/src/snapshots/toolchain__reordering into-coq.snap b/test-harness/src/snapshots/toolchain__reordering into-coq.snap index 316198481..17c28800f 100644 --- a/test-harness/src/snapshots/toolchain__reordering into-coq.snap +++ b/test-harness/src/snapshots/toolchain__reordering into-coq.snap @@ -38,6 +38,10 @@ Inductive t_Foo : Type := | Foo_A : t_Foo | Foo_B : t_Foo. +Record t_Bar : Type := { + 0 : t_Foo_t; +}. + Definition t_Foo_cast_to_repr (x : t_Foo_t) : uint_size := match x with | Foo_A => @@ -51,16 +55,12 @@ Definition t_Foo_cast_to_repr (x : t_Foo_t) : uint_size := Definition f (_ : int32) : t_Foo_t := Foo_At_Foo_t. +Definition g (_ : unit) : t_Bar_t := + Bar (f (@repr WORDSIZE32 32)). + Definition no_dependency_1_ (_ : unit) : unit := tt. Definition no_dependency_2_ (_ : unit) : unit := tt. - -Record t_Bar : Type := { - 0 : t_Foo_t; -}. - -Definition g (_ : unit) : t_Bar_t := - Bar (f (@repr WORDSIZE32 32)). ''' diff --git a/test-harness/src/snapshots/toolchain__reordering into-fstar.snap b/test-harness/src/snapshots/toolchain__reordering into-fstar.snap index f78c53805..385642dd2 100644 --- a/test-harness/src/snapshots/toolchain__reordering into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__reordering into-fstar.snap @@ -36,6 +36,8 @@ type t_Foo = | Foo_A : t_Foo | Foo_B : t_Foo +type t_Bar = | Bar : t_Foo -> t_Bar + let t_Foo_cast_to_repr (x: t_Foo) : isize = match x with | Foo_A -> isz 0 @@ -43,11 +45,9 @@ let t_Foo_cast_to_repr (x: t_Foo) : isize = let f (_: u32) : t_Foo = Foo_A <: t_Foo +let g (_: Prims.unit) : t_Bar = Bar (f 32ul) <: t_Bar + let no_dependency_1_ (_: Prims.unit) : Prims.unit = () let no_dependency_2_ (_: Prims.unit) : Prims.unit = () - -type t_Bar = | Bar : t_Foo -> t_Bar - -let g (_: Prims.unit) : t_Bar = Bar (f 32ul) <: t_Bar ''' diff --git a/test-harness/src/snapshots/toolchain__reordering into-ssprove.snap b/test-harness/src/snapshots/toolchain__reordering into-ssprove.snap index 44e58bfbc..b6655f747 100644 --- a/test-harness/src/snapshots/toolchain__reordering into-ssprove.snap +++ b/test-harness/src/snapshots/toolchain__reordering into-ssprove.snap @@ -66,6 +66,20 @@ Equations Foo_B {L : {fset Location}} {I : Interface} : both L I t_Foo := solve_lift (ret_both (inr (tt : 'unit) : t_Foo)) : both L I t_Foo. Fail Next Obligation. +Definition t_Bar : choice_type := + (t_Foo). +Equations 0 {L : {fset Location}} {I : Interface} (s : both L I t_Bar) : both L I t_Foo := + 0 s := + bind_both s (fun x => + solve_lift (ret_both (x : t_Foo))) : both L I t_Foo. +Fail Next Obligation. +Equations Build_t_Bar {L0 : {fset Location}} {I0 : Interface} {0 : both L0 I0 t_Foo} : both L0 I0 (t_Bar) := + Build_t_Bar := + bind_both 0 (fun 0 => + solve_lift (ret_both ((0) : (t_Bar)))) : both L0 I0 (t_Bar). +Fail Next Obligation. +Notation "'Build_t_Bar' '[' x ']' '(' '0' ':=' y ')'" := (Build_t_Bar (0 := y)). + Equations t_Foo_cast_to_repr {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 t_Foo) : both L1 I1 uint_size := t_Foo_cast_to_repr x := matchb x with @@ -83,6 +97,11 @@ Equations f {L1 : {fset Location}} {I1 : Interface} (_ : both L1 I1 int32) : bot Foo_A : both L1 I1 t_Foo. Fail Next Obligation. +Equations g {L1 : {fset Location}} {I1 : Interface} (_ : both L1 I1 'unit) : both L1 I1 t_Bar := + g _ := + Bar (solve_lift (f (ret_both (32 : int32)))) : both L1 I1 t_Bar. +Fail Next Obligation. + Equations no_dependency_1_ {L1 : {fset Location}} {I1 : Interface} (_ : both L1 I1 'unit) : both L1 I1 'unit := no_dependency_1_ _ := solve_lift (ret_both (tt : 'unit)) : both L1 I1 'unit. @@ -92,23 +111,4 @@ Equations no_dependency_2_ {L1 : {fset Location}} {I1 : Interface} (_ : both L1 no_dependency_2_ _ := solve_lift (ret_both (tt : 'unit)) : both L1 I1 'unit. Fail Next Obligation. - -Definition t_Bar : choice_type := - (t_Foo). -Equations 0 {L : {fset Location}} {I : Interface} (s : both L I t_Bar) : both L I t_Foo := - 0 s := - bind_both s (fun x => - solve_lift (ret_both (x : t_Foo))) : both L I t_Foo. -Fail Next Obligation. -Equations Build_t_Bar {L0 : {fset Location}} {I0 : Interface} {0 : both L0 I0 t_Foo} : both L0 I0 (t_Bar) := - Build_t_Bar := - bind_both 0 (fun 0 => - solve_lift (ret_both ((0) : (t_Bar)))) : both L0 I0 (t_Bar). -Fail Next Obligation. -Notation "'Build_t_Bar' '[' x ']' '(' '0' ':=' y ')'" := (Build_t_Bar (0 := y)). - -Equations g {L1 : {fset Location}} {I1 : Interface} (_ : both L1 I1 'unit) : both L1 I1 t_Bar := - g _ := - Bar (solve_lift (f (ret_both (32 : int32)))) : both L1 I1 t_Bar. -Fail Next Obligation. ''' diff --git a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap index 1a54ff379..73ba38024 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap @@ -33,10 +33,116 @@ module Side_effects open Core open FStar.Mul +type t_A = | A : t_A + +type t_B = | B : t_B + +type t_Bar = { + f_a:bool; + f_b:(t_Array (bool & bool) (sz 6) & bool) +} + +type t_Foo = { + f_x:bool; + f_y:(bool & Alloc.Vec.t_Vec t_Bar Alloc.Alloc.t_Global); + f_z:t_Array t_Bar (sz 6); + f_bar:t_Bar +} + /// Helper function let add3 (x y z: u32) : u32 = Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add x y <: u32) z +/// Test assignation on non-trivial places +let assign_non_trivial_lhs (foo: t_Foo) : t_Foo = + let foo:t_Foo = { foo with f_x = true } <: t_Foo in + let foo:t_Foo = { foo with f_bar = { foo.f_bar with f_a = true } <: t_Bar } <: t_Foo in + let foo:t_Foo = + { + foo with + f_bar + = + { + foo.f_bar with + f_b + = + { + foo.f_bar.f_b with + _1 + = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize foo.f_bar.f_b._1 + (sz 3) + ({ (foo.f_bar.f_b._1.[ sz 3 ] <: (bool & bool)) with _2 = true } <: (bool & bool)) + } + <: + (t_Array (bool & bool) (sz 6) & bool) + } + <: + t_Bar + } + <: + t_Foo + in + let foo:t_Foo = + { + foo with + f_z + = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize foo.f_z + (sz 3) + ({ (foo.f_z.[ sz 3 ] <: t_Bar) with f_a = true } <: t_Bar) + } + <: + t_Foo + in + let foo:t_Foo = + { + foo with + f_y + = + { + foo.f_y with + _2 + = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize foo.f_y._2 + (sz 3) + ({ + (foo.f_y._2.[ sz 3 ] <: t_Bar) with + f_b + = + { + (foo.f_y._2.[ sz 3 ] <: t_Bar).f_b with + _1 + = + Rust_primitives.Hax.Monomorphized_update_at.update_at_usize (foo.f_y._2.[ sz 3 ] + <: + t_Bar) + .f_b + ._1 + (sz 5) + ({ + ((foo.f_y._2.[ sz 3 ] <: t_Bar).f_b._1.[ sz 5 ] <: (bool & bool)) with + _1 = true + } + <: + (bool & bool)) + <: + t_Array (bool & bool) (sz 6) + } + <: + (t_Array (bool & bool) (sz 6) & bool) + } + <: + t_Bar) + } + <: + (bool & Alloc.Vec.t_Vec t_Bar Alloc.Alloc.t_Global) + } + <: + t_Foo + in + foo + /// Question mark without error coercion let direct_result_question_mark (y: Core.Result.t_Result Prims.unit u32) : Core.Result.t_Result i8 u32 = @@ -112,35 +218,44 @@ let local_mutation (x: u32) : u32 = let x:u32 = hoist15 in Core.Num.impl__u32__wrapping_add x y +/// Combine `?` and early return +let monad_lifting (x: u8) : Core.Result.t_Result t_A t_B = + if x >. 123uy + then + match Core.Result.Result_Err (B <: t_B) <: Core.Result.t_Result t_A t_B with + | Core.Result.Result_Ok hoist16 -> Core.Result.Result_Ok hoist16 <: Core.Result.t_Result t_A t_B + | Core.Result.Result_Err err -> Core.Result.Result_Err err <: Core.Result.t_Result t_A t_B + else Core.Result.Result_Ok (A <: t_A) <: Core.Result.t_Result t_A t_B + /// Test question mark on `Option`s with some control flow let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core.Option.t_Option u8 = match x with - | Core.Option.Option_Some hoist19 -> - if hoist19 >. 10uy + | Core.Option.Option_Some hoist22 -> + if hoist22 >. 10uy then match x with - | Core.Option.Option_Some hoist21 -> + | Core.Option.Option_Some hoist24 -> (match - Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist21 3uy) + Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist24 3uy) <: Core.Option.t_Option u8 with - | Core.Option.Option_Some hoist27 -> - (match hoist27 with + | Core.Option.Option_Some hoist30 -> + (match hoist30 with | 3uy -> (match Core.Option.Option_None <: Core.Option.t_Option u8 with | Core.Option.Option_Some some -> let v:u8 = some in (match x with - | Core.Option.Option_Some hoist28 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist29 -> + | Core.Option.Option_Some hoist32 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist28 + hoist31 <: u8) - hoist29) + hoist32) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -150,18 +265,18 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option u8) | 4uy -> (match z with - | Core.Option.Option_Some hoist16 -> - let v:u8 = 4uy +! (if hoist16 >. 4uL <: bool then 0uy else 3uy) in + | Core.Option.Option_Some hoist19 -> + let v:u8 = 4uy +! (if hoist19 >. 4uL <: bool then 0uy else 3uy) in (match x with - | Core.Option.Option_Some hoist28 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist29 -> + | Core.Option.Option_Some hoist32 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist28 + hoist31 <: u8) - hoist29) + hoist32) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -172,14 +287,14 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | _ -> let v:u8 = 12uy in match x with - | Core.Option.Option_Some hoist28 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist29 -> + | Core.Option.Option_Some hoist32 -> Core.Option.Option_Some - (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v hoist28 + (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v hoist31 <: u8) - hoist29) + hoist32) <: Core.Option.t_Option u8 | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option u8 @@ -189,30 +304,30 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option u8 else (match x with - | Core.Option.Option_Some hoist24 -> + | Core.Option.Option_Some hoist27 -> (match y with - | Core.Option.Option_Some hoist23 -> + | Core.Option.Option_Some hoist26 -> (match - Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist24 hoist23) + Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist27 hoist26) <: Core.Option.t_Option u8 with - | Core.Option.Option_Some hoist27 -> - (match hoist27 with + | Core.Option.Option_Some hoist30 -> + (match hoist30 with | 3uy -> (match Core.Option.Option_None <: Core.Option.t_Option u8 with | Core.Option.Option_Some some -> let v:u8 = some in (match x with - | Core.Option.Option_Some hoist28 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist29 -> + | Core.Option.Option_Some hoist32 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist28 + hoist31 <: u8) - hoist29) + hoist32) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -223,18 +338,18 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. Core.Option.Option_None <: Core.Option.t_Option u8) | 4uy -> (match z with - | Core.Option.Option_Some hoist16 -> - let v:u8 = 4uy +! (if hoist16 >. 4uL <: bool then 0uy else 3uy) in + | Core.Option.Option_Some hoist19 -> + let v:u8 = 4uy +! (if hoist19 >. 4uL <: bool then 0uy else 3uy) in (match x with - | Core.Option.Option_Some hoist28 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist29 -> + | Core.Option.Option_Some hoist32 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist28 + hoist31 <: u8) - hoist29) + hoist32) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -246,15 +361,15 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | _ -> let v:u8 = 12uy in match x with - | Core.Option.Option_Some hoist28 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist29 -> + | Core.Option.Option_Some hoist32 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist28 + hoist31 <: u8) - hoist29) + hoist32) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -295,8 +410,8 @@ let simplifiable_question_mark (c: bool) (x: Core.Option.t_Option i32) : Core.Op if c then match x with - | Core.Option.Option_Some hoist33 -> - let a:i32 = hoist33 +! 10l in + | Core.Option.Option_Some hoist36 -> + let a:i32 = hoist36 +! 10l in let b:i32 = 20l in Core.Option.Option_Some (a +! b) <: Core.Option.t_Option i32 | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option i32 @@ -321,119 +436,4 @@ let simplifiable_return (c1 c2 c3: bool) : i32 = let x:i32 = x +! 1l in x else x - -type t_A = | A : t_A - -type t_B = | B : t_B - -type t_Bar = { - f_a:bool; - f_b:(t_Array (bool & bool) (sz 6) & bool) -} - -/// Combine `?` and early return -let monad_lifting (x: u8) : Core.Result.t_Result t_A t_B = - if x >. 123uy - then - match Core.Result.Result_Err (B <: t_B) <: Core.Result.t_Result t_A t_B with - | Core.Result.Result_Ok hoist35 -> Core.Result.Result_Ok hoist35 <: Core.Result.t_Result t_A t_B - | Core.Result.Result_Err err -> Core.Result.Result_Err err <: Core.Result.t_Result t_A t_B - else Core.Result.Result_Ok (A <: t_A) <: Core.Result.t_Result t_A t_B - -type t_Foo = { - f_x:bool; - f_y:(bool & Alloc.Vec.t_Vec t_Bar Alloc.Alloc.t_Global); - f_z:t_Array t_Bar (sz 6); - f_bar:t_Bar -} - -/// Test assignation on non-trivial places -let assign_non_trivial_lhs (foo: t_Foo) : t_Foo = - let foo:t_Foo = { foo with f_x = true } <: t_Foo in - let foo:t_Foo = { foo with f_bar = { foo.f_bar with f_a = true } <: t_Bar } <: t_Foo in - let foo:t_Foo = - { - foo with - f_bar - = - { - foo.f_bar with - f_b - = - { - foo.f_bar.f_b with - _1 - = - Rust_primitives.Hax.Monomorphized_update_at.update_at_usize foo.f_bar.f_b._1 - (sz 3) - ({ (foo.f_bar.f_b._1.[ sz 3 ] <: (bool & bool)) with _2 = true } <: (bool & bool)) - } - <: - (t_Array (bool & bool) (sz 6) & bool) - } - <: - t_Bar - } - <: - t_Foo - in - let foo:t_Foo = - { - foo with - f_z - = - Rust_primitives.Hax.Monomorphized_update_at.update_at_usize foo.f_z - (sz 3) - ({ (foo.f_z.[ sz 3 ] <: t_Bar) with f_a = true } <: t_Bar) - } - <: - t_Foo - in - let foo:t_Foo = - { - foo with - f_y - = - { - foo.f_y with - _2 - = - Rust_primitives.Hax.Monomorphized_update_at.update_at_usize foo.f_y._2 - (sz 3) - ({ - (foo.f_y._2.[ sz 3 ] <: t_Bar) with - f_b - = - { - (foo.f_y._2.[ sz 3 ] <: t_Bar).f_b with - _1 - = - Rust_primitives.Hax.Monomorphized_update_at.update_at_usize (foo.f_y._2.[ sz 3 ] - <: - t_Bar) - .f_b - ._1 - (sz 5) - ({ - ((foo.f_y._2.[ sz 3 ] <: t_Bar).f_b._1.[ sz 5 ] <: (bool & bool)) with - _1 = true - } - <: - (bool & bool)) - <: - t_Array (bool & bool) (sz 6) - } - <: - (t_Array (bool & bool) (sz 6) & bool) - } - <: - t_Bar) - } - <: - (bool & Alloc.Vec.t_Vec t_Bar Alloc.Alloc.t_Global) - } - <: - t_Foo - in - foo ''' diff --git a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap index ebff02a35..401de5fc8 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap @@ -54,6 +54,76 @@ Import choice.Choice.Exports. Obligation Tactic := (* try timeout 8 *) solve_ssprove_obligations. +Definition t_A : choice_type := + 'unit. +Equations Build_t_A : both (fset []) (fset []) (t_A) := + Build_t_A := + solve_lift (ret_both (tt (* Empty tuple *) : (t_A))) : both (fset []) (fset []) (t_A). +Fail Next Obligation. + +Definition t_B : choice_type := + 'unit. +Equations Build_t_B : both (fset []) (fset []) (t_B) := + Build_t_B := + solve_lift (ret_both (tt (* Empty tuple *) : (t_B))) : both (fset []) (fset []) (t_B). +Fail Next Obligation. + +Definition t_Bar : choice_type := + ('bool × nseq ('bool × 'bool) 6 × 'bool). +Equations f_a {L : {fset Location}} {I : Interface} (s : both L I t_Bar) : both L I 'bool := + f_a s := + bind_both s (fun x => + solve_lift (ret_both (fst x : 'bool))) : both L I 'bool. +Fail Next Obligation. +Equations f_b {L : {fset Location}} {I : Interface} (s : both L I t_Bar) : both L I (nseq ('bool × 'bool) 6 × 'bool) := + f_b s := + bind_both s (fun x => + solve_lift (ret_both (snd x : (nseq ('bool × 'bool) 6 × 'bool)))) : both L I (nseq ('bool × 'bool) 6 × 'bool). +Fail Next Obligation. +Equations Build_t_Bar {L0 : {fset Location}} {L1 : {fset Location}} {I0 : Interface} {I1 : Interface} {f_a : both L0 I0 'bool} {f_b : both L1 I1 (nseq ('bool × 'bool) 6 × 'bool)} : both (L0:|:L1) (I0:|:I1) (t_Bar) := + Build_t_Bar := + bind_both f_b (fun f_b => + bind_both f_a (fun f_a => + solve_lift (ret_both ((f_a,f_b) : (t_Bar))))) : both (L0:|:L1) (I0:|:I1) (t_Bar). +Fail Next Obligation. +Notation "'Build_t_Bar' '[' x ']' '(' 'f_a' ':=' y ')'" := (Build_t_Bar (f_a := y) (f_b := f_b x)). +Notation "'Build_t_Bar' '[' x ']' '(' 'f_b' ':=' y ')'" := (Build_t_Bar (f_a := f_a x) (f_b := y)). + +Definition t_Foo : choice_type := + ('bool × 'bool × t_Vec t_Bar t_Global × nseq t_Bar 6 × t_Bar). +Equations f_x {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I 'bool := + f_x s := + bind_both s (fun x => + solve_lift (ret_both (fst (fst (fst x)) : 'bool))) : both L I 'bool. +Fail Next Obligation. +Equations f_y {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I ('bool × t_Vec t_Bar t_Global) := + f_y s := + bind_both s (fun x => + solve_lift (ret_both (snd (fst (fst x)) : ('bool × t_Vec t_Bar t_Global)))) : both L I ('bool × t_Vec t_Bar t_Global). +Fail Next Obligation. +Equations f_z {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I (nseq t_Bar 6) := + f_z s := + bind_both s (fun x => + solve_lift (ret_both (snd (fst x) : (nseq t_Bar 6)))) : both L I (nseq t_Bar 6). +Fail Next Obligation. +Equations f_bar {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I t_Bar := + f_bar s := + bind_both s (fun x => + solve_lift (ret_both (snd x : t_Bar))) : both L I t_Bar. +Fail Next Obligation. +Equations Build_t_Foo {L0 : {fset Location}} {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I0 : Interface} {I1 : Interface} {I2 : Interface} {I3 : Interface} {f_x : both L0 I0 'bool} {f_y : both L1 I1 ('bool × t_Vec t_Bar t_Global)} {f_z : both L2 I2 (nseq t_Bar 6)} {f_bar : both L3 I3 t_Bar} : both (L0:|:L1:|:L2:|:L3) (I0:|:I1:|:I2:|:I3) (t_Foo) := + Build_t_Foo := + bind_both f_bar (fun f_bar => + bind_both f_z (fun f_z => + bind_both f_y (fun f_y => + bind_both f_x (fun f_x => + solve_lift (ret_both ((f_x,f_y,f_z,f_bar) : (t_Foo))))))) : both (L0:|:L1:|:L2:|:L3) (I0:|:I1:|:I2:|:I3) (t_Foo). +Fail Next Obligation. +Notation "'Build_t_Foo' '[' x ']' '(' 'f_x' ':=' y ')'" := (Build_t_Foo (f_x := y) (f_y := f_y x) (f_z := f_z x) (f_bar := f_bar x)). +Notation "'Build_t_Foo' '[' x ']' '(' 'f_y' ':=' y ')'" := (Build_t_Foo (f_x := f_x x) (f_y := y) (f_z := f_z x) (f_bar := f_bar x)). +Notation "'Build_t_Foo' '[' x ']' '(' 'f_z' ':=' y ')'" := (Build_t_Foo (f_x := f_x x) (f_y := f_y x) (f_z := y) (f_bar := f_bar x)). +Notation "'Build_t_Foo' '[' x ']' '(' 'f_bar' ':=' y ')'" := (Build_t_Foo (f_x := f_x x) (f_y := f_y x) (f_z := f_z x) (f_bar := y)). + (*Not implemented yet? todo(item)*) Equations add3 {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I1 : Interface} {I2 : Interface} {I3 : Interface} (x : both L1 I1 int32) (y : both L2 I2 int32) (z : both L3 I3 int32) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) int32 := @@ -61,6 +131,16 @@ Equations add3 {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Locatio solve_lift (impl__u32__wrapping_add (impl__u32__wrapping_add x y) z) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) int32. Fail Next Obligation. +Equations assign_non_trivial_lhs {L1 : {fset Location}} {I1 : Interface} (foo : both L1 I1 t_Foo) : both L1 I1 t_Foo := + assign_non_trivial_lhs foo := + letb _ := assign todo(term) in + letb _ := assign todo(term) in + letb _ := assign todo(term) in + letb _ := assign todo(term) in + letb _ := assign todo(term) in + solve_lift foo : both L1 I1 t_Foo. +Fail Next Obligation. + Equations direct_result_question_mark {L1 : {fset Location}} {I1 : Interface} (y : both L1 I1 (t_Result 'unit int32)) : both L1 I1 (t_Result int8 int32) := direct_result_question_mark y := solve_lift (run (letm[choice_typeMonad.result_bind_code int32] _ := y in @@ -132,37 +212,47 @@ Equations local_mutation {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 impl__u32__wrapping_add x y) : both (L1 :|: fset [y_loc;y_loc]) I1 int32. Fail Next Obligation. +Equations monad_lifting {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int8) : both L1 I1 (t_Result t_A t_B) := + monad_lifting x := + solve_lift (run (ifb x >.? (ret_both (123 : int8)) + then letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist16 := ControlFlow_Continue (Result_Err B) in + letb hoist17 := Result_Ok hoist16 in + letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist18 := ControlFlow_Break hoist17 in + ControlFlow_Continue (never_to_any hoist18) + else ControlFlow_Continue (Result_Ok A))) : both L1 I1 (t_Result t_A t_B). +Fail Next Obligation. + Equations options {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I1 : Interface} {I2 : Interface} {I3 : Interface} (x : both L1 I1 (t_Option int8)) (y : both L2 I2 (t_Option int8)) (z : both L3 I3 (t_Option int64)) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) (t_Option int8) := options x y z := - solve_lift (run (letm[choice_typeMonad.option_bind_code] hoist19 := x in - letb hoist20 := hoist19 >.? (ret_both (10 : int8)) in - letm[choice_typeMonad.option_bind_code] hoist26 := ifb hoist20 - then letm[choice_typeMonad.option_bind_code] hoist21 := x in - Option_Some (letb hoist22 := impl__u8__wrapping_add hoist21 (ret_both (3 : int8)) in - Option_Some hoist22) - else letm[choice_typeMonad.option_bind_code] hoist24 := x in - letm[choice_typeMonad.option_bind_code] hoist23 := y in - Option_Some (letb hoist25 := impl__u8__wrapping_add hoist24 hoist23 in - Option_Some hoist25) in - letm[choice_typeMonad.option_bind_code] hoist27 := hoist26 in - letm[choice_typeMonad.option_bind_code] v := matchb hoist27 with + solve_lift (run (letm[choice_typeMonad.option_bind_code] hoist22 := x in + letb hoist23 := hoist22 >.? (ret_both (10 : int8)) in + letm[choice_typeMonad.option_bind_code] hoist29 := ifb hoist23 + then letm[choice_typeMonad.option_bind_code] hoist24 := x in + Option_Some (letb hoist25 := impl__u8__wrapping_add hoist24 (ret_both (3 : int8)) in + Option_Some hoist25) + else letm[choice_typeMonad.option_bind_code] hoist27 := x in + letm[choice_typeMonad.option_bind_code] hoist26 := y in + Option_Some (letb hoist28 := impl__u8__wrapping_add hoist27 hoist26 in + Option_Some hoist28) in + letm[choice_typeMonad.option_bind_code] hoist30 := hoist29 in + letm[choice_typeMonad.option_bind_code] v := matchb hoist30 with | 3 => Option_None | 4 => - letm[choice_typeMonad.option_bind_code] hoist16 := z in - Option_Some (letb hoist17 := hoist16 >.? (ret_both (4 : int64)) in - letb hoist18 := ifb hoist17 + letm[choice_typeMonad.option_bind_code] hoist19 := z in + Option_Some (letb hoist20 := hoist19 >.? (ret_both (4 : int64)) in + letb hoist21 := ifb hoist20 then ret_both (0 : int8) else ret_both (3 : int8) in - solve_lift ((ret_both (4 : int8)) .+ hoist18)) + solve_lift ((ret_both (4 : int8)) .+ hoist21)) | _ => Option_Some (solve_lift (ret_both (12 : int8))) end in - letm[choice_typeMonad.option_bind_code] hoist28 := x in - letb hoist30 := impl__u8__wrapping_add v hoist28 in - letm[choice_typeMonad.option_bind_code] hoist29 := y in - Option_Some (letb hoist31 := impl__u8__wrapping_add hoist30 hoist29 in - Option_Some hoist31))) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) (t_Option int8). + letm[choice_typeMonad.option_bind_code] hoist31 := x in + letb hoist33 := impl__u8__wrapping_add v hoist31 in + letm[choice_typeMonad.option_bind_code] hoist32 := y in + Option_Some (letb hoist34 := impl__u8__wrapping_add hoist33 hoist32 in + Option_Some hoist34))) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) (t_Option int8). Fail Next Obligation. Definition y_loc : Location := @@ -174,8 +264,8 @@ Equations question_mark {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 letb _ := assign todo(term) in letb _ := assign todo(term) in letb _ := assign todo(term) in - letb hoist32 := x >.? (ret_both (90 : int32)) in - ifb hoist32 + letb hoist35 := x >.? (ret_both (90 : int32)) in + ifb hoist35 then impl__map_err (Result_Err (ret_both (12 : int8))) f_from else () else () in @@ -185,8 +275,8 @@ Fail Next Obligation. Equations simplifiable_question_mark {L1 : {fset Location}} {L2 : {fset Location}} {I1 : Interface} {I2 : Interface} (c : both L1 I1 'bool) (x : both L2 I2 (t_Option int32)) : both (L1 :|: L2) (I1 :|: I2) (t_Option int32) := simplifiable_question_mark c x := solve_lift (run (letm[choice_typeMonad.option_bind_code] a := ifb c - then letm[choice_typeMonad.option_bind_code] hoist33 := x in - Option_Some (hoist33 .+ (ret_both (10 : int32))) + then letm[choice_typeMonad.option_bind_code] hoist36 := x in + Option_Some (hoist36 .+ (ret_both (10 : int32))) else Option_Some (ret_both (0 : int32)) in Option_Some (letb b := ret_both (20 : int32) in Option_Some (a .+ b)))) : both (L1 :|: L2) (I1 :|: I2) (t_Option int32). @@ -201,8 +291,8 @@ Equations simplifiable_return {L1 : {fset Location}} {L2 : {fset Location}} {L3 then letm[choice_typeMonad.result_bind_code int32] _ := ifb c2 then letb _ := assign todo(term) in ifb c3 - then letm[choice_typeMonad.result_bind_code int32] hoist34 := ControlFlow_Break (ret_both (1 : int32)) in - ControlFlow_Continue (never_to_any hoist34) + then letm[choice_typeMonad.result_bind_code int32] hoist37 := ControlFlow_Break (ret_both (1 : int32)) in + ControlFlow_Continue (never_to_any hoist37) else () else () in ControlFlow_Continue (letb _ := assign todo(term) in @@ -210,94 +300,4 @@ Equations simplifiable_return {L1 : {fset Location}} {L2 : {fset Location}} {L3 else () in ControlFlow_Continue x)) : both (L1 :|: L2 :|: L3 :|: fset [x_loc]) (I1 :|: I2 :|: I3) int32. Fail Next Obligation. - -Definition t_A : choice_type := - 'unit. -Equations Build_t_A : both (fset []) (fset []) (t_A) := - Build_t_A := - solve_lift (ret_both (tt (* Empty tuple *) : (t_A))) : both (fset []) (fset []) (t_A). -Fail Next Obligation. - -Definition t_B : choice_type := - 'unit. -Equations Build_t_B : both (fset []) (fset []) (t_B) := - Build_t_B := - solve_lift (ret_both (tt (* Empty tuple *) : (t_B))) : both (fset []) (fset []) (t_B). -Fail Next Obligation. - -Definition t_Bar : choice_type := - ('bool × nseq ('bool × 'bool) 6 × 'bool). -Equations f_a {L : {fset Location}} {I : Interface} (s : both L I t_Bar) : both L I 'bool := - f_a s := - bind_both s (fun x => - solve_lift (ret_both (fst x : 'bool))) : both L I 'bool. -Fail Next Obligation. -Equations f_b {L : {fset Location}} {I : Interface} (s : both L I t_Bar) : both L I (nseq ('bool × 'bool) 6 × 'bool) := - f_b s := - bind_both s (fun x => - solve_lift (ret_both (snd x : (nseq ('bool × 'bool) 6 × 'bool)))) : both L I (nseq ('bool × 'bool) 6 × 'bool). -Fail Next Obligation. -Equations Build_t_Bar {L0 : {fset Location}} {L1 : {fset Location}} {I0 : Interface} {I1 : Interface} {f_a : both L0 I0 'bool} {f_b : both L1 I1 (nseq ('bool × 'bool) 6 × 'bool)} : both (L0:|:L1) (I0:|:I1) (t_Bar) := - Build_t_Bar := - bind_both f_b (fun f_b => - bind_both f_a (fun f_a => - solve_lift (ret_both ((f_a,f_b) : (t_Bar))))) : both (L0:|:L1) (I0:|:I1) (t_Bar). -Fail Next Obligation. -Notation "'Build_t_Bar' '[' x ']' '(' 'f_a' ':=' y ')'" := (Build_t_Bar (f_a := y) (f_b := f_b x)). -Notation "'Build_t_Bar' '[' x ']' '(' 'f_b' ':=' y ')'" := (Build_t_Bar (f_a := f_a x) (f_b := y)). - -Equations monad_lifting {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int8) : both L1 I1 (t_Result t_A t_B) := - monad_lifting x := - solve_lift (run (ifb x >.? (ret_both (123 : int8)) - then letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist35 := ControlFlow_Continue (Result_Err B) in - letb hoist36 := Result_Ok hoist35 in - letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist37 := ControlFlow_Break hoist36 in - ControlFlow_Continue (never_to_any hoist37) - else ControlFlow_Continue (Result_Ok A))) : both L1 I1 (t_Result t_A t_B). -Fail Next Obligation. - -Definition t_Foo : choice_type := - ('bool × 'bool × t_Vec t_Bar t_Global × nseq t_Bar 6 × t_Bar). -Equations f_x {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I 'bool := - f_x s := - bind_both s (fun x => - solve_lift (ret_both (fst (fst (fst x)) : 'bool))) : both L I 'bool. -Fail Next Obligation. -Equations f_y {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I ('bool × t_Vec t_Bar t_Global) := - f_y s := - bind_both s (fun x => - solve_lift (ret_both (snd (fst (fst x)) : ('bool × t_Vec t_Bar t_Global)))) : both L I ('bool × t_Vec t_Bar t_Global). -Fail Next Obligation. -Equations f_z {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I (nseq t_Bar 6) := - f_z s := - bind_both s (fun x => - solve_lift (ret_both (snd (fst x) : (nseq t_Bar 6)))) : both L I (nseq t_Bar 6). -Fail Next Obligation. -Equations f_bar {L : {fset Location}} {I : Interface} (s : both L I t_Foo) : both L I t_Bar := - f_bar s := - bind_both s (fun x => - solve_lift (ret_both (snd x : t_Bar))) : both L I t_Bar. -Fail Next Obligation. -Equations Build_t_Foo {L0 : {fset Location}} {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I0 : Interface} {I1 : Interface} {I2 : Interface} {I3 : Interface} {f_x : both L0 I0 'bool} {f_y : both L1 I1 ('bool × t_Vec t_Bar t_Global)} {f_z : both L2 I2 (nseq t_Bar 6)} {f_bar : both L3 I3 t_Bar} : both (L0:|:L1:|:L2:|:L3) (I0:|:I1:|:I2:|:I3) (t_Foo) := - Build_t_Foo := - bind_both f_bar (fun f_bar => - bind_both f_z (fun f_z => - bind_both f_y (fun f_y => - bind_both f_x (fun f_x => - solve_lift (ret_both ((f_x,f_y,f_z,f_bar) : (t_Foo))))))) : both (L0:|:L1:|:L2:|:L3) (I0:|:I1:|:I2:|:I3) (t_Foo). -Fail Next Obligation. -Notation "'Build_t_Foo' '[' x ']' '(' 'f_x' ':=' y ')'" := (Build_t_Foo (f_x := y) (f_y := f_y x) (f_z := f_z x) (f_bar := f_bar x)). -Notation "'Build_t_Foo' '[' x ']' '(' 'f_y' ':=' y ')'" := (Build_t_Foo (f_x := f_x x) (f_y := y) (f_z := f_z x) (f_bar := f_bar x)). -Notation "'Build_t_Foo' '[' x ']' '(' 'f_z' ':=' y ')'" := (Build_t_Foo (f_x := f_x x) (f_y := f_y x) (f_z := y) (f_bar := f_bar x)). -Notation "'Build_t_Foo' '[' x ']' '(' 'f_bar' ':=' y ')'" := (Build_t_Foo (f_x := f_x x) (f_y := f_y x) (f_z := f_z x) (f_bar := y)). - -Equations assign_non_trivial_lhs {L1 : {fset Location}} {I1 : Interface} (foo : both L1 I1 t_Foo) : both L1 I1 t_Foo := - assign_non_trivial_lhs foo := - letb _ := assign todo(term) in - letb _ := assign todo(term) in - letb _ := assign todo(term) in - letb _ := assign todo(term) in - letb _ := assign todo(term) in - solve_lift foo : both L1 I1 t_Foo. -Fail Next Obligation. ''' diff --git a/test-harness/src/snapshots/toolchain__traits into-fstar.snap b/test-harness/src/snapshots/toolchain__traits into-fstar.snap index 3618a12ac..314fa36ec 100644 --- a/test-harness/src/snapshots/toolchain__traits into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__traits into-fstar.snap @@ -400,6 +400,9 @@ module Traits.Interlaced_consts_types open Core open FStar.Mul +type t_Bar (v_FooConst: usize) (v_FooType: Type0) = + | Bar : t_Array v_FooType v_FooConst -> t_Bar v_FooConst v_FooType + class t_Foo (v_Self: Type0) (v_FooConst: usize) (v_FooType: Type0) = { f_fun_pre: v_FunConst: usize -> @@ -456,9 +459,6 @@ let impl (v_FooConst: usize) (#v_FooType #v_SelfType: Type0) : t_Foo v_SelfType -> () } - -type t_Bar (v_FooConst: usize) (v_FooType: Type0) = - | Bar : t_Array v_FooType v_FooConst -> t_Bar v_FooConst v_FooType ''' "Traits.Recursive_trait_with_assoc_type.fst" = ''' module Traits.Recursive_trait_with_assoc_type @@ -491,17 +491,14 @@ module Traits.Unconstrainted_types_issue_677_ open Core open FStar.Mul +type t_Plus = | Plus : t_Plus + class t_PolyOp (v_Self: Type0) = { f_op_pre:u32 -> u32 -> Type0; f_op_post:u32 -> u32 -> u32 -> Type0; f_op:x0: u32 -> x1: u32 -> Prims.Pure u32 (f_op_pre x0 x1) (fun result -> f_op_post x0 x1 result) } -let twice (#v_OP: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_PolyOp v_OP) (x: u32) - : u32 = f_op #v_OP #FStar.Tactics.Typeclasses.solve x x - -type t_Plus = | Plus : t_Plus - [@@ FStar.Tactics.Typeclasses.tcinstance] let impl: t_PolyOp t_Plus = { @@ -520,6 +517,9 @@ let impl_1: t_PolyOp t_Times = f_op = fun (x: u32) (y: u32) -> x *! y } +let twice (#v_OP: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_PolyOp v_OP) (x: u32) + : u32 = f_op #v_OP #FStar.Tactics.Typeclasses.solve x x + let both (x: u32) : (u32 & u32) = twice #t_Plus x, twice #t_Times x <: (u32 & u32) ''' "Traits.fst" = ''' @@ -546,6 +546,8 @@ let impl__Error__for_application_callback (_: Prims.unit) : Prims.unit -> t_Err let t_Error_cast_to_repr (x: t_Error) : isize = match x with | Error_Fail -> isz 0 +type t_Struct = | Struct : t_Struct + class t_SuperTrait (v_Self: Type0) = { [@@@ FStar.Tactics.Typeclasses.no_method]_super_9442900250278684536:Core.Clone.t_Clone v_Self; f_function_of_super_trait_pre:v_Self -> Type0; @@ -629,8 +631,6 @@ class t_Lang (v_Self: Type0) = { -> Prims.Pure (v_Self & f_Var) (f_s_pre x0 x1) (fun result -> f_s_post x0 x1 result) } -type t_Struct = | Struct : t_Struct - let f (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_Foo v_T) (x: v_T) : Prims.unit = let _:Prims.unit = f_assoc_f #v_T #FStar.Tactics.Typeclasses.solve () in f_method_f #v_T #FStar.Tactics.Typeclasses.solve x From c134d50283bd040a03fd076221a40c5211c1717e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 15 Oct 2024 17:48:53 +0200 Subject: [PATCH 053/253] Reveal the underlying types of `impl Trait` opaque types --- engine/lib/import_thir.ml | 2 +- frontend/exporter/src/types/copied.rs | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index eb44d8c51..27870ae89 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -1019,7 +1019,7 @@ end) : EXPR = struct let impl = c_impl_expr span impl_expr in let item = Concrete_ident.of_def_id (AssociatedItem Type) def_id in TAssociatedType { impl; item } - | Alias { kind = Opaque; def_id; _ } -> + | Alias { kind = Opaque _; def_id; _ } -> TOpaque (Concrete_ident.of_def_id Type def_id) | Alias { kind = Inherent; _ } -> assertion_failure [ span ] "Ty::Alias with AliasTyKind::Inherent" diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 8054f6fe9..0344024d1 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1766,7 +1766,10 @@ pub enum AliasKind { /// An associated type in an inherent impl. Inherent, /// An `impl Trait` opaque type. - Opaque, + Opaque { + /// The real type hidden inside this opaque type. + hidden_ty: Ty, + }, /// A type alias that references opaque types. Likely to always be normalized away. Weak, } @@ -1778,11 +1781,11 @@ impl Alias { s: &S, alias_kind: &rustc_type_ir::AliasTyKind, alias_ty: &rustc_middle::ty::AliasTy<'tcx>, - ) -> Self { + ) -> TyKind { + let tcx = s.base().tcx; use rustc_type_ir::AliasTyKind as RustAliasKind; let kind = match alias_kind { RustAliasKind::Projection => { - let tcx = s.base().tcx; let trait_ref = alias_ty.trait_ref(tcx); // In a case like: // ``` @@ -1803,14 +1806,20 @@ impl Alias { } } RustAliasKind::Inherent => AliasKind::Inherent, - RustAliasKind::Opaque => AliasKind::Opaque, + RustAliasKind::Opaque => { + // Reveal the underlying `impl Trait` type. + let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, alias_ty.args); + AliasKind::Opaque { + hidden_ty: ty.sinto(s), + } + } RustAliasKind::Weak => AliasKind::Weak, }; - Alias { + TyKind::Alias(Alias { kind, args: alias_ty.args.sinto(s), def_id: alias_ty.def_id.sinto(s), - } + }) } } @@ -1903,7 +1912,7 @@ pub enum TyKind { Tuple(Vec), #[custom_arm( rustc_middle::ty::TyKind::Alias(alias_kind, alias_ty) => { - TyKind::Alias(Alias::from(state, alias_kind, alias_ty)) + Alias::from(state, alias_kind, alias_ty) }, )] Alias(Alias), From f540bf72c7fe6152f0ac13e1ed8832c8d489b31f Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 16 Oct 2024 13:20:34 +0200 Subject: [PATCH 054/253] feat(cli): better version information Versions were broken: `cargo hax -V` was displaying the latest tag attached to the commit. So newer commits on main were tagged `v0.1.0-alpha`. Also, if hax is built without git, the version was empty. Now we use `CARGO_PKG_VERSION` as a fallback. --- hax-types/build.rs | 57 +++++++++++++++++++++----------- hax-types/src/cli_options/mod.rs | 9 ++++- hax-types/src/lib.rs | 3 ++ 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/hax-types/build.rs b/hax-types/build.rs index b4ab527a0..bda3c1c49 100644 --- a/hax-types/build.rs +++ b/hax-types/build.rs @@ -1,24 +1,43 @@ -macro_rules! set_empty_env_var_with_git { - ($var:literal, $args: expr) => { - if let None = option_env!($var) { - println!( - "cargo:rustc-env={}={}", - $var, - std::process::Command::new("git") - .args($args) - .output() - .map(|output| String::from_utf8(output.stdout).unwrap()) - .unwrap_or("unknown".into()) - ); - } +macro_rules! set_empty_env_var_with { + ($var:literal, $f: expr) => {{ println!("cargo:rurun-if-env-changed={}", $var); - }; + match option_env!($var) { + Some(value) => value.to_string(), + None => { + let value = $f; + println!("cargo:rustc-env={}={}", $var, value); + value + } + } + }}; +} + +const UNKNOWN: &str = "unknown"; + +fn git_command(args: &[&str]) -> String { + std::process::Command::new("git") + .args(args) + .output() + .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string()) + .ok() + .filter(|s| !s.is_empty()) + .unwrap_or(UNKNOWN.to_string()) } fn main() { - set_empty_env_var_with_git!( - "HAX_GIT_DESCRIBE", - ["describe", "--tags", "--always", "--abbrev=0"] - ); - set_empty_env_var_with_git!("HAX_GIT_COMMIT_HASH", ["rev-parse", "HEAD"]); + let commit_hash = + set_empty_env_var_with!("HAX_GIT_COMMIT_HASH", git_command(&["rev-parse", "HEAD"])); + + set_empty_env_var_with!("HAX_VERSION", { + if commit_hash == UNKNOWN { + env!("CARGO_PKG_VERSION").into() + } else { + git_command(&["tag", "--contains", &commit_hash]) + .lines() + .next() + .and_then(|tag| tag.split_once("hax-v")) + .map(|(_, version)| version.trim().to_string()) + .unwrap_or_else(|| format!("untagged-git-rev-{}", &commit_hash[0..10])) + } + }); } diff --git a/hax-types/src/cli_options/mod.rs b/hax-types/src/cli_options/mod.rs index adecc485f..75b771966 100644 --- a/hax-types/src/cli_options/mod.rs +++ b/hax-types/src/cli_options/mod.rs @@ -405,7 +405,14 @@ pub enum ExportBodyKind { #[derive_group(Serializers)] #[derive(JsonSchema, Parser, Debug, Clone)] -#[command(author, version = concat!("commit=", env!("HAX_GIT_COMMIT_HASH"), " ", "describe=", env!("HAX_GIT_DESCRIBE")), name = "hax", about, long_about = None)] +#[command( + author, + version = crate::HAX_VERSION, + long_version = concat!("\nversion=", env!("HAX_VERSION"), "\n", "commit=", env!("HAX_GIT_COMMIT_HASH")), + name = "hax", + about, + long_about = None +)] pub struct ExtensibleOptions { /// Replace the expansion of each macro matching PATTERN by their /// invocation. PATTERN denotes a rust path (i.e. `A::B::c`) in diff --git a/hax-types/src/lib.rs b/hax-types/src/lib.rs index ab974d41b..b59b7b0d0 100644 --- a/hax-types/src/lib.rs +++ b/hax-types/src/lib.rs @@ -25,3 +25,6 @@ pub mod driver_api; /// The types used to communicate between `cargo-hax` and /// `hax-engine`. pub mod engine_api; + +/// Compile-time version of hax +pub const HAX_VERSION: &str = env!("HAX_VERSION"); From 476cfa3df0a6ff7a8724067c14b49a9077b636c1 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 16 Oct 2024 14:41:16 +0200 Subject: [PATCH 055/253] feat(justfile): test recipies --- justfile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/justfile b/justfile index 1f3478f9d..0abf3bce6 100644 --- a/justfile +++ b/justfile @@ -40,6 +40,17 @@ fmt: cargo fmt cd engine && dune fmt +# Run hax tests: each test crate has a snapshot, so that we track changes in extracted code. If a snapshot changed, please review them with `just test-review`. +test: + cargo test --test toolchain + +_test: + CARGO_TESTS_ASSUME_BUILT=1 cargo test --test toolchain + +# Review snapshots +test-review: (_ensure_command_in_path "cargo-insta" "Insta (https://insta.rs)") + cargo insta review + # Check the coherency between issues labeled `marked-unimplemented` on GitHub and issues mentionned in the engine in the `Unimplemented {issue_id: ...}` errors. @check-issues: just _ensure_command_in_path jq "jq (https://jqlang.github.io/jq/)" From f5c6f4972ab569e33aedc38541e9bb9f399778fd Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 16 Oct 2024 15:52:27 +0200 Subject: [PATCH 056/253] fix(cli): invalidate cargo cache when hax version changes This commit takes into account hax version for cargo cache. Also, if hax was built from a dirty git, the version is tainted with a hash of the driver itself. --- cli/driver/src/callbacks_wrapper.rs | 10 +++++++++- cli/subcommands/build.rs | 17 +++++++++++++++++ cli/subcommands/src/cargo_hax.rs | 24 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/cli/driver/src/callbacks_wrapper.rs b/cli/driver/src/callbacks_wrapper.rs index 5a5bc28a1..1ba359288 100644 --- a/cli/driver/src/callbacks_wrapper.rs +++ b/cli/driver/src/callbacks_wrapper.rs @@ -14,10 +14,18 @@ impl<'a> Callbacks for CallbacksWrapper<'a> { fn config(&mut self, config: &mut interface::Config) { let options = self.options.clone(); config.psess_created = Some(Box::new(move |parse_sess| { - parse_sess.env_depinfo.get_mut().insert(( + let depinfo = parse_sess.env_depinfo.get_mut(); + depinfo.insert(( Symbol::intern(ENV_VAR_OPTIONS_FRONTEND), Some(Symbol::intern(&serde_json::to_string(&options).unwrap())), )); + depinfo.insert(( + Symbol::intern("HAX_CARGO_CACHE_KEY"), + std::env::var("HAX_CARGO_CACHE_KEY") + .ok() + .as_deref() + .map(Symbol::intern), + )); })); self.sub.config(config) } diff --git a/cli/subcommands/build.rs b/cli/subcommands/build.rs index 224b4037c..b1a0402c2 100644 --- a/cli/subcommands/build.rs +++ b/cli/subcommands/build.rs @@ -33,7 +33,24 @@ fn json_schema_static_asset() { .unwrap(); } +fn git_dirty_env_var() { + println!("cargo:rurun-if-env-changed=HAX_GIT_IS_DIRTY"); + let dirty = { + use std::process::Command; + let _ = Command::new("git") + .args(["update-index", "-q", "--refresh"]) + .status(); + !Command::new("git") + .args(["diff-index", "--quiet", "HEAD", "--"]) + .status() + .map(|status| status.success()) + .unwrap_or(true) + }; + println!("cargo:rustc-env=HAX_GIT_IS_DIRTY={}", dirty); +} + fn main() { rustc_version_env_var(); json_schema_static_asset(); + git_dirty_env_var(); } diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index 36d70d9a9..c3ee00316 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -362,6 +362,29 @@ fn target_dir(suffix: &str) -> PathBuf { dir.into() } +/// Gets hax version: if hax is being compiled from a dirty git repo, +/// then this function taints the hax version with the hash of the +/// current executable. This makes sure cargo doesn't cache across +/// different versions of hax, for more information see +/// https://github.com/hacspec/hax/issues/801. +fn get_hax_version() -> String { + let mut version = hax_types::HAX_VERSION.to_string(); + if env!("HAX_GIT_IS_DIRTY") == "true" { + version += &std::env::current_exe() + .ok() + .and_then(|exe_path| std::fs::read(exe_path).ok()) + .map(|contents| { + use std::hash::{DefaultHasher, Hash, Hasher}; + let mut s = DefaultHasher::new(); + contents.hash(&mut s); + format!("hash-exe-{}", s.finish()) + }) + .expect("Expect read path") + } + + version +} + /// Calls `cargo` with a custom driver which computes `haxmeta` files /// in `TARGET`. One `haxmeta` file is produced by crate. Each /// `haxmeta` file contains the full AST of one crate. @@ -393,6 +416,7 @@ fn compute_haxmeta_files(options: &Options) -> (Vec, i32) { ) .env(RUST_LOG_STYLE, rust_log_style()) .env(RUSTFLAGS, rustflags()) + .env("HAX_CARGO_CACHE_KEY", get_hax_version()) .env( ENV_VAR_OPTIONS_FRONTEND, serde_json::to_string(&options) From 1b45ce1fc7903612c1ec1e3ae89159f8a29a5a81 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 16 Oct 2024 15:47:47 +0200 Subject: [PATCH 057/253] Support `impl Trait` in trait resolution --- frontend/exporter/src/traits/resolution.rs | 2 +- .../src/snapshots/toolchain__traits into-fstar.snap | 9 +++++++++ tests/traits/src/lib.rs | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 342025f6f..34b8fdf0c 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -152,7 +152,7 @@ impl<'tcx> PredicateSearcher<'tcx> { pub fn new_for_owner(tcx: TyCtxt<'tcx>, owner_id: DefId) -> Self { let mut out = Self { tcx, - param_env: tcx.param_env(owner_id), + param_env: tcx.param_env(owner_id).with_reveal_all_normalized(tcx), candidates: Default::default(), }; out.extend( diff --git a/test-harness/src/snapshots/toolchain__traits into-fstar.snap b/test-harness/src/snapshots/toolchain__traits into-fstar.snap index 314fa36ec..4aaf4ea2f 100644 --- a/test-harness/src/snapshots/toolchain__traits into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__traits into-fstar.snap @@ -602,6 +602,15 @@ let iter_option (#v_T: Type0) (x: Core.Option.t_Option v_T) : Core.Option.t_Into #FStar.Tactics.Typeclasses.solve (Core.Option.impl__as_ref #v_T x <: Core.Option.t_Option v_T) +let use_impl_trait (_: Prims.unit) : Prims.unit = + let iter:_ = iter_option #bool (Core.Option.Option_Some false <: Core.Option.t_Option bool) in + let tmp0, out:(_ & Core.Option.t_Option bool) = + Core.Iter.Traits.Iterator.f_next #_ #FStar.Tactics.Typeclasses.solve iter + in + let iter:_ = tmp0 in + let _:Core.Option.t_Option bool = out in + () + class t_Foo (v_Self: Type0) = { f_AssocType:Type0; f_AssocType_15525962639250476383:t_SuperTrait f_AssocType; diff --git a/tests/traits/src/lib.rs b/tests/traits/src/lib.rs index 4b3ced22f..9fea11184 100644 --- a/tests/traits/src/lib.rs +++ b/tests/traits/src/lib.rs @@ -83,6 +83,12 @@ fn iter_option<'a, T>(x: &'a Option) -> impl Iterator { x.as_ref().into_iter() } +// Issue #684 +fn use_impl_trait() { + let mut iter = iter_option(&Some(false)); + let _ = iter.next(); +} + mod for_clauses { trait Foo { fn to_t(&self) -> T; From e98abaa7f44318f5882d0aad16f6edbec7d54154 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 17 Oct 2024 14:19:13 +0200 Subject: [PATCH 058/253] Also rename conrete idents within a projector. --- engine/lib/ast_utils.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 7c3a8f412..d8e072ac6 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -306,6 +306,7 @@ module Make (F : Features.T) = struct method! visit_global_ident lvl (x : Global_ident.t) = match x with | `Concrete x -> `Concrete (f lvl x) + | `Projector (`Concrete x) -> `Projector (`Concrete (f lvl x)) | _ -> super#visit_global_ident lvl x method! visit_ty _ t = super#visit_ty TypeLevel t From 9de3aa1334039eca1f0b8671f9199d34d3e51d86 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 17 Oct 2024 14:58:37 +0200 Subject: [PATCH 059/253] fix: justfile --- .utils/rebuild.sh | 2 +- justfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.utils/rebuild.sh b/.utils/rebuild.sh index adadc61ce..150da64f0 100755 --- a/.utils/rebuild.sh +++ b/.utils/rebuild.sh @@ -22,7 +22,7 @@ DUNEJOBS=${DUNEJOBS:-} # required since `set -u` YELLOW=43 GREEN=42 RED=41 -BLACK=40 +BLACK=90 status () { echo -e "\033[1m[rebuild script] \033[30m\033[$1m$2\033[0m"; } cd_rootwise () { diff --git a/justfile b/justfile index 0abf3bce6..abc4b305a 100644 --- a/justfile +++ b/justfile @@ -4,7 +4,7 @@ # Build Rust and OCaml parts and install binaries in PATH. To build # only OCaml parts or only Rust parts, set target to `rust` or # `ocaml`. -@build target='rust ocaml': +@build target='rust+ocaml': ./.utils/rebuild.sh {{target}} alias b := build From 570822e0eefd12e69aef252ddb033a42a4c58fcf Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Mon, 21 Oct 2024 10:43:25 +0200 Subject: [PATCH 060/253] Updates based on Coq backend needs --- engine/lib/generic_printer/generic_printer.ml | 54 +++++++++++++++++++ .../generic_printer_template.ml | 10 +++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 6cce72c72..2c8683f27 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -274,6 +274,59 @@ module Make (F : Features.T) = struct (** [ty_TApp_application ~typ ~generics] prints the type [typ<...generics>]. *) + (** *) + + method virtual item'_Type_struct : + super:item -> + name:concrete_ident lazy_doc -> + generics:generics lazy_doc -> + arguments:(concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> + document + + method virtual item'_Type_tuple_struct : + super:item -> + name:concrete_ident lazy_doc -> + generics:generics lazy_doc -> + arguments:(concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> + document + + method virtual item'_Type_enum : + super:item -> + name:concrete_ident lazy_doc -> + generics:generics lazy_doc -> + variants:(variant lazy_doc) list -> + document + + method _do_not_override_item'_Type ~super ~name ~generics ~variants ~is_struct = + if is_struct + then + match variants with + | [variant] -> + let variant_arguments = + List.map + ~f:(fun (ident,typ,_attrs) -> + (self#_do_not_override_lazy_of_concrete_ident AstPos_variant__arguments ident, + self#_do_not_override_lazy_of_ty AstPos_variant__arguments typ, + [] (* TODO: attrs *))) + variant#v.arguments + in + if variant#v.is_record + then + self#item'_Type_struct + ~super + ~name + ~generics + ~arguments:variant_arguments + else + self#item'_Type_tuple_struct + ~super + ~name + ~generics + ~arguments:variant_arguments + | _ -> self#unreachable () (* TODO: guarantees? *) + else + self#item'_Type_enum ~super ~name ~generics ~variants + (** {2:common-nodes Printers for common nodes} *) method virtual common_array : document list -> document @@ -505,5 +558,6 @@ module Make (F : Features.T) = struct let module View = (val concrete_ident_view) in current_namespace <- View.to_namespace value.ident |> Option.some; super#_do_not_override_lazy_of_item ast_position value + end end diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index be7ccb88b..92b3bda47 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -221,8 +221,14 @@ struct method item'_TyAlias ~super:_ ~name:_ ~generics:_ ~ty:_ = default_document_for "item'_TyAlias" - method item'_Type ~super:_ ~name:_ ~generics:_ ~variants:_ ~is_struct:_ = - default_document_for "item'_Type" + method item'_Type_struct ~super:_ ~name:_ ~generics:_ ~arguments:_ = + default_document_for "item'_Type_struct" + + method item'_Type_tuple_struct ~super:_ ~name:_ ~generics:_ ~arguments:_ = + default_document_for "item'_Type_tuple_struct" + + method item'_Type_enum ~super:_ ~name:_ ~generics:_ ~variants:_ = + default_document_for "item'_Type_enum" method item'_Use ~super:_ ~path:_ ~is_external:_ ~rename:_ = default_document_for "item'_Use" From 3a5f1089d060c867ec2512fa2245b482b0fd3528 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 11:02:10 +0200 Subject: [PATCH 061/253] fix(frontend): issue #1014 --- frontend/exporter/src/types/copied.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 0344024d1..aba6f4fbf 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1369,15 +1369,16 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> None => match kind { // Introduce intermediate `Cast` from `T` to `U` when casting from a `#[repr(T)]` enum to `U` rustc_middle::thir::ExprKind::Cast { source } => { - if let rustc_middle::ty::TyKind::Adt(def, _) = s.thir().exprs[source].ty.kind() + if let rustc_middle::ty::TyKind::Adt(adt, _) = s.thir().exprs[source].ty.kind() { let tcx = s.base().tcx; let contents = kind.sinto(s); - use crate::rustc_middle::ty::util::IntTypeExt; - let repr_type = tcx - .repr_options_of_def(def.did().expect_local()) - .discr_type() - .to_ty(s.base().tcx); + let repr_type = if adt.is_enum() { + use crate::rustc_middle::ty::util::IntTypeExt; + adt.repr().discr_type().to_ty(tcx) + } else { + ty + }; if repr_type == ty { contents } else { From da34b62a2adfd3a90109756b6ae5ed66126eb9b0 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 3 Oct 2024 11:51:08 +0200 Subject: [PATCH 062/253] Rewrite control flow inside loops. --- .../backends/coq/ssprove/ssprove_backend.ml | 1 + engine/backends/fstar/fstar_backend.ml | 4 +- engine/backends/proverif/proverif_backend.ml | 2 +- engine/lib/ast.ml | 15 ++- engine/lib/ast_utils.ml | 79 ++++++++++++ engine/lib/import_thir.ml | 1 + .../lib/phases/phase_drop_needless_returns.ml | 48 -------- .../phases/phase_drop_needless_returns.mli | 4 - .../phase_drop_return_break_continue.ml | 82 +++++++++++++ .../phase_drop_return_break_continue.mli | 8 ++ .../lib/phases/phase_functionalize_loops.ml | 109 +++++++++++------ .../lib/phases/phase_functionalize_loops.mli | 3 +- engine/lib/phases/phase_local_mutation.ml | 33 +++++- .../phase_reconstruct_for_index_loops.ml | 1 + .../lib/phases/phase_reconstruct_for_loops.ml | 2 + .../phases/phase_reconstruct_while_loops.ml | 2 + .../lib/phases/phase_rewrite_control_flow.ml | 112 +++++++++++++++--- engine/lib/side_effect_utils.ml | 18 ++- engine/lib/subtype.ml | 23 +++- engine/names/src/lib.rs | 17 +++ .../Rust_primitives.Hax.Folds.fsti | 19 +++ .../fstar/rust_primitives/Rust_primitives.fst | 16 +++ 22 files changed, 472 insertions(+), 127 deletions(-) delete mode 100644 engine/lib/phases/phase_drop_needless_returns.ml delete mode 100644 engine/lib/phases/phase_drop_needless_returns.mli create mode 100644 engine/lib/phases/phase_drop_return_break_continue.ml create mode 100644 engine/lib/phases/phase_drop_return_break_continue.mli diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index 6db7387c9..d4db317a9 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -1117,6 +1117,7 @@ struct }; label; witness; + control_flow = false; }; typ = e.typ; span = e.span; diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 2ae37c6dd..3e97e4d73 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1738,9 +1738,9 @@ module TransformToInputLanguage = |> Side_effect_utils.Hoist |> Phases.Hoist_disjunctive_patterns |> Phases.Simplify_match_return - |> Phases.Rewrite_control_flow - |> Phases.Drop_needless_returns |> Phases.Local_mutation + |> Phases.Rewrite_control_flow + |> Phases.Drop_return_break_continue |> Phases.Reject.Continue |> Phases.Cf_into_monads |> Phases.Reject.EarlyExit diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index f66a1ea14..3ec1552a1 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -902,7 +902,7 @@ module TransformToInputLanguage = |> Phases.Trivialize_assign_lhs |> Side_effect_utils.Hoist |> Phases.Simplify_match_return - |> Phases.Drop_needless_returns + |> Phases.Drop_return_break_continue |> Phases.Local_mutation |> Phases.Reject.Continue |> Phases.Reject.Dyn diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 684001400..604a76ec5 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -262,6 +262,7 @@ functor body : expr; kind : loop_kind; state : loop_state option; + control_flow : bool; label : string option; witness : F.loop; } @@ -307,13 +308,23 @@ functor and loop_kind = | UnconditionalLoop - | WhileLoop of { condition : expr; witness : F.while_loop } - | ForLoop of { pat : pat; it : expr; witness : F.for_loop } + | WhileLoop of { + condition : expr; + has_return : bool; + witness : F.while_loop; + } + | ForLoop of { + pat : pat; + it : expr; + has_return : bool; + witness : F.for_loop; + } | ForIndexLoop of { start : expr; end_ : expr; var : local_ident; var_typ : ty; + has_return : bool; witness : F.for_index_loop; } diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index d8e072ac6..41da6fa93 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -922,6 +922,85 @@ module Make (F : Features.T) = struct let e = Closure { params; body; captures = [] } in { e; typ = TArrow (List.map ~f:(fun p -> p.typ) params, body.typ); span } + let make_control_flow_pat ~(span : span) ~(typ : ty) + (cf : [ `Break | `Continue ]) (pat : pat) = + match cf with + | `Break -> + { + p = + PConstruct + { + name = + Global_ident.of_name + (Constructor { is_struct = false }) + Core__ops__control_flow__ControlFlow__Break; + args = + [ + { + field = + Global_ident.of_name Field + Core__ops__control_flow__ControlFlow__Break__0; + pat; + }; + ]; + is_record = false; + is_struct = false; + }; + typ; + (* Wrong *) + span; + } + | `Continue -> + { + p = + PConstruct + { + name = + Global_ident.of_name + (Constructor { is_struct = false }) + Core__ops__control_flow__ControlFlow__Continue; + args = + [ + { + field = + Global_ident.of_name Field + Core__ops__control_flow__ControlFlow__Continue__0; + pat; + }; + ]; + is_record = false; + is_struct = false; + }; + typ; + (* Wrong *) + span; + } + + let make_control_flow_expr' ~(span : span) ~(typ : ty) + (cf : [ `Break | `Continue ]) (e : expr) = + match cf with + | `Break -> + call_Constructor Core__ops__control_flow__ControlFlow__Break false [ e ] + span typ + | `Continue -> + call_Constructor Core__ops__control_flow__ControlFlow__Continue false + [ e ] span typ + + let make_control_flow_expr ~(span : span) ~(typ : ty) ~(has_return : bool) + (cf : [ `Return | `Break | `Continue ]) (e : expr) = + match cf with + | `Return -> + make_control_flow_expr' ~span ~typ `Break + (make_control_flow_expr' ~span ~typ `Break e) + | `Break when has_return -> + make_control_flow_expr' ~span ~typ `Break + (make_control_flow_expr' ~span ~typ `Continue e) + | `Break -> make_control_flow_expr' ~span ~typ `Break e + | `Continue when has_return -> + make_control_flow_expr' ~span ~typ `Continue + (make_control_flow_expr' ~span ~typ `Continue e) + | `Continue -> make_control_flow_expr' ~span ~typ `Continue e + let string_lit span (s : string) : expr = { span; typ = TStr; e = Literal (String s) } diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 0dea69dbb..5b5e5e6dd 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -585,6 +585,7 @@ end) : EXPR = struct state = None; label = None; witness = W.loop; + control_flow = false; } | Match { scrutinee; arms } -> let scrutinee = c_expr scrutinee in diff --git a/engine/lib/phases/phase_drop_needless_returns.ml b/engine/lib/phases/phase_drop_needless_returns.ml deleted file mode 100644 index e4a59355e..000000000 --- a/engine/lib/phases/phase_drop_needless_returns.ml +++ /dev/null @@ -1,48 +0,0 @@ -open! Prelude - -module Make (F : Features.T) = - Phase_utils.MakeMonomorphicPhase - (F) - (struct - let phase_id = Diagnostics.Phase.DropNeedlessReturns - - open Ast.Make (F) - module U = Ast_utils.Make (F) - module Visitors = Ast_visitors.Make (F) - - module Error = Phase_utils.MakeError (struct - let ctx = Diagnostics.Context.Phase phase_id - end) - - let visitor = - object (self) - inherit [_] Visitors.map as _super - - method! visit_expr () e = - match e with - | { e = Return { e; _ }; _ } -> e - (* we know [e] is on an exit position: the return is - thus useless, we can skip it *) - | { e = Let { monadic = None; lhs; rhs; body }; _ } -> - let body = self#visit_expr () body in - { e with e = Let { monadic = None; lhs; rhs; body } } - (* If a let expression is an exit node, then it's body - is as well *) - | { e = Match { scrutinee; arms }; _ } -> - let arms = List.map ~f:(self#visit_arm ()) arms in - { e with e = Match { scrutinee; arms } } - | { e = If { cond; then_; else_ }; _ } -> - let then_ = self#visit_expr () then_ in - let else_ = Option.map ~f:(self#visit_expr ()) else_ in - { e with e = If { cond; then_; else_ } } - | _ -> e - (** The invariant here is that [visit_expr] is called only - on expressions that are on exit positions. [visit_expr] - is first called on root expressions, which are (by - definition) exit nodes. Then, [visit_expr] itself makes - recursive calls to sub expressions that are themselves - in exit nodes. **) - end - - let ditems = List.map ~f:(visitor#visit_item ()) - end) diff --git a/engine/lib/phases/phase_drop_needless_returns.mli b/engine/lib/phases/phase_drop_needless_returns.mli deleted file mode 100644 index b53603f1e..000000000 --- a/engine/lib/phases/phase_drop_needless_returns.mli +++ /dev/null @@ -1,4 +0,0 @@ -(** This phase transforms `return e` expressions into `e` when `return -e` is on an exit position. *) - -module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml new file mode 100644 index 000000000..c36143eaf --- /dev/null +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -0,0 +1,82 @@ +open! Prelude + +module Make (F : Features.T) = + Phase_utils.MakeMonomorphicPhase + (F) + (struct + let phase_id = Diagnostics.Phase.DropNeedlessReturns + + open Ast.Make (F) + module U = Ast_utils.Make (F) + module Visitors = Ast_visitors.Make (F) + + module Error = Phase_utils.MakeError (struct + let ctx = Diagnostics.Context.Phase phase_id + end) + + let has_return = + object (_self) + inherit [_] Visitors.reduce as super + method zero = false + method plus = ( || ) + + method! visit_expr' () e = + match e with Return _ -> true | _ -> super#visit_expr' () e + end + + let visitor = + object (self) + inherit [_] Visitors.map as _super + + method! visit_expr (in_loop : bool option) e = + match (e, in_loop) with + | { e = Return { e; _ }; _ }, None -> e + (* we know [e] is on an exit position: the return is + thus useless, we can skip it *) + | { e = Let { monadic = None; lhs; rhs; body }; _ }, _ -> + let body = self#visit_expr in_loop body in + { e with e = Let { monadic = None; lhs; rhs; body } } + (* If a let expression is an exit node, then it's body + is as well *) + | { e = Match { scrutinee; arms }; _ }, _ -> + let arms = List.map ~f:(self#visit_arm in_loop) arms in + { e with e = Match { scrutinee; arms } } + | { e = If { cond; then_; else_ }; _ }, _ -> + let then_ = self#visit_expr in_loop then_ in + let else_ = Option.map ~f:(self#visit_expr in_loop) else_ in + { e with e = If { cond; then_; else_ } } + | { e = Return { e; _ }; span; typ }, Some has_return -> + U.make_control_flow_expr ~has_return ~span ~typ `Return e + | { e = Break { e; _ }; span; typ }, Some has_return -> + U.make_control_flow_expr ~has_return ~span ~typ `Break e + | ( { e = Continue { e = Some (_, e); _ }; span; typ }, + Some has_return ) -> + U.make_control_flow_expr ~has_return ~span ~typ `Continue e + | { span; typ; _ }, Some has_return -> + U.make_control_flow_expr ~has_return ~span ~typ `Continue e + | _ -> e + (** The invariant here is that [visit_expr] is called only + on expressions that are on exit positions. [visit_expr] + is first called on root expressions, which are (by + definition) exit nodes. Then, [visit_expr] itself makes + recursive calls to sub expressions that are themselves + in exit nodes. **) + end + + let loop_visitor = + object (_self) + inherit [_] Visitors.map as super + + method! visit_expr () e = + match e.e with + | Loop ({ body; control_flow; _ } as loop) when control_flow -> + let body = + visitor#visit_expr (Some (has_return#visit_expr () body)) body + in + super#visit_expr () { e with e = Loop { loop with body } } + | _ -> super#visit_expr () e + end + + let ditems = + List.map ~f:(visitor#visit_item None >> loop_visitor#visit_item ()) + end) diff --git a/engine/lib/phases/phase_drop_return_break_continue.mli b/engine/lib/phases/phase_drop_return_break_continue.mli new file mode 100644 index 000000000..fc3df33f5 --- /dev/null +++ b/engine/lib/phases/phase_drop_return_break_continue.mli @@ -0,0 +1,8 @@ +(** This phase transforms `return e` expressions into `e` when `return +e` is on an exit position. It should come after phase `RewriteControlFlow` +and thus eliminate all `return`s. Inside loops it rewrites `return`, +`break` and `continue` as their equivalent in terms of the `ControlFlow` +wrapper that will be handled by the specific fold operators introduced by +phase `FunctionalizeLoops`. *) + +module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE diff --git a/engine/lib/phases/phase_functionalize_loops.ml b/engine/lib/phases/phase_functionalize_loops.ml index b101a8ad7..9458cb1e7 100644 --- a/engine/lib/phases/phase_functionalize_loops.ml +++ b/engine/lib/phases/phase_functionalize_loops.ml @@ -3,7 +3,8 @@ open! Prelude module%inlined_contents Make (F : Features.T with type continue = Features.Off.continue - and type early_exit = Features.Off.early_exit) = + and type early_exit = Features.Off.early_exit + and type break = Features.Off.break) = struct open Ast module FA = F @@ -15,6 +16,9 @@ struct include Features.Off.While_loop include Features.Off.For_index_loop include Features.Off.State_passing_loop + include Features.Off.Continue + include Features.Off.Early_exit + include Features.Off.Break end include @@ -28,6 +32,7 @@ struct module UA = Ast_utils.Make (F) module UB = Ast_utils.Make (FB) + module Visitors = Ast_visitors.Make (F) module S = struct include Features.SUBTYPE.Id @@ -38,6 +43,18 @@ struct invariant : (B.pat * B.expr) option; } + let has_cf = + object (_self) + inherit [_] Visitors.reduce as super + method zero = false + method plus = ( || ) + + method! visit_expr' () e = + match e with + | Return _ | Break _ | Continue _ -> true + | _ -> super#visit_expr' () e + end + let extract_loop_invariant (body : B.expr) : body_and_invariant = match body.e with | Let @@ -76,7 +93,7 @@ struct | StepBy of { n : B.expr; it : iterator } [@@deriving show] - let rec as_iterator' (e : B.expr) : iterator option = + let rec as_iterator (e : B.expr) : iterator option = match e.e with | Construct { @@ -93,12 +110,6 @@ struct Some (Range { start; end_ }) | _ -> meth_as_iterator e - and as_iterator (e : B.expr) : iterator option = - let result = as_iterator' e in - (* UB.Debug.expr ~label:"as_iterator" e; *) - (* " = " ^ [%show: iterator option] result |> Stdio.prerr_endline; *) - result - and meth_as_iterator (e : B.expr) : iterator option = let* f, args = match e.e with @@ -129,29 +140,45 @@ struct Some (ChunksExact { size; slice }) else None - let fn_args_of_iterator (it : iterator) : - (Concrete_ident.name * B.expr list * B.ty) option = + let fn_args_of_iterator (has_cf : bool) (has_return : bool) (it : iterator) + : (Concrete_ident.name * B.expr list * B.ty) option = let open Concrete_ident_generated in let usize = B.TInt { size = SSize; signedness = Unsigned } in match it with | Enumerate (ChunksExact { size; slice }) -> - Some - ( Rust_primitives__hax__folds__fold_enumerated_chunked_slice, - [ size; slice ], - usize ) + let fold_op = + if has_return then + Rust_primitives__hax__folds__fold_enumerated_chunked_slice_return + else if has_cf then + Rust_primitives__hax__folds__fold_enumerated_chunked_slice_cf + else Rust_primitives__hax__folds__fold_enumerated_chunked_slice + in + Some (fold_op, [ size; slice ], usize) | Enumerate (Slice slice) -> - Some - ( Rust_primitives__hax__folds__fold_enumerated_slice, - [ slice ], - usize ) + let fold_op = + if has_return then + Rust_primitives__hax__folds__fold_enumerated_slice_return + else if has_cf then + Rust_primitives__hax__folds__fold_enumerated_slice_cf + else Rust_primitives__hax__folds__fold_enumerated_slice + in + Some (fold_op, [ slice ], usize) | StepBy { n; it = Range { start; end_ } } -> - Some - ( Rust_primitives__hax__folds__fold_range_step_by, - [ start; end_; n ], - start.typ ) + let fold_op = + if has_return then + Rust_primitives__hax__folds__fold_range_step_by_return + else if has_cf then + Rust_primitives__hax__folds__fold_range_step_by_cf + else Rust_primitives__hax__folds__fold_range_step_by + in + Some (fold_op, [ start; end_; n ], start.typ) | Range { start; end_ } -> - Some - (Rust_primitives__hax__folds__fold_range, [ start; end_ ], start.typ) + let fold_op = + if has_return then Rust_primitives__hax__folds__fold_range_return + else if has_cf then Rust_primitives__hax__folds__fold_range_cf + else Rust_primitives__hax__folds__fold_range + in + Some (fold_op, [ start; end_ ], start.typ) | _ -> None [%%inline_defs dmutability + dsafety_kind] @@ -164,8 +191,9 @@ struct | Loop { body; - kind = ForLoop { it; pat; _ }; + kind = ForLoop { it; pat; has_return; _ }; state = Some { init; bpat; _ }; + control_flow; _; } -> let body = dexpr body in @@ -176,8 +204,12 @@ struct let fn : B.expr = UB.make_closure [ bpat; pat ] body body.span in let init = dexpr init in let f, kind, args = - match as_iterator it |> Option.bind ~f:fn_args_of_iterator with + match + as_iterator it + |> Option.bind ~f:(fn_args_of_iterator control_flow has_return) + with | Some (f, args, typ) -> + (* TODO what happens if there is control flow? *) let invariant : B.expr = let default = let pat = MS.pat_PWild ~typ in @@ -188,16 +220,20 @@ struct in (f, Concrete_ident.Kind.Value, args @ [ invariant; init; fn ]) | None -> - ( Core__iter__traits__iterator__Iterator__fold, - AssociatedItem Value, - [ it; init; fn ] ) + let fold : Concrete_ident.name = + if has_return then Rust_primitives__hax__folds__fold_return + else if control_flow then Rust_primitives__hax__folds__fold_cf + else Core__iter__traits__iterator__Iterator__fold + in + (fold, AssociatedItem Value, [ it; init; fn ]) in UB.call ~kind f args span (dty span expr.typ) | Loop { body; - kind = WhileLoop { condition; _ }; + kind = WhileLoop { condition; has_return; _ }; state = Some { init; bpat; _ }; + control_flow; _; } -> let body = dexpr body in @@ -214,19 +250,18 @@ struct ~typ:(TArrow ([ bpat.typ ], body.typ)) ~span:body.span in - UB.call ~kind:(AssociatedItem Value) Rust_primitives__hax__while_loop + let fold_operator : Concrete_ident.name = + if has_return then Rust_primitives__hax__while_loop_return + else if control_flow then Rust_primitives__hax__while_loop_cf + else Rust_primitives__hax__while_loop + in + UB.call ~kind:(AssociatedItem Value) fold_operator [ condition; init; body ] span (dty span expr.typ) | Loop { state = None; _ } -> Error.unimplemented ~issue_id:405 ~details:"Loop without mutation" span | Loop _ -> Error.unimplemented ~issue_id:933 ~details:"Unhandled loop kind" span - | Break _ -> - Error.unimplemented ~issue_id:15 - ~details: - "For now, the AST node [Break] is feature gated only by [loop], \ - there is nothing for having loops but no breaks." - span | [%inline_arms "dexpr'.*" - Loop - Break - Continue - Return] -> map (fun e -> B.{ e; typ = dty expr.span expr.typ; span = expr.span }) | _ -> . diff --git a/engine/lib/phases/phase_functionalize_loops.mli b/engine/lib/phases/phase_functionalize_loops.mli index d8e3c77ed..ccfbe9c15 100644 --- a/engine/lib/phases/phase_functionalize_loops.mli +++ b/engine/lib/phases/phase_functionalize_loops.mli @@ -3,7 +3,8 @@ open! Prelude module Make (F : Features.T with type continue = Features.Off.continue - and type early_exit = Features.Off.early_exit) : sig + and type early_exit = Features.Off.early_exit + and type break = Features.Off.break) : sig include module type of struct module FA = F diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index 9ccd6f869..a1913bfdd 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -78,6 +78,14 @@ struct let rec dexpr e = dexpr_s { s with expr_level = []; drop_expr = false } e and dloop_state = [%inline_body dloop_state] in let span = expr.span in + let local_vars_expr = + let vars = + List.map + ~f:(fun (i, typ) : B.expr -> { e = LocalVar i; typ; span }) + s.loop_level + in + match vars with [ v ] -> v | _ -> UB.make_tuple_expr ~span vars + in match expr.e with | Let { @@ -229,7 +237,20 @@ struct dexpr_s { s with expr_level = []; drop_expr = false } scrutinee in { e = Match { scrutinee; arms }; typ; span = expr.span } - | Loop { body; kind; state; label; witness } -> + | Break { e; label; witness; _ } -> + let e = UB.make_tuple_expr ~span [ dexpr_same e; local_vars_expr ] in + { e = Break { e; label; witness }; span = expr.span; typ = e.typ } + | Continue { e = None; label; witness; _ } -> + let w = Features.On.state_passing_loop in + let e = + UB.make_tuple_expr ~span [ UB.unit_expr expr.span; local_vars_expr ] + in + { + e = Continue { e = Some (w, e); label; witness }; + span = expr.span; + typ = e.typ; + } + | Loop { body; kind; state; label; witness; control_flow } -> let variables_to_output = s.expr_level in (* [adapt]: should we reorder shadowings? *) let observable_mutations, adapt = @@ -295,7 +316,11 @@ struct (* we deal with a for loop: this is always a unit expression (i.e. no [break foo] with [foo] non-unit allowed) *) let typ = List.map ~f:snd observable_mutations |> UB.make_tuple_typ in let loop : B.expr = - { e = Loop { body; kind; state; label; witness }; typ; span } + { + e = Loop { body; kind; state; label; witness; control_flow }; + typ; + span; + } in if adapt && not (List.is_empty variables_to_output) then (* here, we need to introduce the shadowings as bindings *) @@ -318,8 +343,8 @@ struct typ = out.typ; } else loop - | [%inline_arms "dexpr'.*" - Let - Assign - Closure - Loop - If - Match] - -> + | [%inline_arms + "dexpr'.*" - Let - Assign - Closure - Loop - If - Match - Break] -> map (fun e -> let e' = B.{ e; typ = dty expr.span expr.typ; span = expr.span } diff --git a/engine/lib/phases/phase_reconstruct_for_index_loops.ml b/engine/lib/phases/phase_reconstruct_for_index_loops.ml index 4ecdfceca..cc433a864 100644 --- a/engine/lib/phases/phase_reconstruct_for_index_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_index_loops.ml @@ -84,6 +84,7 @@ module%inlined_contents Make (FA : Features.T) = struct end_ = dexpr end_; var; var_typ = dty span typ; + has_return = false; witness = Features.On.for_index_loop; } | [%inline_arms "dloop_kind.*"] -> auto diff --git a/engine/lib/phases/phase_reconstruct_for_loops.ml b/engine/lib/phases/phase_reconstruct_for_loops.ml index a6b3c48b5..57cc7c852 100644 --- a/engine/lib/phases/phase_reconstruct_for_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_loops.ml @@ -251,10 +251,12 @@ struct it = dexpr it; pat = dpat pat; witness = Features.On.for_loop; + has_return = false; }; state = Option.map ~f:(dloop_state expr.span) state; label; witness = S.loop expr.span witness; + control_flow = false; }; span = expr.span; typ = UB.unit_typ; diff --git a/engine/lib/phases/phase_reconstruct_while_loops.ml b/engine/lib/phases/phase_reconstruct_while_loops.ml index 11e955c4a..3edd09036 100644 --- a/engine/lib/phases/phase_reconstruct_while_loops.ml +++ b/engine/lib/phases/phase_reconstruct_while_loops.ml @@ -91,10 +91,12 @@ module%inlined_contents Make (FA : Features.T) = struct { condition = dexpr condition; witness = Features.On.while_loop; + has_return = false; }; state = Option.map ~f:(dloop_state expr.span) state; label; witness = S.loop expr.span witness; + control_flow = false; }; span = expr.span; typ = UB.unit_typ; diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 7531f8584..a68e30874 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -1,5 +1,8 @@ (* This phase rewrites: `if c {return a}; b` as `if c {return a; b} else {b}` - and does the equivalent transformation for pattern matchings. *) + and does the equivalent transformation for pattern matchings. + It rewrites the body of loops considereing `break` and `continue` + as `return` to place them in return position. If a loop contains + a `return` it places it is rewritten inside a pattern matching over the result. *) open! Prelude @@ -11,6 +14,7 @@ module Make (F : Features.T) = open Ast.Make (F) module U = Ast_utils.Make (F) + module M = Ast_builder.Make (F) module Visitors = Ast_visitors.Make (F) module Error = Phase_utils.MakeError (struct @@ -18,24 +22,83 @@ module Make (F : Features.T) = end) let has_return = + object (_self) + inherit [_] Visitors.reduce as super + method zero = false + method plus = ( || ) + + method! visit_expr' in_loop e = + match e with + | Return _ -> true + | (Break _ | Continue _) when in_loop -> true + | _ -> super#visit_expr' in_loop e + end + + let loop_has_cf = object (_self) inherit [_] Visitors.reduce as super method zero = false method plus = ( || ) method! visit_expr' () e = - match e with Return _ -> true | _ -> super#visit_expr' () e + match e with + | Return _ | Break _ | Continue _ -> true + | Loop _ -> false + | _ -> super#visit_expr' () e end let rewrite_control_flow = object (self) inherit [_] Visitors.map as super - method! visit_expr () e = + method! visit_expr in_loop e = + let loop_with_return (loop : expr) stmts_after final pat = + let typ = loop.typ in + let span = loop.span in + (* wrong, we would need to propagate the return type (either by looking at the + return statements (and the type of the expression they contain) or at the return type of the function) *) + let id = U.fresh_local_ident_in [] "ret" in + let module MS = (val U.M.make span) in + let mk_cf_pat = U.make_control_flow_pat ~span ~typ in + let arms = + [ + MS.arm + (mk_cf_pat `Break (U.make_var_pat id typ span)) + (MS.expr_LocalVar ~typ id); + MS.arm + (MS.pat_POr ~subpats:[ mk_cf_pat `Continue pat ] ~typ) + (U.make_lets stmts_after final); + ] + in + MS.expr_Match ~scrutinee:loop ~arms ~typ + in match e.e with - | _ when not (has_return#visit_expr () e) -> e - (* Returns in loops will be handled by issue #196 *) - | Loop _ -> e + (* This is supposed to improve performance but it might actually make it worse in some cases *) + | _ when not (has_return#visit_expr true e) -> e + | Loop loop -> + let return_inside = has_return#visit_expr false loop.body in + let control_flow = + return_inside || loop_has_cf#visit_expr () loop.body + in + let loop_expr = + { + e with + e = + Loop + { + loop with + body = self#visit_expr true loop.body; + control_flow; + }; + } + in + if return_inside then + let id = U.fresh_local_ident_in [] "loop_res" in + let pat = U.make_var_pat id loop_expr.typ loop_expr.span in + let module MS = (val U.M.make loop_expr.span) in + let final = MS.expr_LocalVar ~typ:loop_expr.typ id in + loop_with_return loop_expr [] final pat + else loop_expr | Let _ -> ( (* Collect let bindings to get the sequence of "statements", find the first "statement" that is a @@ -58,12 +121,28 @@ module Make (F : Features.T) = let stmts_before, stmt_and_stmts_after = List.split_while stmts ~f:(fun (_, e) -> match e.e with - | (If _ | Match _) when has_return#visit_expr () e -> + | (If _ | Match _) when has_return#visit_expr in_loop e -> false - | Return _ -> false + | Loop _ when has_return#visit_expr false e -> false + | Return _ | Break _ | Continue _ -> false | _ -> true) in match stmt_and_stmts_after with + | (p, ({ e = Loop loop; _ } as rhs)) :: stmts_after -> + let loop_expr = + { + rhs with + e = + Loop + { + loop with + control_flow = true; + body = self#visit_expr true loop.body; + }; + } + in + U.make_lets stmts_before + (loop_with_return loop_expr stmts_after final p) | (p, ({ e = If { cond; then_; else_ }; _ } as rhs)) :: stmts_after -> (* We know there is no "return" in the condition @@ -78,7 +157,7 @@ module Make (F : Features.T) = in U.make_lets stmts_before { rhs with e = If { cond; then_; else_ } } - |> self#visit_expr () + |> self#visit_expr in_loop | (p, ({ e = Match { scrutinee; arms }; _ } as rhs)) :: stmts_after -> let arms = @@ -90,18 +169,19 @@ module Make (F : Features.T) = in U.make_lets stmts_before { rhs with e = Match { scrutinee; arms } } - |> self#visit_expr () + |> self#visit_expr in_loop (* The statements coming after a "return" are useless. *) - | (_, ({ e = Return _; _ } as rhs)) :: _ -> - U.make_lets stmts_before rhs |> self#visit_expr () + | (_, ({ e = Return _ | Break _ | Continue _; _ } as rhs)) :: _ + -> + U.make_lets stmts_before rhs |> self#visit_expr in_loop | _ -> let stmts = List.map stmts ~f:(fun (p, e) -> - (p, self#visit_expr () e)) + (p, self#visit_expr in_loop e)) in - U.make_lets stmts (self#visit_expr () final)) - | _ -> super#visit_expr () e + U.make_lets stmts (self#visit_expr in_loop final)) + | _ -> super#visit_expr in_loop e end - let ditems = List.map ~f:(rewrite_control_flow#visit_item ()) + let ditems = List.map ~f:(rewrite_control_flow#visit_item false) end) diff --git a/engine/lib/side_effect_utils.ml b/engine/lib/side_effect_utils.ml index 79f66fb0e..1b470019b 100644 --- a/engine/lib/side_effect_utils.ml +++ b/engine/lib/side_effect_utils.ml @@ -284,7 +284,7 @@ struct }, m#plus ceffect effects )) | None -> (e, ceffect)) - | Loop { body; kind; state; label; witness } -> + | Loop { body; kind; state; label; witness; control_flow } -> let kind' = match kind with | UnconditionalLoop -> [] @@ -304,10 +304,12 @@ struct HoistSeq.many env kind_state (fun l effects -> let kind = match (l, kind) with - | condition :: ([ _ ] | []), WhileLoop { witness; _ } -> - WhileLoop { condition; witness } - | it :: ([ _ ] | []), ForLoop { pat; witness; _ } -> - ForLoop { pat; witness; it } + | ( condition :: ([ _ ] | []), + WhileLoop { witness; has_return; _ } ) -> + WhileLoop { condition; has_return; witness } + | ( it :: ([ _ ] | []), + ForLoop { pat; witness; has_return; _ } ) -> + ForLoop { pat; witness; has_return; it } | ([ _ ] | []), UnconditionalLoop -> UnconditionalLoop | _, ForIndexLoop _ -> . | _ -> HoistSeq.err_hoist_invariant e.span Stdlib.__LOC__ @@ -329,7 +331,11 @@ struct in let effects = m#plus effects body_effects in let body = lets_of_bindings lbs body in - ( { e with e = Loop { body; kind; state; label; witness } }, + ( { + e with + e = + Loop { body; kind; state; label; witness; control_flow }; + }, effects )) | If { cond; then_; else_ } -> HoistSeq.one env (self#visit_expr env cond) (fun cond effects -> diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index 5c4656e5b..3acf61b32 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -236,13 +236,14 @@ struct e = dexpr e; witness = S.mutable_variable span witness; } - | Loop { body; kind; state; label; witness } -> + | Loop { body; kind; state; label; witness; control_flow } -> Loop { body = dexpr body; kind = dloop_kind span kind; state = Option.map ~f:(dloop_state span) state; label; + control_flow; witness = S.loop span witness; } | Break { e; label; witness } -> @@ -306,19 +307,29 @@ struct and dloop_kind (span : span) (k : A.loop_kind) : B.loop_kind = match k with | UnconditionalLoop -> UnconditionalLoop - | WhileLoop { condition; witness } -> + | WhileLoop { condition; witness; has_return } -> WhileLoop - { condition = dexpr condition; witness = S.while_loop span witness } - | ForLoop { it; pat; witness } -> + { + condition = dexpr condition; + has_return; + witness = S.while_loop span witness; + } + | ForLoop { it; pat; has_return; witness } -> ForLoop - { it = dexpr it; pat = dpat pat; witness = S.for_loop span witness } - | ForIndexLoop { start; end_; var; var_typ; witness } -> + { + it = dexpr it; + pat = dpat pat; + has_return; + witness = S.for_loop span witness; + } + | ForIndexLoop { start; end_; var; var_typ; has_return; witness } -> ForIndexLoop { start = dexpr start; end_ = dexpr end_; var; var_typ = dty span var_typ; + has_return; witness = S.for_index_loop span witness; } diff --git a/engine/names/src/lib.rs b/engine/names/src/lib.rs index 438dd41f0..9df5efea9 100644 --- a/engine/names/src/lib.rs +++ b/engine/names/src/lib.rs @@ -38,6 +38,11 @@ fn dummy_hax_concrete_ident_wrapper>(x: I, mu let _ = ..; let _ = ..1; + let _ = [ + std::ops::ControlFlow::Break(()), + std::ops::ControlFlow::Continue(()), + ]; + fn iterator_functions(it: It) { let _ = it.clone().step_by(2); let _ = it.clone().enumerate(); @@ -159,6 +164,8 @@ mod hax { enum MutRef {} fn while_loop() {} + fn while_loop_cf() {} + fn while_loop_return() {} fn repeat() {} fn update_at() {} mod monomorphized_update_at { @@ -174,9 +181,19 @@ mod hax { mod folds { fn fold_range() {} + fn fold_range_cf() {} + fn fold_range_return() {} fn fold_range_step_by() {} + fn fold_range_step_by_cf() {} + fn fold_range_step_by_return() {} fn fold_enumerated_slice() {} + fn fold_enumerated_slice_cf() {} + fn fold_enumerated_slice_return() {} fn fold_enumerated_chunked_slice() {} + fn fold_enumerated_chunked_slice_cf() {} + fn fold_enumerated_chunked_slice_return() {} + fn fold_cf() {} + fn fold_return() {} } /// The engine uses this `dropped_body` symbol as a marker value diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti index 181f35135..45c57a4cc 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti @@ -108,3 +108,22 @@ let rec fold_range then fold_range (start +! mk_int 1) end_ inv (f init start) f else init +let fold_range_cf + (#acc_t: Type0) (#u: Lib.IntTypes.inttype) + (start: int_t u) + (end_: int_t u) + (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) + (cf_init: tuple2 (Core.Ops.Control_flow.t_ControlFlow unit unit) acc_t ) + (f: (acc:acc_t -> i:int_t u + -> (tuple2 (Core.Ops.Control_flow.t_ControlFlow unit unit) acc_t ) )) +: Tot (result: acc_t ) + (decreases v end_ - v start) + = + let cf, init = cf_init in + if v start < v end_ + then ( + match cf with + | Core.Ops.Control_flow.ControlFlow_Break _ -> init + | Core.Ops.Control_flow.ControlFlow_Continue _ -> fold_range (start +! mk_int 1) end_ inv (f init start) f + ) + else init diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.fst b/proof-libs/fstar/rust_primitives/Rust_primitives.fst index d80eabfde..a50c66510 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.fst +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.fst @@ -46,7 +46,23 @@ instance array_to_slice_unsize t n: unsize_tc (t_Array t n) = { arr <: t_Slice t); } +(* +type t_ControlFlow (b c: Type) = + | ControlFlow_Continue of c + | ControlFlow_Break of b +*) + let rec f_while_loop #s (condition: s -> bool) (init: s) (f: (i:s -> o:s{o << i})): s = if condition init then f_while_loop #s condition (f init) f else init + +(* let f_while_loop_cf #s #t (condition: s -> bool) (init: s) (f: (i:s -> Core.Ops.Control_flow.t_ControlFlow t s)): s + = + let rec f_while_loop_inner (init: Core.Ops.Control_flow.t_ControlFlow t s) = + match init with + | Core.Ops.Control_flow.ControlFlow_Continue v -> if condition v then f_while_loop_inner (f v) else v + | Core.Ops.Control_flow.ControlFlow_Break _ -> init + if condition init + then f_while_loop #s condition (f init) f + else init *) From b907465b6516edb6da1f3b3162511ddd5ddff096 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 17 Oct 2024 10:45:23 +0200 Subject: [PATCH 063/253] fix(lib/F*): `fold_range_cf` --- .../Rust_primitives.Hax.Folds.fsti | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti index 45c57a4cc..030d08383 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti @@ -108,22 +108,20 @@ let rec fold_range then fold_range (start +! mk_int 1) end_ inv (f init start) f else init -let fold_range_cf +let rec fold_range_cf (#acc_t: Type0) (#u: Lib.IntTypes.inttype) (start: int_t u) (end_: int_t u) (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) - (cf_init: tuple2 (Core.Ops.Control_flow.t_ControlFlow unit unit) acc_t ) - (f: (acc:acc_t -> i:int_t u - -> (tuple2 (Core.Ops.Control_flow.t_ControlFlow unit unit) acc_t ) )) -: Tot (result: acc_t ) - (decreases v end_ - v start) - = - let cf, init = cf_init in + (acc: acc_t {inv acc start}) + (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) /\ inv acc i} + -> tuple:((Core.Ops.Control_flow.t_ControlFlow unit unit) & acc_t) + {let cf, acc = tuple in inv acc (mk_int (v i + 1))})) +: Tot acc_t (decreases v end_ - v start) + = if v start < v end_ - then ( - match cf with - | Core.Ops.Control_flow.ControlFlow_Break _ -> init - | Core.Ops.Control_flow.ControlFlow_Continue _ -> fold_range (start +! mk_int 1) end_ inv (f init start) f - ) - else init + then match f acc start with + | Core.Ops.Control_flow.ControlFlow_Break (), acc -> acc + | Core.Ops.Control_flow.ControlFlow_Continue (), acc -> + fold_range_cf (start +! mk_int 1) end_ inv acc f + else acc From 0d9908e9cadaacce67a5a4ad883613644e45300d Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 12:00:49 +0200 Subject: [PATCH 064/253] fixup merge --- engine/backends/fstar/fstar_backend.ml | 1 - .../deprecated_generic_printer.ml | 5 +---- engine/lib/dune | 6 +++--- .../generic_printer_template.generate.js | 5 ++++- .../lib/generic_printer/generic_printer_template.ml | 11 +++++++---- engine/utils/generate_from_ast/codegen_printer.ml | 9 --------- justfile | 10 +++++++++- 7 files changed, 24 insertions(+), 23 deletions(-) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 946b13fb3..bf3e351a6 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1681,7 +1681,6 @@ let fstar_headers (bo : BackendOptions.t) = in [ opts; "open Core"; "open FStar.Mul" ] |> String.concat ~sep:"\n" -<<<<<<< HEAD (* module GenericPrinter = Generic_rust_printer.Make (InputLanguage) diff --git a/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml index aec4440ab..5cd219b4a 100644 --- a/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml +++ b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml @@ -415,10 +415,7 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct let suffix = match kind with | GPLifetime _ -> space ^^ colon ^^ space ^^ string "'unk" - | GPType { default = None } -> empty - | GPType { default = Some default } -> - space ^^ equals ^^ space - ^^ print#ty_at GenericParam_GPType default + | GPType -> empty | GPConst { typ } -> space ^^ colon ^^ space ^^ print#ty_at GenericParam_GPConst typ diff --git a/engine/lib/dune b/engine/lib/dune index 6195d121e..17a3db14d 100644 --- a/engine/lib/dune +++ b/engine/lib/dune @@ -56,7 +56,7 @@ ast_visitors.ml (with-stdin-from %{ast} - (run generate_visitors visitors))))) + (run generate_from_ast visitors))))) (rule (target generated_generic_printer_base.ml) @@ -67,10 +67,10 @@ generated_generic_printer_base.ml (with-stdin-from %{ast} - (run generate_visitors printer))))) + (run generate_from_ast printer))))) (rule - (target ast_builder_generated.ml) + (target ast_destruct_generated.ml) (deps (:ast ast.ml)) (action diff --git a/engine/lib/generic_printer/generic_printer_template.generate.js b/engine/lib/generic_printer/generic_printer_template.generate.js index 2521256c0..66ec63b8c 100755 --- a/engine/lib/generic_printer/generic_printer_template.generate.js +++ b/engine/lib/generic_printer/generic_printer_template.generate.js @@ -15,8 +15,11 @@ let fmt = path => execSync(`ocamlformat -i ${path}`); // Go to the root of the engine require('process').chdir(`${execSync('git rev-parse --show-toplevel').toString().trim()}/engine`); + // Prints the signature of module `Generic_printer` (using `ocaml-print-intf`) -let mli = execSync(`dune exec -- ocaml-print-intf ${GENERIC_PRINTER}`).toString(); +let mli = execSync(`dune exec -- ocaml-print-intf ${GENERIC_PRINTER}`).toString().split('class virtual base')[2]; + +writeFileSync('/tmp/exported.mli', mli); // Parses all let virtual_methods = [...mli.matchAll(/^( +)method (private )?virtual +(?.*) +:(?.*(\n \1.*)*)/gm)]; diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 92b3bda47..9bd0ea9cd 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -139,7 +139,7 @@ struct method generic_param_kind_GPLifetime ~witness:_ = default_document_for "generic_param_kind_GPLifetime" - method generic_param_kind_GPType ~default:_ = + method generic_param_kind_GPType = default_document_for "generic_param_kind_GPType" method generic_value_GConst _x1 = @@ -221,15 +221,18 @@ struct method item'_TyAlias ~super:_ ~name:_ ~generics:_ ~ty:_ = default_document_for "item'_TyAlias" + method item'_Type ~super:_ ~name:_ ~generics:_ ~variants:_ ~is_struct:_ = + default_document_for "item'_Type" + + method item'_Type_enum ~super:_ ~name:_ ~generics:_ ~variants:_ = + default_document_for "item'_Type_enum" + method item'_Type_struct ~super:_ ~name:_ ~generics:_ ~arguments:_ = default_document_for "item'_Type_struct" method item'_Type_tuple_struct ~super:_ ~name:_ ~generics:_ ~arguments:_ = default_document_for "item'_Type_tuple_struct" - method item'_Type_enum ~super:_ ~name:_ ~generics:_ ~variants:_ = - default_document_for "item'_Type_enum" - method item'_Use ~super:_ ~path:_ ~is_external:_ ~rename:_ = default_document_for "item'_Use" diff --git a/engine/utils/generate_from_ast/codegen_printer.ml b/engine/utils/generate_from_ast/codegen_printer.ml index 75b692d56..99aed4093 100644 --- a/engine/utils/generate_from_ast/codegen_printer.ml +++ b/engine/utils/generate_from_ast/codegen_printer.ml @@ -361,15 +361,6 @@ module Make (F : Features.T) = struct module AST = Ast.Make (F) open Ast.Make (F) - (* module DoNotOverride: sig - type 'a t - val __force (type a) (f: a t): a - end = struct - (** Marks a method that should not be overriden by a printer. *) - type 'a t = 'a - let __force (f: 'a) = 'a - end *) - class virtual base = object (print) %s end diff --git a/justfile b/justfile index abc4b305a..b52f992aa 100644 --- a/justfile +++ b/justfile @@ -28,13 +28,21 @@ expand *FLAGS: # Show the Rust to OCaml generated types available to the engine. @list-types: - just _ensure_binary_availability ocamlformat ocamlformat + just _ensure_command_in_path ocamlformat ocamlformat cd engine && dune describe pp lib/types.ml \ | sed -e '1,/open ParseError/ d' \ | sed '/let rec pp_/,$d' \ | ocamlformat --impl - \ | just _pager +# Show the OCaml module `Generated_generic_printer_base` +@show-generated-printer-ml: + just _ensure_command_in_path ocamlformat ocamlformat + cd engine && dune describe pp lib/generated_generic_printer_base.ml \ + | ocamlformat --impl - \ + | just _pager + + # Format all the code fmt: cargo fmt From d93c2f5079c57e1f51d83272ed1f7a3913844adf Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 12:18:17 +0200 Subject: [PATCH 065/253] feat(gen-print): split `expr::GlobalVar` --- engine/lib/generic_printer/generic_printer.ml | 12 ++++++++++++ .../lib/generic_printer/generic_printer_template.ml | 7 +++++-- engine/utils/generate_from_ast/codegen_printer.ml | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 2c8683f27..e321e92d6 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -521,6 +521,18 @@ module Make (F : Features.T) = struct self#concrete_ident ~local id) ast_position id + method virtual expr'_GlobalVar_concrete: super:expr -> concrete_ident lazy_doc -> document + method virtual expr'_GlobalVar_primitive: super:expr -> primitive_ident -> document + + method _do_not_override_expr'_GlobalVar ~super global_ident = + match global_ident with + | `Concrete concrete -> + let concrete = self#_do_not_override_lazy_of_concrete_ident AstPos_expr'_GlobalVar_x0 concrete in + self#expr'_GlobalVar_concrete ~super concrete + | `Primitive primitive -> + self#expr'_GlobalVar_primitive ~super primitive + | _ -> self#assertion_failure @@ "GlobalVar: expected a concrete or primitive global ident, got:" ^ [%show: global_ident] global_ident + method module_path_separator = "::" (** [module_path_separator] is the default separator for paths. `::` by default *) diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 9bd0ea9cd..01cd50493 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -90,8 +90,11 @@ struct method expr'_EffectAction ~super:_ ~action:_ ~argument:_ = default_document_for "expr'_EffectAction" - method expr'_GlobalVar ~super:_ _x2 = - default_document_for "expr'_GlobalVar" + method expr'_GlobalVar_concrete ~super:_ _x2 = + default_document_for "expr'_GlobalVar_concrete" + + method expr'_GlobalVar_primitive ~super:_ _x2 = + default_document_for "expr'_GlobalVar_primitive" method expr'_If ~super:_ ~cond:_ ~then_:_ ~else_:_ = default_document_for "expr'_If" diff --git a/engine/utils/generate_from_ast/codegen_printer.ml b/engine/utils/generate_from_ast/codegen_printer.ml index 99aed4093..aeb4ddf57 100644 --- a/engine/utils/generate_from_ast/codegen_printer.ml +++ b/engine/utils/generate_from_ast/codegen_printer.ml @@ -25,6 +25,7 @@ let is_hidden_method = "lhs_LhsFieldAccessor"; "local_ident"; "pat'_PConstruct"; + "expr'_GlobalVar"; ] in List.mem ~equal:[%eq: string] list From 80a556644a187e763aeafeaffec92f364a0ceb2d Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 12:24:03 +0200 Subject: [PATCH 066/253] feat(engine/ast): `Impl`: `of_trait`: global ident -> concrete --- engine/backends/coq/coq/coq_backend.ml | 2 +- engine/backends/coq/ssprove/ssprove_backend.ml | 4 ++-- engine/backends/fstar/fstar_backend.ml | 2 +- engine/lib/ast.ml | 2 +- engine/lib/dependencies.ml | 2 +- engine/lib/import_thir.ml | 2 +- engine/lib/print_rust.ml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 6fa264c75..c2fd77fe9 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -582,7 +582,7 @@ struct | Impl { generics; self_ty; of_trait = name, gen_vals; items } -> [ C.AST.Instance - ( pglobal_ident name, + ( pconcrete_ident name, List.map ~f:(pgeneric_param_as_argument span) generics.params, pty span self_ty, args_ty span gen_vals, diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index 61fe6f247..4ea5ab79e 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -1799,7 +1799,7 @@ struct items @ [ SSP.AST.ProgramInstance - ( pglobal_ident name, + ( pconcrete_ident name, pgeneric span generics, pty span self_ty, args_ty span gen_vals, @@ -1865,7 +1865,7 @@ struct ]) items) ); ] - @ [ SSP.AST.HintUnfold (pglobal_ident name, Some (pty span self_ty)) ] + @ [ SSP.AST.HintUnfold (pconcrete_ident name, Some (pty span self_ty)) ] in decls_from_item diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index bf3e351a6..683dc32df 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1419,7 +1419,7 @@ struct in let typ = F.mk_e_app - (F.term @@ F.AST.Name (pglobal_ident e.span trait)) + (F.term @@ F.AST.Name (pconcrete_ident trait)) (List.map ~f:(pgeneric_value e.span) generic_args) in let pat = F.pat @@ F.AST.PatAscribed (pat, (typ, None)) in diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 145acd9cf..672080ebf 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -421,7 +421,7 @@ functor | Impl of { generics : generics; self_ty : ty; - of_trait : global_ident * generic_value list; + of_trait : concrete_ident * generic_value list; items : impl_item list; parent_bounds : (impl_expr * impl_ident) list; safety : safety_kind; diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index b926388d1..a4952b4eb 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -71,7 +71,7 @@ module Make (F : Features.T) = struct -> v#visit_generics () generics @ v#visit_ty () self_ty - @ v#visit_global_ident () (fst of_trait) + @ v#visit_concrete_ident () (fst of_trait) @ concat_map (v#visit_generic_value ()) (snd of_trait) @ concat_map (v#visit_impl_item ()) items @ concat_map diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index c9f3a2916..7b9202d1c 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -1674,7 +1674,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = generics = c_generics generics; self_ty = c_ty item.span self_ty; of_trait = - ( def_id Trait of_trait.def_id, + ( Concrete_ident.of_def_id Trait of_trait.def_id, List.map ~f:(c_generic_value item.span) of_trait.generic_args ); items = diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index c08f65ba0..1fb6f9a78 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -576,7 +576,7 @@ module Raw = struct | Impl { generics; self_ty; of_trait; items; parent_bounds = _; safety } -> let trait = - pglobal_ident e.span (fst of_trait) + pglobal_ident e.span (`Concrete (fst of_trait)) & !"<" & concat ~sep:!"," (List.map ~f:(pgeneric_value e.span) (snd of_trait)) From 8c6cb91969dc4475858ee0a39c0a3994698690cf Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 13:57:16 +0200 Subject: [PATCH 067/253] dune fmt --- .../backends/coq/ssprove/ssprove_backend.ml | 4 +- engine/backends/fstar/fstar_backend.ml | 2 +- engine/lib/generic_printer/generic_printer.ml | 109 +++++++++--------- 3 files changed, 61 insertions(+), 54 deletions(-) diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index 4ea5ab79e..bdae541d6 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -1865,7 +1865,9 @@ struct ]) items) ); ] - @ [ SSP.AST.HintUnfold (pconcrete_ident name, Some (pty span self_ty)) ] + @ [ + SSP.AST.HintUnfold (pconcrete_ident name, Some (pty span self_ty)); + ] in decls_from_item diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 683dc32df..1e3ac766a 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1725,7 +1725,7 @@ let translate_as_experimental_rust m (bo : BackendOptions.t) *) (** Translate as F* (the "legacy" printer) *) -let translate_as_fstar m (bo : BackendOptions.t) ~(bundles : AST.item list list) +let translate_as_fstar m (bo : BackendOptions.t) ~(bundles : AST.item list list) (items : AST.item list) : Types.file list = let show_view Concrete_ident.{ crate; path; definition } = crate :: (path @ [ definition ]) |> String.concat ~sep:"::" diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index e321e92d6..86c7d5691 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -276,56 +276,52 @@ module Make (F : Features.T) = struct (** *) - method virtual item'_Type_struct : - super:item -> - name:concrete_ident lazy_doc -> - generics:generics lazy_doc -> - arguments:(concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> - document - - method virtual item'_Type_tuple_struct : - super:item -> - name:concrete_ident lazy_doc -> - generics:generics lazy_doc -> - arguments:(concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> - document - - method virtual item'_Type_enum : - super:item -> - name:concrete_ident lazy_doc -> - generics:generics lazy_doc -> - variants:(variant lazy_doc) list -> - document - - method _do_not_override_item'_Type ~super ~name ~generics ~variants ~is_struct = - if is_struct - then + method virtual item'_Type_struct + : super:item -> + name:concrete_ident lazy_doc -> + generics:generics lazy_doc -> + arguments: + (concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> + document + + method virtual item'_Type_tuple_struct + : super:item -> + name:concrete_ident lazy_doc -> + generics:generics lazy_doc -> + arguments: + (concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> + document + + method virtual item'_Type_enum + : super:item -> + name:concrete_ident lazy_doc -> + generics:generics lazy_doc -> + variants:variant lazy_doc list -> + document + + method _do_not_override_item'_Type ~super ~name ~generics ~variants + ~is_struct = + if is_struct then match variants with - | [variant] -> - let variant_arguments = - List.map - ~f:(fun (ident,typ,_attrs) -> - (self#_do_not_override_lazy_of_concrete_ident AstPos_variant__arguments ident, - self#_do_not_override_lazy_of_ty AstPos_variant__arguments typ, - [] (* TODO: attrs *))) - variant#v.arguments - in - if variant#v.is_record - then - self#item'_Type_struct - ~super - ~name - ~generics - ~arguments:variant_arguments - else - self#item'_Type_tuple_struct - ~super - ~name - ~generics - ~arguments:variant_arguments + | [ variant ] -> + let variant_arguments = + List.map + ~f:(fun (ident, typ, _attrs) -> + ( self#_do_not_override_lazy_of_concrete_ident + AstPos_variant__arguments ident, + self#_do_not_override_lazy_of_ty AstPos_variant__arguments + typ, + [] (* TODO: attrs *) )) + variant#v.arguments + in + if variant#v.is_record then + self#item'_Type_struct ~super ~name ~generics + ~arguments:variant_arguments + else + self#item'_Type_tuple_struct ~super ~name ~generics + ~arguments:variant_arguments | _ -> self#unreachable () (* TODO: guarantees? *) - else - self#item'_Type_enum ~super ~name ~generics ~variants + else self#item'_Type_enum ~super ~name ~generics ~variants (** {2:common-nodes Printers for common nodes} *) @@ -521,17 +517,26 @@ module Make (F : Features.T) = struct self#concrete_ident ~local id) ast_position id - method virtual expr'_GlobalVar_concrete: super:expr -> concrete_ident lazy_doc -> document - method virtual expr'_GlobalVar_primitive: super:expr -> primitive_ident -> document + method virtual expr'_GlobalVar_concrete + : super:expr -> concrete_ident lazy_doc -> document + + method virtual expr'_GlobalVar_primitive + : super:expr -> primitive_ident -> document method _do_not_override_expr'_GlobalVar ~super global_ident = match global_ident with | `Concrete concrete -> - let concrete = self#_do_not_override_lazy_of_concrete_ident AstPos_expr'_GlobalVar_x0 concrete in + let concrete = + self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_GlobalVar_x0 concrete + in self#expr'_GlobalVar_concrete ~super concrete | `Primitive primitive -> self#expr'_GlobalVar_primitive ~super primitive - | _ -> self#assertion_failure @@ "GlobalVar: expected a concrete or primitive global ident, got:" ^ [%show: global_ident] global_ident + | _ -> + self#assertion_failure + @@ "GlobalVar: expected a concrete or primitive global ident, got:" + ^ [%show: global_ident] global_ident method module_path_separator = "::" (** [module_path_separator] is the default separator for From 7bd736c2b9d510384d6a84411f3355626e0e86a3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 13:57:39 +0200 Subject: [PATCH 068/253] feat(gen-print): better ergnonmics for generics --- engine/lib/generic_printer/generic_printer.ml | 27 ++++++++++++++++ .../generate_from_ast/codegen_printer.ml | 31 ++++++++++++++----- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 86c7d5691..085d1b3dc 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -576,5 +576,32 @@ module Make (F : Features.T) = struct current_namespace <- View.to_namespace value.ident |> Option.some; super#_do_not_override_lazy_of_item ast_position value + method _do_not_override_lazy_of_generics ast_position (value : generics) + : (generics lazy_doc + * generic_param lazy_doc list + * generic_constraint lazy_doc list) + lazy_doc = + let params = + List.map + ~f:(fun x -> + self#_do_not_override_lazy_of_generic_param + AstPos_generics__params x) + value.params + in + let constraints = + List.map + ~f:(fun x -> + self#_do_not_override_lazy_of_generic_constraint + AstPos_generics__constraints x) + value.constraints + in + lazy_doc (fun (lazy_doc, _, _) -> lazy_doc#p) ast_position + ( lazy_doc + (fun (value : generics) -> + self#wrap_generics ast_position value + (self#generics ~params ~constraints)) + ast_position value, + params, + constraints ) end end diff --git a/engine/utils/generate_from_ast/codegen_printer.ml b/engine/utils/generate_from_ast/codegen_printer.ml index aeb4ddf57..27dfcf67f 100644 --- a/engine/utils/generate_from_ast/codegen_printer.ml +++ b/engine/utils/generate_from_ast/codegen_printer.ml @@ -30,6 +30,8 @@ let is_hidden_method = in List.mem ~equal:[%eq: string] list +let lazy_doc_manual_definitions = [ "_do_not_override_lazy_of_generics" ] + let rec of_ty (state : state) (call_method : string -> ty:string -> string) (t : Type.t) : ((unit -> string) -> string -> string) option = let* args = @@ -82,13 +84,13 @@ let rec of_ty (state : state) (call_method : string -> ty:string -> string) ^ " " ^ pos () ^ " " ^ value ^ ")") | _ -> Some (fun pos value -> "(" ^ value ^ ")") -and string_ty_of_ty (state : state) (t : Type.t) = +and string_ty_of_ty' (state : state) (t : Type.t) = if String.is_prefix t.typ ~prefix:"prim___tuple_" then - let args = List.map t.args ~f:(string_ty_of_ty state) in + let args = List.map t.args ~f:(string_ty_of_ty' state) in let n = List.count args ~f:(String.is_suffix ~suffix:"lazy_doc)") in let base = "(" - ^ String.concat ~sep:" * " (List.map t.args ~f:(string_ty_of_ty state)) + ^ String.concat ~sep:" * " (List.map t.args ~f:(string_ty_of_ty' state)) ^ ")" in if [%eq: int] n 1 then "(" ^ base ^ " lazy_doc)" else base @@ -97,7 +99,7 @@ and string_ty_of_ty (state : state) (t : Type.t) = ^ (if List.is_empty t.args then "" else "(" - ^ String.concat ~sep:", " (List.map t.args ~f:(string_ty_of_ty state)) + ^ String.concat ~sep:", " (List.map t.args ~f:(string_ty_of_ty' state)) ^ ") ") ^ t.typ ^ (if List.mem ~equal:[%eq: string] state.names_with_doc t.typ then @@ -105,9 +107,17 @@ and string_ty_of_ty (state : state) (t : Type.t) = else "") ^ ")" -and is_lazy_doc_typ (state : state) = string_ty_of_ty state >> is_lazy_doc_typ' +and is_lazy_doc_typ (state : state) = string_ty_of_ty' state >> is_lazy_doc_typ' and is_lazy_doc_typ' = String.is_suffix ~suffix:"lazy_doc)" +let string_ty_of_ty (state : state) (t : Type.t) = + let s = string_ty_of_ty' state t in + match s with + | "(generics lazy_doc)" -> + "((generics lazy_doc * generic_param lazy_doc list * generic_constraint \ + lazy_doc list) lazy_doc)" + | _ -> s + let meth_name' typ_name variant_name = typ_name ^ if String.is_empty variant_name then "" else "_" ^ variant_name @@ -210,11 +220,16 @@ let print_datatype state (dt : Datatype.t) in let body = wrapper body in sigs := - ("method wrap_" ^ dt.name ^ " _pos (_value: " ^ dt.name + ("method wrap_" ^ dt.name ^ " (_pos: ast_position) (_value: " ^ dt.name ^ ") (doc: document): document = doc") :: !sigs; - head ^ "lazy_doc (fun (value: " ^ dt.name ^ ") -> " ^ body - ^ ") ast_position value" ^ "(**/**)" + let def = + head ^ "lazy_doc (fun (value: " ^ dt.name ^ ") -> " ^ body + ^ ") ast_position value" + in + if List.mem ~equal:[%eq: string] lazy_doc_manual_definitions method_name + then "(* skipping " ^ method_name ^ " *) (**/**)" + else def ^ "(**/**)" in let main = match dt.kind with From 8c703a0b4b2be97be06add2f839d48e075fc78f3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 14:16:30 +0200 Subject: [PATCH 069/253] feat(gen-print): `item'_Type_struct`: tuple_struct arg --- engine/lib/generic_printer/generic_printer.ml | 27 +++++++------------ .../generic_printer_template.ml | 6 ++--- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 085d1b3dc..e500bf5dd 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -280,16 +280,9 @@ module Make (F : Features.T) = struct : super:item -> name:concrete_ident lazy_doc -> generics:generics lazy_doc -> + tuple_struct:bool -> arguments: - (concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> - document - - method virtual item'_Type_tuple_struct - : super:item -> - name:concrete_ident lazy_doc -> - generics:generics lazy_doc -> - arguments: - (concrete_ident lazy_doc * ty lazy_doc * attr lazy_doc list) list -> + (concrete_ident lazy_doc * ty lazy_doc * attr list lazy_doc) list -> document method virtual item'_Type_enum @@ -306,21 +299,19 @@ module Make (F : Features.T) = struct | [ variant ] -> let variant_arguments = List.map - ~f:(fun (ident, typ, _attrs) -> + ~f:(fun (ident, typ, attrs) -> ( self#_do_not_override_lazy_of_concrete_ident AstPos_variant__arguments ident, self#_do_not_override_lazy_of_ty AstPos_variant__arguments typ, - [] (* TODO: attrs *) )) + self#_do_not_override_lazy_of_attrs AstPos_variant__attrs + attrs )) variant#v.arguments in - if variant#v.is_record then - self#item'_Type_struct ~super ~name ~generics - ~arguments:variant_arguments - else - self#item'_Type_tuple_struct ~super ~name ~generics - ~arguments:variant_arguments - | _ -> self#unreachable () (* TODO: guarantees? *) + self#item'_Type_struct ~super ~name ~generics + ~tuple_struct:(not variant#v.is_record) + ~arguments:variant_arguments + | _ -> self#unreachable () else self#item'_Type_enum ~super ~name ~generics ~variants (** {2:common-nodes Printers for common nodes} *) diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 01cd50493..f4314443a 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -230,12 +230,10 @@ struct method item'_Type_enum ~super:_ ~name:_ ~generics:_ ~variants:_ = default_document_for "item'_Type_enum" - method item'_Type_struct ~super:_ ~name:_ ~generics:_ ~arguments:_ = + method item'_Type_struct ~super:_ ~name:_ ~generics:_ ~tuple_struct:_ + ~arguments:_ = default_document_for "item'_Type_struct" - method item'_Type_tuple_struct ~super:_ ~name:_ ~generics:_ ~arguments:_ = - default_document_for "item'_Type_tuple_struct" - method item'_Use ~super:_ ~path:_ ~is_external:_ ~rename:_ = default_document_for "item'_Use" From 2cf1d1a81dd4fc313e78073c3cfa40aadb81caa5 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 14:21:05 +0200 Subject: [PATCH 070/253] feat(gen-print): rename variant to enum variant --- engine/lib/generic_printer/generic_printer.ml | 37 +++++++++++++++---- .../generic_printer_template.ml | 6 +-- .../generate_from_ast/codegen_printer.ml | 1 + 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index e500bf5dd..d67cbe412 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -314,6 +314,25 @@ module Make (F : Features.T) = struct | _ -> self#unreachable () else self#item'_Type_enum ~super ~name ~generics ~variants + method virtual item'_Enum_Variant + : name:concrete_ident lazy_doc -> + arguments: + (concrete_ident lazy_doc * ty lazy_doc * attrs lazy_doc) list -> + is_record:bool -> + attrs:attrs lazy_doc -> + document + + + method _do_not_override_variant + : name:concrete_ident lazy_doc -> + arguments: + (concrete_ident lazy_doc * ty lazy_doc * attrs lazy_doc) list -> + is_record:bool -> + attrs:attrs lazy_doc -> + document + = self#item'_Enum_Variant + + (** {2:common-nodes Printers for common nodes} *) method virtual common_array : document list -> document @@ -586,13 +605,15 @@ module Make (F : Features.T) = struct AstPos_generics__constraints x) value.constraints in - lazy_doc (fun (lazy_doc, _, _) -> lazy_doc#p) ast_position - ( lazy_doc - (fun (value : generics) -> - self#wrap_generics ast_position value - (self#generics ~params ~constraints)) - ast_position value, - params, - constraints ) + lazy_doc + (fun (lazy_doc, _, _) -> lazy_doc#p) + ast_position + ( lazy_doc + (fun (value : generics) -> + self#wrap_generics ast_position value + (self#generics ~params ~constraints)) + ast_position value, + params, + constraints ) end end diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index f4314443a..110873754 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -200,6 +200,9 @@ struct method item'_Alias ~super:_ ~name:_ ~item:_ = default_document_for "item'_Alias" + method item'_Enum_Variant ~name:_ ~arguments:_ ~is_record:_ ~attrs:_ = + default_document_for "item'_Enum_Variant" + method item'_Fn ~super:_ ~name:_ ~generics:_ ~body:_ ~params:_ ~safety:_ = default_document_for "item'_Fn" @@ -359,9 +362,6 @@ struct method ty_TSlice ~witness:_ ~ty:_ = default_document_for "ty_TSlice" method ty_TStr = default_document_for "ty_TStr" - - method variant ~name:_ ~arguments:_ ~is_record:_ ~attrs:_ = - default_document_for "variant" (* END GENERATED *) end end diff --git a/engine/utils/generate_from_ast/codegen_printer.ml b/engine/utils/generate_from_ast/codegen_printer.ml index 27dfcf67f..58b3368ed 100644 --- a/engine/utils/generate_from_ast/codegen_printer.ml +++ b/engine/utils/generate_from_ast/codegen_printer.ml @@ -26,6 +26,7 @@ let is_hidden_method = "local_ident"; "pat'_PConstruct"; "expr'_GlobalVar"; + "variant"; ] in List.mem ~equal:[%eq: string] list From 632484b6d08bb77a631a110140f38301094e0527 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 21 Oct 2024 14:38:32 +0200 Subject: [PATCH 071/253] refactor(gen-print): doc, clean things up --- engine/lib/generic_printer/generic_printer.ml | 246 ++++++++++-------- engine/profile.dump | 0 2 files changed, 133 insertions(+), 113 deletions(-) delete mode 100644 engine/profile.dump diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index d67cbe412..838a32596 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -1,7 +1,3 @@ -(** - The generic printer if -*) - open! Prelude open! Ast open! PPrint @@ -169,15 +165,59 @@ module Make (F : Features.T) = struct with Diagnostics.SpanFreeError.Exn (Data (context, kind)) -> handle context kind + (** {2:specialize-expr Printer settings} *) + + method virtual printer_name : string + (** Mark a path as unreachable *) + + val concrete_ident_view : (module Concrete_ident.VIEW_API) = + (module Concrete_ident.DefaultViewAPI) + (** The concrete ident view to be used *) + + (** {2:specialize-expr Utility functions} *) + method assertion_failure : 'any. string -> 'any = fun details -> let span = Span.to_thir self#current_span in let kind = Types.AssertionFailure { details } in let ctx = Diagnostics.Context.GenericPrinter self#printer_name in Diagnostics.SpanFreeError.raise ~span ctx kind + (** An assertion failed *) - method unreachable : 'any. unit -> 'any = failwith "Unreachable!" - method virtual printer_name : string + method unreachable : 'any. unit -> 'any = + self#assertion_failure "Unreachable" + (** Mark a path as unreachable *) + + method local_ident (id : local_ident) : document = + let module View = (val concrete_ident_view) in + View.local_ident + (match String.chop_prefix ~prefix:"impl " id.name with + | Some _ -> + let name = "impl_" ^ Int.to_string ([%hash: string] id.name) in + { id with name } + | _ -> id) + |> string + (** {2:specialize-expr Printers for special types} *) + + method concrete_ident ~local (id : Concrete_ident.view) : document = + string + (if local then id.definition + else + String.concat ~sep:self#module_path_separator + (id.crate :: (id.path @ [ id.definition ]))) + (** [concrete_ident ~local id] prints a name without path if + [local] is true, otherwise it prints the full path, separated by + `module_path_separator`. *) + + method quote (quote : quote) : document = + List.map + ~f:(function + | `Verbatim code -> string code + | `Expr e -> self#print_expr AstPosition_Quote e + | `Pat p -> self#print_pat AstPosition_Quote p + | `Typ p -> self#print_ty AstPosition_Quote p) + quote.contents + |> concat (** {2:specialize-expr Specialized printers for [expr]} *) @@ -231,6 +271,12 @@ module Make (F : Features.T) = struct method virtual expr'_Construct_tuple : super:expr -> components:expr lazy_doc list -> document + method virtual expr'_GlobalVar_concrete + : super:expr -> concrete_ident lazy_doc -> document + + method virtual expr'_GlobalVar_primitive + : super:expr -> primitive_ident -> document + (** {2:specialize-pat Specialized printers for [pat]} *) method virtual pat'_PConstruct_inductive @@ -274,7 +320,7 @@ module Make (F : Features.T) = struct (** [ty_TApp_application ~typ ~generics] prints the type [typ<...generics>]. *) - (** *) + (** {2:specialize-ty Specialized printers for [item]} *) method virtual item'_Type_struct : super:item -> @@ -284,6 +330,9 @@ module Make (F : Features.T) = struct arguments: (concrete_ident lazy_doc * ty lazy_doc * attr list lazy_doc) list -> document + (** [item'_Type_struct ~super ~name ~generics ~tuple_struct ~arguments] prints the struct definition [struct name arguments]. `tuple_struct` says whether we are dealing with a tuple struct + (e.g. [struct Foo(T1, T2)]) or a named struct + (e.g. [struct Foo {field: T1, other: T2}])? *) method virtual item'_Type_enum : super:item -> @@ -291,53 +340,45 @@ module Make (F : Features.T) = struct generics:generics lazy_doc -> variants:variant lazy_doc list -> document - - method _do_not_override_item'_Type ~super ~name ~generics ~variants - ~is_struct = - if is_struct then - match variants with - | [ variant ] -> - let variant_arguments = - List.map - ~f:(fun (ident, typ, attrs) -> - ( self#_do_not_override_lazy_of_concrete_ident - AstPos_variant__arguments ident, - self#_do_not_override_lazy_of_ty AstPos_variant__arguments - typ, - self#_do_not_override_lazy_of_attrs AstPos_variant__attrs - attrs )) - variant#v.arguments - in - self#item'_Type_struct ~super ~name ~generics - ~tuple_struct:(not variant#v.is_record) - ~arguments:variant_arguments - | _ -> self#unreachable () - else self#item'_Type_enum ~super ~name ~generics ~variants + (** [item'_Type_enum ~super ~name ~generics ~variants] prints + the enum type [enum name { ... }]. *) method virtual item'_Enum_Variant - : name:concrete_ident lazy_doc -> - arguments: - (concrete_ident lazy_doc * ty lazy_doc * attrs lazy_doc) list -> - is_record:bool -> - attrs:attrs lazy_doc -> - document - - - method _do_not_override_variant - : name:concrete_ident lazy_doc -> - arguments: - (concrete_ident lazy_doc * ty lazy_doc * attrs lazy_doc) list -> - is_record:bool -> - attrs:attrs lazy_doc -> - document - = self#item'_Enum_Variant - + : name:concrete_ident lazy_doc -> + arguments: + (concrete_ident lazy_doc * ty lazy_doc * attrs lazy_doc) list -> + is_record:bool -> + attrs:attrs lazy_doc -> + document + (** [item'_Enum_Variant] prints a variant of an enum. *) (** {2:common-nodes Printers for common nodes} *) method virtual common_array : document list -> document (** [common_array values] is a default for printing array-like nodes: array patterns, array expressions. *) + (** {2:defaults Default printers} **) + + method module_path_separator = "::" + (** [module_path_separator] is the default separator for + paths. `::` by default *) + + method pat'_PArray ~super:_ ~args = + List.map ~f:(fun arg -> arg#p) args |> self#common_array + + method expr'_Array ~super:_ args = + List.map ~f:(fun arg -> arg#p) args |> self#common_array + + method pat'_POr ~super:_ ~subpats = + List.map ~f:(fun subpat -> subpat#p) subpats + |> separate (break 1 ^^ char '|' ^^ space) + + (**/**) + (* This section is about defining or overriding + `_do_not_override_` methods. This is internal logic, whence this + is excluded from documentation (with the nice and user friendly + `(**/**)` ocamldoc syntax) *) + method _do_not_override_lhs_LhsFieldAccessor ~e ~typ ~field ~witness = let field = match field with @@ -426,6 +467,21 @@ module Make (F : Features.T) = struct | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> self#assertion_failure "Construct unexpected constructors" + method _do_not_override_expr'_GlobalVar ~super global_ident = + match global_ident with + | `Concrete concrete -> + let concrete = + self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_GlobalVar_x0 concrete + in + self#expr'_GlobalVar_concrete ~super concrete + | `Primitive primitive -> + self#expr'_GlobalVar_primitive ~super primitive + | _ -> + self#assertion_failure + @@ "GlobalVar: expected a concrete or primitive global ident, got:" + ^ [%show: global_ident] global_ident + method _do_not_override_pat'_PConstruct ~super ~constructor ~is_record ~is_struct ~fields = match constructor with @@ -488,25 +544,36 @@ module Make (F : Features.T) = struct self#assertion_failure "malformed [ty.TApp] tuple"; self#ty_TApp_tuple ~types - method pat'_PArray ~super:_ ~args = - List.map ~f:(fun arg -> arg#p) args |> self#common_array - - method expr'_Array ~super:_ args = - List.map ~f:(fun arg -> arg#p) args |> self#common_array - - val concrete_ident_view : (module Concrete_ident.VIEW_API) = - (module Concrete_ident.DefaultViewAPI) - (** The concrete ident view to be used *) + method _do_not_override_item'_Type ~super ~name ~generics ~variants + ~is_struct = + if is_struct then + match variants with + | [ variant ] -> + let variant_arguments = + List.map + ~f:(fun (ident, typ, attrs) -> + ( self#_do_not_override_lazy_of_concrete_ident + AstPos_variant__arguments ident, + self#_do_not_override_lazy_of_ty AstPos_variant__arguments + typ, + self#_do_not_override_lazy_of_attrs AstPos_variant__attrs + attrs )) + variant#v.arguments + in + self#item'_Type_struct ~super ~name ~generics + ~tuple_struct:(not variant#v.is_record) + ~arguments:variant_arguments + | _ -> self#unreachable () + else self#item'_Type_enum ~super ~name ~generics ~variants - method local_ident (id : local_ident) : document = - let module View = (val concrete_ident_view) in - View.local_ident - (match String.chop_prefix ~prefix:"impl " id.name with - | Some _ -> - let name = "impl_" ^ Int.to_string ([%hash: string] id.name) in - { id with name } - | _ -> id) - |> string + method _do_not_override_variant + : name:concrete_ident lazy_doc -> + arguments: + (concrete_ident lazy_doc * ty lazy_doc * attrs lazy_doc) list -> + is_record:bool -> + attrs:attrs lazy_doc -> + document = + self#item'_Enum_Variant method _do_not_override_lazy_of_local_ident ast_position (id : local_ident) = @@ -527,55 +594,6 @@ module Make (F : Features.T) = struct self#concrete_ident ~local id) ast_position id - method virtual expr'_GlobalVar_concrete - : super:expr -> concrete_ident lazy_doc -> document - - method virtual expr'_GlobalVar_primitive - : super:expr -> primitive_ident -> document - - method _do_not_override_expr'_GlobalVar ~super global_ident = - match global_ident with - | `Concrete concrete -> - let concrete = - self#_do_not_override_lazy_of_concrete_ident - AstPos_expr'_GlobalVar_x0 concrete - in - self#expr'_GlobalVar_concrete ~super concrete - | `Primitive primitive -> - self#expr'_GlobalVar_primitive ~super primitive - | _ -> - self#assertion_failure - @@ "GlobalVar: expected a concrete or primitive global ident, got:" - ^ [%show: global_ident] global_ident - - method module_path_separator = "::" - (** [module_path_separator] is the default separator for - paths. `::` by default *) - - method concrete_ident ~local id : document = - string - (if local then id.definition - else - String.concat ~sep:self#module_path_separator - (id.crate :: (id.path @ [ id.definition ]))) - (** [concrete_ident ~local id] prints a name without path if - [local] is true, otherwise it prints the full path, separated by - `module_path_separator`. *) - - method pat'_POr ~super:_ ~subpats = - List.map ~f:(fun subpat -> subpat#p) subpats - |> separate (break 1 ^^ char '|' ^^ space) - - method quote (quote : quote) : document = - List.map - ~f:(function - | `Verbatim code -> string code - | `Expr e -> self#print_expr AstPosition_Quote e - | `Pat p -> self#print_pat AstPosition_Quote p - | `Typ p -> self#print_ty AstPosition_Quote p) - quote.contents - |> concat - method _do_not_override_lazy_of_quote ast_position (value : quote) : quote lazy_doc = lazy_doc (fun (value : quote) -> self#quote value) ast_position value @@ -615,5 +633,7 @@ module Make (F : Features.T) = struct ast_position value, params, constraints ) + + (**/**) end end diff --git a/engine/profile.dump b/engine/profile.dump deleted file mode 100644 index e69de29bb..000000000 From 90058bf1547fb8bb34b06f6b2b4e1e680b313d36 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Mon, 21 Oct 2024 15:39:13 +0200 Subject: [PATCH 072/253] [PV] Remove `Process` and `Toplevel` modules --- engine/backends/proverif/proverif_backend.ml | 36 ++------------------ 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index f66a1ea14..86a9a301e 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -129,14 +129,6 @@ module type MAKE = sig module Letfuns : sig val print : item list -> string end - - module Processes : sig - val print : item list -> string - end - - module Toplevel : sig - val print : item list -> string - end end module Make (Options : OPTS) : MAKE = struct @@ -811,7 +803,8 @@ module Make (Options : OPTS) : MAKE = struct letfun bitstring_err() = let x = construct_fail() in \ bitstring_default().\n\n\ letfun nat_default() = 0.\n\ - fun nat_to_bitstring(nat): bitstring.\n\n\ + fun nat_to_bitstring(nat): bitstring.\n\ + letfun nat_err() = let x = construct_fail() in nat_default().\n\n\ letfun bool_default() = false.\n" let contents items = "" @@ -845,24 +838,6 @@ module Make (Options : OPTS) : MAKE = struct in pure_letfuns_print ^ process_letfuns_print end) - - module Processes = MkSubprinter (struct - let banner = "Processes" - let preamble items = "" - let process_filter item = [%matches? Fn _] item.v && is_process item - - let contents items = - let contents, _ = - Print.items NoAuxInfo (List.filter ~f:process_filter items) - in - contents - end) - - module Toplevel = MkSubprinter (struct - let banner = "Top-level process" - let preamble items = "process\n 0\n" - let contents items = "" - end) end let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) @@ -874,14 +849,9 @@ let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) in let lib_contents = M.Preamble.print items ^ M.DataTypes.print items ^ M.Letfuns.print items - ^ M.Processes.print items in - let analysis_contents = M.Toplevel.print items in let lib_file = Types.{ path = "lib.pvl"; contents = lib_contents } in - let analysis_file = - Types.{ path = "analysis.pv"; contents = analysis_contents } - in - [ lib_file; analysis_file ] + [ lib_file; ] open Phase_utils module DepGraph = Dependencies.Make (InputLanguage) From 331f81d2ecd0383b59e372c9d56bdf916da763ef Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Mon, 21 Oct 2024 15:56:48 +0200 Subject: [PATCH 073/253] Minimal PV extraction example --- examples/Cargo.lock | 35 ++++++++++-- examples/Cargo.toml | 1 + examples/minimal-proverif/Cargo.toml | 8 +++ examples/minimal-proverif/Readme.md | 55 +++++++++++++++++++ .../proofs/proverif/extraction/analysis.pv | 33 +++++++++++ examples/minimal-proverif/src/lib.rs | 24 ++++++++ 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 examples/minimal-proverif/Cargo.toml create mode 100644 examples/minimal-proverif/Readme.md create mode 100644 examples/minimal-proverif/proofs/proverif/extraction/analysis.pv create mode 100644 examples/minimal-proverif/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 61ed48fed..0a3c94c9a 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -181,6 +181,16 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "either" version = "1.9.0" @@ -222,14 +232,16 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hax-bounded-integers" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ + "duplicate", "hax-lib", + "paste", ] [[package]] name = "hax-lib" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros", "num-bigint", @@ -238,9 +250,10 @@ dependencies = [ [[package]] name = "hax-lib-macros" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros-types", + "paste", "proc-macro-error", "proc-macro2", "quote", @@ -249,7 +262,7 @@ dependencies = [ [[package]] name = "hax-lib-macros-types" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "proc-macro2", "quote", @@ -258,6 +271,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex" version = "0.4.3" @@ -370,6 +389,10 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "minimal-proverif" +version = "0.1.0" + [[package]] name = "num-bigint" version = "0.4.4" @@ -430,9 +453,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pretty" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7df1c9ab7..f17f8f6d4 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,6 +5,7 @@ members = [ "sha256", "barrett", "kyber_compress", + "minimal-proverif" ] resolver = "2" diff --git a/examples/minimal-proverif/Cargo.toml b/examples/minimal-proverif/Cargo.toml new file mode 100644 index 000000000..69263bbde --- /dev/null +++ b/examples/minimal-proverif/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "minimal-proverif" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/examples/minimal-proverif/Readme.md b/examples/minimal-proverif/Readme.md new file mode 100644 index 000000000..0907ebbfc --- /dev/null +++ b/examples/minimal-proverif/Readme.md @@ -0,0 +1,55 @@ +# A minimal hax ProVerif example + +This crate demonstrates a minimal example of ProVerif extraction using hax. + +The crate provides functions for implementing a simplistic protocol +between an initiator and receiver, which is defined as follows: +``` +Initiator(payload: u8): let message = Ping(payload) + +Initiator -> Responder: message + +Responder: If message was Ping(payload), + let response = Pong(payload) + else abort + +Responder -> Initiator: response + +Initiator: If response was Pong(payload), + return payload + else abort +``` + +The crate does not implement message transport, only the initiator and responder protocol logic. + +## Extracting into ProVerif +To obtain a ProVerif model of the protocol logic functions, run +``` +cargo hax into pro-verif +``` +This will generate a file `./proofs/proverif/extraction/lib.pvl`. + +## Running a Basic Analysis on the Model +We have provided a handwritten file +`./proofs/proverif/extraction/analysis.pv`, which models the protocol +using the extracted functions in `lib.pvl` and uses ProVerif to verify +that initiator and receiver can both complete the protocol. + +To let ProVerif perform the analysis, from the crate root, run: + +``` +proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv +``` + +The expected final output is +``` +-------------------------------------------------------------- +Verification summary: + +Query not event(Reach_end_Initiator) is false. + +Query not event(Reach_end_Responder) is false. + +-------------------------------------------------------------- +``` + diff --git a/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv b/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv new file mode 100644 index 000000000..dad4b3d45 --- /dev/null +++ b/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv @@ -0,0 +1,33 @@ +(*****************************************) +(* Top-level process *) +(*****************************************) + +event Reach_end_Initiator. +event Reach_end_Responder. + +query event(Reach_end_Initiator). +query event(Reach_end_Responder). + +let Initiator(payload: nat) = + let ping_message = minimal_proverif__send_ping(payload) in + out(c, ping_message); + + in(c, pong_message: minimal_proverif__t_Message ); + let received_payload = accessor_minimal_proverif__Message__Pong_0(pong_message) in + event Reach_end_Initiator; + 0. + +let Responder() = + in(c, ping_message: minimal_proverif__t_Message ); + let minimal_proverif__Message_Message_Ping_c(received_payload) = ping_message in + let pong_message = minimal_proverif__Message_Message_Pong_c(received_payload) in + out(c, pong_message); + event Reach_end_Responder; + 0. + +process + in(c, payload: nat); + + Initiator(payload) | Responder() + + diff --git a/examples/minimal-proverif/src/lib.rs b/examples/minimal-proverif/src/lib.rs new file mode 100644 index 000000000..bdc8032dd --- /dev/null +++ b/examples/minimal-proverif/src/lib.rs @@ -0,0 +1,24 @@ +pub enum Message { + Ping(u8), + Pong(u8), +} + + +pub fn send_ping(input: u8) -> Message { + Message::Ping(input) +} + +pub fn receive_ping(message: Message) -> Result { + match message { + Message::Ping(payload) => Ok(Message::Pong(payload)), + _ => Err(()) + } +} + +pub fn receive_pong(message: Message) -> Result { + match message { + Message::Pong(payload) => Ok(payload), + _ => Err(()) + } +} + From 5d72ac69112c0738cf55a102b2d85c3f3eecff40 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Mon, 21 Oct 2024 16:09:34 +0200 Subject: [PATCH 074/253] Formatting --- engine/backends/proverif/proverif_backend.ml | 2 +- examples/minimal-proverif/src/lib.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 86a9a301e..15e971713 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -851,7 +851,7 @@ let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) M.Preamble.print items ^ M.DataTypes.print items ^ M.Letfuns.print items in let lib_file = Types.{ path = "lib.pvl"; contents = lib_contents } in - [ lib_file; ] + [ lib_file ] open Phase_utils module DepGraph = Dependencies.Make (InputLanguage) diff --git a/examples/minimal-proverif/src/lib.rs b/examples/minimal-proverif/src/lib.rs index bdc8032dd..0924433de 100644 --- a/examples/minimal-proverif/src/lib.rs +++ b/examples/minimal-proverif/src/lib.rs @@ -3,7 +3,6 @@ pub enum Message { Pong(u8), } - pub fn send_ping(input: u8) -> Message { Message::Ping(input) } @@ -11,14 +10,13 @@ pub fn send_ping(input: u8) -> Message { pub fn receive_ping(message: Message) -> Result { match message { Message::Ping(payload) => Ok(Message::Pong(payload)), - _ => Err(()) + _ => Err(()), } } pub fn receive_pong(message: Message) -> Result { match message { Message::Pong(payload) => Ok(payload), - _ => Err(()) + _ => Err(()), } } - From 239cf75f87092b6e891cb498e2c85908ab2cc975 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 17 Oct 2024 10:53:48 +0200 Subject: [PATCH 075/253] Modification for loops control flow. --- engine/backends/fstar/fstar_backend.ml | 3 +- engine/lib/ast.ml | 9 ++- engine/lib/ast_utils.ml | 79 +++++++++++++++---- engine/lib/diagnostics.ml | 2 + engine/lib/import_thir.ml | 4 +- .../phase_drop_return_break_continue.ml | 59 ++++++++++---- .../lib/phases/phase_functionalize_loops.ml | 38 +++++++-- engine/lib/phases/phase_local_mutation.ml | 23 ++++-- engine/lib/phases/phase_reject.ml | 39 +++++++++ .../lib/phases/phase_rewrite_control_flow.ml | 46 ++++++++--- engine/lib/print_rust.ml | 4 +- engine/lib/side_effect_utils.ml | 9 ++- engine/lib/subtype.ml | 7 +- .../Rust_primitives.Hax.Folds.fsti | 32 +++++++- .../fstar/rust_primitives/Rust_primitives.fst | 16 ---- 15 files changed, 284 insertions(+), 86 deletions(-) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 3e97e4d73..2ac2ab8e0 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1742,8 +1742,9 @@ module TransformToInputLanguage = |> Phases.Rewrite_control_flow |> Phases.Drop_return_break_continue |> Phases.Reject.Continue - |> Phases.Cf_into_monads |> Phases.Reject.EarlyExit + |> Phases.Reject.QuestionMark + |> Phases.Reject.Break |> Phases.Functionalize_loops |> Phases.Reject.As_pattern |> Phases.Traits_specs diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 604a76ec5..1bacf1e32 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -267,14 +267,19 @@ functor witness : F.loop; } (* ControlFlow *) - | Break of { e : expr; label : string option; witness : F.break * F.loop } + | Break of { + e : expr; + acc : (F.state_passing_loop * expr) option; + label : string option; + witness : F.break * F.loop; + } | Return of { e : expr; witness : F.early_exit } | QuestionMark of { e : expr; return_typ : ty; witness : F.question_mark } (** The expression `e?`. In opposition to Rust, no implicit coercion is applied on the (potential) error payload of `e`. Coercion should be made explicit within `e`. *) | Continue of { - e : (F.state_passing_loop * expr) option; + acc : (F.state_passing_loop * expr) option; label : string option; witness : F.continue * F.loop; } diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 41da6fa93..4f4f81490 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -922,6 +922,24 @@ module Make (F : Features.T) = struct let e = Closure { params; body; captures = [] } in { e; typ = TArrow (List.map ~f:(fun p -> p.typ) params, body.typ); span } + let make_control_flow_type ~(continue_type : ty) ~(break_type : ty) : ty = + TApp + { + ident = Global_ident.of_name Type Core__ops__control_flow__ControlFlow; + args = [ GType break_type; GType continue_type ]; + } + + let make_cf_return_type ~(acc_type : ty) ~(break_type : ty) + ~(return_type : ty option) : ty = + let break_type = make_tuple_typ [ break_type; acc_type ] in + match return_type with + | Some ret_ty -> + let break_type = + make_control_flow_type ~break_type:ret_ty ~continue_type:break_type + in + make_control_flow_type ~break_type ~continue_type:acc_type + | None -> make_control_flow_type ~break_type ~continue_type:acc_type + let make_control_flow_pat ~(span : span) ~(typ : ty) (cf : [ `Break | `Continue ]) (pat : pat) = match cf with @@ -947,7 +965,6 @@ module Make (F : Features.T) = struct is_struct = false; }; typ; - (* Wrong *) span; } | `Continue -> @@ -972,12 +989,13 @@ module Make (F : Features.T) = struct is_struct = false; }; typ; - (* Wrong *) span; } - let make_control_flow_expr' ~(span : span) ~(typ : ty) - (cf : [ `Break | `Continue ]) (e : expr) = + let make_control_flow_expr' ~(span : span) ~(break_type : ty) + ?(continue_type : ty = unit_typ) (cf : [ `Break | `Continue ]) (e : expr) + = + let typ = make_control_flow_type ~continue_type ~break_type in match cf with | `Break -> call_Constructor Core__ops__control_flow__ControlFlow__Break false [ e ] @@ -986,20 +1004,49 @@ module Make (F : Features.T) = struct call_Constructor Core__ops__control_flow__ControlFlow__Continue false [ e ] span typ - let make_control_flow_expr ~(span : span) ~(typ : ty) ~(has_return : bool) - (cf : [ `Return | `Break | `Continue ]) (e : expr) = + (* We use the following encoding of return, break and continue in the `ControlFlow` enum: + Return e -> Break (Break e) + Break e -> Break ((Continue(e, acc))) + Continue -> Continue(acc) + + In case there is no return we simplify to: + Break e -> (Break (e, acc)) + Continue -> (continue (acc)) + *) + let make_control_flow_expr ~(span : span) ~(break_type : ty) + ~(return_type : ty option) ~(acc : expr) ?(e : expr = unit_expr span) + (cf : [ `Return | `Break | `Continue ]) = match cf with | `Return -> - make_control_flow_expr' ~span ~typ `Break - (make_control_flow_expr' ~span ~typ `Break e) - | `Break when has_return -> - make_control_flow_expr' ~span ~typ `Break - (make_control_flow_expr' ~span ~typ `Continue e) - | `Break -> make_control_flow_expr' ~span ~typ `Break e - | `Continue when has_return -> - make_control_flow_expr' ~span ~typ `Continue - (make_control_flow_expr' ~span ~typ `Continue e) - | `Continue -> make_control_flow_expr' ~span ~typ `Continue e + let continue_type = make_tuple_typ [ break_type; acc.typ ] in + let inner = + make_control_flow_expr' ~break_type:e.typ ~continue_type ~span `Break + e + in + make_control_flow_expr' ~span ~break_type:inner.typ + ~continue_type:acc.typ `Break inner + | `Break -> + let tuple = make_tuple_expr ~span [ e; acc ] in + let inner = + match return_type with + | Some ret_typ -> + make_control_flow_expr' ~span ~break_type:ret_typ + ~continue_type:tuple.typ `Continue tuple + | None -> tuple + in + make_control_flow_expr' ~span ~break_type:inner.typ + ~continue_type:acc.typ `Break inner + | `Continue -> + let break_type = + let tuple_type = make_tuple_typ [ break_type; acc.typ ] in + match return_type with + | Some ret_typ -> + make_control_flow_type ~break_type:ret_typ + ~continue_type:tuple_type + | None -> tuple_type + in + make_control_flow_expr' ~span ~break_type ~continue_type:acc.typ + `Continue acc let string_lit span (s : string) : expr = { span; typ = TStr; e = Literal (String s) } diff --git a/engine/lib/diagnostics.ml b/engine/lib/diagnostics.ml index b04bd5868..590b0aabe 100644 --- a/engine/lib/diagnostics.ml +++ b/engine/lib/diagnostics.ml @@ -12,6 +12,8 @@ module Phase = struct | NotInBackendLang of Backend.t | ArbitraryLhs | Continue + | Break + | QuestionMark | RawOrMutPointer | EarlyExit | AsPattern diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 5b5e5e6dd..d940972c7 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -655,9 +655,9 @@ end) : EXPR = struct (* TODO: labels! *) let e = Option.map ~f:c_expr value in let e = Option.value ~default:(unit_expr span) e in - Break { e; label = None; witness = (W.break, W.loop) } + Break { e; acc = None; label = None; witness = (W.break, W.loop) } | Continue _ -> - Continue { e = None; label = None; witness = (W.continue, W.loop) } + Continue { acc = None; label = None; witness = (W.continue, W.loop) } | Return { value } -> let e = Option.map ~f:c_expr value in let e = Option.value ~default:(unit_expr span) e in diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index c36143eaf..7b3194605 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -1,3 +1,10 @@ +(* This phase removes `return`s in exit position. Inside loops, + it replaces `return`, `break` and `continue` (in exit position) + by their encoding in the `ControlFlow` enum. It replaces another + expression in exit position by an equivalent `continue`. + This phase should comae after `RewriteControlFlow` to ensure all + control flow is in exit position. *) + open! Prelude module Make (F : Features.T) = @@ -14,21 +21,37 @@ module Make (F : Features.T) = let ctx = Diagnostics.Context.Phase phase_id end) + type loop_info = { return_type : ty option; break_type : ty } + let has_return = object (_self) inherit [_] Visitors.reduce as super - method zero = false - method plus = ( || ) + method zero = { return_type = None; break_type = U.unit_typ } + + method plus li1 li2 = + { + return_type = + (match (li1.return_type, li2.return_type) with + | Some t, _ | _, Some t -> Some t + | _ -> None); + break_type = + (if [%eq: ty] li1.break_type U.unit_typ then li2.break_type + else li1.break_type); + } method! visit_expr' () e = - match e with Return _ -> true | _ -> super#visit_expr' () e + match e with + | Return { e; _ } -> + { return_type = Some e.typ; break_type = U.unit_typ } + | Break { e; _ } -> { return_type = None; break_type = e.typ } + | _ -> super#visit_expr' () e end let visitor = object (self) inherit [_] Visitors.map as _super - method! visit_expr (in_loop : bool option) e = + method! visit_expr (in_loop : (loop_info * ty) option) e = match (e, in_loop) with | { e = Return { e; _ }; _ }, None -> e (* we know [e] is on an exit position: the return is @@ -45,15 +68,21 @@ module Make (F : Features.T) = let then_ = self#visit_expr in_loop then_ in let else_ = Option.map ~f:(self#visit_expr in_loop) else_ in { e with e = If { cond; then_; else_ } } - | { e = Return { e; _ }; span; typ }, Some has_return -> - U.make_control_flow_expr ~has_return ~span ~typ `Return e - | { e = Break { e; _ }; span; typ }, Some has_return -> - U.make_control_flow_expr ~has_return ~span ~typ `Break e - | ( { e = Continue { e = Some (_, e); _ }; span; typ }, - Some has_return ) -> - U.make_control_flow_expr ~has_return ~span ~typ `Continue e - | { span; typ; _ }, Some has_return -> - U.make_control_flow_expr ~has_return ~span ~typ `Continue e + | ( { e = Return { e; _ }; span; _ }, + Some ({ return_type; break_type }, acc_type) ) -> + U.make_control_flow_expr ~return_type ~span ~break_type ~e + ~acc:{ e with typ = acc_type } `Return + | ( { e = Break { e; acc = Some (_, acc); _ }; span; _ }, + Some ({ return_type; break_type }, _) ) -> + U.make_control_flow_expr ~return_type ~span ~break_type ~e ~acc + `Break + | ( { e = Continue { acc = Some (_, acc); _ }; span; _ }, + Some ({ return_type; break_type }, _) ) -> + U.make_control_flow_expr ~return_type ~span ~break_type ~acc + `Continue + | { span; _ }, Some ({ return_type; break_type }, _) -> + U.make_control_flow_expr ~return_type ~span ~break_type ~acc:e + `Continue | _ -> e (** The invariant here is that [visit_expr] is called only on expressions that are on exit positions. [visit_expr] @@ -71,7 +100,9 @@ module Make (F : Features.T) = match e.e with | Loop ({ body; control_flow; _ } as loop) when control_flow -> let body = - visitor#visit_expr (Some (has_return#visit_expr () body)) body + visitor#visit_expr + (Some (has_return#visit_expr () body, e.typ)) + body in super#visit_expr () { e with e = Loop { loop with body } } | _ -> super#visit_expr () e diff --git a/engine/lib/phases/phase_functionalize_loops.ml b/engine/lib/phases/phase_functionalize_loops.ml index 9458cb1e7..3af6eadf6 100644 --- a/engine/lib/phases/phase_functionalize_loops.ml +++ b/engine/lib/phases/phase_functionalize_loops.ml @@ -192,17 +192,30 @@ struct { body; kind = ForLoop { it; pat; has_return; _ }; - state = Some { init; bpat; _ }; + state = Some _ as state; + control_flow; + _; + } + | Loop + { + body; + kind = ForLoop { it; pat; has_return = true as has_return; _ }; + state; control_flow; _; } -> + let bpat, init = + match state with + | Some { bpat; init; _ } -> (dpat bpat, dexpr init) + | None -> + let unit = UB.unit_expr span in + (M.pat_PWild ~span ~typ:unit.typ, unit) + in let body = dexpr body in let { body; invariant } = extract_loop_invariant body in let it = dexpr it in let pat = dpat pat in - let bpat = dpat bpat in let fn : B.expr = UB.make_closure [ bpat; pat ] body body.span in - let init = dexpr init in let f, kind, args = match as_iterator it @@ -232,14 +245,27 @@ struct { body; kind = WhileLoop { condition; has_return; _ }; - state = Some { init; bpat; _ }; + state = Some _ as state; + control_flow; + _; + } + | Loop + { + body; + kind = WhileLoop { condition; has_return = true as has_return; _ }; + state; control_flow; _; } -> + let bpat, init = + match state with + | Some { bpat; init; _ } -> (dpat bpat, dexpr init) + | None -> + let unit = UB.unit_expr span in + (M.pat_PWild ~span ~typ:unit.typ, unit) + in let body = dexpr body in let condition = dexpr condition in - let bpat = dpat bpat in - let init = dexpr init in let condition : B.expr = M.expr_Closure ~params:[ bpat ] ~body:condition ~captures:[] ~span:condition.span diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index a1913bfdd..7a36f2155 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -238,15 +238,24 @@ struct in { e = Match { scrutinee; arms }; typ; span = expr.span } | Break { e; label; witness; _ } -> - let e = UB.make_tuple_expr ~span [ dexpr_same e; local_vars_expr ] in - { e = Break { e; label; witness }; span = expr.span; typ = e.typ } - | Continue { e = None; label; witness; _ } -> let w = Features.On.state_passing_loop in - let e = - UB.make_tuple_expr ~span [ UB.unit_expr expr.span; local_vars_expr ] - in { - e = Continue { e = Some (w, e); label; witness }; + e = + Break + { + e = dexpr_same e; + acc = Some (w, local_vars_expr); + label; + witness; + }; + span = expr.span; + typ = local_vars_expr.typ; + } + | Continue { acc = None; label; witness; _ } -> + let w = Features.On.state_passing_loop in + let e = local_vars_expr in + { + e = Continue { acc = Some (w, e); label; witness }; span = expr.span; typ = e.typ; } diff --git a/engine/lib/phases/phase_reject.ml b/engine/lib/phases/phase_reject.ml index 484dda0b3..434fb02cd 100644 --- a/engine/lib/phases/phase_reject.ml +++ b/engine/lib/phases/phase_reject.ml @@ -41,6 +41,45 @@ end module _ (FA : Features.T) : Phase_utils.PHASE = Continue (FA) +module Break (FA : Features.T) = struct + module FB = struct + include FA + include Features.Off.Break + end + + include + Feature_gate.Make (FA) (FB) + (struct + module A = FA + module B = FB + include Feature_gate.DefaultSubtype + + let break = reject + let metadata = make_metadata Break + end) +end + +module QuestionMark (FA : Features.T) = struct + module FB = struct + include FA + include Features.Off.Question_mark + end + + include + Feature_gate.Make (FA) (FB) + (struct + module A = FA + module B = FB + include Feature_gate.DefaultSubtype + + let question_mark = reject + let metadata = make_metadata QuestionMark + end) +end + +module _ (FA : Features.T) : Phase_utils.PHASE = Continue (FA) +module _ (FA : Features.T) : Phase_utils.PHASE = Break (FA) + module RawOrMutPointer (FA : Features.T) = struct module FB = struct include FA diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index a68e30874..953c3cdfe 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -1,6 +1,6 @@ (* This phase rewrites: `if c {return a}; b` as `if c {return a; b} else {b}` and does the equivalent transformation for pattern matchings. - It rewrites the body of loops considereing `break` and `continue` + It rewrites the body of loops considering `break` and `continue` as `return` to place them in return position. If a loop contains a `return` it places it is rewritten inside a pattern matching over the result. *) @@ -34,6 +34,18 @@ module Make (F : Features.T) = | _ -> super#visit_expr' in_loop e end + let loop_return_type = + object (_self) + inherit [_] Visitors.reduce as super + method zero = U.unit_typ + method plus l r = if [%eq: ty] l U.unit_typ then r else l + + method! visit_expr' () e = + match e with + | Return { e; _ } -> e.typ + | _ -> super#visit_expr' () e + end + let loop_has_cf = object (_self) inherit [_] Visitors.reduce as super @@ -53,10 +65,27 @@ module Make (F : Features.T) = method! visit_expr in_loop e = let loop_with_return (loop : expr) stmts_after final pat = - let typ = loop.typ in + let loop = + match loop.e with + | Loop ({ kind; _ } as loop_info) -> + let kind = + match kind with + | ForLoop for_loop -> + ForLoop { for_loop with has_return = true } + | WhileLoop while_loop -> + WhileLoop { while_loop with has_return = true } + | _ -> kind + in + { loop with e = Loop { loop_info with kind } } + | _ -> loop + in + let return_type = loop_return_type#visit_expr () loop in + + let typ = + U.make_control_flow_type ~continue_type:loop.typ + ~break_type:return_type + in let span = loop.span in - (* wrong, we would need to propagate the return type (either by looking at the - return statements (and the type of the expression they contain) or at the return type of the function) *) let id = U.fresh_local_ident_in [] "ret" in let module MS = (val U.M.make span) in let mk_cf_pat = U.make_control_flow_pat ~span ~typ in @@ -64,13 +93,12 @@ module Make (F : Features.T) = [ MS.arm (mk_cf_pat `Break (U.make_var_pat id typ span)) - (MS.expr_LocalVar ~typ id); - MS.arm - (MS.pat_POr ~subpats:[ mk_cf_pat `Continue pat ] ~typ) - (U.make_lets stmts_after final); + (MS.expr_LocalVar ~typ:return_type id); + MS.arm (mk_cf_pat `Continue pat) + (U.make_lets stmts_after final |> self#visit_expr in_loop); ] in - MS.expr_Match ~scrutinee:loop ~arms ~typ + MS.expr_Match ~scrutinee:loop ~arms ~typ:return_type in match e.e with (* This is supposed to improve performance but it might actually make it worse in some cases *) diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index bea5c641a..f00dcf2ff 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -343,8 +343,8 @@ module Raw = struct | Some { init; _ } -> !"(" & main & !")(" & pexpr init & !")" | None -> main) | Break { e; _ } -> !"(break (" & pexpr e & !"))" - | Continue { e = None; _ } -> !"continue" - | Continue { e = Some (_, e); _ } -> + | Continue { acc = None; _ } -> !"continue" + | Continue { acc = Some (_, e); _ } -> !"state_passing_continue!(" & pexpr e & !")" | Return { e; _ } -> !"(return " & pexpr e & !")" | QuestionMark { e; _ } -> !"(" & pexpr e & !")?" diff --git a/engine/lib/side_effect_utils.ml b/engine/lib/side_effect_utils.ml index 1b470019b..3fb874fe2 100644 --- a/engine/lib/side_effect_utils.ml +++ b/engine/lib/side_effect_utils.ml @@ -261,12 +261,12 @@ struct ( { e with e = Return { e = e'; witness } }, m#plus effects (no_lbs { SideEffects.zero with return = Some e'.typ }) )) - | Break { e = e'; label; witness } -> + | Break { e = e'; label; acc; witness } -> HoistSeq.one env (self#visit_expr env e') (fun e' effects -> - ( { e with e = Break { e = e'; label; witness } }, + ( { e with e = Break { e = e'; acc; label; witness } }, m#plus effects (no_lbs { SideEffects.zero with break = Some e'.typ }) )) - | Continue { e = e'; label; witness } -> ( + | Continue { acc = e'; label; witness } -> ( let ceffect = no_lbs { @@ -280,7 +280,8 @@ struct ( { e with e = - Continue { e = Some (witness', e'); label; witness }; + Continue + { acc = Some (witness', e'); label; witness }; }, m#plus ceffect effects )) | None -> (e, ceffect)) diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index 3acf61b32..6698e045e 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -246,10 +246,11 @@ struct control_flow; witness = S.loop span witness; } - | Break { e; label; witness } -> + | Break { e; acc; label; witness } -> Break { e = dexpr e; + acc = Option.map ~f:(S.state_passing_loop span *** dexpr) acc; label; witness = (S.break span *** S.loop span) witness; } @@ -262,10 +263,10 @@ struct return_typ = dty span return_typ; witness = S.question_mark span witness; } - | Continue { e; label; witness = w1, w2 } -> + | Continue { acc; label; witness = w1, w2 } -> Continue { - e = Option.map ~f:(S.state_passing_loop span *** dexpr) e; + acc = Option.map ~f:(S.state_passing_loop span *** dexpr) acc; label; witness = (S.continue span w1, S.loop span w2); } diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti index 030d08383..243da67d4 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti @@ -115,13 +115,37 @@ let rec fold_range_cf (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) (acc: acc_t {inv acc start}) (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) /\ inv acc i} - -> tuple:((Core.Ops.Control_flow.t_ControlFlow unit unit) & acc_t) - {let cf, acc = tuple in inv acc (mk_int (v i + 1))})) + -> tuple:((Core.Ops.Control_flow.t_ControlFlow (unit & acc_t) acc_t)) + { + let acc = match tuple with + | Core.Ops.Control_flow.ControlFlow_Break ((), acc) + | Core.Ops.Control_flow.ControlFlow_Continue acc -> acc in + inv acc (mk_int (v i + 1))})) : Tot acc_t (decreases v end_ - v start) = if v start < v end_ then match f acc start with - | Core.Ops.Control_flow.ControlFlow_Break (), acc -> acc - | Core.Ops.Control_flow.ControlFlow_Continue (), acc -> + | Core.Ops.Control_flow.ControlFlow_Break ((), acc) -> acc + | Core.Ops.Control_flow.ControlFlow_Continue acc -> fold_range_cf (start +! mk_int 1) end_ inv acc f else acc + +let rec fold_range_return + (#acc_t: Type0) (#ret_t: Type0) (#u: Lib.IntTypes.inttype) + (start: int_t u) + (end_: int_t u) + (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) + (acc: acc_t {inv acc start}) + (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) /\ inv acc i} + -> tuple:((Core.Ops.Control_flow.t_ControlFlow (Core.Ops.Control_flow.t_ControlFlow ret_t (unit & acc_t))) acc_t) + )) +: Tot (Core.Ops.Control_flow.t_ControlFlow ret_t acc_t) (decreases v end_ - v start) + = + if v start < v end_ + then match f acc start with + | Core.Ops.Control_flow.ControlFlow_Break (Core.Ops.Control_flow.ControlFlow_Break res)-> Core.Ops.Control_flow.ControlFlow_Break res + + | Core.Ops.Control_flow.ControlFlow_Break (Core.Ops.Control_flow.ControlFlow_Continue ((), res)) -> Core.Ops.Control_flow.ControlFlow_Continue res + | Core.Ops.Control_flow.ControlFlow_Continue acc -> + fold_range_return (start +! mk_int 1) end_ inv acc f + else Core.Ops.Control_flow.ControlFlow_Continue acc diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.fst b/proof-libs/fstar/rust_primitives/Rust_primitives.fst index a50c66510..d80eabfde 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.fst +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.fst @@ -46,23 +46,7 @@ instance array_to_slice_unsize t n: unsize_tc (t_Array t n) = { arr <: t_Slice t); } -(* -type t_ControlFlow (b c: Type) = - | ControlFlow_Continue of c - | ControlFlow_Break of b -*) - let rec f_while_loop #s (condition: s -> bool) (init: s) (f: (i:s -> o:s{o << i})): s = if condition init then f_while_loop #s condition (f init) f else init - -(* let f_while_loop_cf #s #t (condition: s -> bool) (init: s) (f: (i:s -> Core.Ops.Control_flow.t_ControlFlow t s)): s - = - let rec f_while_loop_inner (init: Core.Ops.Control_flow.t_ControlFlow t s) = - match init with - | Core.Ops.Control_flow.ControlFlow_Continue v -> if condition v then f_while_loop_inner (f v) else v - | Core.Ops.Control_flow.ControlFlow_Break _ -> init - if condition init - then f_while_loop #s condition (f init) f - else init *) From 7f9e6c9afd1633f51a192b12148eeaec41e7b2c3 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 21 Oct 2024 17:28:00 +0200 Subject: [PATCH 076/253] Fix wrong type after dropping returns. --- .../phases/phase_drop_return_break_continue.ml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index 7b3194605..a8ef7d48a 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -58,16 +58,25 @@ module Make (F : Features.T) = thus useless, we can skip it *) | { e = Let { monadic = None; lhs; rhs; body }; _ }, _ -> let body = self#visit_expr in_loop body in - { e with e = Let { monadic = None; lhs; rhs; body } } + { + e with + e = Let { monadic = None; lhs; rhs; body }; + typ = body.typ; + } (* If a let expression is an exit node, then it's body is as well *) | { e = Match { scrutinee; arms }; _ }, _ -> let arms = List.map ~f:(self#visit_arm in_loop) arms in - { e with e = Match { scrutinee; arms } } + let typ = + match arms with + | { arm; _ } :: _ -> arm.body.typ + | [] -> e.typ + in + { e with e = Match { scrutinee; arms }; typ } | { e = If { cond; then_; else_ }; _ }, _ -> let then_ = self#visit_expr in_loop then_ in let else_ = Option.map ~f:(self#visit_expr in_loop) else_ in - { e with e = If { cond; then_; else_ } } + { e with e = If { cond; then_; else_ }; typ = then_.typ } | ( { e = Return { e; _ }; span; _ }, Some ({ return_type; break_type }, acc_type) ) -> U.make_control_flow_expr ~return_type ~span ~break_type ~e From cf5ba079f73edf01ba75437b0ccd89911d4fc7ca Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 22 Oct 2024 09:29:01 +0200 Subject: [PATCH 077/253] fix(engine/import_thir): never drop bodies of constants --- engine/lib/import_thir.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 0dea69dbb..b48c37ba6 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -1462,7 +1462,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = name = Concrete_ident.of_def_id Value (Option.value_exn item.def_id); generics = c_generics generics; - body = c_body body; + body = c_expr body; params = []; safety = Safe; } From 782b9f227093ebf196e6ac9e737a06711ba613c1 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 22 Oct 2024 09:15:26 +0200 Subject: [PATCH 078/253] Tests for return/break/continue in loops. --- .../lib/phases/phase_rewrite_control_flow.ml | 4 + .../toolchain__loops into-fstar.snap | 195 ++++++++++++++++++ ..._mut-ref-functionalization into-fstar.snap | 2 +- .../toolchain__side-effects into-fstar.snap | 21 +- tests/loops/src/lib.rs | 77 +++++++ 5 files changed, 284 insertions(+), 15 deletions(-) diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 953c3cdfe..97602ba5a 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -142,6 +142,10 @@ module Make (F : Features.T) = (* This avoids adding `let _ = ()` *) | { p = PWild; _ }, { e = GlobalVar (`TupleCons 0); _ } -> stmts_after + (* This avoids adding `let x = x` *) + | { p = PBinding { var; _ }; _ }, { e = LocalVar evar; _ } + when Local_ident.equal var evar -> + stmts_after | stmt -> stmt :: stmts_after in U.make_lets (branch_stmts @ stmts_to_add) final diff --git a/test-harness/src/snapshots/toolchain__loops into-fstar.snap b/test-harness/src/snapshots/toolchain__loops into-fstar.snap index 695f8bf5b..d101e88f8 100644 --- a/test-harness/src/snapshots/toolchain__loops into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__loops into-fstar.snap @@ -27,6 +27,201 @@ stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' diagnostics = [] [stdout.files] +"Loops.Control_flow.fst" = ''' +module Loops.Control_flow +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_M = { f_m:Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global } + +let impl__M__decoded_message (self: t_M) + : Core.Option.t_Option (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = + match + Rust_primitives.Hax.Folds.fold_range_return (sz 0) + (Alloc.Vec.impl_1__len #u8 #Alloc.Alloc.t_Global self.f_m <: usize) + (fun temp_0_ temp_1_ -> + let _:Prims.unit = temp_0_ in + let _:usize = temp_1_ in + true) + () + (fun temp_0_ i -> + let _:Prims.unit = temp_0_ in + let i:usize = i in + if i >. sz 5 <: bool + then + Core.Ops.Control_flow.ControlFlow_Break + (Core.Ops.Control_flow.ControlFlow_Break + (Core.Option.Option_None + <: + Core.Option.t_Option (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Option.t_Option (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) + (Prims.unit & Prims.unit)) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow + (Core.Option.t_Option (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) + (Prims.unit & Prims.unit)) Prims.unit + else + Core.Ops.Control_flow.ControlFlow_Continue () + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow + (Core.Option.t_Option (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global)) + (Prims.unit & Prims.unit)) Prims.unit) + with + | Core.Ops.Control_flow.ControlFlow_Break ret -> ret + | Core.Ops.Control_flow.ControlFlow_Continue _ -> + Core.Option.Option_Some + (Core.Clone.f_clone #(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) + #FStar.Tactics.Typeclasses.solve + self.f_m) + <: + Core.Option.t_Option (Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) + +let bigger_power_2_ (x: i32) : i32 = + let pow:i32 = 1l in + Rust_primitives.f_while_loop_cf (fun pow -> + let pow:i32 = pow in + pow <. 1000000l <: bool) + pow + (fun pow -> + let pow:i32 = pow in + let pow:i32 = pow *! 2l in + if pow <. x + then + let pow:i32 = pow *! 3l in + if true + then + Core.Ops.Control_flow.ControlFlow_Break ((), pow <: (Prims.unit & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32 + else + Core.Ops.Control_flow.ControlFlow_Continue (pow *! 2l) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32 + else + Core.Ops.Control_flow.ControlFlow_Continue (pow *! 2l) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32) + +let double_sum (_: Prims.unit) : i32 = + let sum:i32 = 0l in + let sum:i32 = + Rust_primitives.Hax.Folds.fold_range_cf 1l + 10l + (fun sum temp_1_ -> + let sum:i32 = sum in + let _:i32 = temp_1_ in + true) + sum + (fun sum i -> + let sum:i32 = sum in + let i:i32 = i in + if i <. 0l <: bool + then + Core.Ops.Control_flow.ControlFlow_Break ((), sum <: (Prims.unit & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32 + else + Core.Ops.Control_flow.ControlFlow_Continue (sum +! i <: i32) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32) + in + sum *! 2l + +let double_sum2 (_: Prims.unit) : i32 = + let sum:i32 = 0l in + let sum2:i32 = 0l in + let sum, sum2:(i32 & i32) = + Rust_primitives.Hax.Folds.fold_range_cf 1l + 10l + (fun temp_0_ temp_1_ -> + let sum, sum2:(i32 & i32) = temp_0_ in + let _:i32 = temp_1_ in + true) + (sum, sum2 <: (i32 & i32)) + (fun temp_0_ i -> + let sum, sum2:(i32 & i32) = temp_0_ in + let i:i32 = i in + if i <. 0l <: bool + then + Core.Ops.Control_flow.ControlFlow_Break + ((), (sum, sum2 <: (i32 & i32)) <: (Prims.unit & (i32 & i32))) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & (i32 & i32)) (i32 & i32) + else + let sum:i32 = sum +! i in + Core.Ops.Control_flow.ControlFlow_Continue (sum, sum2 +! i <: (i32 & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & (i32 & i32)) (i32 & i32)) + in + sum +! sum2 + +let double_sum2_return (v: t_Slice i32) : i32 = + let sum:i32 = 0l in + let sum2:i32 = 0l in + match + Rust_primitives.Hax.f_fold_return (Core.Iter.Traits.Collect.f_into_iter #(t_Slice i32) + #FStar.Tactics.Typeclasses.solve + v + <: + Core.Slice.Iter.t_Iter i32) + (sum, sum2 <: (i32 & i32)) + (fun temp_0_ i -> + let sum, sum2:(i32 & i32) = temp_0_ in + let i:i32 = i in + if i <. 0l <: bool + then + Core.Ops.Control_flow.ControlFlow_Break + (Core.Ops.Control_flow.ControlFlow_Break 0l + <: + Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & (i32 & i32))) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & (i32 & i32))) (i32 & i32) + else + let sum:i32 = sum +! i in + Core.Ops.Control_flow.ControlFlow_Continue (sum, sum2 +! i <: (i32 & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & (i32 & i32))) (i32 & i32)) + with + | Core.Ops.Control_flow.ControlFlow_Break ret -> ret + | Core.Ops.Control_flow.ControlFlow_Continue (sum, sum2) -> sum +! sum2 + +let double_sum_return (v: t_Slice i32) : i32 = + let sum:i32 = 0l in + match + Rust_primitives.Hax.f_fold_return (Core.Iter.Traits.Collect.f_into_iter #(t_Slice i32) + #FStar.Tactics.Typeclasses.solve + v + <: + Core.Slice.Iter.t_Iter i32) + sum + (fun sum i -> + let sum:i32 = sum in + let i:i32 = i in + if i <. 0l <: bool + then + Core.Ops.Control_flow.ControlFlow_Break + (Core.Ops.Control_flow.ControlFlow_Break 0l + <: + Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) i32 + else + Core.Ops.Control_flow.ControlFlow_Continue (sum +! i <: i32) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) i32) + with + | Core.Ops.Control_flow.ControlFlow_Break ret -> ret + | Core.Ops.Control_flow.ControlFlow_Continue sum -> sum *! 2l +''' "Loops.For_loops.fst" = ''' module Loops.For_loops #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" diff --git a/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap b/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap index d902bca92..fee5eaadb 100644 --- a/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__mut-ref-functionalization into-fstar.snap @@ -270,7 +270,7 @@ let test_append (_: Prims.unit) : Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = let vec1:Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = tmp0 in let vec2:Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = tmp1 in let _:Prims.unit = () in - let vec1:(Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global & Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global) = + let vec1:Alloc.Vec.t_Vec u8 Alloc.Alloc.t_Global = Alloc.Vec.impl_1__append #u8 #Alloc.Alloc.t_Global vec1 diff --git a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap index 73ba38024..a75b44a71 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap @@ -169,13 +169,13 @@ let early_returns (x: u32) : u32 = then match true with | true -> 34ul - | _ -> Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul 3ul <: u32) x + | _ -> + let x, hoist5:(u32 & u32) = x, 3ul <: (u32 & u32) in + Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul hoist5 <: u32) x else let x:u32 = x +! 9ul in - Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul (x +! 1ul <: u32) - <: - u32) - x + let x, hoist5:(u32 & u32) = x, x +! 1ul <: (u32 & u32) in + Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul hoist5 <: u32) x /// Exercise local mutation with control flow and loops let local_mutation (x: u32) : u32 = @@ -393,7 +393,6 @@ let question_mark (x: u32) : Core.Result.t_Result u32 u32 = then match Core.Result.Result_Err 12uy <: Core.Result.t_Result Prims.unit u8 with | Core.Result.Result_Ok ok -> - let _:Prims.unit = ok in Core.Result.Result_Ok (Core.Num.impl__u32__wrapping_add 3ul x) <: Core.Result.t_Result u32 u32 @@ -427,13 +426,7 @@ let simplifiable_return (c1 c2 c3: bool) : i32 = if c2 then let x:i32 = x +! 10l in - if c3 - then 1l - else - let x:i32 = x +! 1l in - x - else - let x:i32 = x +! 1l in - x + if c3 then 1l else x +! 1l + else x +! 1l else x ''' diff --git a/tests/loops/src/lib.rs b/tests/loops/src/lib.rs index 7c209eee1..a2157fd0d 100644 --- a/tests/loops/src/lib.rs +++ b/tests/loops/src/lib.rs @@ -139,3 +139,80 @@ mod while_loops { x + 12 } } + +mod control_flow { + fn double_sum() -> i32 { + let mut sum = 0; + for i in 1..10 { + if i < 0 { + break; + } + sum += i; + } + sum *= 2; + sum + } + fn double_sum2() -> i32 { + let mut sum = 0; + let mut sum2 = 0; + for i in 1..10 { + if i < 0 { + break; + } + sum += i; + sum2 += i + } + sum + sum2 + } + fn double_sum_return(v: &[i32]) -> i32 { + let mut sum = 0; + for i in v { + if *i < 0 { + return 0; + } + sum += *i; + } + sum *= 2; + sum + } + fn double_sum2_return(v: &[i32]) -> i32 { + let mut sum = 0; + let mut sum2 = 0; + for i in v { + if *i < 0 { + return 0; + } + sum += *i; + sum2 += *i + } + sum + sum2 + } + fn bigger_power_2(x: i32) -> i32 { + let mut pow = 1; + while pow < 1000000 { + pow *= 2; + if pow < x { + pow *= 3; + if true { + break; + } + } + pow *= 2 + } + pow + } + struct M { + m: Vec, + } + + impl M { + fn decoded_message(&self) -> Option> { + for i in 0..self.m.len() { + if i > 5 { + return None; + } + } + return Some(self.m.clone()); + } + } +} From 8e4bafdc34d3a4cdfcf1279b70398c0de8d9b0d2 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 22 Oct 2024 10:54:11 +0200 Subject: [PATCH 079/253] Remove invariants in control flow folds. --- .../fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti index 243da67d4..f0ac821a8 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Folds.fsti @@ -113,8 +113,8 @@ let rec fold_range_cf (start: int_t u) (end_: int_t u) (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) - (acc: acc_t {inv acc start}) - (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) /\ inv acc i} + (acc: acc_t ) + (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) } -> tuple:((Core.Ops.Control_flow.t_ControlFlow (unit & acc_t) acc_t)) { let acc = match tuple with @@ -135,8 +135,8 @@ let rec fold_range_return (start: int_t u) (end_: int_t u) (inv: acc_t -> (i:int_t u{fold_range_wf_index start end_ false (v i)}) -> Type0) - (acc: acc_t {inv acc start}) - (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) /\ inv acc i} + (acc: acc_t ) + (f: (acc:acc_t -> i:int_t u {v i <= v end_ /\ fold_range_wf_index start end_ true (v i) } -> tuple:((Core.Ops.Control_flow.t_ControlFlow (Core.Ops.Control_flow.t_ControlFlow ret_t (unit & acc_t))) acc_t) )) : Tot (Core.Ops.Control_flow.t_ControlFlow ret_t acc_t) (decreases v end_ - v start) From e7e0f94652bc88ecd95d57ba167bd3d626c69bf3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 22 Oct 2024 11:09:26 +0200 Subject: [PATCH 080/253] feat(engine/ast): add `origin` to quotes --- engine/backends/fstar/fstar_backend.ml | 2 +- engine/backends/proverif/proverif_backend.ml | 2 +- engine/lib/ast.ml | 25 ++++++++++++++++++- engine/lib/ast_utils.ml | 14 +++++++++++ engine/lib/generic_printer/generic_printer.ml | 2 +- .../phases/phase_transform_hax_lib_inline.ml | 17 ++++++++++++- engine/lib/print_rust.ml | 2 +- engine/lib/subtype.ml | 2 +- .../generate_from_ast/codegen_visitor.ml | 1 + 9 files changed, 60 insertions(+), 7 deletions(-) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 2ae37c6dd..ef086b1c5 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1462,7 +1462,7 @@ struct let tcinst = F.term @@ F.AST.Var FStar_Parser_Const.tcinstance_lid in F.decls ~fsti:ctx.interface_mode ~attrs:[ tcinst ] @@ F.AST.TopLevelLet (NoLetQualifier, [ (pat, body) ]) - | Quote quote -> + | Quote { quote; _ } -> let fstar_opts = Attrs.find_unique_attr e.attrs ~f:(function | ItemQuote q -> Some q.fstar_options diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index f66a1ea14..ce1e247e3 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -628,7 +628,7 @@ module Make (Options : OPTS) : MAKE = struct ^^ separate_map hardline (fun variant -> fun_and_reduc name variant) variants - | Quote quote -> print#quote quote + | Quote { quote; _ } -> print#quote quote | _ -> empty method! expr_let : lhs:pat -> rhs:expr -> expr fn = diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 684001400..c56637ba3 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -99,6 +99,29 @@ type literal = type 'mut_witness mutability = Mutable of 'mut_witness | Immutable [@@deriving show, yojson, hash, compare, sexp, hash, eq] +type item_kind = + [ `Fn + | `TyAlias + | `Type + | `IMacroInvokation + | `Trait + | `Impl + | `Alias + | `Use + | `Quote + | `HaxError + | `NotImplementedYet ] +[@@deriving show, yojson, hash, compare, sexp, hash, eq] +(** Describes the (shallow) kind of an item. *) + +type item_quote_origin = { + item_kind : item_kind; + item_ident : concrete_ident; + position : [ `Before | `After | `Replace ]; +} +[@@deriving show, yojson, hash, compare, sexp, hash, eq] +(** From where does a quote item comes from? *) + module Make = functor (F : Features.T) @@ -434,7 +457,7 @@ functor is_external : bool; rename : string option; } - | Quote of quote + | Quote of { quote : quote; origin : item_quote_origin } | HaxError of string | NotImplementedYet diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index d8e072ac6..1a6889c46 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -999,6 +999,20 @@ module Make (F : Features.T) = struct in Some { pat; typ; typ_span = Some span; attrs = [] } + let kind_of_item (item : item) : item_kind = + match item.v with + | Fn _ -> `Fn + | TyAlias _ -> `TyAlias + | Type _ -> `Type + | IMacroInvokation _ -> `IMacroInvokation + | Trait _ -> `Trait + | Impl _ -> `Impl + | Alias _ -> `Alias + | Use _ -> `Use + | Quote _ -> `Quote + | HaxError _ -> `HaxError + | NotImplementedYet -> `NotImplementedYet + let rec expr_of_lhs (span : span) (lhs : lhs) : expr = match lhs with | LhsLocalVar { var; typ } -> { e = LocalVar var; typ; span } diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index c18ef0a6a..13f6b629d 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -407,7 +407,7 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct safety ^^ !^"fn" ^^ space ^^ print#concrete_ident name ^^ generics ^^ params ^^ iblock braces (print#expr_at Item_Fn_body body) - | Quote quote -> print#quote quote + | Quote { quote; _ } -> print#quote quote | _ -> string "item not implemented" method generic_param' : generic_param fn = diff --git a/engine/lib/phases/phase_transform_hax_lib_inline.ml b/engine/lib/phases/phase_transform_hax_lib_inline.ml index d2b2a4527..2bfacdfa2 100644 --- a/engine/lib/phases/phase_transform_hax_lib_inline.ml +++ b/engine/lib/phases/phase_transform_hax_lib_inline.ml @@ -166,6 +166,7 @@ module%inlined_contents Make (F : Features.T) = struct let before, after = let map_fst = List.map ~f:fst in try + let replace = Attrs.late_skip item.attrs in Attrs.associated_items Attr_payloads.AssocRole.ItemQuote item.attrs |> List.map ~f:(fun assoc_item -> let e : A.expr = @@ -181,7 +182,6 @@ module%inlined_contents Make (F : Features.T) = struct (* ^ (UA.LiftToFullAst.expr e |> Print_rust.pexpr_str) *) ^ [%show: A.expr] e) in - let v : B.item' = Quote quote in let span = e.span in let position, attr = Attrs.find_unique_attr assoc_item.attrs ~f:(function @@ -192,6 +192,21 @@ module%inlined_contents Make (F : Features.T) = struct "Malformed `Quote` item: could not find a \ ItemQuote payload") in + let v : B.item' = + let origin : item_quote_origin = + { + item_kind = UA.kind_of_item item; + item_ident = item.ident; + position = + (if replace then `Replace + else + match position with + | After -> `After + | Before -> `Before); + } + in + Quote { quote; origin } + in let attrs = [ Attr_payloads.to_attr attr assoc_item.span ] in (B.{ v; span; ident = item.ident; attrs }, position)) |> List.partition_tf ~f:(snd >> [%matches? Types.Before]) diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index bea5c641a..80d64bf5e 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -592,7 +592,7 @@ module Raw = struct & !"{" & List.map ~f:pimpl_item items |> concat ~sep:!"\n" & !"}" - | Quote quote -> pquote e.span quote & !";" + | Quote { quote; _ } -> pquote e.span quote & !";" | _ -> raise NotImplemented in pattrs e.attrs & pi diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index 5c4656e5b..643f04acb 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -532,7 +532,7 @@ struct } | Alias { name; item } -> B.Alias { name; item } | Use { path; is_external; rename } -> B.Use { path; is_external; rename } - | Quote quote -> Quote (dquote span quote) + | Quote { quote; origin } -> Quote { quote = dquote span quote; origin } | HaxError e -> B.HaxError e | NotImplementedYet -> B.NotImplementedYet diff --git a/engine/utils/generate_from_ast/codegen_visitor.ml b/engine/utils/generate_from_ast/codegen_visitor.ml index 9a8b62725..e9e65ad24 100644 --- a/engine/utils/generate_from_ast/codegen_visitor.ml +++ b/engine/utils/generate_from_ast/codegen_visitor.ml @@ -233,6 +233,7 @@ let is_allowed_opaque name = "quote"; "float_kind"; "int_kind"; + "item_quote_origin"; ] in List.mem ~equal:String.equal allowlist name From 67661a713b1d048c0ad5eebfa39b45d2c34053f9 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 22 Oct 2024 11:09:48 +0200 Subject: [PATCH 081/253] fix(justfile) --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index abc4b305a..fb88b7f22 100644 --- a/justfile +++ b/justfile @@ -28,7 +28,7 @@ expand *FLAGS: # Show the Rust to OCaml generated types available to the engine. @list-types: - just _ensure_binary_availability ocamlformat ocamlformat + just _ensure_command_in_path ocamlformat ocamlformat cd engine && dune describe pp lib/types.ml \ | sed -e '1,/open ParseError/ d' \ | sed '/let rec pp_/,$d' \ From 4bac27e10ceb8a980b6fd58b5876238f9a641acc Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 22 Oct 2024 11:13:38 +0200 Subject: [PATCH 082/253] chore(engine): remove stale comment --- engine/backends/fstar/fstar_backend.ml | 43 -------------------------- 1 file changed, 43 deletions(-) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 1e3ac766a..0ee9c0e93 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1681,49 +1681,6 @@ let fstar_headers (bo : BackendOptions.t) = in [ opts; "open Core"; "open FStar.Mul" ] |> String.concat ~sep:"\n" -(* -module GenericPrinter = Generic_rust_printer.Make (InputLanguage) - -(** Use the generic printer instead of the F* printer. For now, there -is no generic printer for F*, that's why we currently just use the -Rust generic printer. Thus currently this exists only for debugging -purposes. *) -let translate_as_experimental_rust m (bo : BackendOptions.t) - (items : AST.item list) : Types.file list = - let show_view Concrete_ident.{ crate; path; definition } = - crate :: (path @ [ definition ]) |> String.concat ~sep:"::" - in - U.group_items_by_namespace items - |> Map.to_alist - |> List.concat_map ~f:(fun (ns, items) -> - let mod_name = - String.concat ~sep:"." - (List.map - ~f:(map_first_letter String.uppercase) - (fst ns :: snd ns)) - in - let string_of_items _ _ items = - let r = GenericPrinter.items () items in - let str = Generic_printer_api.AnnotatedString.to_string r in - let sm = Generic_printer_api.AnnotatedString.to_sourcemap r in - let r = (str, sm) in - (r, r) - in - let impl, intf = string_of_items bo m items in - let make ~ext (body, sourcemap) = - if String.is_empty body then None - else - Some - Types. - { - path = mod_name ^ "." ^ ext; - contents = body; - sourcemap = Some sourcemap; - } - in - List.filter_map ~f:Fn.id [ make ~ext:"rs" impl ]) -*) - (** Translate as F* (the "legacy" printer) *) let translate_as_fstar m (bo : BackendOptions.t) ~(bundles : AST.item list list) (items : AST.item list) : Types.file list = From 324beb811e54708a08a7e210907af0606a6471b2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 16 Oct 2024 17:14:05 +0200 Subject: [PATCH 083/253] Remove some unused types --- frontend/exporter/src/types/copied.rs | 35 --------------------------- 1 file changed, 35 deletions(-) diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index aba6f4fbf..3a925d3db 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -3543,30 +3543,6 @@ pub struct OpaqueTy { pub in_trait: bool, } -/// Reflects [`rustc_hir::LifetimeName`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::LifetimeName, state: S as tcx)] -#[derive(Clone, Debug, JsonSchema)] -#[derive_group(Serializers)] -pub enum LifetimeName { - Param(GlobalIdent), - ImplicitObjectLifetimeDefault, - Error, - Infer, - Static, -} - -/// Reflects [`rustc_hir::Lifetime`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::Lifetime, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Lifetime { - pub hir_id: HirId, - pub ident: Ident, - pub res: LifetimeName, -} - /// Reflects [`rustc_middle::ty::TraitRef`] #[derive_group(Serializers)] #[derive(AdtInto)] @@ -4065,17 +4041,6 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_span::symbol::Ide } } -/// Reflects [`rustc_hir::PredicateOrigin`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::PredicateOrigin, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum PredicateOrigin { - WhereClause, - GenericParam, - ImplTrait, -} - /// Reflects [`rustc_middle::ty::AssocItem`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::AssocItem, state: S as s)] From 68276839cbce5d9d7550d9799dd03edfc57e2a91 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 16 Oct 2024 17:16:04 +0200 Subject: [PATCH 084/253] Remove footgun-y `SInto` impl --- frontend/exporter/src/state.rs | 5 ++++- frontend/exporter/src/types/copied.rs | 18 ++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index cb3aa5254..cded9784b 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -342,7 +342,10 @@ impl ImplInfos { Self { generics: tcx.generics_of(did).sinto(s), typ: tcx.type_of(did).instantiate_identity().sinto(s), - trait_ref: tcx.impl_trait_ref(did).sinto(s), + trait_ref: tcx + .impl_trait_ref(did) + .map(|trait_ref| trait_ref.instantiate_identity()) + .sinto(s), clauses: tcx.predicates_defined_on(did).predicates.sinto(s), } } diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 3a925d3db..07b43c6c8 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -3134,19 +3134,6 @@ pub enum AssocItemKind { Type, } -#[cfg(feature = "rustc")] -impl< - 'tcx, - S, - D: Clone, - T: SInto + rustc_middle::ty::TypeFoldable>, - > SInto for rustc_middle::ty::EarlyBinder<'tcx, T> -{ - fn sinto(&self, s: &S) -> D { - self.clone().instantiate_identity().sinto(s) - } -} - /// Reflects [`rustc_hir::Impl`]. #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Impl<'tcx>, state: S as s)] @@ -3159,7 +3146,10 @@ pub struct Impl { pub defaultness_span: Option, pub generics: Generics, #[map({ - s.base().tcx.impl_trait_ref(s.owner_id()).sinto(s) + s.base().tcx + .impl_trait_ref(s.owner_id()) + .map(|trait_ref| trait_ref.instantiate_identity()) + .sinto(s) })] pub of_trait: Option, pub self_ty: Ty, From 88706403f9bfbdb9e87e79e4eb2d961b6d8f1d6d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Oct 2024 11:22:21 +0200 Subject: [PATCH 085/253] Remove unneeded hack --- frontend/exporter/src/traits/utils.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/frontend/exporter/src/traits/utils.rs b/frontend/exporter/src/traits/utils.rs index 92c11fd2f..f2e0e1f07 100644 --- a/frontend/exporter/src/traits/utils.rs +++ b/frontend/exporter/src/traits/utils.rs @@ -53,19 +53,8 @@ pub fn predicates_of_or_above<'tcx>( _ => {} } - // Add some extra predicates that aren't in `predicates_defined_on`. + // Add the extra `Self: Trait` predicate. match def_kind { - OpaqueTy => { - // An opaque type (e.g. `impl Trait`) provides predicates by itself: we need to - // account for them. - // TODO: is this still useful? The test that used to require this doesn't anymore. - predicates.extend( - tcx.explicit_item_bounds(did) - .skip_binder() // Skips an `EarlyBinder`, likely for GATs - .iter() - .filter_map(|(clause, _span)| clause.as_trait_clause()), - ) - } Trait => { // Add the special `Self: Trait` clause. // Copied from the code of `tcx.predicates_of()`. From 85a7ad4867d5f0a0e0b15de7bfa0139b8fb196a2 Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Tue, 22 Oct 2024 14:05:13 +0200 Subject: [PATCH 086/253] some fixes for iterators.f_next and update_at_usize --- proof-libs/fstar/core/Core.Iter.Traits.Iterator.fst | 4 ++-- proof-libs/fstar/core/Core.Iter.fsti | 12 ++++++------ proof-libs/fstar/core/Core.Ops.Range.fsti | 4 ++-- .../Rust_primitives.Hax.Monomorphized_update_at.fst | 3 --- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/proof-libs/fstar/core/Core.Iter.Traits.Iterator.fst b/proof-libs/fstar/core/Core.Iter.Traits.Iterator.fst index 6a9c67564..4573af0d4 100644 --- a/proof-libs/fstar/core/Core.Iter.Traits.Iterator.fst +++ b/proof-libs/fstar/core/Core.Iter.Traits.Iterator.fst @@ -7,7 +7,7 @@ on their own. This is handy for revealing only certain fields of the instances of the `iterator` trait. *) unfold type t_next self item - = self -> self * option item + = self -> self * Core.Option.t_Option item unfold type t_contains self item = self -> item -> Type0 unfold type t_fold self (item: Type0) (contains: t_contains self item) @@ -31,7 +31,7 @@ unfold type t_all self item class iterator (self: Type u#0): Type u#1 = { [@@@FStar.Tactics.Typeclasses.no_method] f_Item: Type0; - f_next: self -> self * option f_Item; + f_next: self -> self * Core.Option.t_Option f_Item; f_contains: self -> f_Item -> Type0; f_fold: #b:Type0 -> s:self -> b -> (b -> i:f_Item{f_contains s i} -> b) -> b; f_enumerate: self -> Core.Iter.Adapters.Enumerate.t_Enumerate self; diff --git a/proof-libs/fstar/core/Core.Iter.fsti b/proof-libs/fstar/core/Core.Iter.fsti index ef2095e7f..f7dfc58a7 100644 --- a/proof-libs/fstar/core/Core.Iter.fsti +++ b/proof-libs/fstar/core/Core.Iter.fsti @@ -28,10 +28,10 @@ instance iterator_enumerate it {| i: iterator it |}: iterator (Core.Iter.Adapter let open Core.Ops in let iter, opt = f_next iter in match opt with - | Some value -> if v count = max_usize - then {iter; count }, None - else {iter; count = count +. sz 1}, Some (count, value) - | None -> {iter; count}, None + | Core.Option.Option_Some value -> if v count = max_usize + then {iter; count }, Core.Option.Option_None + else {iter; count = count +. sz 1}, Core.Option.Option_Some (count, value) + | Core.Option.Option_None -> {iter; count}, Core.Option.Option_None ); f_contains = iterator_enumerate_contains it i; f_fold = iterator_enumerate_fold it i; @@ -84,7 +84,7 @@ val iterator_slice_all (t: eqtype): t_all (t_Slice t) t instance iterator_slice (t: eqtype): iterator (t_Slice t) = { f_Item = t; f_next = iterator_slice_next t; - // size_hint = (fun s -> Some (Rust_primitives.Arrays.length s)); + // size_hint = (fun s -> Core.Option.Option_Some (Rust_primitives.Arrays.length s)); f_contains = iterator_slice_contains t; f_fold = iterator_slice_fold t; f_enumerate = iterator_slice_enumerate t; @@ -106,7 +106,7 @@ val iterator_array_all (t: eqtype) len: t_all (t_Array t len) t instance iterator_array (t: eqtype) len: iterator (t_Array t len) = { f_Item = t; f_next = iterator_array_next t len; - // size_hint = (fun (_s: t_Array t len) -> Some len); + // size_hint = (fun (_s: t_Array t len) -> Core.Option.Option_Some len); f_contains = iterator_array_contains t len; f_fold = iterator_array_fold t len; f_enumerate = iterator_array_enumerate t len; diff --git a/proof-libs/fstar/core/Core.Ops.Range.fsti b/proof-libs/fstar/core/Core.Ops.Range.fsti index fffe32635..edb10cf4b 100644 --- a/proof-libs/fstar/core/Core.Ops.Range.fsti +++ b/proof-libs/fstar/core/Core.Ops.Range.fsti @@ -23,8 +23,8 @@ val iterator_range_all t: t_all (t_Range (Rust_primitives.int_t t)) (Rust_primit instance iterator_range t: iterator (t_Range (Rust_primitives.int_t t)) = { f_Item = Rust_primitives.int_t t; f_next = (fun {f_start; f_end} -> - if f_start >=. f_end then ({f_start; f_end}, None) - else ({f_start = f_start +. Rust_primitives.mk_int 0; f_end}, Some f_start) + if f_start >=. f_end then ({f_start; f_end}, Core.Option.Option_None) + else ({f_start = f_start +. Rust_primitives.mk_int 0; f_end}, Core.Option.Option_Some f_start) ); f_contains = (fun x i -> v i < v x.f_end /\ v i >= v x.f_start); f_fold = (fun #b r init f -> if r.f_start >=. r.f_end then init diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fst b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fst index b85761e91..8093a8a52 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fst +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Hax.Monomorphized_update_at.fst @@ -4,9 +4,6 @@ open Rust_primitives open Rust_primitives.Hax open Core.Ops.Range -let update_at_usize s i x = - update_at s i x - let update_at_range #n s i x = let res = update_at s i x in admit(); // To be proved // see issue #423 From 09b1ee5005194a043de6ed6412b65db06eb6bb5b Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 14:10:36 +0200 Subject: [PATCH 087/253] More involved ProVerif example (WIP) --- examples/Cargo.lock | 202 +++++++++++++++++++++++++++++++ examples/Cargo.toml | 3 +- examples/proverif-psk/Cargo.toml | 13 ++ examples/proverif-psk/Readme.md | 55 +++++++++ examples/proverif-psk/src/lib.rs | 139 +++++++++++++++++++++ 5 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 examples/proverif-psk/Cargo.toml create mode 100644 examples/proverif-psk/Readme.md create mode 100644 examples/proverif-psk/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 0a3c94c9a..88bc2e0b4 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -59,6 +59,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -110,6 +116,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -220,8 +227,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -346,6 +355,24 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kyber_compress" version = "0.1.0" @@ -372,6 +399,48 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libcrux" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d9dcd435758db03438089760c55a45e6bcab7e4e299ee261f75225ab29d482" +dependencies = [ + "getrandom", + "libcrux-hacl", + "libcrux-platform", + "libjade-sys", + "rand", +] + +[[package]] +name = "libcrux-hacl" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b2581ce493c5c22700077b5552b47be69b67b8176716572b02856218db0b68" +dependencies = [ + "cc", + "libcrux-platform", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647e39666194b11df17c19451d1154b9be79df98b9821532560c2ecad0cf3410" +dependencies = [ + "libc", +] + +[[package]] +name = "libjade-sys" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4d22bba476bf8f5aebe36ccfd0e56dba8707e0c3b5c76996576028f48ffb8e" +dependencies = [ + "cc", + "libcrux-platform", +] + [[package]] name = "lob_backend" version = "0.1.0" @@ -383,6 +452,12 @@ dependencies = [ "serde", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.6.4" @@ -392,6 +467,9 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "minimal-proverif" version = "0.1.0" +dependencies = [ + "hax-lib", +] [[package]] name = "num-bigint" @@ -457,6 +535,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "pretty" version = "0.12.3" @@ -511,6 +598,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proverif-psk" +version = "0.1.0" +dependencies = [ + "hax-lib", + "libcrux", + "rand", +] + [[package]] name = "psm" version = "0.1.21" @@ -529,6 +625,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -736,6 +862,61 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + [[package]] name = "winapi" version = "0.3.9" @@ -775,3 +956,24 @@ checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f17f8f6d4..6425df82e 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,7 +5,8 @@ members = [ "sha256", "barrett", "kyber_compress", - "minimal-proverif" + "minimal-proverif", + "proverif-psk" ] resolver = "2" diff --git a/examples/proverif-psk/Cargo.toml b/examples/proverif-psk/Cargo.toml new file mode 100644 index 000000000..03103d4b0 --- /dev/null +++ b/examples/proverif-psk/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "proverif-psk" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hax-lib.workspace = true +libcrux = "=0.0.2-pre.2" + +[dev-dependencies] +rand = { version = "0.8" } diff --git a/examples/proverif-psk/Readme.md b/examples/proverif-psk/Readme.md new file mode 100644 index 000000000..0907ebbfc --- /dev/null +++ b/examples/proverif-psk/Readme.md @@ -0,0 +1,55 @@ +# A minimal hax ProVerif example + +This crate demonstrates a minimal example of ProVerif extraction using hax. + +The crate provides functions for implementing a simplistic protocol +between an initiator and receiver, which is defined as follows: +``` +Initiator(payload: u8): let message = Ping(payload) + +Initiator -> Responder: message + +Responder: If message was Ping(payload), + let response = Pong(payload) + else abort + +Responder -> Initiator: response + +Initiator: If response was Pong(payload), + return payload + else abort +``` + +The crate does not implement message transport, only the initiator and responder protocol logic. + +## Extracting into ProVerif +To obtain a ProVerif model of the protocol logic functions, run +``` +cargo hax into pro-verif +``` +This will generate a file `./proofs/proverif/extraction/lib.pvl`. + +## Running a Basic Analysis on the Model +We have provided a handwritten file +`./proofs/proverif/extraction/analysis.pv`, which models the protocol +using the extracted functions in `lib.pvl` and uses ProVerif to verify +that initiator and receiver can both complete the protocol. + +To let ProVerif perform the analysis, from the crate root, run: + +``` +proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv +``` + +The expected final output is +``` +-------------------------------------------------------------- +Verification summary: + +Query not event(Reach_end_Initiator) is false. + +Query not event(Reach_end_Responder) is false. + +-------------------------------------------------------------- +``` + diff --git a/examples/proverif-psk/src/lib.rs b/examples/proverif-psk/src/lib.rs new file mode 100644 index 000000000..ace689070 --- /dev/null +++ b/examples/proverif-psk/src/lib.rs @@ -0,0 +1,139 @@ +use hax_lib as hax; +use libcrux::aead::{self, Algorithm}; + +pub struct Message(aead::Tag, Vec); + +pub struct KeyIv(libcrux::aead::Key, libcrux::aead::Iv); + +const AEAD_KEY_NONCE: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305) + + Algorithm::nonce_size(Algorithm::Chacha20Poly1305); + +const AEAD_KEY_LENGTH: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305); + +const EMPTY_AAD: &[u8; 0] = b""; +const RESPONSE_KEY_CONTEXT: &[u8; 12] = b"response-key"; + +#[derive(Debug)] +pub enum Error { + CryptoError, + OtherError, +} + +impl From for Error { + fn from(_value: libcrux::aead::Error) -> Error { + Error::CryptoError + } +} + +impl From for Error { + fn from(_value: libcrux::hkdf::Error) -> Error { + Error::CryptoError + } +} + +impl From for Error { + fn from(_value: std::array::TryFromSliceError) -> Error { + Error::OtherError + } +} + +fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { + let key_iv_bytes = + libcrux::hkdf::expand(libcrux::hkdf::Algorithm::Sha256, ikm, info, AEAD_KEY_NONCE)?; + + let (key_bytes, iv_bytes) = key_iv_bytes.split_at(AEAD_KEY_LENGTH); + let key = + libcrux::aead::Key::from_slice(libcrux::aead::Algorithm::Chacha20Poly1305, key_bytes)?; + + let iv = libcrux::aead::Iv(iv_bytes.try_into()?); + Ok(KeyIv(key, iv)) +} + +fn serialize_key_iv(key_iv: &KeyIv) -> Vec { + let mut result = Vec::new(); + result.extend_from_slice(key_iv.1 .0.as_ref()); + match &key_iv.0 { + aead::Key::Chacha20Poly1305(k) => result.extend_from_slice(k.0.as_ref()), + _ => unimplemented!(), + } + result +} + +fn deserialize_key_iv(bytes: &[u8]) -> Result { + let iv = aead::Iv::new(&bytes[..12])?; + let key = aead::Key::from_slice(Algorithm::Chacha20Poly1305, &bytes[12..])?; + Ok(KeyIv(key, iv)) +} + +#[hax::proverif::replace("fun $proverif_psk::encrypt (KeyIv, bitstring): Message.")] +pub fn encrypt(key_iv: &KeyIv, message: &[u8]) -> Result { + let (tag, ctxt) = + libcrux::aead::encrypt_detached(&key_iv.0, message, aead::Iv(key_iv.1 .0), EMPTY_AAD)?; + Ok(Message(tag, ctxt)) +} + +fn decrypt(key_iv: &KeyIv, message: Message) -> Result, Error> { + libcrux::aead::decrypt_detached( + &key_iv.0, + message.1, + aead::Iv(key_iv.1 .0), + EMPTY_AAD, + &message.0, + ) + .map_err(|_| Error::CryptoError) +} + +pub fn initiate(ikm: &[u8], psk: &KeyIv) -> Result<(Message, KeyIv), Error> { + let response_key_iv = derive_key_iv(ikm, RESPONSE_KEY_CONTEXT)?; + + let serialized_responder_key = serialize_key_iv(&response_key_iv); + + let initiator_message = encrypt(psk, &serialized_responder_key)?; + + Ok((initiator_message, response_key_iv)) +} + +pub fn respond(psk: &KeyIv, payload: &[u8], message: Message) -> Result { + let response_key_bytes = decrypt(psk, message)?; + + let response_key_iv = deserialize_key_iv(&response_key_bytes)?; + + let responder_message = encrypt(&response_key_iv, payload)?; + + Ok(responder_message) +} + +pub fn finish(message: Message, response_key_iv: &KeyIv) -> Result, Error> { + let response_bytes = decrypt(response_key_iv, message)?; + + Ok(response_bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + use rand::{rngs::OsRng, RngCore}; + + fn random_array() -> [u8; L] { + let mut rng = OsRng; + let mut seed = [0; L]; + rng.try_fill_bytes(&mut seed).unwrap(); + seed + } + let payload = b"SECRET"; + let ikm_psk = random_array::<32>(); + let ikm_responder_key = random_array::<32>(); + + let psk = derive_key_iv(&ikm_psk, b"pre-shared-key") + .map_err(|_| Error::CryptoError) + .unwrap(); + + let (initiator_message, response_key) = initiate(&ikm_responder_key, &psk).unwrap(); + let responder_message = respond(&psk, payload, initiator_message).unwrap(); + let initiator_finish = finish(responder_message, &response_key).unwrap(); + assert_eq!(payload.to_vec(), initiator_finish); + } +} From e468f22c92f1f292c5bf9ffbecdcd9dabdda9e18 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 22 Oct 2024 14:13:41 +0200 Subject: [PATCH 088/253] fix(sourcemaps): include ppx yojson primitives --- engine/utils/sourcemaps/prelude.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/utils/sourcemaps/prelude.ml b/engine/utils/sourcemaps/prelude.ml index c68769180..e4d6ca4bd 100644 --- a/engine/utils/sourcemaps/prelude.ml +++ b/engine/utils/sourcemaps/prelude.ml @@ -1,4 +1,5 @@ include Base +include Ppx_yojson_conv_lib.Yojson_conv.Primitives let ( << ) f g x = f (g x) let ( >> ) f g x = g (f x) From 80c33f34ae37fd7814145fc128b02fe36f2453f4 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 22 Oct 2024 14:15:50 +0200 Subject: [PATCH 089/253] Fix return in nested loops. --- .../phase_drop_return_break_continue.ml | 14 ++- .../lib/phases/phase_rewrite_control_flow.ml | 28 ++++-- .../toolchain__loops into-fstar.snap | 96 +++++++++++++++++++ tests/loops/src/lib.rs | 28 ++++++ 4 files changed, 155 insertions(+), 11 deletions(-) diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index a8ef7d48a..339f38bdc 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -44,6 +44,9 @@ module Make (F : Features.T) = | Return { e; _ } -> { return_type = Some e.typ; break_type = U.unit_typ } | Break { e; _ } -> { return_type = None; break_type = e.typ } + (* We should avoid catching returns and breaks of a nested + loops as they could have different types. *) + | Loop _ -> { return_type = None; break_type = U.unit_typ } | _ -> super#visit_expr' () e end @@ -108,9 +111,18 @@ module Make (F : Features.T) = method! visit_expr () e = match e.e with | Loop ({ body; control_flow; _ } as loop) when control_flow -> + let acc_type = + match e.typ with + | TApp { ident; args = [ GType _; GType continue_type ] } + when Ast.Global_ident.equal ident + (Ast.Global_ident.of_name Type + Core__ops__control_flow__ControlFlow) -> + continue_type + | _ -> e.typ + in let body = visitor#visit_expr - (Some (has_return#visit_expr () body, e.typ)) + (Some (has_return#visit_expr () body, acc_type)) body in super#visit_expr () { e with e = Loop { loop with body } } diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 97602ba5a..820b41b2b 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -37,12 +37,12 @@ module Make (F : Features.T) = let loop_return_type = object (_self) inherit [_] Visitors.reduce as super - method zero = U.unit_typ - method plus l r = if [%eq: ty] l U.unit_typ then r else l + method zero = (U.unit_typ, None) + method plus l r = if [%eq: ty] (fst l) U.unit_typ then r else l method! visit_expr' () e = match e with - | Return { e; _ } -> e.typ + | Return { e; witness; _ } -> (e.typ, Some witness) | _ -> super#visit_expr' () e end @@ -65,6 +65,12 @@ module Make (F : Features.T) = method! visit_expr in_loop e = let loop_with_return (loop : expr) stmts_after final pat = + let return_type, witness = loop_return_type#visit_expr () loop in + + let typ = + U.make_control_flow_type ~continue_type:loop.typ + ~break_type:return_type + in let loop = match loop.e with | Loop ({ kind; _ } as loop_info) -> @@ -79,21 +85,23 @@ module Make (F : Features.T) = { loop with e = Loop { loop_info with kind } } | _ -> loop in - let return_type = loop_return_type#visit_expr () loop in - - let typ = - U.make_control_flow_type ~continue_type:loop.typ - ~break_type:return_type - in + let loop = { loop with typ } in let span = loop.span in let id = U.fresh_local_ident_in [] "ret" in let module MS = (val U.M.make span) in let mk_cf_pat = U.make_control_flow_pat ~span ~typ in + let return_expr = + let inner_e = MS.expr_LocalVar ~typ:return_type id in + match witness with + | Some witness -> + MS.expr_Return ~typ:return_type ~witness ~inner_e + | None -> inner_e + in let arms = [ MS.arm (mk_cf_pat `Break (U.make_var_pat id typ span)) - (MS.expr_LocalVar ~typ:return_type id); + return_expr; MS.arm (mk_cf_pat `Continue pat) (U.make_lets stmts_after final |> self#visit_expr in_loop); ] diff --git a/test-harness/src/snapshots/toolchain__loops into-fstar.snap b/test-harness/src/snapshots/toolchain__loops into-fstar.snap index d101e88f8..2c35945ca 100644 --- a/test-harness/src/snapshots/toolchain__loops into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__loops into-fstar.snap @@ -221,6 +221,102 @@ let double_sum_return (v: t_Slice i32) : i32 = with | Core.Ops.Control_flow.ControlFlow_Break ret -> ret | Core.Ops.Control_flow.ControlFlow_Continue sum -> sum *! 2l + +let nested (_: Prims.unit) : i32 = + let sum:i32 = 0l in + let sum:i32 = + Rust_primitives.Hax.Folds.fold_range 1l + 10l + (fun sum temp_1_ -> + let sum:i32 = sum in + let _:i32 = temp_1_ in + true) + sum + (fun sum i -> + let sum:i32 = sum in + let i:i32 = i in + let sum:i32 = + Rust_primitives.Hax.Folds.fold_range_cf 1l + 10l + (fun sum temp_1_ -> + let sum:i32 = sum in + let _:i32 = temp_1_ in + true) + sum + (fun sum j -> + let sum:i32 = sum in + let j:i32 = j in + if j <. 0l <: bool + then + Core.Ops.Control_flow.ControlFlow_Break ((), sum <: (Prims.unit & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32 + else + Core.Ops.Control_flow.ControlFlow_Continue (sum +! j <: i32) + <: + Core.Ops.Control_flow.t_ControlFlow (Prims.unit & i32) i32) + in + sum +! i) + in + sum *! 2l + +let nested_return (_: Prims.unit) : i32 = + let sum:i32 = 0l in + match + Rust_primitives.Hax.Folds.fold_range_return 1l + 10l + (fun sum temp_1_ -> + let sum:i32 = sum in + let _:i32 = temp_1_ in + true) + sum + (fun sum i -> + let sum:i32 = sum in + let i:i32 = i in + match + Rust_primitives.Hax.Folds.fold_range_return 1l + 10l + (fun sum temp_1_ -> + let sum:i32 = sum in + let _:i32 = temp_1_ in + true) + sum + (fun sum j -> + let sum:i32 = sum in + let j:i32 = j in + if j <. 0l <: bool + then + Core.Ops.Control_flow.ControlFlow_Break + (Core.Ops.Control_flow.ControlFlow_Break 0l + <: + Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) i32 + else + Core.Ops.Control_flow.ControlFlow_Continue (sum +! j <: i32) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) i32) + <: + Core.Ops.Control_flow.t_ControlFlow i32 i32 + with + | Core.Ops.Control_flow.ControlFlow_Break ret -> + Core.Ops.Control_flow.ControlFlow_Break + (Core.Ops.Control_flow.ControlFlow_Break ret + <: + Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) i32 + | Core.Ops.Control_flow.ControlFlow_Continue sum -> + Core.Ops.Control_flow.ControlFlow_Continue (sum +! i <: i32) + <: + Core.Ops.Control_flow.t_ControlFlow + (Core.Ops.Control_flow.t_ControlFlow i32 (Prims.unit & i32)) i32) + with + | Core.Ops.Control_flow.ControlFlow_Break ret -> ret + | Core.Ops.Control_flow.ControlFlow_Continue sum -> sum *! 2l ''' "Loops.For_loops.fst" = ''' module Loops.For_loops diff --git a/tests/loops/src/lib.rs b/tests/loops/src/lib.rs index a2157fd0d..e9f5c89fa 100644 --- a/tests/loops/src/lib.rs +++ b/tests/loops/src/lib.rs @@ -215,4 +215,32 @@ mod control_flow { return Some(self.m.clone()); } } + fn nested() -> i32 { + let mut sum = 0; + for i in 1..10 { + for j in 1..10 { + if j < 0 { + break; + } + sum += j; + } + sum += i; + } + sum *= 2; + sum + } + fn nested_return() -> i32 { + let mut sum = 0; + for i in 1..10 { + for j in 1..10 { + if j < 0 { + return 0; + } + sum += j; + } + sum += i; + } + sum *= 2; + sum + } } From 4dc6e46b9e08226899ed9bf8dc4f482f6d2b37d4 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Mon, 21 Oct 2024 15:39:13 +0200 Subject: [PATCH 090/253] [PV] Remove `Process` and `Toplevel` modules --- engine/backends/proverif/proverif_backend.ml | 36 ++------------------ 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index ce1e247e3..474c9b7b3 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -129,14 +129,6 @@ module type MAKE = sig module Letfuns : sig val print : item list -> string end - - module Processes : sig - val print : item list -> string - end - - module Toplevel : sig - val print : item list -> string - end end module Make (Options : OPTS) : MAKE = struct @@ -811,7 +803,8 @@ module Make (Options : OPTS) : MAKE = struct letfun bitstring_err() = let x = construct_fail() in \ bitstring_default().\n\n\ letfun nat_default() = 0.\n\ - fun nat_to_bitstring(nat): bitstring.\n\n\ + fun nat_to_bitstring(nat): bitstring.\n\ + letfun nat_err() = let x = construct_fail() in nat_default().\n\n\ letfun bool_default() = false.\n" let contents items = "" @@ -845,24 +838,6 @@ module Make (Options : OPTS) : MAKE = struct in pure_letfuns_print ^ process_letfuns_print end) - - module Processes = MkSubprinter (struct - let banner = "Processes" - let preamble items = "" - let process_filter item = [%matches? Fn _] item.v && is_process item - - let contents items = - let contents, _ = - Print.items NoAuxInfo (List.filter ~f:process_filter items) - in - contents - end) - - module Toplevel = MkSubprinter (struct - let banner = "Top-level process" - let preamble items = "process\n 0\n" - let contents items = "" - end) end let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) @@ -874,14 +849,9 @@ let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) in let lib_contents = M.Preamble.print items ^ M.DataTypes.print items ^ M.Letfuns.print items - ^ M.Processes.print items in - let analysis_contents = M.Toplevel.print items in let lib_file = Types.{ path = "lib.pvl"; contents = lib_contents } in - let analysis_file = - Types.{ path = "analysis.pv"; contents = analysis_contents } - in - [ lib_file; analysis_file ] + [ lib_file; ] open Phase_utils module DepGraph = Dependencies.Make (InputLanguage) From 2bd0304266890bdae33e3358d966f5d7698ca25a Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Mon, 21 Oct 2024 15:56:48 +0200 Subject: [PATCH 091/253] Minimal PV extraction example --- examples/Cargo.lock | 35 ++++++++++-- examples/Cargo.toml | 1 + examples/minimal-proverif/Cargo.toml | 8 +++ examples/minimal-proverif/Readme.md | 55 +++++++++++++++++++ .../proofs/proverif/extraction/analysis.pv | 33 +++++++++++ examples/minimal-proverif/src/lib.rs | 24 ++++++++ 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 examples/minimal-proverif/Cargo.toml create mode 100644 examples/minimal-proverif/Readme.md create mode 100644 examples/minimal-proverif/proofs/proverif/extraction/analysis.pv create mode 100644 examples/minimal-proverif/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 61ed48fed..0a3c94c9a 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -181,6 +181,16 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "either" version = "1.9.0" @@ -222,14 +232,16 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hax-bounded-integers" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ + "duplicate", "hax-lib", + "paste", ] [[package]] name = "hax-lib" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros", "num-bigint", @@ -238,9 +250,10 @@ dependencies = [ [[package]] name = "hax-lib-macros" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros-types", + "paste", "proc-macro-error", "proc-macro2", "quote", @@ -249,7 +262,7 @@ dependencies = [ [[package]] name = "hax-lib-macros-types" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "proc-macro2", "quote", @@ -258,6 +271,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex" version = "0.4.3" @@ -370,6 +389,10 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "minimal-proverif" +version = "0.1.0" + [[package]] name = "num-bigint" version = "0.4.4" @@ -430,9 +453,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pretty" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7df1c9ab7..f17f8f6d4 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,6 +5,7 @@ members = [ "sha256", "barrett", "kyber_compress", + "minimal-proverif" ] resolver = "2" diff --git a/examples/minimal-proverif/Cargo.toml b/examples/minimal-proverif/Cargo.toml new file mode 100644 index 000000000..69263bbde --- /dev/null +++ b/examples/minimal-proverif/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "minimal-proverif" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/examples/minimal-proverif/Readme.md b/examples/minimal-proverif/Readme.md new file mode 100644 index 000000000..0907ebbfc --- /dev/null +++ b/examples/minimal-proverif/Readme.md @@ -0,0 +1,55 @@ +# A minimal hax ProVerif example + +This crate demonstrates a minimal example of ProVerif extraction using hax. + +The crate provides functions for implementing a simplistic protocol +between an initiator and receiver, which is defined as follows: +``` +Initiator(payload: u8): let message = Ping(payload) + +Initiator -> Responder: message + +Responder: If message was Ping(payload), + let response = Pong(payload) + else abort + +Responder -> Initiator: response + +Initiator: If response was Pong(payload), + return payload + else abort +``` + +The crate does not implement message transport, only the initiator and responder protocol logic. + +## Extracting into ProVerif +To obtain a ProVerif model of the protocol logic functions, run +``` +cargo hax into pro-verif +``` +This will generate a file `./proofs/proverif/extraction/lib.pvl`. + +## Running a Basic Analysis on the Model +We have provided a handwritten file +`./proofs/proverif/extraction/analysis.pv`, which models the protocol +using the extracted functions in `lib.pvl` and uses ProVerif to verify +that initiator and receiver can both complete the protocol. + +To let ProVerif perform the analysis, from the crate root, run: + +``` +proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv +``` + +The expected final output is +``` +-------------------------------------------------------------- +Verification summary: + +Query not event(Reach_end_Initiator) is false. + +Query not event(Reach_end_Responder) is false. + +-------------------------------------------------------------- +``` + diff --git a/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv b/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv new file mode 100644 index 000000000..dad4b3d45 --- /dev/null +++ b/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv @@ -0,0 +1,33 @@ +(*****************************************) +(* Top-level process *) +(*****************************************) + +event Reach_end_Initiator. +event Reach_end_Responder. + +query event(Reach_end_Initiator). +query event(Reach_end_Responder). + +let Initiator(payload: nat) = + let ping_message = minimal_proverif__send_ping(payload) in + out(c, ping_message); + + in(c, pong_message: minimal_proverif__t_Message ); + let received_payload = accessor_minimal_proverif__Message__Pong_0(pong_message) in + event Reach_end_Initiator; + 0. + +let Responder() = + in(c, ping_message: minimal_proverif__t_Message ); + let minimal_proverif__Message_Message_Ping_c(received_payload) = ping_message in + let pong_message = minimal_proverif__Message_Message_Pong_c(received_payload) in + out(c, pong_message); + event Reach_end_Responder; + 0. + +process + in(c, payload: nat); + + Initiator(payload) | Responder() + + diff --git a/examples/minimal-proverif/src/lib.rs b/examples/minimal-proverif/src/lib.rs new file mode 100644 index 000000000..bdc8032dd --- /dev/null +++ b/examples/minimal-proverif/src/lib.rs @@ -0,0 +1,24 @@ +pub enum Message { + Ping(u8), + Pong(u8), +} + + +pub fn send_ping(input: u8) -> Message { + Message::Ping(input) +} + +pub fn receive_ping(message: Message) -> Result { + match message { + Message::Ping(payload) => Ok(Message::Pong(payload)), + _ => Err(()) + } +} + +pub fn receive_pong(message: Message) -> Result { + match message { + Message::Pong(payload) => Ok(payload), + _ => Err(()) + } +} + From d6df2144ffab0718a0ab52f326207360e166633f Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Mon, 21 Oct 2024 16:09:34 +0200 Subject: [PATCH 092/253] Formatting --- engine/backends/proverif/proverif_backend.ml | 2 +- examples/minimal-proverif/src/lib.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 474c9b7b3..2a1fd7d99 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -851,7 +851,7 @@ let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) M.Preamble.print items ^ M.DataTypes.print items ^ M.Letfuns.print items in let lib_file = Types.{ path = "lib.pvl"; contents = lib_contents } in - [ lib_file; ] + [ lib_file ] open Phase_utils module DepGraph = Dependencies.Make (InputLanguage) diff --git a/examples/minimal-proverif/src/lib.rs b/examples/minimal-proverif/src/lib.rs index bdc8032dd..0924433de 100644 --- a/examples/minimal-proverif/src/lib.rs +++ b/examples/minimal-proverif/src/lib.rs @@ -3,7 +3,6 @@ pub enum Message { Pong(u8), } - pub fn send_ping(input: u8) -> Message { Message::Ping(input) } @@ -11,14 +10,13 @@ pub fn send_ping(input: u8) -> Message { pub fn receive_ping(message: Message) -> Result { match message { Message::Ping(payload) => Ok(Message::Pong(payload)), - _ => Err(()) + _ => Err(()), } } pub fn receive_pong(message: Message) -> Result { match message { Message::Pong(payload) => Ok(payload), - _ => Err(()) + _ => Err(()), } } - From ab75c52db6dcd6a23e3ef8a5eec26a9a90a0f1f1 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 14:10:36 +0200 Subject: [PATCH 093/253] More involved ProVerif example (WIP) --- examples/Cargo.lock | 202 +++++++++++++++++++++++++++++++ examples/Cargo.toml | 3 +- examples/proverif-psk/Cargo.toml | 13 ++ examples/proverif-psk/Readme.md | 55 +++++++++ examples/proverif-psk/src/lib.rs | 139 +++++++++++++++++++++ 5 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 examples/proverif-psk/Cargo.toml create mode 100644 examples/proverif-psk/Readme.md create mode 100644 examples/proverif-psk/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 0a3c94c9a..88bc2e0b4 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -59,6 +59,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -110,6 +116,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -220,8 +227,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -346,6 +355,24 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kyber_compress" version = "0.1.0" @@ -372,6 +399,48 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libcrux" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d9dcd435758db03438089760c55a45e6bcab7e4e299ee261f75225ab29d482" +dependencies = [ + "getrandom", + "libcrux-hacl", + "libcrux-platform", + "libjade-sys", + "rand", +] + +[[package]] +name = "libcrux-hacl" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b2581ce493c5c22700077b5552b47be69b67b8176716572b02856218db0b68" +dependencies = [ + "cc", + "libcrux-platform", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647e39666194b11df17c19451d1154b9be79df98b9821532560c2ecad0cf3410" +dependencies = [ + "libc", +] + +[[package]] +name = "libjade-sys" +version = "0.0.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4d22bba476bf8f5aebe36ccfd0e56dba8707e0c3b5c76996576028f48ffb8e" +dependencies = [ + "cc", + "libcrux-platform", +] + [[package]] name = "lob_backend" version = "0.1.0" @@ -383,6 +452,12 @@ dependencies = [ "serde", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.6.4" @@ -392,6 +467,9 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "minimal-proverif" version = "0.1.0" +dependencies = [ + "hax-lib", +] [[package]] name = "num-bigint" @@ -457,6 +535,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "pretty" version = "0.12.3" @@ -511,6 +598,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proverif-psk" +version = "0.1.0" +dependencies = [ + "hax-lib", + "libcrux", + "rand", +] + [[package]] name = "psm" version = "0.1.21" @@ -529,6 +625,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -736,6 +862,61 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + [[package]] name = "winapi" version = "0.3.9" @@ -775,3 +956,24 @@ checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f17f8f6d4..6425df82e 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,7 +5,8 @@ members = [ "sha256", "barrett", "kyber_compress", - "minimal-proverif" + "minimal-proverif", + "proverif-psk" ] resolver = "2" diff --git a/examples/proverif-psk/Cargo.toml b/examples/proverif-psk/Cargo.toml new file mode 100644 index 000000000..03103d4b0 --- /dev/null +++ b/examples/proverif-psk/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "proverif-psk" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hax-lib.workspace = true +libcrux = "=0.0.2-pre.2" + +[dev-dependencies] +rand = { version = "0.8" } diff --git a/examples/proverif-psk/Readme.md b/examples/proverif-psk/Readme.md new file mode 100644 index 000000000..0907ebbfc --- /dev/null +++ b/examples/proverif-psk/Readme.md @@ -0,0 +1,55 @@ +# A minimal hax ProVerif example + +This crate demonstrates a minimal example of ProVerif extraction using hax. + +The crate provides functions for implementing a simplistic protocol +between an initiator and receiver, which is defined as follows: +``` +Initiator(payload: u8): let message = Ping(payload) + +Initiator -> Responder: message + +Responder: If message was Ping(payload), + let response = Pong(payload) + else abort + +Responder -> Initiator: response + +Initiator: If response was Pong(payload), + return payload + else abort +``` + +The crate does not implement message transport, only the initiator and responder protocol logic. + +## Extracting into ProVerif +To obtain a ProVerif model of the protocol logic functions, run +``` +cargo hax into pro-verif +``` +This will generate a file `./proofs/proverif/extraction/lib.pvl`. + +## Running a Basic Analysis on the Model +We have provided a handwritten file +`./proofs/proverif/extraction/analysis.pv`, which models the protocol +using the extracted functions in `lib.pvl` and uses ProVerif to verify +that initiator and receiver can both complete the protocol. + +To let ProVerif perform the analysis, from the crate root, run: + +``` +proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv +``` + +The expected final output is +``` +-------------------------------------------------------------- +Verification summary: + +Query not event(Reach_end_Initiator) is false. + +Query not event(Reach_end_Responder) is false. + +-------------------------------------------------------------- +``` + diff --git a/examples/proverif-psk/src/lib.rs b/examples/proverif-psk/src/lib.rs new file mode 100644 index 000000000..ace689070 --- /dev/null +++ b/examples/proverif-psk/src/lib.rs @@ -0,0 +1,139 @@ +use hax_lib as hax; +use libcrux::aead::{self, Algorithm}; + +pub struct Message(aead::Tag, Vec); + +pub struct KeyIv(libcrux::aead::Key, libcrux::aead::Iv); + +const AEAD_KEY_NONCE: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305) + + Algorithm::nonce_size(Algorithm::Chacha20Poly1305); + +const AEAD_KEY_LENGTH: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305); + +const EMPTY_AAD: &[u8; 0] = b""; +const RESPONSE_KEY_CONTEXT: &[u8; 12] = b"response-key"; + +#[derive(Debug)] +pub enum Error { + CryptoError, + OtherError, +} + +impl From for Error { + fn from(_value: libcrux::aead::Error) -> Error { + Error::CryptoError + } +} + +impl From for Error { + fn from(_value: libcrux::hkdf::Error) -> Error { + Error::CryptoError + } +} + +impl From for Error { + fn from(_value: std::array::TryFromSliceError) -> Error { + Error::OtherError + } +} + +fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { + let key_iv_bytes = + libcrux::hkdf::expand(libcrux::hkdf::Algorithm::Sha256, ikm, info, AEAD_KEY_NONCE)?; + + let (key_bytes, iv_bytes) = key_iv_bytes.split_at(AEAD_KEY_LENGTH); + let key = + libcrux::aead::Key::from_slice(libcrux::aead::Algorithm::Chacha20Poly1305, key_bytes)?; + + let iv = libcrux::aead::Iv(iv_bytes.try_into()?); + Ok(KeyIv(key, iv)) +} + +fn serialize_key_iv(key_iv: &KeyIv) -> Vec { + let mut result = Vec::new(); + result.extend_from_slice(key_iv.1 .0.as_ref()); + match &key_iv.0 { + aead::Key::Chacha20Poly1305(k) => result.extend_from_slice(k.0.as_ref()), + _ => unimplemented!(), + } + result +} + +fn deserialize_key_iv(bytes: &[u8]) -> Result { + let iv = aead::Iv::new(&bytes[..12])?; + let key = aead::Key::from_slice(Algorithm::Chacha20Poly1305, &bytes[12..])?; + Ok(KeyIv(key, iv)) +} + +#[hax::proverif::replace("fun $proverif_psk::encrypt (KeyIv, bitstring): Message.")] +pub fn encrypt(key_iv: &KeyIv, message: &[u8]) -> Result { + let (tag, ctxt) = + libcrux::aead::encrypt_detached(&key_iv.0, message, aead::Iv(key_iv.1 .0), EMPTY_AAD)?; + Ok(Message(tag, ctxt)) +} + +fn decrypt(key_iv: &KeyIv, message: Message) -> Result, Error> { + libcrux::aead::decrypt_detached( + &key_iv.0, + message.1, + aead::Iv(key_iv.1 .0), + EMPTY_AAD, + &message.0, + ) + .map_err(|_| Error::CryptoError) +} + +pub fn initiate(ikm: &[u8], psk: &KeyIv) -> Result<(Message, KeyIv), Error> { + let response_key_iv = derive_key_iv(ikm, RESPONSE_KEY_CONTEXT)?; + + let serialized_responder_key = serialize_key_iv(&response_key_iv); + + let initiator_message = encrypt(psk, &serialized_responder_key)?; + + Ok((initiator_message, response_key_iv)) +} + +pub fn respond(psk: &KeyIv, payload: &[u8], message: Message) -> Result { + let response_key_bytes = decrypt(psk, message)?; + + let response_key_iv = deserialize_key_iv(&response_key_bytes)?; + + let responder_message = encrypt(&response_key_iv, payload)?; + + Ok(responder_message) +} + +pub fn finish(message: Message, response_key_iv: &KeyIv) -> Result, Error> { + let response_bytes = decrypt(response_key_iv, message)?; + + Ok(response_bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + use rand::{rngs::OsRng, RngCore}; + + fn random_array() -> [u8; L] { + let mut rng = OsRng; + let mut seed = [0; L]; + rng.try_fill_bytes(&mut seed).unwrap(); + seed + } + let payload = b"SECRET"; + let ikm_psk = random_array::<32>(); + let ikm_responder_key = random_array::<32>(); + + let psk = derive_key_iv(&ikm_psk, b"pre-shared-key") + .map_err(|_| Error::CryptoError) + .unwrap(); + + let (initiator_message, response_key) = initiate(&ikm_responder_key, &psk).unwrap(); + let responder_message = respond(&psk, payload, initiator_message).unwrap(); + let initiator_finish = finish(responder_message, &response_key).unwrap(); + assert_eq!(payload.to_vec(), initiator_finish); + } +} From 365d7e4120d80994c143c8ee6644915e19444cc5 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 14:49:29 +0200 Subject: [PATCH 094/253] Add ProVerif replacements --- examples/Cargo.lock | 3 --- examples/proverif-psk/src/lib.rs | 9 ++++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 88bc2e0b4..4be61c380 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -467,9 +467,6 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "minimal-proverif" version = "0.1.0" -dependencies = [ - "hax-lib", -] [[package]] name = "num-bigint" diff --git a/examples/proverif-psk/src/lib.rs b/examples/proverif-psk/src/lib.rs index ace689070..f90c1d312 100644 --- a/examples/proverif-psk/src/lib.rs +++ b/examples/proverif-psk/src/lib.rs @@ -1,8 +1,10 @@ use hax_lib as hax; use libcrux::aead::{self, Algorithm}; +#[hax::proverif::replace("type $:{Message}.")] pub struct Message(aead::Tag, Vec); +#[hax::proverif::replace("type $:{KeyIv}.")] pub struct KeyIv(libcrux::aead::Key, libcrux::aead::Iv); const AEAD_KEY_NONCE: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305) @@ -37,6 +39,7 @@ impl From for Error { } } +#[hax::pv_constructor] // or cleaner with `proverif::replace()`? fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { let key_iv_bytes = libcrux::hkdf::expand(libcrux::hkdf::Algorithm::Sha256, ikm, info, AEAD_KEY_NONCE)?; @@ -49,6 +52,7 @@ fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { Ok(KeyIv(key, iv)) } +#[hax::proverif::replace("fun ${serialize_key_iv} ($:{KeyIv}): bitstring.")] fn serialize_key_iv(key_iv: &KeyIv) -> Vec { let mut result = Vec::new(); result.extend_from_slice(key_iv.1 .0.as_ref()); @@ -59,19 +63,22 @@ fn serialize_key_iv(key_iv: &KeyIv) -> Vec { result } + +#[hax::proverif::replace("reduc forall k: ${KeyIv}; ${deserialize_key_iv}(${serialize_key_iv}(k)) = k.")] fn deserialize_key_iv(bytes: &[u8]) -> Result { let iv = aead::Iv::new(&bytes[..12])?; let key = aead::Key::from_slice(Algorithm::Chacha20Poly1305, &bytes[12..])?; Ok(KeyIv(key, iv)) } -#[hax::proverif::replace("fun $proverif_psk::encrypt (KeyIv, bitstring): Message.")] +#[hax::proverif::replace("fun ${encrypt} ($:{KeyIv}, bitstring): $:{Message}.")] pub fn encrypt(key_iv: &KeyIv, message: &[u8]) -> Result { let (tag, ctxt) = libcrux::aead::encrypt_detached(&key_iv.0, message, aead::Iv(key_iv.1 .0), EMPTY_AAD)?; Ok(Message(tag, ctxt)) } +#[hax::proverif::replace("reduc forall m: bitstring, k: $:{KeyIv}; ${decrypt}(k, ${encrypt}(k, m)) = m.")] fn decrypt(key_iv: &KeyIv, message: Message) -> Result, Error> { libcrux::aead::decrypt_detached( &key_iv.0, From 717e689f4a5cfcb3d43919d621e931f5ceb6cb9b Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 15:21:24 +0200 Subject: [PATCH 095/253] Print quoted type definitions --- engine/backends/proverif/proverif_backend.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 2a1fd7d99..ee03faa8b 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -815,7 +815,11 @@ module Make (Options : OPTS) : MAKE = struct let preamble items = "" let filter_data_types items = - List.filter ~f:(fun item -> [%matches? Type _] item.v) items + List.filter + ~f:(fun item -> + [%matches? Type _] item.v + || [%matches? Quote { origin = { item_kind = `Type; _ }; _ }] item.v) + items let contents items = let contents, _ = Print.items NoAuxInfo (filter_data_types items) in From 18f5d81c90521f0f71ca145acdbb6551ead3ec87 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 16:20:40 +0200 Subject: [PATCH 096/253] Complete ProVerif replacements --- examples/Cargo.lock | 3 --- examples/proverif-psk/src/lib.rs | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 88bc2e0b4..4be61c380 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -467,9 +467,6 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "minimal-proverif" version = "0.1.0" -dependencies = [ - "hax-lib", -] [[package]] name = "num-bigint" diff --git a/examples/proverif-psk/src/lib.rs b/examples/proverif-psk/src/lib.rs index f90c1d312..643077181 100644 --- a/examples/proverif-psk/src/lib.rs +++ b/examples/proverif-psk/src/lib.rs @@ -1,7 +1,12 @@ use hax_lib as hax; use libcrux::aead::{self, Algorithm}; -#[hax::proverif::replace("type $:{Message}.")] +#[hax::proverif::replace("type $:{Message}. +const $:{Message}_default_value: $:{Message}. +letfun $:{Message}_default() = + $:{Message}_default_value. +letfun $:{Message}_err() = + let x = construct_fail() in $:{Message}_default_value.")] pub struct Message(aead::Tag, Vec); #[hax::proverif::replace("type $:{KeyIv}.")] From 796e86d8fbb1eed2a49357d27d02270d947d9359 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 16:21:28 +0200 Subject: [PATCH 097/253] Analysis for PSK example --- .../proofs/proverif/extraction/analysis.pv | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 examples/proverif-psk/proofs/proverif/extraction/analysis.pv diff --git a/examples/proverif-psk/proofs/proverif/extraction/analysis.pv b/examples/proverif-psk/proofs/proverif/extraction/analysis.pv new file mode 100644 index 000000000..96b4d3ccd --- /dev/null +++ b/examples/proverif-psk/proofs/proverif/extraction/analysis.pv @@ -0,0 +1,38 @@ +(*****************************************) +(* Top-level processes *) +(*****************************************) + +event InitiatorFinished(bitstring). +event ResponderFinished(bitstring). + +free PSK: proverif_psk__t_KeyIv [private]. +free SECRET_PAYLOAD: bitstring [private]. + +query initiator_result: bitstring; event(InitiatorFinished(initiator_result)). +query responder_result: bitstring; event(ResponderFinished(responder_result)). + +query attacker(PSK). +query attacker(SECRET_PAYLOAD). + +let Initiator(psk: proverif_psk__t_KeyIv) = + new ikm: bitstring; + let (initiator_message: proverif_psk__t_Message, response_key: proverif_psk__t_KeyIv) = proverif_psk__initiate(ikm, psk) in + out(c, initiator_message); + in(c, response_message: proverif_psk__t_Message); + let response = proverif_psk__finish(response_message, response_key) in + event InitiatorFinished(response). + +let Responder(psk: proverif_psk__t_KeyIv, payload: bitstring) = + in(c, initiator_message: proverif_psk__t_Message); + let response_message = proverif_psk__respond( + psk, + payload, + initiator_message + ) in + event ResponderFinished(payload); + out(c, response_message). + +process + Initiator(PSK) | Responder(PSK, SECRET_PAYLOAD) + + From 60bbbefe6576b2a9a1019f7a17f3a40ae4f501bf Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 16:27:19 +0200 Subject: [PATCH 098/253] Update PSK example Readme --- examples/proverif-psk/Readme.md | 37 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/examples/proverif-psk/Readme.md b/examples/proverif-psk/Readme.md index 0907ebbfc..fba20d018 100644 --- a/examples/proverif-psk/Readme.md +++ b/examples/proverif-psk/Readme.md @@ -1,26 +1,29 @@ -# A minimal hax ProVerif example +# A hax ProVerif example -This crate demonstrates a minimal example of ProVerif extraction using hax. +This crate demonstrates an example of ProVerif extraction using hax. -The crate provides functions for implementing a simplistic protocol +The crate provides functions for implementing a simplistic pre-shared-key (PSK) based protocol between an initiator and receiver, which is defined as follows: ``` -Initiator(payload: u8): let message = Ping(payload) +Initiator(psk: AEADKey)): + let response_key = AEAD.KeyGen() + let message = AEAD.Encrypt(psk, response_key) Initiator -> Responder: message -Responder: If message was Ping(payload), - let response = Pong(payload) - else abort +Responder(psk: AEADKey, payload: &[u8]): + let response_key = AEAD.Decrypt(psk, message) + let response = AEAD.Encrypt(response_key, payload) Responder -> Initiator: response -Initiator: If response was Pong(payload), - return payload - else abort +Initiator(response_key, response): + let output = AEAD.Decrypt(response_key, response) + return output ``` -The crate does not implement message transport, only the initiator and responder protocol logic. +The crate does not implement message transport, only the initiator and +responder protocol logic. ## Extracting into ProVerif To obtain a ProVerif model of the protocol logic functions, run @@ -33,7 +36,9 @@ This will generate a file `./proofs/proverif/extraction/lib.pvl`. We have provided a handwritten file `./proofs/proverif/extraction/analysis.pv`, which models the protocol using the extracted functions in `lib.pvl` and uses ProVerif to verify -that initiator and receiver can both complete the protocol. + +- that initiator and receiver can both complete the protocol, as well as +- confidentiality of the pre-shared key and the protocol payload To let ProVerif perform the analysis, from the crate root, run: @@ -46,9 +51,13 @@ The expected final output is -------------------------------------------------------------- Verification summary: -Query not event(Reach_end_Initiator) is false. +Query not event(InitiatorFinished(initiator_result)) is false. + +Query not event(ResponderFinished(responder_result)) is false. + +Query not attacker(PSK[]) is true. -Query not event(Reach_end_Responder) is false. +Query not attacker(SECRET_PAYLOAD[]) is true. -------------------------------------------------------------- ``` From 004095504a013db0cc53d997f5680ee1f9c0e2a2 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 16:29:06 +0200 Subject: [PATCH 099/253] Include handwritten model for comparison --- examples/proverif-psk/Readme.md | 2 ++ examples/proverif-psk/psk.pv | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 examples/proverif-psk/psk.pv diff --git a/examples/proverif-psk/Readme.md b/examples/proverif-psk/Readme.md index fba20d018..b7e56fed1 100644 --- a/examples/proverif-psk/Readme.md +++ b/examples/proverif-psk/Readme.md @@ -25,6 +25,8 @@ Initiator(response_key, response): The crate does not implement message transport, only the initiator and responder protocol logic. +A handwritten ProVerif model of this protocol is included in `psk.pv` for comparison. + ## Extracting into ProVerif To obtain a ProVerif model of the protocol logic functions, run ``` diff --git a/examples/proverif-psk/psk.pv b/examples/proverif-psk/psk.pv new file mode 100644 index 000000000..b372981a0 --- /dev/null +++ b/examples/proverif-psk/psk.pv @@ -0,0 +1,39 @@ +free c: channel. + +type key [typeConverter]. + +fun senc(bitstring, key): bitstring. +reduc forall m: bitstring, k: key; sdec(senc(m,k), k) = m. + +fun key_to_bitstring(key): bitstring. +reduc forall k: key; bitstring_to_key(key_to_bitstring(k)) = k. + +event InitiatorFinished(bitstring). +event ResponderFinished(bitstring). + +free PSK: key [private]. +free SECRET_PAYLOAD: bitstring [private]. + +query initiator_result: bitstring; event(InitiatorFinished(initiator_result)). +query responder_result: bitstring; event(ResponderFinished(responder_result)). + +query attacker(PSK). +query attacker(SECRET_PAYLOAD). + +let Initiator(psk: key) = + new response_key: key; + let initiator_message = senc(key_to_bitstring(response_key), psk) in + out(c, initiator_message); + in(c, response_message: bitstring); + let response = sdec(response_message, response_key) in + event InitiatorFinished(response). + +let Responder(psk: key, payload: bitstring) = + in(c, initiator_message: bitstring); + let response_key = sdec(initiator_message, psk) in + let response_message = senc(payload, bitstring_to_key(response_key)) in + event ResponderFinished(payload); + out(c, response_message). + +process + Initiator(PSK) | Responder(PSK, SECRET_PAYLOAD) From 41f8e6e477defe343481f1c534d1321e1f06530f Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Tue, 22 Oct 2024 16:43:51 +0200 Subject: [PATCH 100/253] Justification for `proverif::replace` --- examples/proverif-psk/Readme.md | 13 ++++++++++++- examples/proverif-psk/psk.pv | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/proverif-psk/Readme.md b/examples/proverif-psk/Readme.md index b7e56fed1..ebfba4f08 100644 --- a/examples/proverif-psk/Readme.md +++ b/examples/proverif-psk/Readme.md @@ -5,7 +5,7 @@ This crate demonstrates an example of ProVerif extraction using hax. The crate provides functions for implementing a simplistic pre-shared-key (PSK) based protocol between an initiator and receiver, which is defined as follows: ``` -Initiator(psk: AEADKey)): +Initiator(psk: AEADKey): let response_key = AEAD.KeyGen() let message = AEAD.Encrypt(psk, response_key) @@ -27,6 +27,17 @@ responder protocol logic. A handwritten ProVerif model of this protocol is included in `psk.pv` for comparison. +### On the use of `proverif::replace()` +Since ProVerif operates in a symbolic world, certain operations have +to be represented abstractly, in in symbolic terms. In this case, we +give symbolic replacements for serialization and deserialization, as +well as cryptographic operations such as encryption and +decryption. They are thus treated as ideal implementations of their +respective functionality in ProVerif's analysis of the protocol. To +obtain assurance that these operations are correct and implemented +securely, one of hax' other backends can be used. + + ## Extracting into ProVerif To obtain a ProVerif model of the protocol logic functions, run ``` diff --git a/examples/proverif-psk/psk.pv b/examples/proverif-psk/psk.pv index b372981a0..c93327114 100644 --- a/examples/proverif-psk/psk.pv +++ b/examples/proverif-psk/psk.pv @@ -1,6 +1,6 @@ free c: channel. -type key [typeConverter]. +type key. fun senc(bitstring, key): bitstring. reduc forall m: bitstring, k: key; sdec(senc(m,k), k) = m. From c981af36bc3a9ed60463e9417e43bd86a4fbb379 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Oct 2024 13:41:10 +0200 Subject: [PATCH 101/253] Reorganize `exporter/types` into appropriate submodules --- frontend/exporter/src/constant_utils.rs | 3 + frontend/exporter/src/types/copied.rs | 4128 ----------------- frontend/exporter/src/types/def_id.rs | 101 +- frontend/exporter/src/types/hir.rs | 1141 +++++ frontend/exporter/src/types/index.rs | 11 - frontend/exporter/src/types/mir.rs | 168 +- frontend/exporter/src/types/mod.rs | 18 +- frontend/exporter/src/types/new/mod.rs | 2 + .../exporter/src/types/new/variant_infos.rs | 35 + frontend/exporter/src/types/replaced.rs | 23 - frontend/exporter/src/types/span.rs | 295 ++ frontend/exporter/src/types/thir.rs | 897 ++++ frontend/exporter/src/types/todo.rs | 21 - frontend/exporter/src/types/tokens.rs | 156 + frontend/exporter/src/types/ty.rs | 1435 ++++++ 15 files changed, 4238 insertions(+), 4196 deletions(-) delete mode 100644 frontend/exporter/src/types/copied.rs create mode 100644 frontend/exporter/src/types/hir.rs delete mode 100644 frontend/exporter/src/types/index.rs create mode 100644 frontend/exporter/src/types/new/variant_infos.rs delete mode 100644 frontend/exporter/src/types/replaced.rs create mode 100644 frontend/exporter/src/types/span.rs create mode 100644 frontend/exporter/src/types/thir.rs delete mode 100644 frontend/exporter/src/types/todo.rs create mode 100644 frontend/exporter/src/types/tokens.rs create mode 100644 frontend/exporter/src/types/ty.rs diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index bb1a81463..4da2ab29a 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -111,6 +111,9 @@ pub struct ConstantFieldExpr { /// two construct to one same `ConstantExpr` type. pub type ConstantExpr = Decorated; +// For ConstantKind we merge all the cases (Ty, Val, Unevaluated) into one +pub type ConstantKind = ConstantExpr; + #[cfg(feature = "rustc")] pub use self::rustc::*; #[cfg(feature = "rustc")] diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs deleted file mode 100644 index 07b43c6c8..000000000 --- a/frontend/exporter/src/types/copied.rs +++ /dev/null @@ -1,4128 +0,0 @@ -use crate::prelude::*; -use std::sync::Arc; - -#[cfg(feature = "rustc")] -use rustc_middle::ty; -#[cfg(feature = "rustc")] -use rustc_span::def_id::DefId as RDefId; - -impl std::hash::Hash for DefId { - fn hash(&self, state: &mut H) { - let DefId { - krate, - path, - index: _, // intentionally discarding index - is_local: _, // intentionally discarding is_local - } = self; - krate.hash(state); - path.hash(state); - } -} - -#[cfg(feature = "rustc")] -pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> DefId { - let tcx = s.base().tcx; - let def_path = tcx.def_path(def_id); - let krate = tcx.crate_name(def_path.krate); - DefId { - path: def_path.data.iter().map(|x| x.sinto(s)).collect(), - krate: format!("{}", krate), - index: ( - rustc_hir::def_id::CrateNum::as_u32(def_id.krate), - rustc_hir::def_id::DefIndex::as_u32(def_id.index), - ), - is_local: def_id.is_local(), - } -} - -#[cfg(feature = "rustc")] -impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { - fn sinto(&self, s: &S) -> DefId { - if let Some(def_id) = s.with_item_cache(*self, |cache| cache.def_id.clone()) { - return def_id; - } - let def_id = translate_def_id(s, *self); - s.with_item_cache(*self, |cache| cache.def_id = Some(def_id.clone())); - def_id - } -} - -#[cfg(feature = "rustc")] -impl From<&DefId> for rustc_span::def_id::DefId { - fn from<'tcx>(def_id: &DefId) -> Self { - let (krate, index) = def_id.index; - Self { - krate: rustc_hir::def_id::CrateNum::from_u32(krate), - index: rustc_hir::def_id::DefIndex::from_u32(index), - } - } -} - -// Impl to be able to use hax's `DefId` for many rustc queries. -#[cfg(feature = "rustc")] -impl rustc_middle::query::IntoQueryParam for &DefId { - fn into_query_param(self) -> RDefId { - self.into() - } -} - -#[cfg(feature = "rustc")] -impl std::convert::From for Path { - fn from(v: DefId) -> Vec { - std::iter::once(v.krate) - .chain(v.path.into_iter().filter_map(|item| match item.data { - DefPathItem::TypeNs(s) - | DefPathItem::ValueNs(s) - | DefPathItem::MacroNs(s) - | DefPathItem::LifetimeNs(s) => Some(s), - _ => None, - })) - .collect() - } -} - -pub type GlobalIdent = DefId; -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::def_id::LocalDefId { - fn sinto(&self, st: &S) -> DefId { - self.to_def_id().sinto(st) - } -} - -/// Reflects [`rustc_middle::thir::LogicalOp`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'a, S>, from: rustc_middle::thir::LogicalOp, state: S as _s)] -pub enum LogicalOp { - And, - Or, -} - -/// Reflects [`rustc_middle::thir::LintLevel`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'slt, S: UnderOwnerState<'slt> + HasThir<'slt>>, from: rustc_middle::thir::LintLevel, state: S as gstate)] -pub enum LintLevel { - Inherited, - Explicit(HirId), -} - -/// Reflects [`rustc_ast::ast::AttrStyle`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(, from: rustc_ast::ast::AttrStyle, state: S as _s)] -pub enum AttrStyle { - Outer, - Inner, -} - -/// Reflects [`rustc_ast::ast::Attribute`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::Attribute, state: S as gstate)] -pub struct Attribute { - pub kind: AttrKind, - #[map(x.as_usize())] - pub id: usize, - pub style: AttrStyle, - pub span: Span, -} - -/// Reflects [`rustc_attr::InlineAttr`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_attr::InlineAttr, state: S as _s)] -pub enum InlineAttr { - None, - Hint, - Always, - Never, -} - -/// Generic container for decorating items with a type, a span, -/// attributes and other meta-data. -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Decorated { - pub ty: Ty, - pub span: Span, - pub contents: Box, - pub hir_id: Option<(usize, usize)>, - pub attributes: Vec, -} - -/// Reflects [`rustc_middle::mir::UnOp`] -#[derive_group(Serializers)] -#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] -#[args(<'slt, S: UnderOwnerState<'slt>>, from: rustc_middle::mir::UnOp, state: S as _s)] -pub enum UnOp { - Not, - Neg, - PtrMetadata, -} - -/// Reflects [`rustc_middle::mir::BinOp`] -#[derive_group(Serializers)] -#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] -#[args(<'slt, S: UnderOwnerState<'slt>>, from: rustc_middle::mir::BinOp, state: S as _s)] -pub enum BinOp { - // We merge the checked and unchecked variants because in either case overflow is failure. - #[custom_arm( - rustc_middle::mir::BinOp::Add | rustc_middle::mir::BinOp::AddUnchecked => BinOp::Add, - )] - Add, - #[custom_arm( - rustc_middle::mir::BinOp::Sub | rustc_middle::mir::BinOp::SubUnchecked => BinOp::Sub, - )] - Sub, - #[custom_arm( - rustc_middle::mir::BinOp::Mul | rustc_middle::mir::BinOp::MulUnchecked => BinOp::Mul, - )] - Mul, - AddWithOverflow, - SubWithOverflow, - MulWithOverflow, - Div, - Rem, - BitXor, - BitAnd, - BitOr, - #[custom_arm( - rustc_middle::mir::BinOp::Shl | rustc_middle::mir::BinOp::ShlUnchecked => BinOp::Shl, - )] - Shl, - #[custom_arm( - rustc_middle::mir::BinOp::Shr | rustc_middle::mir::BinOp::ShrUnchecked => BinOp::Shr, - )] - Shr, - Eq, - Lt, - Le, - Ne, - Ge, - Gt, - Cmp, - Offset, -} - -pub type Pat = Decorated; -pub type Expr = Decorated; - -/// Reflects [`rustc_middle::mir::BinOp`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::middle::region::ScopeData, state: S as gstate)] -pub enum ScopeData { - Node, - CallSite, - Arguments, - Destruction, - IfThen, - Remainder(FirstStatementIndex), -} - -/// Reflects [`rustc_middle::mir::BinOp`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::middle::region::Scope, state: S as gstate)] -pub struct Scope { - pub id: ItemLocalId, - pub data: ScopeData, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::mir::Const<'tcx> { - fn sinto(&self, s: &S) -> ConstantExpr { - use rustc_middle::mir::Const; - let tcx = s.base().tcx; - match self { - Const::Val(const_value, ty) => { - const_value_to_constant_expr(s, *ty, *const_value, rustc_span::DUMMY_SP) - } - Const::Ty(_ty, c) => c.sinto(s), - Const::Unevaluated(ucv, _ty) => { - use crate::rustc_middle::query::Key; - let span = tcx - .def_ident_span(ucv.def) - .unwrap_or_else(|| ucv.def.default_span(tcx)); - if ucv.promoted.is_some() { - self.eval_constant(s) - .unwrap_or_else(|| { - supposely_unreachable_fatal!(s, "UnevalPromotedConstant"; {self, ucv}); - }) - .sinto(s) - } else { - match self.translate_uneval(s, ucv.shrink(), span) { - TranslateUnevalRes::EvaluatedConstant(c) => c.sinto(s), - TranslateUnevalRes::GlobalName(c) => c, - } - } - } - } - } -} - -// For ConstantKind we merge all the cases (Ty, Val, Unevaluated) into one -pub type ConstantKind = ConstantExpr; - -#[cfg(feature = "rustc")] -impl SInto for rustc_middle::mir::interpret::AllocId { - fn sinto(&self, _: &S) -> u64 { - self.0.get() - } -} - -/// Reflects [`rustc_hir::hir_id::HirId`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::hir_id::HirId, state: S as gstate)] -pub struct HirId { - owner: DefId, - local_id: usize, - // attrs: String -} -// TODO: If not working: See original - -#[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>> SInto for rustc_hir::hir_id::OwnerId { - fn sinto(&self, s: &S) -> DefId { - self.to_def_id().sinto(s) - } -} - -/// Reflects [`rustc_ast::ast::LitFloatType`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitFloatType, state: S as gstate)] -pub enum LitFloatType { - Suffixed(FloatTy), - Unsuffixed, -} -/// Reflects [`rustc_hir::Movability`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S>, from: rustc_hir::Movability, state: S as _s)] -pub enum Movability { - Static, - Movable, -} - -/// Reflects [`rustc_middle::infer::canonical::CanonicalTyVarKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalTyVarKind, state: S as gstate)] -pub enum CanonicalTyVarKind { - General(UniverseIndex), - Int, - Float, -} - -/// Reflects [`rustc_middle::ty::ParamTy`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ParamTy, state: S as gstate)] -pub struct ParamTy { - pub index: u32, - pub name: Symbol, -} - -/// Reflects [`rustc_middle::ty::ParamConst`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(, from: rustc_middle::ty::ParamConst, state: S as gstate)] -pub struct ParamConst { - pub index: u32, - pub name: Symbol, -} - -/// A predicate without `Self`, for use in `dyn Trait`. -/// -/// Reflects [`rustc_middle::ty::ExistentialPredicate`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ExistentialPredicate<'tcx>, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum ExistentialPredicate { - /// E.g. `From`. Note that this isn't `T: From` with a given `T`, this is just - /// `From`. Could be written `?: From`. - Trait(ExistentialTraitRef), - /// E.g. `Iterator::Item = u64`. Could be written `::Item = u64`. - Projection(ExistentialProjection), - /// E.g. `Send`. - AutoTrait(DefId), -} - -/// Reflects [`rustc_type_ir::ExistentialTraitRef`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_type_ir::ExistentialTraitRef>, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ExistentialTraitRef { - pub def_id: DefId, - pub args: Vec, -} - -/// Reflects [`rustc_type_ir::ExistentialProjection`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_type_ir::ExistentialProjection>, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ExistentialProjection { - pub def_id: DefId, - pub args: Vec, - pub term: Term, -} - -/// Reflects [`rustc_middle::ty::DynKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(, from: rustc_middle::ty::DynKind, state: S as _s)] -pub enum DynKind { - Dyn, - DynStar, -} - -/// Reflects [`rustc_middle::ty::BoundTyKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTyKind, state: S as gstate)] -pub enum BoundTyKind { - Anon, - Param(DefId, Symbol), -} - -/// Reflects [`rustc_middle::ty::BoundTy`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTy, state: S as gstate)] -pub struct BoundTy { - pub var: BoundVar, - pub kind: BoundTyKind, -} - -/// Reflects [`rustc_middle::ty::BoundRegionKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegionKind, state: S as gstate)] -pub enum BoundRegionKind { - BrAnon, - BrNamed(DefId, Symbol), - BrEnv, -} - -/// Reflects [`rustc_middle::ty::BoundRegion`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegion, state: S as gstate)] -pub struct BoundRegion { - pub var: BoundVar, - pub kind: BoundRegionKind, -} - -/// Reflects [`rustc_middle::ty::PlaceholderRegion`] -pub type PlaceholderRegion = Placeholder; -/// Reflects [`rustc_middle::ty::PlaceholderConst`] -pub type PlaceholderConst = Placeholder; -/// Reflects [`rustc_middle::ty::PlaceholderType`] -pub type PlaceholderType = Placeholder; - -/// Reflects [`rustc_middle::ty::Placeholder`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Placeholder { - pub universe: UniverseIndex, - pub bound: T, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> - for rustc_middle::ty::Placeholder -{ - fn sinto(&self, s: &S) -> Placeholder { - Placeholder { - universe: self.universe.sinto(s), - bound: self.bound.sinto(s), - } - } -} - -/// Reflects [`rustc_middle::infer::canonical::Canonical`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Canonical { - pub max_universe: UniverseIndex, - pub variables: Vec, - pub value: T, -} -/// Reflects [`rustc_middle::ty::CanonicalUserType`] -pub type CanonicalUserType = Canonical; - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> - for rustc_middle::infer::canonical::Canonical<'tcx, T> -{ - fn sinto(&self, s: &S) -> Canonical { - Canonical { - max_universe: self.max_universe.sinto(s), - variables: self.variables.iter().map(|v| v.kind.sinto(s)).collect(), - value: self.value.sinto(s), - } - } -} - -/// Reflects [`rustc_middle::infer::canonical::CanonicalVarKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalVarKind>, state: S as gstate)] -pub enum CanonicalVarInfo { - Ty(CanonicalTyVarKind), - PlaceholderTy(PlaceholderType), - Region(UniverseIndex), - PlaceholderRegion(PlaceholderRegion), - Const(UniverseIndex), - PlaceholderConst(PlaceholderConst), - Effect, -} - -/// Reflects [`rustc_middle::ty::UserSelfTy`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserSelfTy<'tcx>, state: S as gstate)] -pub struct UserSelfTy { - pub impl_def_id: DefId, - pub self_ty: Ty, -} - -/// Reflects [`rustc_middle::ty::UserArgs`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserArgs<'tcx>, state: S as gstate)] -pub struct UserArgs { - pub args: Vec, - pub user_self_ty: Option, -} - -/// Reflects [`rustc_middle::ty::UserType`]: this is currently -/// disabled, and everything is printed as debug in the -/// [`UserType::Todo`] variant. -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserType<'tcx>, state: S as _s)] -pub enum UserType { - // TODO: for now, we don't use user types at all. - // We disable it for now, since it cause the following to fail: - // - // pub const MY_VAL: u16 = 5; - // pub type Alias = MyStruct; // Using the literal 5, it goes through - // - // pub struct MyStruct {} - // - // impl MyStruct { - // pub const MY_CONST: u16 = VAL; - // } - // - // pub fn do_something() -> u32 { - // u32::from(Alias::MY_CONST) - // } - // - // In this case, we get a [rustc_middle::ty::ConstKind::Bound] in - // [do_something], which we are not able to translate. - // See: https://github.com/hacspec/hax/pull/209 - - // Ty(Ty), - // TypeOf(DefId, UserArgs), - #[todo] - Todo(String), -} - -/// Reflects [`rustc_hir::def::CtorKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_hir::def::CtorKind, state: S as _s)] -pub enum CtorKind { - Fn, - Const, -} - -/// Reflects [`rustc_hir::def::CtorOf`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_hir::def::CtorOf, state: S as _s)] -pub enum CtorOf { - Struct, - Variant, -} - -/// Reflects [`rustc_middle::ty::VariantDiscr`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::VariantDiscr, state: S as gstate)] -pub enum DiscriminantDefinition { - Explicit(DefId), - Relative(u32), -} - -/// Reflects [`rustc_middle::ty::util::Discr`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::util::Discr<'tcx>, state: S as gstate)] -pub struct DiscriminantValue { - pub val: u128, - pub ty: Ty, -} - -/// Reflects [`rustc_middle::ty::Visibility`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum Visibility { - Public, - Restricted(Id), -} - -#[cfg(feature = "rustc")] -impl, U> SInto> for rustc_middle::ty::Visibility { - fn sinto(&self, s: &S) -> Visibility { - use rustc_middle::ty::Visibility as T; - match self { - T::Public => Visibility::Public, - T::Restricted(id) => Visibility::Restricted(id.sinto(s)), - } - } -} - -/// Reflects [`rustc_middle::ty::FieldDef`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct FieldDef { - pub did: DefId, - /// Field definition of [tuple - /// structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types) - /// are anonymous, in that case `name` is [`None`]. - pub name: Option, - pub vis: Visibility, - pub ty: Ty, - pub span: Span, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::FieldDef { - fn sinto(&self, s: &S) -> FieldDef { - let tcx = s.base().tcx; - let ty = { - let generics = rustc_middle::ty::GenericArgs::identity_for_item(tcx, self.did); - self.ty(tcx, generics).sinto(s) - }; - let name = { - let name = self.name.sinto(s); - let is_user_provided = { - // SH: Note that the only way I found of checking if the user wrote the name or if it - // is just an integer generated by rustc is by checking if it is just made of - // numerals... - name.parse::().is_err() - }; - is_user_provided.then_some(name) - }; - - FieldDef { - did: self.did.sinto(s), - name, - vis: self.vis.sinto(s), - ty, - span: tcx.def_span(self.did).sinto(s), - } - } -} - -/// Reflects [`rustc_middle::ty::VariantDef`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct VariantDef { - pub def_id: DefId, - pub ctor: Option<(CtorKind, DefId)>, - pub name: Symbol, - pub discr_def: DiscriminantDefinition, - pub discr_val: DiscriminantValue, - /// The definitions of the fields on this variant. In case of - /// [tuple - /// structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types), - /// the fields are anonymous, otherwise fields are named. - pub fields: Vec, - /// Span of the definition of the variant - pub span: Span, -} - -#[cfg(feature = "rustc")] -impl VariantDef { - fn sfrom<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - def: &ty::VariantDef, - discr_val: ty::util::Discr<'tcx>, - ) -> Self { - VariantDef { - def_id: def.def_id.sinto(s), - ctor: def.ctor.sinto(s), - name: def.name.sinto(s), - discr_def: def.discr.sinto(s), - discr_val: discr_val.sinto(s), - fields: def.fields.raw.sinto(s), - span: s.base().tcx.def_span(def.def_id).sinto(s), - } - } -} - -/// Reflects [`rustc_middle::ty::EarlyParamRegion`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::EarlyParamRegion, state: S as gstate)] -pub struct EarlyParamRegion { - pub index: u32, - pub name: Symbol, -} - -/// Reflects [`rustc_middle::ty::LateParamRegion`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::LateParamRegion, state: S as gstate)] -pub struct LateParamRegion { - pub scope: DefId, - pub bound_region: BoundRegionKind, -} - -/// Reflects [`rustc_middle::ty::RegionKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::RegionKind<'tcx>, state: S as gstate)] -pub enum RegionKind { - ReEarlyParam(EarlyParamRegion), - ReBound(DebruijnIndex, BoundRegion), - ReLateParam(LateParamRegion), - ReStatic, - ReVar(RegionVid), - RePlaceholder(PlaceholderRegion), - ReErased, - ReError(ErrorGuaranteed), -} - -/// Reflects [`rustc_middle::ty::Region`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Region<'tcx>, state: S as s)] -pub struct Region { - #[value(self.kind().sinto(s))] - pub kind: RegionKind, -} - -/// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericArgKind<'tcx>, state: S as s)] -pub enum GenericArg { - Lifetime(Region), - Type(Ty), - Const(ConstantExpr), -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::GenericArg<'tcx> { - fn sinto(&self, s: &S) -> GenericArg { - self.unpack().sinto(s) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto> - for rustc_middle::ty::GenericArgsRef<'tcx> -{ - fn sinto(&self, s: &S) -> Vec { - self.iter().map(|v| v.unpack().sinto(s)).collect() - } -} - -/// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitIntType, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum LitIntType { - Signed(IntTy), - Unsigned(UintTy), - Unsuffixed, -} - -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::FruInfo<'tcx>, state: S as gstate)] -/// Field Record Update (FRU) informations, this reflects [`rustc_middle::thir::FruInfo`] -pub struct FruInfo { - /// The base, e.g. `Foo {x: 1, .. base}` - pub base: Expr, - pub field_types: Vec, -} - -/// A field expression: a field name along with a value -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct FieldExpr { - pub field: DefId, - pub value: Expr, -} - -/// A field pattern: a field name along with a pattern -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct FieldPat { - pub field: DefId, - pub pattern: Pat, -} - -/// Reflects [`rustc_middle::thir::AdtExpr`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct AdtExpr { - pub info: VariantInformations, - pub user_ty: Option, - pub fields: Vec, - pub base: Option, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr<'tcx> { - fn sinto(&self, s: &S) -> AdtExpr { - let variants = self.adt_def.variants(); - let variant: &rustc_middle::ty::VariantDef = &variants[self.variant_index]; - AdtExpr { - info: get_variant_information(&self.adt_def, self.variant_index, s), - fields: self - .fields - .iter() - .map(|f| FieldExpr { - field: variant.fields[f.name].did.sinto(s), - value: f.expr.sinto(s), - }) - .collect(), - base: self.base.sinto(s), - user_ty: self.user_ty.sinto(s), - } - } -} - -/// Reflects [`rustc_span::Loc`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Loc { - pub line: usize, - pub col: usize, -} - -/// Reflects [`rustc_span::hygiene::DesugaringKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_span::hygiene::DesugaringKind, state: S as _s)] -pub enum DesugaringKind { - CondTemporary, - QuestionMark, - TryBlock, - YeetExpr, - OpaqueTy, - Async, - Await, - ForLoop, - WhileLoop, - BoundModifier, -} - -/// Reflects [`rustc_span::hygiene::AstPass`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_span::hygiene::AstPass, state: S as _s)] -pub enum AstPass { - StdImports, - TestHarness, - ProcMacroHarness, -} - -/// Reflects [`rustc_span::hygiene::MacroKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_span::hygiene::MacroKind, state: S as _s)] -pub enum MacroKind { - Bang, - Attr, - Derive, -} - -/// Reflects [`rustc_span::hygiene::ExpnKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_span::hygiene::ExpnKind, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ExpnKind { - Root, - Macro(MacroKind, Symbol), - AstPass(AstPass), - Desugaring(DesugaringKind), -} - -/// Reflects [`rustc_span::edition::Edition`] -#[derive(AdtInto)] -#[args(, from: rustc_span::edition::Edition, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum Edition { - Edition2015, - Edition2018, - Edition2021, - Edition2024, -} - -/// Reflects [`rustc_span::hygiene::ExpnData`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_span::hygiene::ExpnData, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct ExpnData { - pub kind: ExpnKind, - // pub parent: Box, - pub call_site: Span, - pub def_site: Span, - #[map(x.as_ref().map(|x| x.clone().iter().map(|x|x.sinto(state)).collect()))] - pub allow_internal_unstable: Option>, - pub edition: Edition, - pub macro_def_id: Option, - pub parent_module: Option, - pub local_inner_macros: bool, -} - -/// Reflects [`rustc_span::Span`] -#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug, JsonSchema, Eq, Ord)] -pub struct Span { - pub lo: Loc, - pub hi: Loc, - pub filename: FileName, - /// Original rustc span; can be useful for reporting rustc - /// diagnostics (this is used in Charon) - #[cfg(feature = "rustc")] - #[serde(skip)] - pub rust_span_data: Option, - #[cfg(not(feature = "rustc"))] - #[serde(skip)] - pub rust_span_data: Option<()>, - // expn_backtrace: Vec, -} - -/// We need to define manual `impl`s of `Span`: we want to skip the -/// field `rust_span_data`. The derive macros from `bincode` don't -/// allow that, see https://github.com/bincode-org/bincode/issues/452. -const _: () = { - impl bincode::Encode for Span { - fn encode( - &self, - encoder: &mut E, - ) -> core::result::Result<(), bincode::error::EncodeError> { - bincode::Encode::encode(&self.lo, encoder)?; - bincode::Encode::encode(&self.hi, encoder)?; - bincode::Encode::encode(&self.filename, encoder)?; - Ok(()) - } - } - - impl bincode::Decode for Span { - fn decode( - decoder: &mut D, - ) -> core::result::Result { - Ok(Self { - lo: bincode::Decode::decode(decoder)?, - hi: bincode::Decode::decode(decoder)?, - filename: bincode::Decode::decode(decoder)?, - rust_span_data: None, - }) - } - } - - impl<'de> bincode::BorrowDecode<'de> for Span { - fn borrow_decode>( - decoder: &mut D, - ) -> core::result::Result { - Ok(Self { - lo: bincode::BorrowDecode::borrow_decode(decoder)?, - hi: bincode::BorrowDecode::borrow_decode(decoder)?, - filename: bincode::BorrowDecode::borrow_decode(decoder)?, - rust_span_data: None, - }) - } - } -}; - -const _: () = { - // `rust_span_data` is a metadata that should *not* be taken into - // account while hashing or comparing - - impl std::hash::Hash for Span { - fn hash(&self, state: &mut H) { - self.lo.hash(state); - self.hi.hash(state); - self.filename.hash(state); - } - } - impl PartialEq for Span { - fn eq(&self, other: &Self) -> bool { - self.lo == other.lo && self.hi == other.hi && self.filename == other.filename - } - } - - impl PartialOrd for Span { - fn partial_cmp(&self, other: &Self) -> Option { - Some( - self.lo.partial_cmp(&other.lo)?.then( - self.hi - .partial_cmp(&other.hi)? - .then(self.filename.partial_cmp(&other.filename)?), - ), - ) - } - } -}; - -#[cfg(feature = "rustc")] -impl From for Loc { - fn from(val: rustc_span::Loc) -> Self { - Loc { - line: val.line, - col: val.col_display, - } - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>> SInto for rustc_span::Span { - fn sinto(&self, s: &S) -> Span { - if let Some(span) = s.with_global_cache(|cache| cache.spans.get(self).cloned()) { - return span; - } - let span = translate_span(*self, s.base().tcx.sess); - s.with_global_cache(|cache| cache.spans.insert(*self, span.clone())); - span - } -} - -/// Reflects [`rustc_middle::thir::LocalVarId`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct LocalIdent { - pub name: String, - pub id: HirId, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir::LocalVarId { - fn sinto(&self, s: &S) -> LocalIdent { - LocalIdent { - name: s - .base() - .local_ctx - .borrow() - .vars - .get(self) - .s_unwrap(s) - .to_string(), - id: self.0.sinto(s), - } - } -} - -/// Reflects [`rustc_span::source_map::Spanned`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Spanned { - pub node: T, - pub span: Span, -} -#[cfg(feature = "rustc")] -impl<'s, S: UnderOwnerState<'s>, T: SInto, U> SInto> - for rustc_span::source_map::Spanned -{ - fn sinto<'a>(&self, s: &S) -> Spanned { - Spanned { - node: self.node.sinto(s), - span: self.span.sinto(s), - } - } -} - -impl<'tcx, S> SInto for PathBuf { - fn sinto(&self, _: &S) -> PathBuf { - self.clone() - } -} - -/// Reflects [`rustc_span::RealFileName`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[args(, from: rustc_span::RealFileName, state: S as _s)] -pub enum RealFileName { - LocalPath(PathBuf), - Remapped { - local_path: Option, - virtual_name: PathBuf, - }, -} - -#[cfg(feature = "rustc")] -impl SInto for rustc_data_structures::stable_hasher::Hash64 { - fn sinto(&self, _: &S) -> u64 { - self.as_u64() - } -} - -/// Reflects [`rustc_span::FileName`] -#[derive(AdtInto)] -#[args(, from: rustc_span::FileName, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum FileName { - Real(RealFileName), - QuoteExpansion(u64), - Anon(u64), - MacroExpansion(u64), - ProcMacroSourceCode(u64), - CliCrateAttr(u64), - Custom(String), - // #[map(FileName::DocTest(x.0.to_str().unwrap().into()))] - #[custom_arm(FROM_TYPE::DocTest(x, _) => TO_TYPE::DocTest(x.to_str().unwrap().into()),)] - DocTest(String), - InlineAsm(u64), -} - -impl FileName { - pub fn to_string(&self) -> String { - match self { - Self::Real(RealFileName::LocalPath(path)) - | Self::Real(RealFileName::Remapped { - local_path: Some(path), - .. - }) - | Self::Real(RealFileName::Remapped { - virtual_name: path, .. - }) => format!("{}", path.display()), - _ => format!("{:?}", self), - } - } - pub fn to_path(&self) -> Option<&std::path::Path> { - match self { - Self::Real(RealFileName::LocalPath(path)) - | Self::Real(RealFileName::Remapped { - local_path: Some(path), - .. - }) - | Self::Real(RealFileName::Remapped { - virtual_name: path, .. - }) => Some(path), - _ => None, - } - } -} - -/// Reflects partially [`rustc_middle::ty::InferTy`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S>, from: rustc_middle::ty::InferTy, state: S as gstate)] -pub enum InferTy { - #[custom_arm(FROM_TYPE::TyVar(..) => TO_TYPE::TyVar,)] - TyVar, /*TODO?*/ - #[custom_arm(FROM_TYPE::IntVar(..) => TO_TYPE::IntVar,)] - IntVar, /*TODO?*/ - #[custom_arm(FROM_TYPE::FloatVar(..) => TO_TYPE::FloatVar,)] - FloatVar, /*TODO?*/ - FreshTy(u32), - FreshIntTy(u32), - FreshFloatTy(u32), -} - -/// Reflects [`rustc_middle::thir::BlockSafety`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S>, from: rustc_middle::thir::BlockSafety, state: S as _s)] -pub enum BlockSafety { - Safe, - BuiltinUnsafe, - #[custom_arm(FROM_TYPE::ExplicitUnsafe{..} => BlockSafety::ExplicitUnsafe,)] - ExplicitUnsafe, -} - -/// Reflects [`rustc_middle::thir::Block`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Block, state: S as gstate)] -pub struct Block { - pub targeted_by_break: bool, - pub region_scope: Scope, - pub span: Span, - pub stmts: Vec, - pub expr: Option, - pub safety_mode: BlockSafety, -} - -/// Reflects [`rustc_ast::ast::BindingMode`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::ast::BindingMode, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct BindingMode { - #[value(self.0.sinto(s))] - pub by_ref: ByRef, - #[value(self.1.sinto(s))] - pub mutability: Mutability, -} - -/// Reflects [`rustc_ast::ast::ByRef`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::ast::ByRef, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ByRef { - Yes(Mutability), - No, -} - -/// Reflects [`rustc_middle::thir::Stmt`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Stmt<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Stmt { - pub kind: StmtKind, -} - -/// Reflects [`rustc_ast::token::Delimiter`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::token::Delimiter, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Delimiter { - Parenthesis, - Brace, - Bracket, - Invisible, -} - -/// Reflects [`rustc_ast::tokenstream::TokenTree`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::TokenTree, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum TokenTree { - Token(Token, Spacing), - Delimited(DelimSpan, DelimSpacing, Delimiter, TokenStream), -} - -/// Reflects [`rustc_ast::tokenstream::Spacing`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::Spacing, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Spacing { - Alone, - Joint, - JointHidden, -} - -/// Reflects [`rustc_ast::token::BinOpToken`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::token::BinOpToken, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum BinOpToken { - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - And, - Or, - Shl, - Shr, -} - -/// Reflects [`rustc_ast::token::TokenKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::TokenKind, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum TokenKind { - Eq, - Lt, - Le, - EqEq, - Ne, - Ge, - Gt, - AndAnd, - OrOr, - Not, - Tilde, - BinOp(BinOpToken), - BinOpEq(BinOpToken), - At, - Dot, - DotDot, - DotDotDot, - DotDotEq, - Comma, - Semi, - Colon, - RArrow, - LArrow, - FatArrow, - Pound, - Dollar, - Question, - SingleQuote, - OpenDelim(Delimiter), - CloseDelim(Delimiter), - // Literal(l: Lit), - Ident(Symbol, bool), - Lifetime(Symbol), - // Interpolated(n: Nonterminal), - // DocComment(k: CommentKind, ats: AttrStyle, s: Symbol), - Eof, - #[todo] - Todo(String), -} - -#[cfg(feature = "rustc")] -impl SInto for rustc_ast::token::IdentIsRaw { - fn sinto(&self, _s: &S) -> bool { - match self { - Self::Yes => true, - Self::No => false, - } - } -} - -/// Reflects [`rustc_ast::token::Token`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::Token, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Token { - pub kind: TokenKind, - pub span: Span, -} - -/// Reflects [`rustc_ast::ast::DelimArgs`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::ast::DelimArgs, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct DelimArgs { - pub dspan: DelimSpan, - pub delim: Delimiter, - pub tokens: TokenStream, -} - -/// Reflects [`rustc_ast::ast::MacCall`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::ast::MacCall, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct MacCall { - #[map(x.segments.iter().map(|rustc_ast::ast::PathSegment{ident, ..}| ident.as_str().into()).collect())] - pub path: Path, - pub args: DelimArgs, -} - -/// Reflects [`rustc_ast::tokenstream::TokenStream`] as a plain -/// string. If you need to reshape that into Rust tokens or construct, -/// please use, e.g., `syn`. -pub type TokenStream = String; -#[cfg(feature = "rustc")] -impl<'t, S> SInto for rustc_ast::tokenstream::TokenStream { - fn sinto(&self, _: &S) -> String { - rustc_ast_pretty::pprust::tts_to_string(self) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::BlockId { - fn sinto(&self, s: &S) -> Block { - s.thir().blocks[*self].sinto(s) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::StmtId { - fn sinto(&self, s: &S) -> Stmt { - s.thir().stmts[*self].sinto(s) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> { - fn sinto(&self, s: &S) -> Expr { - let (hir_id, attributes) = self.hir_id_and_attributes(s); - let hir_id = hir_id.map(|hir_id| hir_id.index()); - let unrolled = self.unroll_scope(s); - let rustc_middle::thir::Expr { span, kind, ty, .. } = unrolled; - let contents = match macro_invocation_of_span(span, s).map(ExprKind::MacroInvokation) { - Some(contents) => contents, - None => match kind { - // Introduce intermediate `Cast` from `T` to `U` when casting from a `#[repr(T)]` enum to `U` - rustc_middle::thir::ExprKind::Cast { source } => { - if let rustc_middle::ty::TyKind::Adt(adt, _) = s.thir().exprs[source].ty.kind() - { - let tcx = s.base().tcx; - let contents = kind.sinto(s); - let repr_type = if adt.is_enum() { - use crate::rustc_middle::ty::util::IntTypeExt; - adt.repr().discr_type().to_ty(tcx) - } else { - ty - }; - if repr_type == ty { - contents - } else { - ExprKind::Cast { - source: Decorated { - ty: repr_type.sinto(s), - span: span.sinto(s), - contents: Box::new(contents), - hir_id, - attributes: vec![], - }, - } - } - } else { - kind.sinto(s) - } - } - rustc_middle::thir::ExprKind::NonHirLiteral { lit, .. } => { - let cexpr: ConstantExpr = - (ConstantExprKind::Literal(scalar_int_to_constant_literal(s, lit, ty))) - .decorate(ty.sinto(s), span.sinto(s)); - return cexpr.into(); - } - rustc_middle::thir::ExprKind::ZstLiteral { .. } => match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def, _generics) => { - /* TODO: translate generics - let tcx = s.base().tcx; - let sig = &tcx.fn_sig(*def).instantiate(tcx, generics); - let ret: rustc_middle::ty::Ty = tcx.erase_late_bound_regions(sig.output()); - let inputs = sig.inputs(); - let indexes = inputs.skip_binder().iter().enumerate().map(|(i, _)| i); - let params = indexes.map(|i| inputs.map_bound(|tys| tys[i])); - let params: Vec = - params.map(|i| tcx.erase_late_bound_regions(i)).collect(); - */ - return Expr { - contents: Box::new(ExprKind::GlobalName { id: def.sinto(s) }), - span: self.span.sinto(s), - ty: ty.sinto(s), - hir_id, - attributes, - }; - } - _ => { - if ty.is_phantom_data() { - let rustc_middle::ty::Adt(def, _) = ty.kind() else { - supposely_unreachable_fatal!(s[span], "PhantomDataNotAdt"; {kind, ty}) - }; - let adt_def = AdtExpr { - info: get_variant_information( - def, - rustc_target::abi::FIRST_VARIANT, - s, - ), - user_ty: None, - base: None, - fields: vec![], - }; - return Expr { - contents: Box::new(ExprKind::Adt(adt_def)), - span: self.span.sinto(s), - ty: ty.sinto(s), - hir_id, - attributes, - }; - } else { - supposely_unreachable!( - s[span], - "ZstLiteral ty≠FnDef(...) or PhantomData"; - {kind, span, ty} - ); - kind.sinto(s) - } - } - }, - rustc_middle::thir::ExprKind::Field { - lhs, - variant_index, - name, - } => { - let lhs_ty = s.thir().exprs[lhs].ty.kind(); - let idx = variant_index.index(); - if idx != 0 { - let _ = supposely_unreachable!( - s[span], - "ExprKindFieldIdxNonZero"; { - kind, - span, - ty, - ty.kind() - } - ); - }; - match lhs_ty { - rustc_middle::ty::TyKind::Adt(adt_def, _generics) => { - let variant = adt_def.variant(variant_index); - ExprKind::Field { - field: variant.fields[name].did.sinto(s), - lhs: lhs.sinto(s), - } - } - rustc_middle::ty::TyKind::Tuple(..) => ExprKind::TupleField { - field: name.index(), - lhs: lhs.sinto(s), - }, - _ => supposely_unreachable_fatal!( - s[span], - "ExprKindFieldBadTy"; { - kind, - span, - ty.kind(), - lhs_ty - } - ), - } - } - _ => kind.sinto(s), - }, - }; - Decorated { - ty: ty.sinto(s), - span: span.sinto(s), - contents: Box::new(contents), - hir_id, - attributes, - } - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ExprId { - fn sinto(&self, s: &S) -> Expr { - s.thir().exprs[*self].sinto(s) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { - fn sinto(&self, s: &S) -> Pat { - let rustc_middle::thir::Pat { span, kind, ty } = self; - let contents = match kind { - rustc_middle::thir::PatKind::Leaf { subpatterns } => match ty.kind() { - rustc_middle::ty::TyKind::Adt(adt_def, args) => { - (rustc_middle::thir::PatKind::Variant { - adt_def: *adt_def, - args, - variant_index: rustc_target::abi::VariantIdx::from_usize(0), - subpatterns: subpatterns.clone(), - }) - .sinto(s) - } - rustc_middle::ty::TyKind::Tuple(..) => PatKind::Tuple { - subpatterns: subpatterns - .iter() - .map(|pat| pat.pattern.clone()) - .collect::>() - .sinto(s), - }, - _ => supposely_unreachable_fatal!( - s[span], - "PatLeafNonAdtTy"; - {ty.kind(), kind} - ), - }, - _ => kind.sinto(s), - }; - Decorated { - ty: ty.sinto(s), - span: span.sinto(s), - contents: Box::new(contents), - hir_id: None, - attributes: vec![], - } - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ArmId { - fn sinto(&self, s: &S) -> Arm { - s.thir().arms[*self].sinto(s) - } -} - -/// Reflects [`rustc_type_ir::IntTy`] -#[derive(AdtInto)] -#[args(, from: rustc_type_ir::IntTy, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum IntTy { - Isize, - I8, - I16, - I32, - I64, - I128, -} - -/// Reflects [`rustc_type_ir::FloatTy`] -#[derive(AdtInto)] -#[args(, from: rustc_type_ir::FloatTy, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum FloatTy { - F16, - F32, - F64, - F128, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S> SInto for rustc_ast::ast::FloatTy { - fn sinto(&self, _: &S) -> FloatTy { - use rustc_ast::ast::FloatTy as T; - match self { - T::F16 => FloatTy::F16, - T::F32 => FloatTy::F32, - T::F64 => FloatTy::F64, - T::F128 => FloatTy::F128, - } - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S> SInto for rustc_ast::ast::IntTy { - fn sinto(&self, _: &S) -> IntTy { - use rustc_ast::ast::IntTy as T; - match self { - T::Isize => IntTy::Isize, - T::I8 => IntTy::I8, - T::I16 => IntTy::I16, - T::I32 => IntTy::I32, - T::I64 => IntTy::I64, - T::I128 => IntTy::I128, - } - } -} -#[cfg(feature = "rustc")] -impl<'tcx, S> SInto for rustc_ast::ast::UintTy { - fn sinto(&self, _: &S) -> UintTy { - use rustc_ast::ast::UintTy as T; - match self { - T::Usize => UintTy::Usize, - T::U8 => UintTy::U8, - T::U16 => UintTy::U16, - T::U32 => UintTy::U32, - T::U64 => UintTy::U64, - T::U128 => UintTy::U128, - } - } -} - -/// Reflects [`rustc_type_ir::UintTy`] -#[derive(AdtInto)] -#[args(, from: rustc_type_ir::UintTy, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum UintTy { - Usize, - U8, - U16, - U32, - U64, - U128, -} - -impl ToString for IntTy { - fn to_string(&self) -> String { - use IntTy::*; - match self { - Isize => "isize".to_string(), - I8 => "i8".to_string(), - I16 => "i16".to_string(), - I32 => "i32".to_string(), - I64 => "i64".to_string(), - I128 => "i128".to_string(), - } - } -} - -impl ToString for UintTy { - fn to_string(&self) -> String { - use UintTy::*; - match self { - Usize => "usize".to_string(), - U8 => "u8".to_string(), - U16 => "u16".to_string(), - U32 => "u32".to_string(), - U64 => "u64".to_string(), - U128 => "u128".to_string(), - } - } -} - -/// Reflects [`rustc_middle::ty::TypeAndMut`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TypeAndMut<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct TypeAndMut { - pub ty: Box, - pub mutbl: Mutability, -} - -#[cfg(feature = "rustc")] -impl> SInto> for rustc_middle::ty::List { - fn sinto(&self, s: &S) -> Vec { - self.iter().map(|x| x.sinto(s)).collect() - } -} - -/// Reflects [`rustc_middle::ty::GenericParamDef`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericParamDef, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct GenericParamDef { - pub name: Symbol, - pub def_id: DefId, - pub index: u32, - pub pure_wrt_drop: bool, - #[value( - match self.kind { - ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, - ty::GenericParamDefKind::Type { has_default, synthetic } => GenericParamDefKind::Type { has_default, synthetic }, - ty::GenericParamDefKind::Const { has_default, is_host_effect, .. } => { - let ty = s.base().tcx.type_of(self.def_id).instantiate_identity().sinto(s); - GenericParamDefKind::Const { has_default, is_host_effect, ty } - }, - } - )] - pub kind: GenericParamDefKind, -} - -/// Reflects [`rustc_middle::ty::GenericParamDefKind`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum GenericParamDefKind { - Lifetime, - Type { - has_default: bool, - synthetic: bool, - }, - Const { - has_default: bool, - is_host_effect: bool, - ty: Ty, - }, -} - -/// Reflects [`rustc_middle::ty::Generics`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Generics, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct TyGenerics { - pub parent: Option, - pub parent_count: usize, - #[from(own_params)] - pub params: Vec, - // pub param_def_id_to_index: FxHashMap, - pub has_self: bool, - pub has_late_bound_regions: Option, -} - -/// This type merges the information from -/// `rustc_type_ir::AliasKind` and `rustc_middle::ty::AliasTy` -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Alias { - pub kind: AliasKind, - pub args: Vec, - pub def_id: DefId, -} - -/// Reflects [`rustc_middle::ty::AliasKind`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AliasKind { - /// The projection of a trait type: `>::Type<...>` - Projection { - /// The `impl Trait for Ty` in `Ty: Trait<..., Type = U>`. - impl_expr: ImplExpr, - /// The `Type` in `Ty: Trait<..., Type = U>`. - assoc_item: AssocItem, - }, - /// An associated type in an inherent impl. - Inherent, - /// An `impl Trait` opaque type. - Opaque { - /// The real type hidden inside this opaque type. - hidden_ty: Ty, - }, - /// A type alias that references opaque types. Likely to always be normalized away. - Weak, -} - -#[cfg(feature = "rustc")] -impl Alias { - #[tracing::instrument(level = "trace", skip(s))] - fn from<'tcx, S: UnderOwnerState<'tcx>>( - s: &S, - alias_kind: &rustc_type_ir::AliasTyKind, - alias_ty: &rustc_middle::ty::AliasTy<'tcx>, - ) -> TyKind { - let tcx = s.base().tcx; - use rustc_type_ir::AliasTyKind as RustAliasKind; - let kind = match alias_kind { - RustAliasKind::Projection => { - let trait_ref = alias_ty.trait_ref(tcx); - // In a case like: - // ``` - // impl Trait for Result - // where - // for<'a> &'a Result: IntoIterator, - // for<'a> <&'a Result as IntoIterator>::Item: Copy, - // {} - // ``` - // the `&'a Result as IntoIterator` trait ref has escaping bound variables - // yet we dont have a binder around (could even be several). Binding this correctly - // is therefore difficult. Since our trait resolution ignores lifetimes anyway, we - // just erase them. See also https://github.com/hacspec/hax/issues/747. - let trait_ref = crate::traits::erase_and_norm(tcx, s.param_env(), trait_ref); - AliasKind::Projection { - assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), - impl_expr: solve_trait(s, ty::Binder::dummy(trait_ref)), - } - } - RustAliasKind::Inherent => AliasKind::Inherent, - RustAliasKind::Opaque => { - // Reveal the underlying `impl Trait` type. - let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, alias_ty.args); - AliasKind::Opaque { - hidden_ty: ty.sinto(s), - } - } - RustAliasKind::Weak => AliasKind::Weak, - }; - TyKind::Alias(Alias { - kind, - args: alias_ty.args.sinto(s), - def_id: alias_ty.def_id.sinto(s), - }) - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { - fn sinto(&self, s: &S) -> Box { - Box::new(self.sinto(s)) - } -} - -/// Reflects [`rustc_middle::ty::Ty`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Ty { - pub kind: Arc, -} - -impl Ty { - pub fn kind(&self) -> &TyKind { - self.kind.as_ref() - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { - fn sinto(&self, s: &S) -> Ty { - if let Some(ty) = s.with_cache(|cache| cache.tys.get(self).cloned()) { - return ty; - } - let ty = Ty { - kind: Arc::new(self.kind().sinto(s)), - }; - s.with_cache(|cache| cache.tys.insert(*self, ty.clone())); - ty - } -} - -/// Reflects [`rustc_middle::ty::TyKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TyKind<'tcx>, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum TyKind { - Bool, - Char, - Int(IntTy), - Uint(UintTy), - Float(FloatTy), - - #[custom_arm( - rustc_middle::ty::TyKind::FnPtr(sig) => arrow_of_sig(sig, state), - rustc_middle::ty::TyKind::FnDef(def, generics) => { - let tcx = state.base().tcx; - arrow_of_sig(&tcx.fn_sig(*def).instantiate(tcx, generics), state) - }, - FROM_TYPE::Closure (_defid, generics) => { - let sig = generics.as_closure().sig(); - let sig = state.base().tcx.signature_unclosure(sig, rustc_hir::Safety::Safe); - arrow_of_sig(&sig, state) - }, - )] - /// Reflects [`rustc_middle::ty::TyKind::FnPtr`], [`rustc_middle::ty::TyKind::FnDef`] and [`rustc_middle::ty::TyKind::Closure`] - Arrow(Box), - - #[custom_arm( - rustc_middle::ty::TyKind::Adt(adt_def, generics) => { - let def_id = adt_def.did().sinto(state); - let generic_args: Vec = generics.sinto(state); - let trait_refs = solve_item_traits(state, adt_def.did(), generics, None); - TyKind::Adt { def_id, generic_args, trait_refs } - }, - )] - Adt { - /// Reflects [`rustc_middle::ty::TyKind::Adt`]'s substitutions - generic_args: Vec, - /// Predicates required by the type, e.g. `T: Sized` for `Option` or `B: 'a + ToOwned` - /// for `Cow<'a, B>`. - trait_refs: Vec, - def_id: DefId, - }, - Foreign(DefId), - Str, - Array(Box, #[map(Box::new(x.sinto(state)))] Box), - Slice(Box), - RawPtr(Box, Mutability), - Ref(Region, Box, Mutability), - Dynamic(Vec>, Region, DynKind), - Coroutine(DefId, Vec), - Never, - Tuple(Vec), - #[custom_arm( - rustc_middle::ty::TyKind::Alias(alias_kind, alias_ty) => { - Alias::from(state, alias_kind, alias_ty) - }, - )] - Alias(Alias), - Param(ParamTy), - Bound(DebruijnIndex, BoundTy), - Placeholder(PlaceholderType), - Infer(InferTy), - #[custom_arm(rustc_middle::ty::TyKind::Error(..) => TyKind::Error,)] - Error, - #[todo] - Todo(String), -} - -/// Reflects [`rustc_middle::thir::StmtKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::StmtKind<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum StmtKind { - Expr { - scope: Scope, - expr: Expr, - }, - Let { - remainder_scope: Scope, - init_scope: Scope, - pattern: Pat, - initializer: Option, - else_block: Option, - lint_level: LintLevel, - #[value(attribute_from_scope(gstate, init_scope).1)] - /// The attribute on this `let` binding - attributes: Vec, - }, -} - -/// Reflects [`rustc_middle::ty::Variance`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::ty::Variance, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum Variance { - Covariant, - Invariant, - Contravariant, - Bivariant, -} - -/// Reflects [`rustc_middle::ty::CanonicalUserTypeAnnotation`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CanonicalUserTypeAnnotation<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct CanonicalUserTypeAnnotation { - pub user_ty: CanonicalUserType, - pub span: Span, - pub inferred_ty: Ty, -} - -/// Reflects [`rustc_middle::thir::Ascription`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::Ascription<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Ascription { - pub annotation: CanonicalUserTypeAnnotation, - pub variance: Variance, -} - -/// Reflects [`rustc_hir::RangeEnd`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::RangeEnd, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum RangeEnd { - Included, - Excluded, -} - -/// Reflects [`rustc_middle::thir::PatRange`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRange<'tcx>, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct PatRange { - pub lo: PatRangeBoundary, - pub hi: PatRangeBoundary, - pub end: RangeEnd, -} - -/// Reflects [`rustc_middle::thir::PatRangeBoundary`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRangeBoundary<'tcx>, state: S as state)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum PatRangeBoundary { - Finite(ConstantExpr), - NegInfinity, - PosInfinity, -} - -/// Reflects [`rustc_middle::ty::AdtKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AdtKind, state: S as _s)] -pub enum AdtKind { - Struct, - Union, - Enum, -} - -// This comes from MIR -// TODO: add the generics and the predicates -/// Reflects [`rustc_middle::ty::AdtDef`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct AdtDef { - pub did: DefId, - pub adt_kind: AdtKind, - pub variants: IndexVec, - pub flags: AdtFlags, - pub repr: ReprOptions, -} - -/// Reflects [`rustc_middle::ty::ReprOptions`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ReprOptions, state: S as s)] -pub struct ReprOptions { - pub int: Option, - #[value({ - use crate::rustc_middle::ty::util::IntTypeExt; - self.discr_type().to_ty(s.base().tcx).sinto(s) - })] - pub typ: Ty, - pub align: Option, - pub pack: Option, - pub flags: ReprFlags, - pub field_shuffle_seed: u64, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtDef<'tcx> { - fn sinto(&self, s: &S) -> AdtDef { - let variants = self - .variants() - .iter_enumerated() - .map(|(variant_idx, variant)| { - let discr = if self.is_enum() { - self.discriminant_for_variant(s.base().tcx, variant_idx) - } else { - // Structs and unions have a single variant. - assert_eq!(variant_idx.index(), 0); - rustc_middle::ty::util::Discr { - val: 0, - ty: s.base().tcx.types.isize, - } - }; - VariantDef::sfrom(s, variant, discr) - }) - .collect(); - AdtDef { - did: self.did().sinto(s), - adt_kind: self.adt_kind().sinto(s), - variants, - flags: self.flags().sinto(s), - repr: self.repr().sinto(s), - } - } -} - -/// Describe the kind of a variant -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum VariantKind { - /// The variant is the only variant of a `struct` type - Struct { - /// Are the fields on this struct all named? - named: bool, - }, - /// The variant is the only variant of a `union` type - Union, - /// The variant is one of the many variants of a `enum` type - Enum { - /// The index of this variant in the `enum` - index: VariantIdx, - /// Are the fields on this struct all named? - named: bool, - }, -} - -/// Describe a variant -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct VariantInformations { - pub type_namespace: DefId, - - pub typ: DefId, - pub variant: DefId, - pub kind: VariantKind, -} - -/// Reflects [`rustc_middle::thir::PatKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::PatKind<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -#[append(rustc_middle::thir::PatKind::Leaf {..} => fatal!(gstate, "PatKind::Leaf: should never come up"),)] -pub enum PatKind { - Wild, - AscribeUserType { - ascription: Ascription, - subpattern: Pat, - }, - #[custom_arm( - rustc_middle::thir::PatKind::Binding {name, mode, var, ty, subpattern, is_primary} => { - let local_ctx = gstate.base().local_ctx; - local_ctx.borrow_mut().vars.insert(*var, name.to_string()); - PatKind::Binding { - mode: mode.sinto(gstate), - var: var.sinto(gstate), - ty: ty.sinto(gstate), - subpattern: subpattern.sinto(gstate), - is_primary: is_primary.sinto(gstate), - } - } - )] - Binding { - mode: BindingMode, - var: LocalIdent, // name VS var? TODO - ty: Ty, - subpattern: Option, - is_primary: bool, - }, - #[custom_arm( - FROM_TYPE::Variant {adt_def, variant_index, args, subpatterns} => { - let variants = adt_def.variants(); - let variant: &rustc_middle::ty::VariantDef = &variants[*variant_index]; - TO_TYPE::Variant { - info: get_variant_information(adt_def, *variant_index, gstate), - subpatterns: subpatterns - .iter() - .map(|f| FieldPat { - field: variant.fields[f.field].did.sinto(gstate), - pattern: f.pattern.sinto(gstate), - }) - .collect(), - args: args.sinto(gstate), - } - } - )] - Variant { - info: VariantInformations, - args: Vec, - subpatterns: Vec, - }, - #[disable_mapping] - Tuple { - subpatterns: Vec, - }, - Deref { - subpattern: Pat, - }, - DerefPattern { - subpattern: Pat, - }, - Constant { - value: ConstantExpr, - }, - InlineConstant { - def: DefId, - subpattern: Pat, - }, - Range(PatRange), - Slice { - prefix: Vec, - slice: Option, - suffix: Vec, - }, - Array { - prefix: Vec, - slice: Option, - suffix: Vec, - }, - Or { - pats: Vec, - }, - Never, - Error(ErrorGuaranteed), -} - -/// Reflects [`rustc_middle::thir::Arm`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Arm<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Arm { - pub pattern: Pat, - pub guard: Option, - pub body: Expr, - pub lint_level: LintLevel, - pub scope: Scope, - pub span: Span, - #[value(attribute_from_scope(gstate, scope).1)] - attributes: Vec, -} - -/// Reflects [`rustc_hir::Safety`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::Safety, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Safety { - Unsafe, - Safe, -} - -/// Reflects [`rustc_middle::ty::adjustment::PointerCoercion`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::ty::adjustment::PointerCoercion, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum PointerCoercion { - ReifyFnPointer, - UnsafeFnPointer, - ClosureFnPointer(Safety), - MutToConstPointer, - ArrayToPointer, - Unsize, -} - -/// Reflects [`rustc_middle::mir::BorrowKind`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::mir::BorrowKind, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum BorrowKind { - Shared, - Fake(FakeBorrowKind), - Mut { kind: MutBorrowKind }, -} - -/// Reflects [`rustc_middle::mir::MutBorrowKind`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::mir::MutBorrowKind, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum MutBorrowKind { - Default, - TwoPhaseBorrow, - ClosureCapture, -} - -/// Reflects [`rustc_middle::mir::FakeBorrowKind`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::mir::FakeBorrowKind, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum FakeBorrowKind { - /// A shared (deep) borrow. Data must be immutable and is aliasable. - Deep, - /// The immediately borrowed place must be immutable, but projections from - /// it don't need to be. This is used to prevent match guards from replacing - /// the scrutinee. For example, a fake borrow of `a.b` doesn't - /// conflict with a mutable borrow of `a.b.c`. - Shallow, -} - -/// Reflects [`rustc_ast::ast::StrStyle`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::ast::StrStyle, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum StrStyle { - Cooked, - Raw(u8), -} - -/// Reflects [`rustc_ast::ast::LitKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitKind, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum LitKind { - Str(Symbol, StrStyle), - ByteStr(Vec, StrStyle), - CStr(Vec, StrStyle), - Byte(u8), - Char(char), - Int( - #[serde(with = "serialize_int::unsigned")] - #[schemars(with = "String")] - u128, - LitIntType, - ), - Float(Symbol, LitFloatType), - Bool(bool), - Err(ErrorGuaranteed), -} - -#[cfg(feature = "rustc")] -impl SInto for rustc_data_structures::packed::Pu128 { - fn sinto(&self, _s: &S) -> u128 { - self.0 - } -} - -// FIXME: typo: invo**C**ation -#[allow(rustdoc::private_intra_doc_links)] -/// Describe a macro invocation, using -/// [`macro_invocation_of_raw_mac_invocation`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct MacroInvokation { - pub macro_ident: DefId, - pub argument: String, - pub span: Span, -} - -/// Reflects [`rustc_hir::ImplicitSelfKind`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::ImplicitSelfKind, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ImplicitSelfKind { - Imm, - Mut, - RefImm, - RefMut, - None, -} - -/// Reflects [`rustc_ast::token::CommentKind`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::token::CommentKind, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum CommentKind { - Line, - Block, -} - -/// Reflects [`rustc_ast::ast::AttrArgs`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrArgs, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AttrArgs { - Empty, - Delimited(DelimArgs), - - Eq(Span, AttrArgsEq), - // #[todo] - // Todo(String), -} - -/// Reflects [`rustc_ast::ast::AttrArgsEq`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrArgsEq, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AttrArgsEq { - Hir(MetaItemLit), - #[todo] - Ast(String), - // Ast(P), -} - -/// Reflects [`rustc_ast::ast::MetaItemLit`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MetaItemLit, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct MetaItemLit { - pub symbol: Symbol, - pub suffix: Option, - pub kind: LitKind, - pub span: Span, -} - -/// Reflects [`rustc_ast::ast::AttrItem`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrItem, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct AttrItem { - #[map(rustc_ast_pretty::pprust::path_to_string(x))] - pub path: String, - pub args: AttrArgs, - pub tokens: Option, -} - -#[cfg(feature = "rustc")] -impl SInto for rustc_ast::tokenstream::LazyAttrTokenStream { - fn sinto(&self, st: &S) -> String { - rustc_ast::tokenstream::TokenStream::new(self.to_attr_token_stream().to_token_trees()) - .sinto(st) - } -} - -/// Reflects [`rustc_ast::ast::NormalAttr`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::NormalAttr, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct NormalAttr { - pub item: AttrItem, - pub tokens: Option, -} - -/// Reflects [`rustc_ast::AttrKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::AttrKind, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AttrKind { - Normal(NormalAttr), - DocComment(CommentKind, Symbol), -} - -/// Reflects [`rustc_middle::thir::Param`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Param<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Param { - pub pat: Option, - pub ty: Ty, - pub ty_span: Option, - pub self_kind: Option, - pub hir_id: Option, - #[value(hir_id.map(|id| { - s.base().tcx.hir().attrs(id).sinto(s) - }).unwrap_or(vec![]))] - /// attributes on this parameter - pub attributes: Vec, -} - -/// Reflects [`rustc_middle::thir::ExprKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::ExprKind<'tcx>, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -#[append( - rustc_middle::thir::ExprKind::Scope {..} => { - fatal!(gstate, "Scope should have been eliminated at this point"); - }, - rustc_middle::thir::ExprKind::Field {..} => { - fatal!(gstate, "Field should have been eliminated at this point"); - }, - rustc_middle::thir::ExprKind::NonHirLiteral {..} => { - fatal!(gstate, "NonHirLiteral should have been eliminated at this point"); - }, -)] -pub enum ExprKind { - Box { - value: Expr, - }, - #[disable_mapping] - MacroInvokation(MacroInvokation), - /// Resugared macros calls. This is deprecated: see - /// . - If { - if_then_scope: Scope, - cond: Expr, - then: Expr, - else_opt: Option, - }, - #[map({ - let e = gstate.thir().exprs[*fun].unroll_scope(gstate); - let (generic_args, r#trait, bounds_impls); - // A function is any expression whose type is something callable - let fun = match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def_id, generics) => { - let (hir_id, attributes) = e.hir_id_and_attributes(gstate); - let hir_id = hir_id.map(|hir_id| hir_id.index()); - let contents = Box::new(ExprKind::GlobalName { - id: def_id.sinto(gstate) - }); - let mut translated_generics = generics.sinto(gstate); - let tcx = gstate.base().tcx; - r#trait = (|| { - let assoc_item = tcx.opt_associated_item(*def_id)?; - let impl_expr = self_clause_for_item(gstate, &assoc_item, generics)?; - let assoc_generics = tcx.generics_of(assoc_item.def_id); - let assoc_generics = translated_generics.drain(0..assoc_generics.parent_count).collect(); - Some((impl_expr, assoc_generics)) - })(); - generic_args = translated_generics; - bounds_impls = solve_item_traits(gstate, *def_id, generics, None); - Expr { - contents, - span: e.span.sinto(gstate), - ty: e.ty.sinto(gstate), - hir_id, - attributes, - } - }, - rustc_middle::ty::TyKind::FnPtr(..) => { - generic_args = vec![]; // A function pointer has no generics - bounds_impls = vec![]; // A function pointer has no bounds - r#trait = None; // A function pointer is not a method - e.sinto(gstate) - }, - ty_kind => supposely_unreachable_fatal!( - gstate[e.span], - "CallNotTyFnDef"; - {e, ty_kind} - ) - }; - TO_TYPE::Call { - ty: ty.sinto(gstate), - args: args.sinto(gstate), - generic_args, - from_hir_call: from_hir_call.sinto(gstate), - fn_span: fn_span.sinto(gstate), - bounds_impls, - r#trait, - fun, - } - })] - /// A call to a function or a method. - /// - /// Example: `f(0i8)`, where `f` has signature `fn f(t: T) -> ()`. - Call { - /// The type of the function, substitution applied. - /// - /// Example: for the call `f(0i8)`, this is `i8 -> ()`. - ty: Ty, - /// The function itself. This can be something else than a - /// name, e.g. a closure. - /// - /// Example: for the call `f(0i8)`, this is `f`. - fun: Expr, // TODO: can [ty] and [fun.ty] be different? - /// The arguments given to the function. - /// - /// Example: for the call `f(0i8)`, this is `[0i8]`. - args: Vec, - from_hir_call: bool, - fn_span: Span, - /// The generic arguments given to the function. - /// - /// Example: for the call `f(0i8)`, this is the type `i8`. - #[not_in_source] - generic_args: Vec, - /// The implementations for the bounds of the function. - /// - /// Example: for the call `f(0i8)`, this is two implementation - /// expressions, one for the explicit bound `i8: Clone` and - /// one for the implicit `i8: Sized`. - #[not_in_source] - bounds_impls: Vec, - /// `trait` is `None` if this is a function call or a method - /// to an inherent trait. If this is a method call from a - /// trait `Trait`, then it contains the concrete - /// implementation of `Trait` it is called on, and the generic - /// arguments that comes from the trait declaration. - /// - /// Example: `f(0i8)` is a function call, hence the field - /// `impl` is `None`. - /// - /// Example: - /// ```ignore - /// trait MyTrait { - /// fn meth(...) {...} - /// } - /// fn example_call>(x: SelfType) { - /// x.meth::(...) - /// } - /// ``` - /// Here, in the call `x.meth::(...)`, `r#trait` will - /// be `Some((..., [SelfType, TraitType, 12]))`, and `generic_args` - /// will be `[String]`. - #[not_in_source] - r#trait: Option<(ImplExpr, Vec)>, - }, - Deref { - arg: Expr, - }, - Binary { - op: BinOp, - lhs: Expr, - rhs: Expr, - }, - LogicalOp { - op: LogicalOp, - lhs: Expr, - rhs: Expr, - }, - Unary { - op: UnOp, - arg: Expr, - }, - Cast { - source: Expr, - }, - Use { - source: Expr, - }, // Use a lexpr to get a vexpr. - NeverToAny { - source: Expr, - }, - PointerCoercion { - cast: PointerCoercion, - source: Expr, - }, - Loop { - body: Expr, - }, - Match { - scrutinee: Expr, - arms: Vec, - }, - Let { - expr: Expr, - pat: Pat, - }, - Block { - #[serde(flatten)] - block: Block, - }, - Assign { - lhs: Expr, - rhs: Expr, - }, - AssignOp { - op: BinOp, - lhs: Expr, - rhs: Expr, - }, - #[disable_mapping] - Field { - field: DefId, - lhs: Expr, - }, - - #[disable_mapping] - TupleField { - field: usize, - lhs: Expr, - }, - Index { - lhs: Expr, - index: Expr, - }, - VarRef { - id: LocalIdent, - }, - #[disable_mapping] - ConstRef { - id: ParamConst, - }, - #[disable_mapping] - GlobalName { - id: GlobalIdent, - }, - UpvarRef { - closure_def_id: DefId, - var_hir_id: LocalIdent, - }, - Borrow { - borrow_kind: BorrowKind, - arg: Expr, - }, - AddressOf { - mutability: Mutability, - arg: Expr, - }, - Break { - label: Scope, - value: Option, - }, - Continue { - label: Scope, - }, - Return { - value: Option, - }, - ConstBlock { - did: DefId, - args: Vec, - }, - Repeat { - value: Expr, - count: ConstantExpr, - }, - Array { - fields: Vec, - }, - Tuple { - fields: Vec, - }, - Adt(AdtExpr), - PlaceTypeAscription { - source: Expr, - user_ty: Option, - }, - ValueTypeAscription { - source: Expr, - user_ty: Option, - }, - #[custom_arm(FROM_TYPE::Closure(e) => { - let (thir, expr_entrypoint) = get_thir(e.closure_id, gstate); - let s = &State::from_thir(gstate.base(), gstate.owner_id(), thir.clone()); - TO_TYPE::Closure { - params: thir.params.raw.sinto(s), - body: expr_entrypoint.sinto(s), - upvars: e.upvars.sinto(gstate), - movability: e.movability.sinto(gstate) - } - }, - )] - Closure { - params: Vec, - body: Expr, - upvars: Vec, - movability: Option, - }, - Literal { - lit: Spanned, - neg: bool, // TODO - }, - //zero space type - // This is basically used for functions! e.g. `::from` - ZstLiteral { - user_ty: Option, - }, - NamedConst { - def_id: GlobalIdent, - args: Vec, - user_ty: Option, - #[not_in_source] - #[value({ - let tcx = gstate.base().tcx; - tcx.opt_associated_item(*def_id).as_ref().and_then(|assoc| { - self_clause_for_item(gstate, assoc, args) - }) - })] - r#impl: Option, - }, - ConstParam { - param: ParamConst, - def_id: GlobalIdent, - }, - StaticRef { - alloc_id: u64, - ty: Ty, - def_id: GlobalIdent, - }, - Yield { - value: Expr, - }, - #[todo] - Todo(String), -} - -#[cfg(feature = "rustc")] -pub trait ExprKindExt<'tcx> { - fn hir_id_and_attributes>( - &self, - s: &S, - ) -> (Option, Vec); - fn unroll_scope + HasThir<'tcx>>( - &self, - s: &S, - ) -> rustc_middle::thir::Expr<'tcx>; -} - -#[cfg(feature = "rustc")] -impl<'tcx> ExprKindExt<'tcx> for rustc_middle::thir::Expr<'tcx> { - fn hir_id_and_attributes>( - &self, - s: &S, - ) -> (Option, Vec) { - match &self.kind { - rustc_middle::thir::ExprKind::Scope { - region_scope: scope, - .. - } => attribute_from_scope(s, scope), - _ => (None, vec![]), - } - } - fn unroll_scope + HasThir<'tcx>>( - &self, - s: &S, - ) -> rustc_middle::thir::Expr<'tcx> { - // TODO: when we see a loop, we should lookup its label! label is actually a scope id - // we remove scopes here, whence the TODO - match self.kind { - rustc_middle::thir::ExprKind::Scope { value, .. } => { - s.thir().exprs[value].unroll_scope(s) - } - _ => self.clone(), - } - } -} - -/// Reflects [`rustc_middle::ty::FnSig`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::FnSig<'tcx>, state: S as s)] -pub struct TyFnSig { - #[value(self.inputs().sinto(s))] - pub inputs: Vec, - #[value(self.output().sinto(s))] - pub output: Ty, - pub c_variadic: bool, - pub safety: Safety, - pub abi: Abi, -} - -/// Reflects [`rustc_middle::ty::PolyFnSig`] -pub type PolyFnSig = Binder; - -/// Function definition -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct FnDef { - pub header: FnHeader, - pub params: Vec, - pub ret: Ty, - pub body: Body, - pub sig_span: Span, -} - -/// Reflects [`rustc_hir::FnDecl`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnDecl<'tcx>, state: S as tcx)] -pub struct FnDecl { - pub inputs: Vec, - pub output: FnRetTy, - pub c_variadic: bool, - pub implicit_self: ImplicitSelfKind, - pub lifetime_elision_allowed: bool, -} - -/// Reflects [`rustc_hir::FnSig`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnSig<'tcx>, state: S as tcx)] -pub struct FnSig { - pub header: FnHeader, - pub decl: FnDecl, - pub span: Span, -} - -/// Reflects [`rustc_hir::FnHeader`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::FnHeader, state: S as tcx)] -pub struct FnHeader { - pub safety: Safety, - pub constness: Constness, - pub asyncness: IsAsync, - pub abi: Abi, -} - -pub type ThirBody = Expr; - -#[cfg(feature = "rustc")] -impl<'x: 'tcx, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { - fn sinto(self: &rustc_hir::Ty<'x>, s: &S) -> Ty { - // **Important:** - // We need a local id here, and we get it from the owner id, which must - // be local. It is safe to do so, because if we have access to a HIR ty, - // it necessarily means we are exploring a local item (we don't have - // access to the HIR of external objects, only their MIR). - let ctx = - rustc_hir_analysis::collect::ItemCtxt::new(s.base().tcx, s.owner_id().expect_local()); - ctx.lower_ty(self).sinto(s) - } -} - -/// Reflects [`rustc_hir::UseKind`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::UseKind, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum UseKind { - Single, - Glob, - ListStem, -} - -/// Reflects [`rustc_hir::IsAuto`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::IsAuto, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum IsAuto { - Yes, - No, -} - -/// Reflects [`rustc_hir::Defaultness`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::Defaultness, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum Defaultness { - Default { has_value: bool }, - Final, -} - -/// Reflects [`rustc_hir::ImplPolarity`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ImplPolarity, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ImplPolarity { - Positive, - Negative(Span), -} - -/// Reflects [`rustc_hir::Constness`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::Constness, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum Constness { - Const, - NotConst, -} - -/// Reflects [`rustc_hir::Generics`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Generics<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Generics { - pub params: Vec>, - #[value(region_bounds_at_current_owner(tcx))] - pub bounds: GenericBounds, - pub has_where_clause_predicates: bool, - pub where_clause_span: Span, - pub span: Span, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> - for rustc_hir::ImplItemRef -{ - fn sinto(&self, s: &S) -> ImplItem { - let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; - let impl_item = tcx.hir().impl_item(self.id); - let s = with_owner_id(s.base(), (), (), impl_item.owner_id.to_def_id()); - impl_item.sinto(&s) - } -} - -/// Reflects [`rustc_hir::ParamName`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ParamName { - Plain(LocalIdent), - Fresh, - Error, -} - -/// Reflects [`rustc_hir::LifetimeParamKind`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::LifetimeParamKind, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum LifetimeParamKind { - Explicit, - Elided(MissingLifetimeKind), - Error, -} - -/// Reflects [`rustc_hir::AnonConst`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AnonConst, state: S as s)] -pub struct AnonConst { - pub hir_id: HirId, - pub def_id: GlobalIdent, - #[map({ - body_from_id::(*x, &with_owner_id(s.base(), (), (), hir_id.owner.to_def_id())) - })] - pub body: Body, -} - -/// Reflects [`rustc_hir::ConstArg`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArg<'tcx>, state: S as s)] -pub struct ConstArg { - pub hir_id: HirId, - pub kind: ConstArgKind, - pub is_desugared_from_effects: bool, -} - -/// Reflects [`rustc_hir::ConstArgKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArgKind<'tcx>, state: S as s)] -pub enum ConstArgKind { - Path(QPath), - Anon(AnonConst), -} - -/// Reflects [`rustc_hir::GenericParamKind`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParamKind<'tcx>, state: S as tcx)] -pub enum GenericParamKind { - Lifetime { - kind: LifetimeParamKind, - }, - Type { - /// On use site, Rust always give us all the generic - /// parameters, no matter the defaultness. This information is - /// thus not so useful. At the same time, as discussed in - /// https://github.com/hacspec/hax/issues/310, extracting this - /// default type causes failures when querying Rust for trait - /// resolution. We thus decided to disable this feature. If - /// this default type information is useful to you, please - /// open an issue on https://github.com/hacspec/hax. - #[map(x.map(|_ty| ()))] - default: Option<()>, - synthetic: bool, - }, - Const { - ty: Ty, - default: Option>, - }, -} - -/// Reflects [`rustc_hir::GenericParam`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParam<'tcx>, state: S as s)] -pub struct GenericParam { - pub hir_id: HirId, - pub def_id: GlobalIdent, - #[map(match x { - rustc_hir::ParamName::Plain(loc_ident) => - ParamName::Plain(LocalIdent { - name: loc_ident.as_str().to_string(), - id: self.hir_id.sinto(s) - }), - rustc_hir::ParamName::Fresh => - ParamName::Fresh, - rustc_hir::ParamName::Error => - ParamName::Error, - })] - pub name: ParamName, - pub span: Span, - pub pure_wrt_drop: bool, - pub kind: GenericParamKind, - pub colon_span: Option, - #[value(s.base().tcx.hir().attrs(*hir_id).sinto(s))] - attributes: Vec, -} - -/// Reflects [`rustc_hir::ImplItem`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItem<'tcx>, state: S as s)] -pub struct ImplItem { - pub ident: Ident, - pub owner_id: DefId, - pub generics: Generics, - pub kind: ImplItemKind, - pub defaultness: Defaultness, - pub span: Span, - pub vis_span: Span, - #[value(ItemAttributes::from_owner_id(s, *owner_id))] - /// the attributes on this impl item - pub attributes: ItemAttributes, -} - -/// Reflects [`rustc_hir::ImplItemKind`], inlining the body of the items. -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItemKind<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ImplItemKind { - Const(Ty, Body), - #[custom_arm(rustc_hir::ImplItemKind::Fn(sig, body) => { - ImplItemKind::Fn(make_fn_def::(sig, body, s)) - },)] - Fn(FnDef), - #[custom_arm(rustc_hir::ImplItemKind::Type(t) => { - let parent_bounds = { - let (tcx, owner_id) = (s.base().tcx, s.owner_id()); - let assoc_item = tcx.opt_associated_item(owner_id).unwrap(); - let impl_did = assoc_item.impl_container(tcx).unwrap(); - tcx.explicit_item_bounds(assoc_item.trait_item_def_id.unwrap()) - .skip_binder() // Skips an `EarlyBinder`, likely for GATs - .iter() - .copied() - .filter_map(|(clause, span)| super_clause_to_clause_and_impl_expr(s, impl_did, clause, span)) - .collect::>() - }; - ImplItemKind::Type { - ty: t.sinto(s), - parent_bounds - } - },)] - /// An associated type with its parent bounds inlined. - Type { - ty: Ty, - parent_bounds: Vec<(Clause, ImplExpr, Span)>, - }, -} - -/// Reflects [`rustc_hir::AssocItemKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AssocItemKind, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum AssocItemKind { - Const, - Fn { has_self: bool }, - Type, -} - -/// Reflects [`rustc_hir::Impl`]. -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Impl<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Impl { - pub safety: Safety, - pub polarity: ImplPolarity, - pub defaultness: Defaultness, - pub defaultness_span: Option, - pub generics: Generics, - #[map({ - s.base().tcx - .impl_trait_ref(s.owner_id()) - .map(|trait_ref| trait_ref.instantiate_identity()) - .sinto(s) - })] - pub of_trait: Option, - pub self_ty: Ty, - pub items: Vec>, - #[value({ - let (tcx, owner_id) = (s.base().tcx, s.owner_id()); - let trait_did = tcx.trait_id_of_impl(owner_id); - if let Some(trait_did) = trait_did { - tcx.explicit_super_predicates_of(trait_did) - .predicates - .iter() - .copied() - .filter_map(|(clause, span)| super_clause_to_clause_and_impl_expr(s, owner_id, clause, span)) - .collect::>() - } else { - vec![] - } - })] - /// The clauses and impl expressions corresponding to the impl's - /// trait (if not inherent) super bounds (if any). - pub parent_bounds: Vec<(Clause, ImplExpr, Span)>, -} - -/// Reflects [`rustc_hir::IsAsync`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::IsAsync, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum IsAsync { - Async(Span), - NotAsync, -} - -/// Reflects [`rustc_hir::FnRetTy`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnRetTy<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum FnRetTy { - DefaultReturn(Span), - Return(Ty), -} - -/// Reflects [`rustc_hir::VariantData`] -#[derive_group(Serializers)] -#[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::VariantData<'tcx>, state: S as tcx)] -pub enum VariantData { - Struct { - fields: Vec, - recovered: bool, - }, - Tuple(Vec, HirId, GlobalIdent), - Unit(HirId, GlobalIdent), -} - -#[cfg(feature = "rustc")] -impl SInto for rustc_ast::ast::Recovered { - fn sinto(&self, _s: &S) -> bool { - match self { - Self::Yes(_) => true, - Self::No => false, - } - } -} - -/// Reflects [`rustc_hir::FieldDef`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FieldDef<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct HirFieldDef { - pub span: Span, - pub vis_span: Span, - pub ident: Ident, - pub hir_id: HirId, - pub def_id: GlobalIdent, - pub ty: Ty, - #[value(s.base().tcx.hir().attrs(*hir_id).sinto(s))] - attributes: Vec, -} - -/// Reflects [`rustc_hir::Variant`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Variant<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Variant { - pub ident: Ident, - pub hir_id: HirId, - pub def_id: GlobalIdent, - #[map(x.sinto(&with_owner_id(s.base(), (), (), self.def_id.to_def_id())))] - pub data: VariantData, - pub disr_expr: Option>, - #[value({ - let tcx = s.base().tcx; - let variant = tcx - .adt_def(s.owner_id()) - .variants() - .into_iter() - .find(|v| v.def_id == self.def_id.into()).unwrap(); - variant.discr.sinto(s) - })] - pub discr: DiscriminantDefinition, - pub span: Span, - #[value(s.base().tcx.hir().attrs(*hir_id).sinto(s))] - pub attributes: Vec, -} - -/// Reflects [`rustc_hir::UsePath`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::UsePath<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct UsePath { - pub span: Span, - #[map(x.iter().map(|res| res.sinto(s)).collect())] - pub res: Vec, - pub segments: Vec, - #[value(self.segments.iter().last().and_then(|segment| { - match s.base().tcx.hir_node_by_def_id(segment.hir_id.owner.def_id) { - rustc_hir::Node::Item(rustc_hir::Item { - ident, - kind: rustc_hir::ItemKind::Use(_, _), - .. - }) if ident.name.to_ident_string() != "" => Some(ident.name.to_ident_string()), - _ => None, - } - }))] - pub rename: Option, -} - -/// Reflects [`rustc_hir::def::Res`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::Res, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum Res { - Def(DefKind, DefId), - PrimTy(PrimTy), - SelfTyParam { - trait_: DefId, - }, - SelfTyAlias { - alias_to: DefId, - forbid_generic: bool, - is_trait_impl: bool, - }, - SelfCtor(DefId), - Local(HirId), - ToolMod, - NonMacroAttr(NonMacroAttrKind), - Err, -} - -/// Reflects [`rustc_hir::PrimTy`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::PrimTy, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum PrimTy { - Int(IntTy), - Uint(UintTy), - Float(FloatTy), - Str, - Bool, - Char, -} - -/// Reflects [`rustc_hir::def::NonMacroAttrKind`] -#[derive(AdtInto)] -#[args(, from: rustc_hir::def::NonMacroAttrKind, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum NonMacroAttrKind { - Builtin(Symbol), - Tool, - DeriveHelper, - DeriveHelperCompat, -} - -/// Reflects [`rustc_hir::PathSegment`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::PathSegment<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct PathSegment { - pub ident: Ident, - pub hir_id: HirId, - pub res: Res, - #[map(args.map(|args| args.sinto(s)))] - pub args: Option, - pub infer_args: bool, -} - -/// Reflects [`rustc_hir::ItemKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ItemKind<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub enum ItemKind { - #[disable_mapping] - MacroInvokation(MacroInvokation), - ExternCrate(Option), - Use(UsePath, UseKind), - Static(Ty, Mutability, Body), - Const(Ty, Generics, Body), - #[custom_arm( - rustc_hir::ItemKind::Fn(sig, generics, body) => { - ItemKind::Fn(generics.sinto(s), make_fn_def::(sig, body, s)) - } - )] - Fn(Generics, FnDef), - Macro(MacroDef, MacroKind), - Mod(Vec>), - ForeignMod { - abi: Abi, - items: Vec>, - }, - GlobalAsm(InlineAsm), - TyAlias( - #[map({ - let s = &State { - base: Base {ty_alias_mode: true, ..s.base()}, - owner_id: s.owner_id(), - thir: (), - mir: (), - binder: (), - }; - x.sinto(s) - })] - Ty, - Generics, - ), - OpaqueTy(OpaqueTy), - Enum( - EnumDef, - Generics, - #[value({ - let tcx = s.base().tcx; - tcx.repr_options_of_def(s.owner_id().expect_local()).sinto(s) - })] - ReprOptions, - ), - Struct(VariantData, Generics), - Union(VariantData, Generics), - Trait( - IsAuto, - Safety, - Generics, - GenericBounds, - Vec>, - ), - TraitAlias(Generics, GenericBounds), - Impl(Impl), -} - -pub type EnumDef = Vec>; - -/// Reflects [`rustc_hir::TraitItemKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItemKind<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, JsonSchema)] -#[derive_group(Serializers)] -pub enum TraitItemKind { - Const(Ty, Option), - #[custom_arm( - rustc_hir::TraitItemKind::Fn(sig, rustc_hir::TraitFn::Required(id)) => { - TraitItemKind::RequiredFn(sig.sinto(tcx), id.sinto(tcx)) - } - )] - /// Reflects a required [`rustc_hir::TraitItemKind::Fn`] - RequiredFn(FnSig, Vec), - #[custom_arm( - rustc_hir::TraitItemKind::Fn(sig, rustc_hir::TraitFn::Provided(body)) => { - TraitItemKind::ProvidedFn(sig.sinto(tcx), make_fn_def::(sig, body, tcx)) - } - )] - /// Reflects a provided [`rustc_hir::TraitItemKind::Fn`] - ProvidedFn(FnSig, FnDef), - #[custom_arm( - rustc_hir::TraitItemKind::Type(b, ty) => { - TraitItemKind::Type(b.sinto(tcx), ty.map(|t| t.sinto(tcx))) - } - )] - Type(GenericBounds, Option), -} - -/// Reflects [`rustc_hir::TraitItem`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItem<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct TraitItem { - pub ident: Ident, - pub owner_id: DefId, - pub generics: Generics, - pub kind: TraitItemKind, - pub span: Span, - pub defaultness: Defaultness, - #[value(ItemAttributes::from_owner_id(s, *owner_id))] - /// The attributes on this trait item - pub attributes: ItemAttributes, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> - for rustc_hir::EnumDef<'tcx> -{ - fn sinto(&self, s: &S) -> EnumDef { - self.variants.iter().map(|v| v.sinto(s)).collect() - } -} - -#[cfg(feature = "rustc")] -impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> - for rustc_hir::TraitItemRef -{ - fn sinto(&self, s: &S) -> TraitItem { - let s = with_owner_id(s.base(), (), (), self.id.owner_id.to_def_id()); - let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; - tcx.hir().trait_item(self.id).sinto(&s) - } -} - -#[cfg(feature = "rustc")] -impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> - for rustc_hir::Mod<'a> -{ - fn sinto(&self, s: &S) -> Vec> { - inline_macro_invocations(self.item_ids.iter().copied(), s) - // .iter() - // .map(|item_id| item_id.sinto(s)) - // .collect() - } -} - -/// Reflects [`rustc_hir::ForeignItemKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItemKind<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, JsonSchema)] -#[derive_group(Serializers)] -pub enum ForeignItemKind { - Fn(FnDecl, Vec, Generics, Safety), - Static(Ty, Mutability, Safety), - Type, -} - -/// Reflects [`rustc_hir::ForeignItem`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItem<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct ForeignItem { - pub ident: Ident, - pub kind: ForeignItemKind, - pub owner_id: DefId, - pub span: Span, - pub vis_span: Span, -} - -#[cfg(feature = "rustc")] -impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> - for rustc_hir::ForeignItemRef -{ - fn sinto(&self, s: &S) -> ForeignItem { - let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; - tcx.hir().foreign_item(self.id).sinto(s) - } -} - -/// Reflects [`rustc_hir::OpaqueTy`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::OpaqueTy<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct OpaqueTy { - pub generics: Generics, - pub bounds: GenericBounds, - pub origin: OpaqueTyOrigin, - pub in_trait: bool, -} - -/// Reflects [`rustc_middle::ty::TraitRef`] -#[derive_group(Serializers)] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitRef<'tcx>, state: S as tcx)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct TraitRef { - pub def_id: DefId, - #[from(args)] - /// reflects the `args` field - pub generic_args: Vec, -} - -/// Reflects [`rustc_middle::ty::TraitPredicate`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitPredicate<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct TraitPredicate { - pub trait_ref: TraitRef, - #[map(*x == rustc_middle::ty::PredicatePolarity::Positive)] - #[from(polarity)] - pub is_positive: bool, -} - -/// Reflects [`rustc_middle::ty::OutlivesPredicate`] as a named struct -/// instead of a tuple struct. This is because the script converting -/// JSONSchema types to OCaml doesn't support tuple structs, and this -/// is the only tuple struct in the whole AST. -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct OutlivesPredicate { - pub lhs: T, - pub rhs: Region, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, T, U> SInto> - for rustc_middle::ty::OutlivesPredicate<'tcx, T> -where - T: SInto, -{ - fn sinto(&self, s: &S) -> OutlivesPredicate where { - OutlivesPredicate { - lhs: self.0.sinto(s), - rhs: self.1.sinto(s), - } - } -} - -/// Reflects [`rustc_middle::ty::RegionOutlivesPredicate`] -pub type RegionOutlivesPredicate = OutlivesPredicate; -/// Reflects [`rustc_middle::ty::TypeOutlivesPredicate`] -pub type TypeOutlivesPredicate = OutlivesPredicate; - -/// Reflects [`rustc_middle::ty::Term`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Term { - Ty(Ty), - Const(ConstantExpr), -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Term<'tcx> { - fn sinto(&self, s: &S) -> Term { - use rustc_middle::ty::TermKind; - match self.unpack() { - TermKind::Ty(ty) => Term::Ty(ty.sinto(s)), - TermKind::Const(c) => Term::Const(c.sinto(s)), - } - } -} - -/// Expresses a constraints over an associated type. -/// -/// For instance: -/// ```text -/// fn f>(...) -/// ^^^^^^^^^^ -/// ``` -/// (provided the trait `Foo` has an associated type `S`). -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ProjectionPredicate { - /// The `impl Trait for Ty` in `Ty: Trait<..., Type = U>`. - pub impl_expr: ImplExpr, - /// The `Type` in `Ty: Trait<..., Type = U>`. - pub assoc_item: AssocItem, - /// The type `U` in `Ty: Trait<..., Type = U>`. - pub ty: Ty, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderBinderState<'tcx>> SInto - for rustc_middle::ty::ProjectionPredicate<'tcx> -{ - fn sinto(&self, s: &S) -> ProjectionPredicate { - let tcx = s.base().tcx; - let alias_ty = &self.projection_term.expect_ty(tcx); - let poly_trait_ref = s.binder().rebind(alias_ty.trait_ref(tcx)); - let Term::Ty(ty) = self.term.sinto(s) else { - unreachable!() - }; - ProjectionPredicate { - impl_expr: solve_trait(s, poly_trait_ref), - assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), - ty, - } - } -} - -/// Reflects [`rustc_middle::ty::ClauseKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderBinderState<'tcx>>, from: rustc_middle::ty::ClauseKind<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum ClauseKind { - Trait(TraitPredicate), - RegionOutlives(RegionOutlivesPredicate), - TypeOutlives(TypeOutlivesPredicate), - Projection(ProjectionPredicate), - ConstArgHasType(ConstantExpr, Ty), - WellFormed(GenericArg), - ConstEvaluatable(ConstantExpr), -} - -/// Reflects [`rustc_middle::ty::Clause`] and adds a hash-consed predicate identifier. -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Clause { - pub kind: Binder, - pub id: PredicateId, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clause<'tcx> { - fn sinto(&self, s: &S) -> Clause { - let kind = self.kind().sinto(s); - let id = kind.clone().map(PredicateKind::Clause).predicate_id(); - Clause { kind, id } - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto - for rustc_middle::ty::PolyTraitPredicate<'tcx> -{ - fn sinto(&self, s: &S) -> Clause { - let kind: Binder<_> = self.sinto(s); - let kind: Binder = kind.map(ClauseKind::Trait); - let id = kind.clone().map(PredicateKind::Clause).predicate_id(); - Clause { kind, id } - } -} - -/// Reflects [`rustc_middle::ty::Predicate`] and adds a hash-consed predicate identifier. -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Predicate { - pub kind: Binder, - pub id: PredicateId, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Predicate<'tcx> { - fn sinto(&self, s: &S) -> Predicate { - let kind = self.kind().sinto(s); - let id = kind.predicate_id(); - Predicate { kind, id } - } -} - -/// Reflects [`rustc_middle::ty::BoundVariableKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundVariableKind, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum BoundVariableKind { - Ty(BoundTyKind), - Region(BoundRegionKind), - Const, -} - -/// Reflects [`rustc_middle::ty::Binder`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Binder { - pub value: T, - pub bound_vars: Vec, -} - -impl Binder { - pub fn as_ref(&self) -> Binder<&T> { - Binder { - value: &self.value, - bound_vars: self.bound_vars.clone(), - } - } - - pub fn hax_skip_binder(self) -> T { - self.value - } - - pub fn hax_skip_binder_ref(&self) -> &T { - &self.value - } - - pub fn map(self, f: impl FnOnce(T) -> U) -> Binder { - Binder { - value: f(self.value), - bound_vars: self.bound_vars, - } - } - - pub fn inner_mut(&mut self) -> &mut T { - &mut self.value - } - - pub fn rebind(&self, value: U) -> Binder { - self.as_ref().map(|_| value) - } -} - -/// Reflects [`rustc_middle::ty::GenericPredicates`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericPredicates<'tcx>, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct GenericPredicates { - pub parent: Option, - // FIXME: Switch from `Predicate` to `Clause` (will require correct handling of binders). - #[value(self.predicates.iter().map(|(clause, span)| (clause.as_predicate().sinto(s), span.sinto(s))).collect())] - pub predicates: Vec<(Predicate, Span)>, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto> - for rustc_middle::ty::Binder<'tcx, T1> -where - T1: SInto, T2>, -{ - fn sinto(&self, s: &S) -> Binder { - let bound_vars = self.bound_vars().sinto(s); - let value = { - let under_binder_s = &State { - base: s.base(), - owner_id: s.owner_id(), - binder: self.as_ref().map_bound(|_| ()), - thir: (), - mir: (), - }; - self.as_ref().skip_binder().sinto(under_binder_s) - }; - Binder { value, bound_vars } - } -} - -/// Reflects [`rustc_middle::ty::SubtypePredicate`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::SubtypePredicate<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct SubtypePredicate { - pub a_is_expected: bool, - pub a: Ty, - pub b: Ty, -} - -/// Reflects [`rustc_middle::ty::CoercePredicate`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CoercePredicate<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct CoercePredicate { - pub a: Ty, - pub b: Ty, -} - -/// Reflects [`rustc_middle::ty::AliasRelationDirection`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AliasRelationDirection, state: S as _tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AliasRelationDirection { - Equate, - Subtype, -} - -/// Reflects [`rustc_middle::ty::ClosureArgs`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: ty::ClosureArgs>, state: S as s)] -#[derive(Clone, Debug, JsonSchema)] -#[derive_group(Serializers)] -pub struct ClosureArgs { - #[value(self.kind().sinto(s))] - pub kind: ClosureKind, - #[value(self.parent_args().sinto(s))] - pub parent_args: Vec, - #[value(self.sig().sinto(s))] - pub sig: PolyFnSig, - #[value(self.upvar_tys().sinto(s))] - pub upvar_tys: Vec, -} - -/// Reflects [`rustc_middle::ty::ClosureKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ClosureKind, state: S as _tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum ClosureKind { - Fn, - FnMut, - FnOnce, -} - -/// Reflects [`rustc_middle::ty::PredicateKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderBinderState<'tcx>>, from: rustc_middle::ty::PredicateKind<'tcx>, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum PredicateKind { - Clause(ClauseKind), - ObjectSafe(DefId), - Subtype(SubtypePredicate), - Coerce(CoercePredicate), - ConstEquate(ConstantExpr, ConstantExpr), - Ambiguous, - AliasRelate(Term, Term, AliasRelationDirection), - NormalizesTo(NormalizesTo), -} - -/// Reflects [`rustc_middle::ty::ImplSubject`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum ImplSubject { - Trait { - /// The trait that is implemented by this impl block. - trait_pred: TraitPredicate, - /// The `ImplExpr`s required to satisfy the predicates on the trait declaration. E.g.: - /// ```ignore - /// trait Foo: Bar {} - /// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`. - /// ``` - required_impl_exprs: Vec, - }, - Inherent(Ty), -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<'tcx> { - fn sinto(&self, s: &S) -> ImplSubject { - let tcx = s.base().tcx; - match self { - ty::ImplSubject::Inherent(ty) => ImplSubject::Inherent(ty.sinto(s)), - ty::ImplSubject::Trait(trait_ref) => { - // Also record the polarity. - let polarity = tcx.impl_polarity(s.owner_id()); - let trait_pred = TraitPredicate { - trait_ref: trait_ref.sinto(s), - is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive), - }; - let required_impl_exprs = - solve_item_traits(s, trait_ref.def_id, trait_ref.args, None); - ImplSubject::Trait { - trait_pred, - required_impl_exprs, - } - } - } - } -} - -/// Reflects [`rustc_hir::GenericBounds`] -type GenericBounds = Vec; - -/// Compute the bounds for the owner registed in the state `s` -#[cfg(feature = "rustc")] -fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> GenericBounds { - let tcx = s.base().tcx; - - // According to what kind of node we are looking at, we should - // either call `predicates_defined_on` or `item_bounds` - let use_item_bounds = { - if let Some(oid) = s.owner_id().as_local() { - let hir_id = tcx.local_def_id_to_hir_id(oid); - let node = tcx.hir_node(hir_id); - use rustc_hir as hir; - matches!( - node, - hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Type(..), - .. - }) | hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }), - .. - }) - ) - } else { - false - } - }; - - let clauses: Vec> = if use_item_bounds { - tcx.item_bounds(s.owner_id()) - .instantiate_identity() - .iter() - .collect() - } else { - tcx.predicates_defined_on(s.owner_id()) - .predicates - .iter() - .map(|(x, _span)| x) - .copied() - .collect() - }; - clauses.sinto(s) -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::GenericBounds<'tcx> { - fn sinto(&self, s: &S) -> GenericBounds { - region_bounds_at_current_owner(s) - } -} - -/// Reflects [`rustc_hir::OpaqueTyOrigin`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::OpaqueTyOrigin, state: S as tcx)] -#[derive(Clone, Debug, JsonSchema)] -#[derive_group(Serializers)] -pub enum OpaqueTyOrigin { - FnReturn(GlobalIdent), - AsyncFn(GlobalIdent), - TyAlias { in_assoc_ty: bool }, -} - -/// Reflects [`rustc_ast::ast::MacroDef`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MacroDef, state: S as tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct MacroDef { - pub body: DelimArgs, - pub macro_rules: bool, -} - -/// Reflects [`rustc_hir::Item`] (and [`rustc_hir::ItemId`]) -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct Item { - pub def_id: Option, - pub owner_id: DefId, - pub span: Span, - pub vis_span: Span, - pub kind: ItemKind, - pub attributes: ItemAttributes, - pub expn_backtrace: Vec, -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::Item<'tcx> { - fn sinto(&self, s: &S) -> Item { - let name: String = self.ident.name.to_ident_string(); - let s = &with_owner_id(s.base(), (), (), self.owner_id.to_def_id()); - let owner_id: DefId = self.owner_id.sinto(s); - let def_id = Path::from(owner_id.clone()) - .ends_with(&[name]) - .then(|| owner_id.clone()); - Item { - def_id, - owner_id, - span: self.span.sinto(s), - vis_span: self.span.sinto(s), - kind: self.kind.sinto(s), - attributes: ItemAttributes::from_owner_id(s, self.owner_id), - expn_backtrace: self.span.macro_backtrace().map(|o| o.sinto(s)).collect(), - } - } -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::ItemId { - fn sinto(&self, s: &S) -> Item { - let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; - tcx.hir().item(*self).sinto(s) - } -} - -/// Reflects [`rustc_span::symbol::Ident`] -pub type Ident = (Symbol, Span); - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_span::symbol::Ident { - fn sinto(&self, s: &S) -> Ident { - (self.name.sinto(s), self.span.sinto(s)) - } -} - -/// Reflects [`rustc_middle::ty::AssocItem`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::AssocItem, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct AssocItem { - pub def_id: DefId, - pub name: Symbol, - pub kind: AssocKind, - #[value(get_container_for_assoc_item(s, self))] - pub container: AssocItemContainer, - /// Whether this item has a value (e.g. this is `false` for trait methods without default - /// implementations). - #[value(self.defaultness(s.base().tcx).has_value())] - pub has_value: bool, - pub fn_has_self_parameter: bool, - pub opt_rpitit_info: Option, -} - -/// Reflects [`rustc_middle::ty::ImplTraitInTraitData`] -#[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::ImplTraitInTraitData, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum ImplTraitInTraitData { - Trait { - fn_def_id: DefId, - opaque_def_id: DefId, - }, - Impl { - fn_def_id: DefId, - }, -} - -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AssocItemContainer { - TraitContainer { - trait_id: DefId, - }, - TraitImplContainer { - impl_id: DefId, - implemented_trait: DefId, - implemented_trait_item: DefId, - /// Whether the corresponding trait item had a default (and therefore this one overrides - /// it). - overrides_default: bool, - }, - InherentImplContainer { - impl_id: DefId, - }, -} - -#[cfg(feature = "rustc")] -fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( - s: &S, - item: &ty::AssocItem, -) -> AssocItemContainer { - let container_id = item.container_id(s.base().tcx); - match item.container { - ty::AssocItemContainer::TraitContainer => AssocItemContainer::TraitContainer { - trait_id: container_id.sinto(s), - }, - ty::AssocItemContainer::ImplContainer => { - if let Some(implemented_trait_item) = item.trait_item_def_id { - AssocItemContainer::TraitImplContainer { - impl_id: container_id.sinto(s), - implemented_trait: s - .base() - .tcx - .trait_of_item(implemented_trait_item) - .unwrap() - .sinto(s), - implemented_trait_item: implemented_trait_item.sinto(s), - overrides_default: s.base().tcx.defaultness(implemented_trait_item).has_value(), - } - } else { - AssocItemContainer::InherentImplContainer { - impl_id: container_id.sinto(s), - } - } - } - } -} - -/// Reflects [`rustc_middle::ty::AssocKind`] -#[derive(AdtInto)] -#[args(, from: rustc_middle::ty::AssocKind, state: S as _tcx)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum AssocKind { - Const, - Fn, - Type, -} diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index 517ebd8cd..c0594ca6c 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -12,14 +12,23 @@ use hax_adt_into::derive_group; +#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] +use crate::prelude::*; #[cfg(not(feature = "extract_names_mode"))] use crate::{AdtInto, JsonSchema}; -#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] -use crate::{BaseState, SInto}; +#[cfg(feature = "rustc")] +use rustc_span::def_id::DefId as RDefId; pub type Symbol = String; +#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] +impl<'t, S> SInto for rustc_span::symbol::Symbol { + fn sinto(&self, _s: &S) -> Symbol { + self.to_ident_string() + } +} + #[derive_group(Serializers)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] @@ -67,6 +76,94 @@ impl std::fmt::Debug for DefId { } } +impl std::hash::Hash for DefId { + fn hash(&self, state: &mut H) { + let DefId { + krate, + path, + index: _, // intentionally discarding index + is_local: _, // intentionally discarding is_local + } = self; + krate.hash(state); + path.hash(state); + } +} + +#[cfg(feature = "rustc")] +pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> DefId { + let tcx = s.base().tcx; + let def_path = tcx.def_path(def_id); + let krate = tcx.crate_name(def_path.krate); + DefId { + path: def_path.data.iter().map(|x| x.sinto(s)).collect(), + krate: format!("{}", krate), + index: ( + rustc_hir::def_id::CrateNum::as_u32(def_id.krate), + rustc_hir::def_id::DefIndex::as_u32(def_id.index), + ), + is_local: def_id.is_local(), + } +} + +#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] +impl<'s, S: BaseState<'s>> SInto for RDefId { + fn sinto(&self, s: &S) -> DefId { + if let Some(def_id) = s.with_item_cache(*self, |cache| cache.def_id.clone()) { + return def_id; + } + let def_id = translate_def_id(s, *self); + s.with_item_cache(*self, |cache| cache.def_id = Some(def_id.clone())); + def_id + } +} + +#[cfg(feature = "rustc")] +impl From<&DefId> for RDefId { + fn from<'tcx>(def_id: &DefId) -> Self { + let (krate, index) = def_id.index; + Self { + krate: rustc_hir::def_id::CrateNum::from_u32(krate), + index: rustc_hir::def_id::DefIndex::from_u32(index), + } + } +} + +// Impl to be able to use hax's `DefId` for many rustc queries. +#[cfg(feature = "rustc")] +impl rustc_middle::query::IntoQueryParam for &DefId { + fn into_query_param(self) -> RDefId { + self.into() + } +} + +#[cfg(not(feature = "extract_names_mode"))] +pub type Path = Vec; + +#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] +impl std::convert::From for Path { + fn from(v: DefId) -> Vec { + std::iter::once(v.krate) + .chain(v.path.into_iter().filter_map(|item| match item.data { + DefPathItem::TypeNs(s) + | DefPathItem::ValueNs(s) + | DefPathItem::MacroNs(s) + | DefPathItem::LifetimeNs(s) => Some(s), + _ => None, + })) + .collect() + } +} + +#[cfg(not(feature = "extract_names_mode"))] +pub type GlobalIdent = DefId; + +#[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::def_id::LocalDefId { + fn sinto(&self, st: &S) -> DefId { + self.to_def_id().sinto(st) + } +} + /// Reflects [`rustc_hir::definitions::DefPathData`] #[derive_group(Serializers)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] diff --git a/frontend/exporter/src/types/hir.rs b/frontend/exporter/src/types/hir.rs new file mode 100644 index 000000000..102b24991 --- /dev/null +++ b/frontend/exporter/src/types/hir.rs @@ -0,0 +1,1141 @@ +//! Copies of the relevant `HIR` types. HIR represents the code of a rust crate post-macro +//! expansion. It is close to the parsed AST, modulo some desugarings (and macro expansion). +//! +//! This module also includes some `rustc_ast` definitions when they show up in HIR. +use crate::prelude::*; +use crate::sinto_todo; + +#[cfg(feature = "rustc")] +use rustc_middle::ty; + +/// Reflects [`rustc_hir::hir_id::HirId`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::hir_id::HirId, state: S as gstate)] +pub struct HirId { + owner: DefId, + local_id: usize, + // attrs: String +} +// TODO: If not working: See original + +#[cfg(feature = "rustc")] +impl<'tcx, S: BaseState<'tcx>> SInto for rustc_hir::hir_id::OwnerId { + fn sinto(&self, s: &S) -> DefId { + self.to_def_id().sinto(s) + } +} + +/// Reflects [`rustc_ast::ast::LitFloatType`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitFloatType, state: S as gstate)] +pub enum LitFloatType { + Suffixed(FloatTy), + Unsuffixed, +} + +/// Reflects [`rustc_hir::Movability`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S>, from: rustc_hir::Movability, state: S as _s)] +pub enum Movability { + Static, + Movable, +} + +pub type Mutability = bool; + +#[cfg(feature = "rustc")] +impl SInto for rustc_hir::Mutability { + fn sinto(&self, _s: &S) -> Mutability { + match self { + rustc_hir::Mutability::Mut => true, + _ => false, + } + } +} + +/// Reflects [`rustc_hir::def::CtorKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(, from: rustc_hir::def::CtorKind, state: S as _s)] +pub enum CtorKind { + Fn, + Const, +} + +/// Reflects [`rustc_hir::def::CtorOf`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(, from: rustc_hir::def::CtorOf, state: S as _s)] +pub enum CtorOf { + Struct, + Variant, +} + +/// Reflects [`rustc_hir::RangeEnd`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::RangeEnd, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum RangeEnd { + Included, + Excluded, +} + +/// Reflects [`rustc_hir::Safety`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::Safety, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Safety { + Unsafe, + Safe, +} + +/// Reflects [`rustc_hir::ImplicitSelfKind`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::ImplicitSelfKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ImplicitSelfKind { + Imm, + Mut, + RefImm, + RefMut, + None, +} + +/// Reflects [`rustc_hir::FnDecl`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnDecl<'tcx>, state: S as tcx)] +pub struct FnDecl { + pub inputs: Vec, + pub output: FnRetTy, + pub c_variadic: bool, + pub implicit_self: ImplicitSelfKind, + pub lifetime_elision_allowed: bool, +} + +/// Reflects [`rustc_hir::FnSig`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnSig<'tcx>, state: S as tcx)] +pub struct FnSig { + pub header: FnHeader, + pub decl: FnDecl, + pub span: Span, +} + +/// Reflects [`rustc_hir::FnHeader`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::FnHeader, state: S as tcx)] +pub struct FnHeader { + pub safety: Safety, + pub constness: Constness, + pub asyncness: IsAsync, + pub abi: Abi, +} + +sinto_todo!(rustc_target::spec::abi, Abi); + +/// Function definition +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct FnDef { + pub header: FnHeader, + pub params: Vec, + pub ret: Ty, + pub body: Body, + pub sig_span: Span, +} + +#[cfg(feature = "rustc")] +impl<'x: 'tcx, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { + fn sinto(self: &rustc_hir::Ty<'x>, s: &S) -> Ty { + // **Important:** + // We need a local id here, and we get it from the owner id, which must + // be local. It is safe to do so, because if we have access to a HIR ty, + // it necessarily means we are exploring a local item (we don't have + // access to the HIR of external objects, only their MIR). + let ctx = + rustc_hir_analysis::collect::ItemCtxt::new(s.base().tcx, s.owner_id().expect_local()); + ctx.lower_ty(self).sinto(s) + } +} + +/// Reflects [`rustc_hir::UseKind`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::UseKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum UseKind { + Single, + Glob, + ListStem, +} + +/// Reflects [`rustc_hir::IsAuto`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::IsAuto, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum IsAuto { + Yes, + No, +} + +/// Reflects [`rustc_hir::Defaultness`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::Defaultness, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Defaultness { + Default { has_value: bool }, + Final, +} + +/// Reflects [`rustc_hir::ImplPolarity`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ImplPolarity, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ImplPolarity { + Positive, + Negative(Span), +} + +/// Reflects [`rustc_hir::Constness`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::Constness, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Constness { + Const, + NotConst, +} + +/// Reflects [`rustc_hir::Generics`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Generics<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Generics { + pub params: Vec>, + #[value(region_bounds_at_current_owner(tcx))] + pub bounds: GenericBounds, + pub has_where_clause_predicates: bool, + pub where_clause_span: Span, + pub span: Span, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> + for rustc_hir::ImplItemRef +{ + fn sinto(&self, s: &S) -> ImplItem { + let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; + let impl_item = tcx.hir().impl_item(self.id); + let s = with_owner_id(s.base(), (), (), impl_item.owner_id.to_def_id()); + impl_item.sinto(&s) + } +} + +/// Reflects [`rustc_hir::ParamName`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ParamName { + Plain(LocalIdent), + Fresh, + Error, +} + +/// Reflects [`rustc_hir::LifetimeParamKind`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::LifetimeParamKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum LifetimeParamKind { + Explicit, + Elided(MissingLifetimeKind), + Error, +} + +/// Reflects [`rustc_hir::AnonConst`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AnonConst, state: S as s)] +pub struct AnonConst { + pub hir_id: HirId, + pub def_id: GlobalIdent, + #[map({ + body_from_id::(*x, &with_owner_id(s.base(), (), (), hir_id.owner.to_def_id())) + })] + pub body: Body, +} + +/// Reflects [`rustc_hir::ConstArg`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArg<'tcx>, state: S as s)] +pub struct ConstArg { + pub hir_id: HirId, + pub kind: ConstArgKind, + pub is_desugared_from_effects: bool, +} + +/// Reflects [`rustc_hir::ConstArgKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArgKind<'tcx>, state: S as s)] +pub enum ConstArgKind { + Path(QPath), + Anon(AnonConst), +} + +/// Reflects [`rustc_hir::GenericParamKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParamKind<'tcx>, state: S as tcx)] +pub enum GenericParamKind { + Lifetime { + kind: LifetimeParamKind, + }, + Type { + /// On use site, Rust always give us all the generic + /// parameters, no matter the defaultness. This information is + /// thus not so useful. At the same time, as discussed in + /// https://github.com/hacspec/hax/issues/310, extracting this + /// default type causes failures when querying Rust for trait + /// resolution. We thus decided to disable this feature. If + /// this default type information is useful to you, please + /// open an issue on https://github.com/hacspec/hax. + #[map(x.map(|_ty| ()))] + default: Option<()>, + synthetic: bool, + }, + Const { + ty: Ty, + default: Option>, + }, +} + +/// Reflects [`rustc_hir::GenericParam`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParam<'tcx>, state: S as s)] +pub struct GenericParam { + pub hir_id: HirId, + pub def_id: GlobalIdent, + #[map(match x { + rustc_hir::ParamName::Plain(loc_ident) => + ParamName::Plain(LocalIdent { + name: loc_ident.as_str().to_string(), + id: self.hir_id.sinto(s) + }), + rustc_hir::ParamName::Fresh => + ParamName::Fresh, + rustc_hir::ParamName::Error => + ParamName::Error, + })] + pub name: ParamName, + pub span: Span, + pub pure_wrt_drop: bool, + pub kind: GenericParamKind, + pub colon_span: Option, + #[value(s.base().tcx.hir().attrs(*hir_id).sinto(s))] + attributes: Vec, +} + +/// Reflects [`rustc_hir::ImplItem`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItem<'tcx>, state: S as s)] +pub struct ImplItem { + pub ident: Ident, + pub owner_id: DefId, + pub generics: Generics, + pub kind: ImplItemKind, + pub defaultness: Defaultness, + pub span: Span, + pub vis_span: Span, + #[value(ItemAttributes::from_owner_id(s, *owner_id))] + /// the attributes on this impl item + pub attributes: ItemAttributes, +} + +/// Reflects [`rustc_hir::ImplItemKind`], inlining the body of the items. +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItemKind<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ImplItemKind { + Const(Ty, Body), + #[custom_arm(rustc_hir::ImplItemKind::Fn(sig, body) => { + ImplItemKind::Fn(make_fn_def::(sig, body, s)) + },)] + Fn(FnDef), + #[custom_arm(rustc_hir::ImplItemKind::Type(t) => { + let parent_bounds = { + let (tcx, owner_id) = (s.base().tcx, s.owner_id()); + let assoc_item = tcx.opt_associated_item(owner_id).unwrap(); + let impl_did = assoc_item.impl_container(tcx).unwrap(); + tcx.explicit_item_bounds(assoc_item.trait_item_def_id.unwrap()) + .skip_binder() // Skips an `EarlyBinder`, likely for GATs + .iter() + .copied() + .filter_map(|(clause, span)| super_clause_to_clause_and_impl_expr(s, impl_did, clause, span)) + .collect::>() + }; + ImplItemKind::Type { + ty: t.sinto(s), + parent_bounds + } + },)] + /// An associated type with its parent bounds inlined. + Type { + ty: Ty, + parent_bounds: Vec<(Clause, ImplExpr, Span)>, + }, +} + +/// Reflects [`rustc_hir::AssocItemKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AssocItemKind, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum AssocItemKind { + Const, + Fn { has_self: bool }, + Type, +} + +/// Reflects [`rustc_hir::Impl`]. +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Impl<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Impl { + pub safety: Safety, + pub polarity: ImplPolarity, + pub defaultness: Defaultness, + pub defaultness_span: Option, + pub generics: Generics, + #[map({ + s.base().tcx + .impl_trait_ref(s.owner_id()) + .map(|trait_ref| trait_ref.instantiate_identity()) + .sinto(s) + })] + pub of_trait: Option, + pub self_ty: Ty, + pub items: Vec>, + #[value({ + let (tcx, owner_id) = (s.base().tcx, s.owner_id()); + let trait_did = tcx.trait_id_of_impl(owner_id); + if let Some(trait_did) = trait_did { + tcx.explicit_super_predicates_of(trait_did) + .predicates + .iter() + .copied() + .filter_map(|(clause, span)| super_clause_to_clause_and_impl_expr(s, owner_id, clause, span)) + .collect::>() + } else { + vec![] + } + })] + /// The clauses and impl expressions corresponding to the impl's + /// trait (if not inherent) super bounds (if any). + pub parent_bounds: Vec<(Clause, ImplExpr, Span)>, +} + +/// Reflects [`rustc_hir::IsAsync`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::IsAsync, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum IsAsync { + Async(Span), + NotAsync, +} + +/// Reflects [`rustc_hir::FnRetTy`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnRetTy<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum FnRetTy { + DefaultReturn(Span), + Return(Ty), +} + +/// Reflects [`rustc_hir::VariantData`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::VariantData<'tcx>, state: S as tcx)] +pub enum VariantData { + Struct { + fields: Vec, + recovered: bool, + }, + Tuple(Vec, HirId, GlobalIdent), + Unit(HirId, GlobalIdent), +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_ast::ast::Recovered { + fn sinto(&self, _s: &S) -> bool { + match self { + Self::Yes(_) => true, + Self::No => false, + } + } +} + +/// Reflects [`rustc_hir::FieldDef`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FieldDef<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct HirFieldDef { + pub span: Span, + pub vis_span: Span, + pub ident: Ident, + pub hir_id: HirId, + pub def_id: GlobalIdent, + pub ty: Ty, + #[value(s.base().tcx.hir().attrs(*hir_id).sinto(s))] + attributes: Vec, +} + +/// Reflects [`rustc_hir::Variant`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Variant<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Variant { + pub ident: Ident, + pub hir_id: HirId, + pub def_id: GlobalIdent, + #[map(x.sinto(&with_owner_id(s.base(), (), (), self.def_id.to_def_id())))] + pub data: VariantData, + pub disr_expr: Option>, + #[value({ + let tcx = s.base().tcx; + let variant = tcx + .adt_def(s.owner_id()) + .variants() + .into_iter() + .find(|v| v.def_id == self.def_id.into()).unwrap(); + variant.discr.sinto(s) + })] + pub discr: DiscriminantDefinition, + pub span: Span, + #[value(s.base().tcx.hir().attrs(*hir_id).sinto(s))] + pub attributes: Vec, +} + +/// Reflects [`rustc_hir::UsePath`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::UsePath<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct UsePath { + pub span: Span, + #[map(x.iter().map(|res| res.sinto(s)).collect())] + pub res: Vec, + pub segments: Vec, + #[value(self.segments.iter().last().and_then(|segment| { + match s.base().tcx.hir_node_by_def_id(segment.hir_id.owner.def_id) { + rustc_hir::Node::Item(rustc_hir::Item { + ident, + kind: rustc_hir::ItemKind::Use(_, _), + .. + }) if ident.name.to_ident_string() != "" => Some(ident.name.to_ident_string()), + _ => None, + } + }))] + pub rename: Option, +} + +/// Reflects [`rustc_hir::def::Res`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::Res, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Res { + Def(DefKind, DefId), + PrimTy(PrimTy), + SelfTyParam { + trait_: DefId, + }, + SelfTyAlias { + alias_to: DefId, + forbid_generic: bool, + is_trait_impl: bool, + }, + SelfCtor(DefId), + Local(HirId), + ToolMod, + NonMacroAttr(NonMacroAttrKind), + Err, +} + +/// Reflects [`rustc_hir::PrimTy`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::PrimTy, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum PrimTy { + Int(IntTy), + Uint(UintTy), + Float(FloatTy), + Str, + Bool, + Char, +} + +/// Reflects [`rustc_hir::def::NonMacroAttrKind`] +#[derive(AdtInto)] +#[args(, from: rustc_hir::def::NonMacroAttrKind, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum NonMacroAttrKind { + Builtin(Symbol), + Tool, + DeriveHelper, + DeriveHelperCompat, +} + +/// Reflects [`rustc_hir::PathSegment`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::PathSegment<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct PathSegment { + pub ident: Ident, + pub hir_id: HirId, + pub res: Res, + #[map(args.map(|args| args.sinto(s)))] + pub args: Option, + pub infer_args: bool, +} + +/// Reflects [`rustc_hir::ItemKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ItemKind<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ItemKind { + #[disable_mapping] + MacroInvokation(MacroInvokation), + ExternCrate(Option), + Use(UsePath, UseKind), + Static(Ty, Mutability, Body), + Const(Ty, Generics, Body), + #[custom_arm( + rustc_hir::ItemKind::Fn(sig, generics, body) => { + ItemKind::Fn(generics.sinto(s), make_fn_def::(sig, body, s)) + } + )] + Fn(Generics, FnDef), + Macro(MacroDef, MacroKind), + Mod(Vec>), + ForeignMod { + abi: Abi, + items: Vec>, + }, + GlobalAsm(InlineAsm), + TyAlias( + #[map({ + let s = &State { + base: Base {ty_alias_mode: true, ..s.base()}, + owner_id: s.owner_id(), + thir: (), + mir: (), + binder: (), + }; + x.sinto(s) + })] + Ty, + Generics, + ), + OpaqueTy(OpaqueTy), + Enum( + EnumDef, + Generics, + #[value({ + let tcx = s.base().tcx; + tcx.repr_options_of_def(s.owner_id().expect_local()).sinto(s) + })] + ReprOptions, + ), + Struct(VariantData, Generics), + Union(VariantData, Generics), + Trait( + IsAuto, + Safety, + Generics, + GenericBounds, + Vec>, + ), + TraitAlias(Generics, GenericBounds), + Impl(Impl), +} + +pub type EnumDef = Vec>; + +/// Reflects [`rustc_hir::TraitItemKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItemKind<'tcx>, state: S as tcx)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] +pub enum TraitItemKind { + Const(Ty, Option), + #[custom_arm( + rustc_hir::TraitItemKind::Fn(sig, rustc_hir::TraitFn::Required(id)) => { + TraitItemKind::RequiredFn(sig.sinto(tcx), id.sinto(tcx)) + } + )] + /// Reflects a required [`rustc_hir::TraitItemKind::Fn`] + RequiredFn(FnSig, Vec), + #[custom_arm( + rustc_hir::TraitItemKind::Fn(sig, rustc_hir::TraitFn::Provided(body)) => { + TraitItemKind::ProvidedFn(sig.sinto(tcx), make_fn_def::(sig, body, tcx)) + } + )] + /// Reflects a provided [`rustc_hir::TraitItemKind::Fn`] + ProvidedFn(FnSig, FnDef), + #[custom_arm( + rustc_hir::TraitItemKind::Type(b, ty) => { + TraitItemKind::Type(b.sinto(tcx), ty.map(|t| t.sinto(tcx))) + } + )] + Type(GenericBounds, Option), +} + +/// Reflects [`rustc_hir::TraitItem`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItem<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct TraitItem { + pub ident: Ident, + pub owner_id: DefId, + pub generics: Generics, + pub kind: TraitItemKind, + pub span: Span, + pub defaultness: Defaultness, + #[value(ItemAttributes::from_owner_id(s, *owner_id))] + /// The attributes on this trait item + pub attributes: ItemAttributes, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> + for rustc_hir::EnumDef<'tcx> +{ + fn sinto(&self, s: &S) -> EnumDef { + self.variants.iter().map(|v| v.sinto(s)).collect() + } +} + +#[cfg(feature = "rustc")] +impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> + for rustc_hir::TraitItemRef +{ + fn sinto(&self, s: &S) -> TraitItem { + let s = with_owner_id(s.base(), (), (), self.id.owner_id.to_def_id()); + let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; + tcx.hir().trait_item(self.id).sinto(&s) + } +} + +#[cfg(feature = "rustc")] +impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> + for rustc_hir::Mod<'a> +{ + fn sinto(&self, s: &S) -> Vec> { + inline_macro_invocations(self.item_ids.iter().copied(), s) + // .iter() + // .map(|item_id| item_id.sinto(s)) + // .collect() + } +} + +/// Reflects [`rustc_hir::ForeignItemKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItemKind<'tcx>, state: S as tcx)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] +pub enum ForeignItemKind { + Fn(FnDecl, Vec, Generics, Safety), + Static(Ty, Mutability, Safety), + Type, +} + +/// Reflects [`rustc_hir::ForeignItem`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItem<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct ForeignItem { + pub ident: Ident, + pub kind: ForeignItemKind, + pub owner_id: DefId, + pub span: Span, + pub vis_span: Span, +} + +#[cfg(feature = "rustc")] +impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> + for rustc_hir::ForeignItemRef +{ + fn sinto(&self, s: &S) -> ForeignItem { + let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; + tcx.hir().foreign_item(self.id).sinto(s) + } +} + +/// Reflects [`rustc_hir::OpaqueTy`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::OpaqueTy<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct OpaqueTy { + pub generics: Generics, + pub bounds: GenericBounds, + pub origin: OpaqueTyOrigin, + pub in_trait: bool, +} + +/// Reflects [`rustc_hir::GenericBounds`] +type GenericBounds = Vec; + +/// Compute the bounds for the owner registed in the state `s` +#[cfg(feature = "rustc")] +fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> GenericBounds { + let tcx = s.base().tcx; + + // According to what kind of node we are looking at, we should + // either call `predicates_defined_on` or `item_bounds` + let use_item_bounds = { + if let Some(oid) = s.owner_id().as_local() { + let hir_id = tcx.local_def_id_to_hir_id(oid); + let node = tcx.hir_node(hir_id); + use rustc_hir as hir; + matches!( + node, + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Type(..), + .. + }) | hir::Node::Item(hir::Item { + kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }), + .. + }) + ) + } else { + false + } + }; + + let clauses: Vec> = if use_item_bounds { + tcx.item_bounds(s.owner_id()) + .instantiate_identity() + .iter() + .collect() + } else { + tcx.predicates_defined_on(s.owner_id()) + .predicates + .iter() + .map(|(x, _span)| x) + .copied() + .collect() + }; + clauses.sinto(s) +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::GenericBounds<'tcx> { + fn sinto(&self, s: &S) -> GenericBounds { + region_bounds_at_current_owner(s) + } +} + +/// Reflects [`rustc_hir::OpaqueTyOrigin`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::OpaqueTyOrigin, state: S as tcx)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] +pub enum OpaqueTyOrigin { + FnReturn(GlobalIdent), + AsyncFn(GlobalIdent), + TyAlias { in_assoc_ty: bool }, +} + +/// Reflects [`rustc_ast::ast::MacroDef`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MacroDef, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct MacroDef { + pub body: DelimArgs, + pub macro_rules: bool, +} + +/// Reflects [`rustc_hir::Item`] (and [`rustc_hir::ItemId`]) +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Item { + pub def_id: Option, + pub owner_id: DefId, + pub span: Span, + pub vis_span: Span, + pub kind: ItemKind, + pub attributes: ItemAttributes, + pub expn_backtrace: Vec, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::Item<'tcx> { + fn sinto(&self, s: &S) -> Item { + let name: String = self.ident.name.to_ident_string(); + let s = &with_owner_id(s.base(), (), (), self.owner_id.to_def_id()); + let owner_id: DefId = self.owner_id.sinto(s); + let def_id = Path::from(owner_id.clone()) + .ends_with(&[name]) + .then(|| owner_id.clone()); + Item { + def_id, + owner_id, + span: self.span.sinto(s), + vis_span: self.span.sinto(s), + kind: self.kind.sinto(s), + attributes: ItemAttributes::from_owner_id(s, self.owner_id), + expn_backtrace: self.span.macro_backtrace().map(|o| o.sinto(s)).collect(), + } + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::ItemId { + fn sinto(&self, s: &S) -> Item { + let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; + tcx.hir().item(*self).sinto(s) + } +} + +/// Reflects [`rustc_span::symbol::Ident`] +pub type Ident = (Symbol, Span); + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_span::symbol::Ident { + fn sinto(&self, s: &S) -> Ident { + (self.name.sinto(s), self.span.sinto(s)) + } +} + +/// Reflects [`rustc_ast::ast::AttrStyle`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(, from: rustc_ast::ast::AttrStyle, state: S as _s)] +pub enum AttrStyle { + Outer, + Inner, +} + +/// Reflects [`rustc_ast::ast::Attribute`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::Attribute, state: S as gstate)] +pub struct Attribute { + pub kind: AttrKind, + #[map(x.as_usize())] + pub id: usize, + pub style: AttrStyle, + pub span: Span, +} + +/// Reflects [`rustc_attr::InlineAttr`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_attr::InlineAttr, state: S as _s)] +pub enum InlineAttr { + None, + Hint, + Always, + Never, +} + +/// Reflects [`rustc_ast::ast::BindingMode`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::ast::BindingMode, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct BindingMode { + #[value(self.0.sinto(s))] + pub by_ref: ByRef, + #[value(self.1.sinto(s))] + pub mutability: Mutability, +} + +/// Reflects [`rustc_ast::ast::ByRef`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::ast::ByRef, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ByRef { + Yes(Mutability), + No, +} + +/// Reflects [`rustc_ast::ast::StrStyle`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::ast::StrStyle, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum StrStyle { + Cooked, + Raw(u8), +} + +/// Reflects [`rustc_ast::ast::LitKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitKind, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum LitKind { + Str(Symbol, StrStyle), + ByteStr(Vec, StrStyle), + CStr(Vec, StrStyle), + Byte(u8), + Char(char), + Int( + #[serde(with = "serialize_int::unsigned")] + #[schemars(with = "String")] + u128, + LitIntType, + ), + Float(Symbol, LitFloatType), + Bool(bool), + Err(ErrorGuaranteed), +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_data_structures::packed::Pu128 { + fn sinto(&self, _s: &S) -> u128 { + self.0 + } +} + +// FIXME: typo: invo**C**ation +#[allow(rustdoc::private_intra_doc_links)] +/// Describe a macro invocation, using +/// [`macro_invocation_of_raw_mac_invocation`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct MacroInvokation { + pub macro_ident: DefId, + pub argument: String, + pub span: Span, +} + +/// Reflects [`rustc_ast::token::CommentKind`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::token::CommentKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum CommentKind { + Line, + Block, +} + +/// Reflects [`rustc_ast::ast::AttrArgs`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrArgs, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AttrArgs { + Empty, + Delimited(DelimArgs), + + Eq(Span, AttrArgsEq), + // #[todo] + // Todo(String), +} + +/// Reflects [`rustc_ast::ast::AttrArgsEq`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrArgsEq, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AttrArgsEq { + Hir(MetaItemLit), + #[todo] + Ast(String), + // Ast(P), +} + +/// Reflects [`rustc_ast::ast::MetaItemLit`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MetaItemLit, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct MetaItemLit { + pub symbol: Symbol, + pub suffix: Option, + pub kind: LitKind, + pub span: Span, +} + +/// Reflects [`rustc_ast::ast::AttrItem`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::AttrItem, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct AttrItem { + #[map(rustc_ast_pretty::pprust::path_to_string(x))] + pub path: String, + pub args: AttrArgs, + pub tokens: Option, +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_ast::tokenstream::LazyAttrTokenStream { + fn sinto(&self, st: &S) -> String { + rustc_ast::tokenstream::TokenStream::new(self.to_attr_token_stream().to_token_trees()) + .sinto(st) + } +} + +/// Reflects [`rustc_ast::ast::NormalAttr`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::NormalAttr, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct NormalAttr { + pub item: AttrItem, + pub tokens: Option, +} + +/// Reflects [`rustc_ast::AttrKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::AttrKind, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AttrKind { + Normal(NormalAttr), + DocComment(CommentKind, Symbol), +} + +sinto_todo!(rustc_hir::def, DefKind); +sinto_todo!(rustc_hir, GenericArgs<'a> as HirGenericArgs); +sinto_todo!(rustc_hir, InlineAsm<'a>); +sinto_todo!(rustc_hir, MissingLifetimeKind); +sinto_todo!(rustc_hir, QPath<'tcx>); +sinto_todo!(rustc_hir, WhereRegionPredicate<'tcx>); +sinto_todo!(rustc_hir, WhereEqPredicate<'tcx>); +sinto_todo!(rustc_hir, OwnerId); diff --git a/frontend/exporter/src/types/index.rs b/frontend/exporter/src/types/index.rs deleted file mode 100644 index 2a9c2cc18..000000000 --- a/frontend/exporter/src/types/index.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(feature = "rustc")] -use crate::prelude::*; -use crate::sinto_as_usize; - -sinto_as_usize!(rustc_middle::ty, DebruijnIndex); -sinto_as_usize!(rustc_middle::ty, UniverseIndex); -sinto_as_usize!(rustc_middle::ty, BoundVar); -sinto_as_usize!(rustc_middle::middle::region, FirstStatementIndex); -sinto_as_usize!(rustc_hir::hir_id, ItemLocalId); -sinto_as_usize!(rustc_target::abi, VariantIdx); -sinto_as_usize!(rustc_middle::ty, RegionVid); diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 8bb408eec..444110720 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -1,4 +1,9 @@ +//! Copies of the relevant `MIR` types. MIR represents a rust (function) body as a CFG. It's a +//! semantically rich representation that contains no high-level control-flow operations like loops +//! or patterns; instead the control flow is entirely described by gotos and switches on integer +//! values. use crate::prelude::*; +use crate::sinto_as_usize; #[cfg(feature = "rustc")] use tracing::trace; @@ -1062,11 +1067,167 @@ make_idx_wrapper!(rustc_middle::mir, Local); make_idx_wrapper!(rustc_middle::ty, UserTypeAnnotationIndex); make_idx_wrapper!(rustc_target::abi, FieldIdx); +/// Reflects [`rustc_middle::mir::UnOp`] +#[derive_group(Serializers)] +#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] +#[args(<'slt, S: UnderOwnerState<'slt>>, from: rustc_middle::mir::UnOp, state: S as _s)] +pub enum UnOp { + Not, + Neg, + PtrMetadata, +} + +/// Reflects [`rustc_middle::mir::BinOp`] +#[derive_group(Serializers)] +#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] +#[args(<'slt, S: UnderOwnerState<'slt>>, from: rustc_middle::mir::BinOp, state: S as _s)] +pub enum BinOp { + // We merge the checked and unchecked variants because in either case overflow is failure. + #[custom_arm( + rustc_middle::mir::BinOp::Add | rustc_middle::mir::BinOp::AddUnchecked => BinOp::Add, + )] + Add, + #[custom_arm( + rustc_middle::mir::BinOp::Sub | rustc_middle::mir::BinOp::SubUnchecked => BinOp::Sub, + )] + Sub, + #[custom_arm( + rustc_middle::mir::BinOp::Mul | rustc_middle::mir::BinOp::MulUnchecked => BinOp::Mul, + )] + Mul, + AddWithOverflow, + SubWithOverflow, + MulWithOverflow, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + #[custom_arm( + rustc_middle::mir::BinOp::Shl | rustc_middle::mir::BinOp::ShlUnchecked => BinOp::Shl, + )] + Shl, + #[custom_arm( + rustc_middle::mir::BinOp::Shr | rustc_middle::mir::BinOp::ShrUnchecked => BinOp::Shr, + )] + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt, + Cmp, + Offset, +} + +/// Reflects [`rustc_middle::mir::ScopeData`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::middle::region::ScopeData, state: S as gstate)] +pub enum ScopeData { + Node, + CallSite, + Arguments, + Destruction, + IfThen, + Remainder(FirstStatementIndex), +} + +sinto_as_usize!(rustc_middle::middle::region, FirstStatementIndex); + +/// Reflects [`rustc_middle::mir::BinOp`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::middle::region::Scope, state: S as gstate)] +pub struct Scope { + pub id: ItemLocalId, + pub data: ScopeData, +} + +sinto_as_usize!(rustc_hir::hir_id, ItemLocalId); + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::mir::Const<'tcx> { + fn sinto(&self, s: &S) -> ConstantExpr { + use rustc_middle::mir::Const; + let tcx = s.base().tcx; + match self { + Const::Val(const_value, ty) => { + const_value_to_constant_expr(s, *ty, *const_value, rustc_span::DUMMY_SP) + } + Const::Ty(_ty, c) => c.sinto(s), + Const::Unevaluated(ucv, _ty) => { + use crate::rustc_middle::query::Key; + let span = tcx + .def_ident_span(ucv.def) + .unwrap_or_else(|| ucv.def.default_span(tcx)); + if ucv.promoted.is_some() { + self.eval_constant(s) + .unwrap_or_else(|| { + supposely_unreachable_fatal!(s, "UnevalPromotedConstant"; {self, ucv}); + }) + .sinto(s) + } else { + match self.translate_uneval(s, ucv.shrink(), span) { + TranslateUnevalRes::EvaluatedConstant(c) => c.sinto(s), + TranslateUnevalRes::GlobalName(c) => c, + } + } + } + } + } +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_middle::mir::interpret::AllocId { + fn sinto(&self, _: &S) -> u64 { + self.0.get() + } +} + +/// Reflects [`rustc_middle::mir::BorrowKind`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::mir::BorrowKind, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum BorrowKind { + Shared, + Fake(FakeBorrowKind), + Mut { kind: MutBorrowKind }, +} + +/// Reflects [`rustc_middle::mir::MutBorrowKind`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::mir::MutBorrowKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum MutBorrowKind { + Default, + TwoPhaseBorrow, + ClosureCapture, +} + +/// Reflects [`rustc_middle::mir::FakeBorrowKind`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::mir::FakeBorrowKind, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum FakeBorrowKind { + /// A shared (deep) borrow. Data must be immutable and is aliasable. + Deep, + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. This is used to prevent match guards from replacing + /// the scrutinee. For example, a fake borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, +} + +sinto_todo!(rustc_ast::ast, InlineAsmTemplatePiece); +sinto_todo!(rustc_ast::ast, InlineAsmOptions); sinto_todo!(rustc_middle::ty, InstanceKind<'tcx>); sinto_todo!(rustc_middle::mir, UserTypeProjections); sinto_todo!(rustc_middle::mir, LocalInfo<'tcx>); -sinto_todo!(rustc_ast::ast, InlineAsmTemplatePiece); -sinto_todo!(rustc_ast::ast, InlineAsmOptions); sinto_todo!(rustc_middle::mir, InlineAsmOperand<'tcx>); sinto_todo!(rustc_middle::mir, AssertMessage<'tcx>); sinto_todo!(rustc_middle::mir, UnwindAction); @@ -1077,5 +1238,6 @@ sinto_todo!(rustc_middle::mir, MirSource<'tcx>); sinto_todo!(rustc_middle::mir, CoroutineInfo<'tcx>); sinto_todo!(rustc_middle::mir, VarDebugInfo<'tcx>); sinto_todo!(rustc_middle::mir, CallSource); +sinto_todo!(rustc_middle::mir, UnwindTerminateReason); sinto_todo!(rustc_middle::mir::coverage, CoverageKind); -sinto_todo!(rustc_span, ErrorGuaranteed); +sinto_todo!(rustc_middle::mir::interpret, ConstAllocation<'a>); diff --git a/frontend/exporter/src/types/mod.rs b/frontend/exporter/src/types/mod.rs index 9a1acfa6a..2ff6b8f6c 100644 --- a/frontend/exporter/src/types/mod.rs +++ b/frontend/exporter/src/types/mod.rs @@ -1,23 +1,25 @@ // There's a conflict between `mir::ScalarInt`and `todo::ScalarInt` but it doesn't matter. #![allow(ambiguous_glob_reexports)] -mod copied; mod def_id; -mod index; +mod hir; mod mir; #[cfg(feature = "rustc")] mod mir_traits; mod new; -mod replaced; pub(crate) mod serialize_int; -mod todo; +mod span; +mod thir; +mod tokens; +mod ty; -pub use copied::*; pub use def_id::*; -pub use index::*; +pub use hir::*; pub use mir::*; #[cfg(feature = "rustc")] pub use mir_traits::*; pub use new::*; -pub use replaced::*; -pub use todo::*; +pub use span::*; +pub use thir::*; +pub use tokens::*; +pub use ty::*; diff --git a/frontend/exporter/src/types/new/mod.rs b/frontend/exporter/src/types/new/mod.rs index c53569f9b..d6c48f609 100644 --- a/frontend/exporter/src/types/new/mod.rs +++ b/frontend/exporter/src/types/new/mod.rs @@ -6,9 +6,11 @@ mod impl_infos; mod item_attributes; mod predicate_id; mod typed_constant_kind; +mod variant_infos; pub use full_def::*; pub use impl_infos::*; pub use item_attributes::*; pub use predicate_id::*; pub use typed_constant_kind::*; +pub use variant_infos::*; diff --git a/frontend/exporter/src/types/new/variant_infos.rs b/frontend/exporter/src/types/new/variant_infos.rs new file mode 100644 index 000000000..d43f1b8d5 --- /dev/null +++ b/frontend/exporter/src/types/new/variant_infos.rs @@ -0,0 +1,35 @@ +use crate::prelude::*; +use crate::sinto_as_usize; + +/// Describe the kind of a variant +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum VariantKind { + /// The variant is the only variant of a `struct` type + Struct { + /// Are the fields on this struct all named? + named: bool, + }, + /// The variant is the only variant of a `union` type + Union, + /// The variant is one of the many variants of a `enum` type + Enum { + /// The index of this variant in the `enum` + index: VariantIdx, + /// Are the fields on this struct all named? + named: bool, + }, +} + +sinto_as_usize!(rustc_target::abi, VariantIdx); + +/// Describe a variant +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct VariantInformations { + pub type_namespace: DefId, + + pub typ: DefId, + pub variant: DefId, + pub kind: VariantKind, +} diff --git a/frontend/exporter/src/types/replaced.rs b/frontend/exporter/src/types/replaced.rs deleted file mode 100644 index fb4731238..000000000 --- a/frontend/exporter/src/types/replaced.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub type Path = Vec; -pub type Mutability = bool; - -#[cfg(feature = "rustc")] -mod rustc { - use super::*; - use crate::prelude::*; - - impl<'t, S> SInto for rustc_span::symbol::Symbol { - fn sinto(&self, _s: &S) -> Symbol { - self.to_ident_string() - } - } - - impl SInto for rustc_hir::Mutability { - fn sinto(&self, _s: &S) -> Mutability { - match self { - rustc_hir::Mutability::Mut => true, - _ => false, - } - } - } -} diff --git a/frontend/exporter/src/types/span.rs b/frontend/exporter/src/types/span.rs new file mode 100644 index 000000000..5fe436da9 --- /dev/null +++ b/frontend/exporter/src/types/span.rs @@ -0,0 +1,295 @@ +use crate::prelude::*; +use crate::sinto_todo; + +/// Reflects [`rustc_span::Loc`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Loc { + pub line: usize, + pub col: usize, +} + +/// Reflects [`rustc_span::hygiene::DesugaringKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(, from: rustc_span::hygiene::DesugaringKind, state: S as _s)] +pub enum DesugaringKind { + CondTemporary, + QuestionMark, + TryBlock, + YeetExpr, + OpaqueTy, + Async, + Await, + ForLoop, + WhileLoop, + BoundModifier, +} + +/// Reflects [`rustc_span::hygiene::AstPass`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(, from: rustc_span::hygiene::AstPass, state: S as _s)] +pub enum AstPass { + StdImports, + TestHarness, + ProcMacroHarness, +} + +/// Reflects [`rustc_span::hygiene::MacroKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(, from: rustc_span::hygiene::MacroKind, state: S as _s)] +pub enum MacroKind { + Bang, + Attr, + Derive, +} + +/// Reflects [`rustc_span::hygiene::ExpnKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_span::hygiene::ExpnKind, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ExpnKind { + Root, + Macro(MacroKind, Symbol), + AstPass(AstPass), + Desugaring(DesugaringKind), +} + +/// Reflects [`rustc_span::edition::Edition`] +#[derive(AdtInto)] +#[args(, from: rustc_span::edition::Edition, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Edition { + Edition2015, + Edition2018, + Edition2021, + Edition2024, +} + +/// Reflects [`rustc_span::hygiene::ExpnData`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_span::hygiene::ExpnData, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct ExpnData { + pub kind: ExpnKind, + // pub parent: Box, + pub call_site: Span, + pub def_site: Span, + #[map(x.as_ref().map(|x| x.clone().iter().map(|x|x.sinto(state)).collect()))] + pub allow_internal_unstable: Option>, + pub edition: Edition, + pub macro_def_id: Option, + pub parent_module: Option, + pub local_inner_macros: bool, +} + +/// Reflects [`rustc_span::Span`] +#[derive(::serde::Serialize, ::serde::Deserialize, Clone, Debug, JsonSchema, Eq, Ord)] +pub struct Span { + pub lo: Loc, + pub hi: Loc, + pub filename: FileName, + /// Original rustc span; can be useful for reporting rustc + /// diagnostics (this is used in Charon) + #[cfg(feature = "rustc")] + #[serde(skip)] + pub rust_span_data: Option, + #[cfg(not(feature = "rustc"))] + #[serde(skip)] + pub rust_span_data: Option<()>, + // expn_backtrace: Vec, +} + +/// We need to define manual `impl`s of `Span`: we want to skip the +/// field `rust_span_data`. The derive macros from `bincode` don't +/// allow that, see https://github.com/bincode-org/bincode/issues/452. +const _: () = { + impl bincode::Encode for Span { + fn encode( + &self, + encoder: &mut E, + ) -> core::result::Result<(), bincode::error::EncodeError> { + bincode::Encode::encode(&self.lo, encoder)?; + bincode::Encode::encode(&self.hi, encoder)?; + bincode::Encode::encode(&self.filename, encoder)?; + Ok(()) + } + } + + impl bincode::Decode for Span { + fn decode( + decoder: &mut D, + ) -> core::result::Result { + Ok(Self { + lo: bincode::Decode::decode(decoder)?, + hi: bincode::Decode::decode(decoder)?, + filename: bincode::Decode::decode(decoder)?, + rust_span_data: None, + }) + } + } + + impl<'de> bincode::BorrowDecode<'de> for Span { + fn borrow_decode>( + decoder: &mut D, + ) -> core::result::Result { + Ok(Self { + lo: bincode::BorrowDecode::borrow_decode(decoder)?, + hi: bincode::BorrowDecode::borrow_decode(decoder)?, + filename: bincode::BorrowDecode::borrow_decode(decoder)?, + rust_span_data: None, + }) + } + } +}; + +const _: () = { + // `rust_span_data` is a metadata that should *not* be taken into + // account while hashing or comparing + + impl std::hash::Hash for Span { + fn hash(&self, state: &mut H) { + self.lo.hash(state); + self.hi.hash(state); + self.filename.hash(state); + } + } + impl PartialEq for Span { + fn eq(&self, other: &Self) -> bool { + self.lo == other.lo && self.hi == other.hi && self.filename == other.filename + } + } + + impl PartialOrd for Span { + fn partial_cmp(&self, other: &Self) -> Option { + Some( + self.lo.partial_cmp(&other.lo)?.then( + self.hi + .partial_cmp(&other.hi)? + .then(self.filename.partial_cmp(&other.filename)?), + ), + ) + } + } +}; + +#[cfg(feature = "rustc")] +impl From for Loc { + fn from(val: rustc_span::Loc) -> Self { + Loc { + line: val.line, + col: val.col_display, + } + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: BaseState<'tcx>> SInto for rustc_span::Span { + fn sinto(&self, s: &S) -> Span { + if let Some(span) = s.with_global_cache(|cache| cache.spans.get(self).cloned()) { + return span; + } + let span = translate_span(*self, s.base().tcx.sess); + s.with_global_cache(|cache| cache.spans.insert(*self, span.clone())); + span + } +} + +/// Reflects [`rustc_span::source_map::Spanned`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Spanned { + pub node: T, + pub span: Span, +} +#[cfg(feature = "rustc")] +impl<'s, S: UnderOwnerState<'s>, T: SInto, U> SInto> + for rustc_span::source_map::Spanned +{ + fn sinto<'a>(&self, s: &S) -> Spanned { + Spanned { + node: self.node.sinto(s), + span: self.span.sinto(s), + } + } +} + +impl<'tcx, S> SInto for PathBuf { + fn sinto(&self, _: &S) -> PathBuf { + self.clone() + } +} + +/// Reflects [`rustc_span::RealFileName`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[args(, from: rustc_span::RealFileName, state: S as _s)] +pub enum RealFileName { + LocalPath(PathBuf), + Remapped { + local_path: Option, + virtual_name: PathBuf, + }, +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_data_structures::stable_hasher::Hash64 { + fn sinto(&self, _: &S) -> u64 { + self.as_u64() + } +} + +/// Reflects [`rustc_span::FileName`] +#[derive(AdtInto)] +#[args(, from: rustc_span::FileName, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum FileName { + Real(RealFileName), + QuoteExpansion(u64), + Anon(u64), + MacroExpansion(u64), + ProcMacroSourceCode(u64), + CliCrateAttr(u64), + Custom(String), + // #[map(FileName::DocTest(x.0.to_str().unwrap().into()))] + #[custom_arm(FROM_TYPE::DocTest(x, _) => TO_TYPE::DocTest(x.to_str().unwrap().into()),)] + DocTest(String), + InlineAsm(u64), +} + +impl FileName { + pub fn to_string(&self) -> String { + match self { + Self::Real(RealFileName::LocalPath(path)) + | Self::Real(RealFileName::Remapped { + local_path: Some(path), + .. + }) + | Self::Real(RealFileName::Remapped { + virtual_name: path, .. + }) => format!("{}", path.display()), + _ => format!("{:?}", self), + } + } + pub fn to_path(&self) -> Option<&std::path::Path> { + match self { + Self::Real(RealFileName::LocalPath(path)) + | Self::Real(RealFileName::Remapped { + local_path: Some(path), + .. + }) + | Self::Real(RealFileName::Remapped { + virtual_name: path, .. + }) => Some(path), + _ => None, + } + } +} + +sinto_todo!(rustc_span, ErrorGuaranteed); diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs new file mode 100644 index 000000000..d2a28379e --- /dev/null +++ b/frontend/exporter/src/types/thir.rs @@ -0,0 +1,897 @@ +//! Copies of the relevant `THIR` types. THIR represents a HIR (function) body augmented with type +//! information and lightly desugared. +use crate::prelude::*; + +/// Reflects [`rustc_middle::thir::LogicalOp`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'a, S>, from: rustc_middle::thir::LogicalOp, state: S as _s)] +pub enum LogicalOp { + And, + Or, +} + +/// Reflects [`rustc_middle::thir::LintLevel`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'slt, S: UnderOwnerState<'slt> + HasThir<'slt>>, from: rustc_middle::thir::LintLevel, state: S as gstate)] +pub enum LintLevel { + Inherited, + Explicit(HirId), +} + +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::FruInfo<'tcx>, state: S as gstate)] +/// Field Record Update (FRU) informations, this reflects [`rustc_middle::thir::FruInfo`] +pub struct FruInfo { + /// The base, e.g. `Foo {x: 1, .. base}` + pub base: Expr, + pub field_types: Vec, +} + +/// A field expression: a field name along with a value +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct FieldExpr { + pub field: DefId, + pub value: Expr, +} + +/// Reflects [`rustc_middle::thir::AdtExpr`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct AdtExpr { + pub info: VariantInformations, + pub user_ty: Option, + pub fields: Vec, + pub base: Option, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr<'tcx> { + fn sinto(&self, s: &S) -> AdtExpr { + let variants = self.adt_def.variants(); + let variant: &rustc_middle::ty::VariantDef = &variants[self.variant_index]; + AdtExpr { + info: get_variant_information(&self.adt_def, self.variant_index, s), + fields: self + .fields + .iter() + .map(|f| FieldExpr { + field: variant.fields[f.name].did.sinto(s), + value: f.expr.sinto(s), + }) + .collect(), + base: self.base.sinto(s), + user_ty: self.user_ty.sinto(s), + } + } +} + +/// Reflects [`rustc_middle::thir::LocalVarId`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct LocalIdent { + pub name: String, + pub id: HirId, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir::LocalVarId { + fn sinto(&self, s: &S) -> LocalIdent { + LocalIdent { + name: s + .base() + .local_ctx + .borrow() + .vars + .get(self) + .s_unwrap(s) + .to_string(), + id: self.0.sinto(s), + } + } +} + +/// Reflects [`rustc_middle::thir::BlockSafety`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S>, from: rustc_middle::thir::BlockSafety, state: S as _s)] +pub enum BlockSafety { + Safe, + BuiltinUnsafe, + #[custom_arm(FROM_TYPE::ExplicitUnsafe{..} => BlockSafety::ExplicitUnsafe,)] + ExplicitUnsafe, +} + +/// Reflects [`rustc_middle::thir::Block`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Block, state: S as gstate)] +pub struct Block { + pub targeted_by_break: bool, + pub region_scope: Scope, + pub span: Span, + pub stmts: Vec, + pub expr: Option, + pub safety_mode: BlockSafety, +} + +/// Reflects [`rustc_middle::thir::Stmt`] +#[derive(AdtInto)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Stmt<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Stmt { + pub kind: StmtKind, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::BlockId { + fn sinto(&self, s: &S) -> Block { + s.thir().blocks[*self].sinto(s) + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::StmtId { + fn sinto(&self, s: &S) -> Stmt { + s.thir().stmts[*self].sinto(s) + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> { + fn sinto(&self, s: &S) -> Expr { + let (hir_id, attributes) = self.hir_id_and_attributes(s); + let hir_id = hir_id.map(|hir_id| hir_id.index()); + let unrolled = self.unroll_scope(s); + let rustc_middle::thir::Expr { span, kind, ty, .. } = unrolled; + let contents = match macro_invocation_of_span(span, s).map(ExprKind::MacroInvokation) { + Some(contents) => contents, + None => match kind { + // Introduce intermediate `Cast` from `T` to `U` when casting from a `#[repr(T)]` enum to `U` + rustc_middle::thir::ExprKind::Cast { source } => { + if let rustc_middle::ty::TyKind::Adt(adt, _) = s.thir().exprs[source].ty.kind() + { + let tcx = s.base().tcx; + let contents = kind.sinto(s); + let repr_type = if adt.is_enum() { + use crate::rustc_middle::ty::util::IntTypeExt; + adt.repr().discr_type().to_ty(tcx) + } else { + ty + }; + if repr_type == ty { + contents + } else { + ExprKind::Cast { + source: Decorated { + ty: repr_type.sinto(s), + span: span.sinto(s), + contents: Box::new(contents), + hir_id, + attributes: vec![], + }, + } + } + } else { + kind.sinto(s) + } + } + rustc_middle::thir::ExprKind::NonHirLiteral { lit, .. } => { + let cexpr: ConstantExpr = + (ConstantExprKind::Literal(scalar_int_to_constant_literal(s, lit, ty))) + .decorate(ty.sinto(s), span.sinto(s)); + return cexpr.into(); + } + rustc_middle::thir::ExprKind::ZstLiteral { .. } => match ty.kind() { + rustc_middle::ty::TyKind::FnDef(def, _generics) => { + /* TODO: translate generics + let tcx = s.base().tcx; + let sig = &tcx.fn_sig(*def).instantiate(tcx, generics); + let ret: rustc_middle::ty::Ty = tcx.erase_late_bound_regions(sig.output()); + let inputs = sig.inputs(); + let indexes = inputs.skip_binder().iter().enumerate().map(|(i, _)| i); + let params = indexes.map(|i| inputs.map_bound(|tys| tys[i])); + let params: Vec = + params.map(|i| tcx.erase_late_bound_regions(i)).collect(); + */ + return Expr { + contents: Box::new(ExprKind::GlobalName { id: def.sinto(s) }), + span: self.span.sinto(s), + ty: ty.sinto(s), + hir_id, + attributes, + }; + } + _ => { + if ty.is_phantom_data() { + let rustc_middle::ty::Adt(def, _) = ty.kind() else { + supposely_unreachable_fatal!(s[span], "PhantomDataNotAdt"; {kind, ty}) + }; + let adt_def = AdtExpr { + info: get_variant_information( + def, + rustc_target::abi::FIRST_VARIANT, + s, + ), + user_ty: None, + base: None, + fields: vec![], + }; + return Expr { + contents: Box::new(ExprKind::Adt(adt_def)), + span: self.span.sinto(s), + ty: ty.sinto(s), + hir_id, + attributes, + }; + } else { + supposely_unreachable!( + s[span], + "ZstLiteral ty≠FnDef(...) or PhantomData"; + {kind, span, ty} + ); + kind.sinto(s) + } + } + }, + rustc_middle::thir::ExprKind::Field { + lhs, + variant_index, + name, + } => { + let lhs_ty = s.thir().exprs[lhs].ty.kind(); + let idx = variant_index.index(); + if idx != 0 { + let _ = supposely_unreachable!( + s[span], + "ExprKindFieldIdxNonZero"; { + kind, + span, + ty, + ty.kind() + } + ); + }; + match lhs_ty { + rustc_middle::ty::TyKind::Adt(adt_def, _generics) => { + let variant = adt_def.variant(variant_index); + ExprKind::Field { + field: variant.fields[name].did.sinto(s), + lhs: lhs.sinto(s), + } + } + rustc_middle::ty::TyKind::Tuple(..) => ExprKind::TupleField { + field: name.index(), + lhs: lhs.sinto(s), + }, + _ => supposely_unreachable_fatal!( + s[span], + "ExprKindFieldBadTy"; { + kind, + span, + ty.kind(), + lhs_ty + } + ), + } + } + _ => kind.sinto(s), + }, + }; + Decorated { + ty: ty.sinto(s), + span: span.sinto(s), + contents: Box::new(contents), + hir_id, + attributes, + } + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ExprId { + fn sinto(&self, s: &S) -> Expr { + s.thir().exprs[*self].sinto(s) + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { + fn sinto(&self, s: &S) -> Pat { + let rustc_middle::thir::Pat { span, kind, ty } = self; + let contents = match kind { + rustc_middle::thir::PatKind::Leaf { subpatterns } => match ty.kind() { + rustc_middle::ty::TyKind::Adt(adt_def, args) => { + (rustc_middle::thir::PatKind::Variant { + adt_def: *adt_def, + args, + variant_index: rustc_target::abi::VariantIdx::from_usize(0), + subpatterns: subpatterns.clone(), + }) + .sinto(s) + } + rustc_middle::ty::TyKind::Tuple(..) => PatKind::Tuple { + subpatterns: subpatterns + .iter() + .map(|pat| pat.pattern.clone()) + .collect::>() + .sinto(s), + }, + _ => supposely_unreachable_fatal!( + s[span], + "PatLeafNonAdtTy"; + {ty.kind(), kind} + ), + }, + _ => kind.sinto(s), + }; + Decorated { + ty: ty.sinto(s), + span: span.sinto(s), + contents: Box::new(contents), + hir_id: None, + attributes: vec![], + } + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ArmId { + fn sinto(&self, s: &S) -> Arm { + s.thir().arms[*self].sinto(s) + } +} + +/// Reflects [`rustc_middle::thir::StmtKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::StmtKind<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum StmtKind { + Expr { + scope: Scope, + expr: Expr, + }, + Let { + remainder_scope: Scope, + init_scope: Scope, + pattern: Pat, + initializer: Option, + else_block: Option, + lint_level: LintLevel, + #[value(attribute_from_scope(gstate, init_scope).1)] + /// The attribute on this `let` binding + attributes: Vec, + }, +} + +/// Reflects [`rustc_middle::thir::Ascription`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::Ascription<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Ascription { + pub annotation: CanonicalUserTypeAnnotation, + pub variance: Variance, +} + +/// Reflects [`rustc_middle::thir::PatRange`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRange<'tcx>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct PatRange { + pub lo: PatRangeBoundary, + pub hi: PatRangeBoundary, + pub end: RangeEnd, +} + +/// Reflects [`rustc_middle::thir::PatRangeBoundary`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRangeBoundary<'tcx>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum PatRangeBoundary { + Finite(ConstantExpr), + NegInfinity, + PosInfinity, +} + +/// A field pattern: a field name along with a pattern +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct FieldPat { + pub field: DefId, + pub pattern: Pat, +} + +pub type Pat = Decorated; + +/// Reflects [`rustc_middle::thir::PatKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::PatKind<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +#[append(rustc_middle::thir::PatKind::Leaf {..} => fatal!(gstate, "PatKind::Leaf: should never come up"),)] +pub enum PatKind { + Wild, + AscribeUserType { + ascription: Ascription, + subpattern: Pat, + }, + #[custom_arm( + rustc_middle::thir::PatKind::Binding {name, mode, var, ty, subpattern, is_primary} => { + let local_ctx = gstate.base().local_ctx; + local_ctx.borrow_mut().vars.insert(*var, name.to_string()); + PatKind::Binding { + mode: mode.sinto(gstate), + var: var.sinto(gstate), + ty: ty.sinto(gstate), + subpattern: subpattern.sinto(gstate), + is_primary: is_primary.sinto(gstate), + } + } + )] + Binding { + mode: BindingMode, + var: LocalIdent, // name VS var? TODO + ty: Ty, + subpattern: Option, + is_primary: bool, + }, + #[custom_arm( + FROM_TYPE::Variant {adt_def, variant_index, args, subpatterns} => { + let variants = adt_def.variants(); + let variant: &rustc_middle::ty::VariantDef = &variants[*variant_index]; + TO_TYPE::Variant { + info: get_variant_information(adt_def, *variant_index, gstate), + subpatterns: subpatterns + .iter() + .map(|f| FieldPat { + field: variant.fields[f.field].did.sinto(gstate), + pattern: f.pattern.sinto(gstate), + }) + .collect(), + args: args.sinto(gstate), + } + } + )] + Variant { + info: VariantInformations, + args: Vec, + subpatterns: Vec, + }, + #[disable_mapping] + Tuple { + subpatterns: Vec, + }, + Deref { + subpattern: Pat, + }, + DerefPattern { + subpattern: Pat, + }, + Constant { + value: ConstantExpr, + }, + InlineConstant { + def: DefId, + subpattern: Pat, + }, + Range(PatRange), + Slice { + prefix: Vec, + slice: Option, + suffix: Vec, + }, + Array { + prefix: Vec, + slice: Option, + suffix: Vec, + }, + Or { + pats: Vec, + }, + Never, + Error(ErrorGuaranteed), +} + +/// Reflects [`rustc_middle::thir::Arm`] +#[derive(AdtInto)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Arm<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Arm { + pub pattern: Pat, + pub guard: Option, + pub body: Expr, + pub lint_level: LintLevel, + pub scope: Scope, + pub span: Span, + #[value(attribute_from_scope(gstate, scope).1)] + attributes: Vec, +} + +/// Reflects [`rustc_middle::thir::Param`] +#[derive(AdtInto)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Param<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Param { + pub pat: Option, + pub ty: Ty, + pub ty_span: Option, + pub self_kind: Option, + pub hir_id: Option, + #[value(hir_id.map(|id| { + s.base().tcx.hir().attrs(id).sinto(s) + }).unwrap_or(vec![]))] + /// attributes on this parameter + pub attributes: Vec, +} + +pub type ThirBody = Expr; +pub type Expr = Decorated; + +/// Reflects [`rustc_middle::thir::ExprKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::ExprKind<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +#[append( + rustc_middle::thir::ExprKind::Scope {..} => { + fatal!(gstate, "Scope should have been eliminated at this point"); + }, + rustc_middle::thir::ExprKind::Field {..} => { + fatal!(gstate, "Field should have been eliminated at this point"); + }, + rustc_middle::thir::ExprKind::NonHirLiteral {..} => { + fatal!(gstate, "NonHirLiteral should have been eliminated at this point"); + }, +)] +pub enum ExprKind { + Box { + value: Expr, + }, + #[disable_mapping] + MacroInvokation(MacroInvokation), + /// Resugared macros calls. This is deprecated: see + /// . + If { + if_then_scope: Scope, + cond: Expr, + then: Expr, + else_opt: Option, + }, + #[map({ + let e = gstate.thir().exprs[*fun].unroll_scope(gstate); + let (generic_args, r#trait, bounds_impls); + // A function is any expression whose type is something callable + let fun = match ty.kind() { + rustc_middle::ty::TyKind::FnDef(def_id, generics) => { + let (hir_id, attributes) = e.hir_id_and_attributes(gstate); + let hir_id = hir_id.map(|hir_id| hir_id.index()); + let contents = Box::new(ExprKind::GlobalName { + id: def_id.sinto(gstate) + }); + let mut translated_generics = generics.sinto(gstate); + let tcx = gstate.base().tcx; + r#trait = (|| { + let assoc_item = tcx.opt_associated_item(*def_id)?; + let impl_expr = self_clause_for_item(gstate, &assoc_item, generics)?; + let assoc_generics = tcx.generics_of(assoc_item.def_id); + let assoc_generics = translated_generics.drain(0..assoc_generics.parent_count).collect(); + Some((impl_expr, assoc_generics)) + })(); + generic_args = translated_generics; + bounds_impls = solve_item_traits(gstate, *def_id, generics, None); + Expr { + contents, + span: e.span.sinto(gstate), + ty: e.ty.sinto(gstate), + hir_id, + attributes, + } + }, + rustc_middle::ty::TyKind::FnPtr(..) => { + generic_args = vec![]; // A function pointer has no generics + bounds_impls = vec![]; // A function pointer has no bounds + r#trait = None; // A function pointer is not a method + e.sinto(gstate) + }, + ty_kind => supposely_unreachable_fatal!( + gstate[e.span], + "CallNotTyFnDef"; + {e, ty_kind} + ) + }; + TO_TYPE::Call { + ty: ty.sinto(gstate), + args: args.sinto(gstate), + generic_args, + from_hir_call: from_hir_call.sinto(gstate), + fn_span: fn_span.sinto(gstate), + bounds_impls, + r#trait, + fun, + } + })] + /// A call to a function or a method. + /// + /// Example: `f(0i8)`, where `f` has signature `fn f(t: T) -> ()`. + Call { + /// The type of the function, substitution applied. + /// + /// Example: for the call `f(0i8)`, this is `i8 -> ()`. + ty: Ty, + /// The function itself. This can be something else than a + /// name, e.g. a closure. + /// + /// Example: for the call `f(0i8)`, this is `f`. + fun: Expr, // TODO: can [ty] and [fun.ty] be different? + /// The arguments given to the function. + /// + /// Example: for the call `f(0i8)`, this is `[0i8]`. + args: Vec, + from_hir_call: bool, + fn_span: Span, + /// The generic arguments given to the function. + /// + /// Example: for the call `f(0i8)`, this is the type `i8`. + #[not_in_source] + generic_args: Vec, + /// The implementations for the bounds of the function. + /// + /// Example: for the call `f(0i8)`, this is two implementation + /// expressions, one for the explicit bound `i8: Clone` and + /// one for the implicit `i8: Sized`. + #[not_in_source] + bounds_impls: Vec, + /// `trait` is `None` if this is a function call or a method + /// to an inherent trait. If this is a method call from a + /// trait `Trait`, then it contains the concrete + /// implementation of `Trait` it is called on, and the generic + /// arguments that comes from the trait declaration. + /// + /// Example: `f(0i8)` is a function call, hence the field + /// `impl` is `None`. + /// + /// Example: + /// ```ignore + /// trait MyTrait { + /// fn meth(...) {...} + /// } + /// fn example_call>(x: SelfType) { + /// x.meth::(...) + /// } + /// ``` + /// Here, in the call `x.meth::(...)`, `r#trait` will + /// be `Some((..., [SelfType, TraitType, 12]))`, and `generic_args` + /// will be `[String]`. + #[not_in_source] + r#trait: Option<(ImplExpr, Vec)>, + }, + Deref { + arg: Expr, + }, + Binary { + op: BinOp, + lhs: Expr, + rhs: Expr, + }, + LogicalOp { + op: LogicalOp, + lhs: Expr, + rhs: Expr, + }, + Unary { + op: UnOp, + arg: Expr, + }, + Cast { + source: Expr, + }, + Use { + source: Expr, + }, // Use a lexpr to get a vexpr. + NeverToAny { + source: Expr, + }, + PointerCoercion { + cast: PointerCoercion, + source: Expr, + }, + Loop { + body: Expr, + }, + Match { + scrutinee: Expr, + arms: Vec, + }, + Let { + expr: Expr, + pat: Pat, + }, + Block { + #[serde(flatten)] + block: Block, + }, + Assign { + lhs: Expr, + rhs: Expr, + }, + AssignOp { + op: BinOp, + lhs: Expr, + rhs: Expr, + }, + #[disable_mapping] + Field { + field: DefId, + lhs: Expr, + }, + + #[disable_mapping] + TupleField { + field: usize, + lhs: Expr, + }, + Index { + lhs: Expr, + index: Expr, + }, + VarRef { + id: LocalIdent, + }, + #[disable_mapping] + ConstRef { + id: ParamConst, + }, + #[disable_mapping] + GlobalName { + id: GlobalIdent, + }, + UpvarRef { + closure_def_id: DefId, + var_hir_id: LocalIdent, + }, + Borrow { + borrow_kind: BorrowKind, + arg: Expr, + }, + AddressOf { + mutability: Mutability, + arg: Expr, + }, + Break { + label: Scope, + value: Option, + }, + Continue { + label: Scope, + }, + Return { + value: Option, + }, + ConstBlock { + did: DefId, + args: Vec, + }, + Repeat { + value: Expr, + count: ConstantExpr, + }, + Array { + fields: Vec, + }, + Tuple { + fields: Vec, + }, + Adt(AdtExpr), + PlaceTypeAscription { + source: Expr, + user_ty: Option, + }, + ValueTypeAscription { + source: Expr, + user_ty: Option, + }, + #[custom_arm(FROM_TYPE::Closure(e) => { + let (thir, expr_entrypoint) = get_thir(e.closure_id, gstate); + let s = &State::from_thir(gstate.base(), gstate.owner_id(), thir.clone()); + TO_TYPE::Closure { + params: thir.params.raw.sinto(s), + body: expr_entrypoint.sinto(s), + upvars: e.upvars.sinto(gstate), + movability: e.movability.sinto(gstate) + } + }, + )] + Closure { + params: Vec, + body: Expr, + upvars: Vec, + movability: Option, + }, + Literal { + lit: Spanned, + neg: bool, // TODO + }, + //zero space type + // This is basically used for functions! e.g. `::from` + ZstLiteral { + user_ty: Option, + }, + NamedConst { + def_id: GlobalIdent, + args: Vec, + user_ty: Option, + #[not_in_source] + #[value({ + let tcx = gstate.base().tcx; + tcx.opt_associated_item(*def_id).as_ref().and_then(|assoc| { + self_clause_for_item(gstate, assoc, args) + }) + })] + r#impl: Option, + }, + ConstParam { + param: ParamConst, + def_id: GlobalIdent, + }, + StaticRef { + alloc_id: u64, + ty: Ty, + def_id: GlobalIdent, + }, + Yield { + value: Expr, + }, + #[todo] + Todo(String), +} + +#[cfg(feature = "rustc")] +pub trait ExprKindExt<'tcx> { + fn hir_id_and_attributes>( + &self, + s: &S, + ) -> (Option, Vec); + fn unroll_scope + HasThir<'tcx>>( + &self, + s: &S, + ) -> rustc_middle::thir::Expr<'tcx>; +} + +#[cfg(feature = "rustc")] +impl<'tcx> ExprKindExt<'tcx> for rustc_middle::thir::Expr<'tcx> { + fn hir_id_and_attributes>( + &self, + s: &S, + ) -> (Option, Vec) { + match &self.kind { + rustc_middle::thir::ExprKind::Scope { + region_scope: scope, + .. + } => attribute_from_scope(s, scope), + _ => (None, vec![]), + } + } + fn unroll_scope + HasThir<'tcx>>( + &self, + s: &S, + ) -> rustc_middle::thir::Expr<'tcx> { + // TODO: when we see a loop, we should lookup its label! label is actually a scope id + // we remove scopes here, whence the TODO + match self.kind { + rustc_middle::thir::ExprKind::Scope { value, .. } => { + s.thir().exprs[value].unroll_scope(s) + } + _ => self.clone(), + } + } +} diff --git a/frontend/exporter/src/types/todo.rs b/frontend/exporter/src/types/todo.rs deleted file mode 100644 index c164478e1..000000000 --- a/frontend/exporter/src/types/todo.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::prelude::*; -use crate::sinto_todo; -sinto_todo!(rustc_middle::ty, ScalarInt); -sinto_todo!(rustc_middle::ty, AdtFlags); -sinto_todo!(rustc_middle::ty, NormalizesTo<'tcx>); -sinto_todo!(rustc_abi, IntegerType); -sinto_todo!(rustc_abi, ReprFlags); -sinto_todo!(rustc_abi, Align); -sinto_todo!(rustc_middle::mir::interpret, ConstAllocation<'a>); -sinto_todo!(rustc_middle::mir, UnwindTerminateReason); -sinto_todo!(rustc_ast::tokenstream, DelimSpan); -sinto_todo!(rustc_ast::tokenstream, DelimSpacing); -sinto_todo!(rustc_hir::def, DefKind); -sinto_todo!(rustc_hir, GenericArgs<'a> as HirGenericArgs); -sinto_todo!(rustc_hir, InlineAsm<'a>); -sinto_todo!(rustc_target::spec::abi, Abi); -sinto_todo!(rustc_hir, MissingLifetimeKind); -sinto_todo!(rustc_hir, QPath<'tcx>); -sinto_todo!(rustc_hir, WhereRegionPredicate<'tcx>); -sinto_todo!(rustc_hir, WhereEqPredicate<'tcx>); -sinto_todo!(rustc_hir, OwnerId); diff --git a/frontend/exporter/src/types/tokens.rs b/frontend/exporter/src/types/tokens.rs new file mode 100644 index 000000000..4b1764738 --- /dev/null +++ b/frontend/exporter/src/types/tokens.rs @@ -0,0 +1,156 @@ +//! Copies of types related to tokens and syntax representation of rust, as well as macros. +use crate::prelude::*; + +/// Reflects [`rustc_ast::token::Delimiter`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::token::Delimiter, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Delimiter { + Parenthesis, + Brace, + Bracket, + Invisible, +} + +/// Reflects [`rustc_ast::tokenstream::TokenTree`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::TokenTree, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum TokenTree { + Token(Token, Spacing), + Delimited(DelimSpan, DelimSpacing, Delimiter, TokenStream), +} + +sinto_todo!(rustc_ast::tokenstream, DelimSpan); +sinto_todo!(rustc_ast::tokenstream, DelimSpacing); + +/// Reflects [`rustc_ast::tokenstream::Spacing`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::Spacing, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Spacing { + Alone, + Joint, + JointHidden, +} + +/// Reflects [`rustc_ast::token::BinOpToken`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::token::BinOpToken, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum BinOpToken { + Plus, + Minus, + Star, + Slash, + Percent, + Caret, + And, + Or, + Shl, + Shr, +} + +/// Reflects [`rustc_ast::token::TokenKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::TokenKind, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum TokenKind { + Eq, + Lt, + Le, + EqEq, + Ne, + Ge, + Gt, + AndAnd, + OrOr, + Not, + Tilde, + BinOp(BinOpToken), + BinOpEq(BinOpToken), + At, + Dot, + DotDot, + DotDotDot, + DotDotEq, + Comma, + Semi, + Colon, + RArrow, + LArrow, + FatArrow, + Pound, + Dollar, + Question, + SingleQuote, + OpenDelim(Delimiter), + CloseDelim(Delimiter), + // Literal(l: Lit), + Ident(Symbol, bool), + Lifetime(Symbol), + // Interpolated(n: Nonterminal), + // DocComment(k: CommentKind, ats: AttrStyle, s: Symbol), + Eof, + #[todo] + Todo(String), +} + +#[cfg(feature = "rustc")] +impl SInto for rustc_ast::token::IdentIsRaw { + fn sinto(&self, _s: &S) -> bool { + match self { + Self::Yes => true, + Self::No => false, + } + } +} + +/// Reflects [`rustc_ast::token::Token`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::Token, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Token { + pub kind: TokenKind, + pub span: Span, +} + +/// Reflects [`rustc_ast::ast::DelimArgs`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::ast::DelimArgs, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct DelimArgs { + pub dspan: DelimSpan, + pub delim: Delimiter, + pub tokens: TokenStream, +} + +/// Reflects [`rustc_ast::ast::MacCall`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::ast::MacCall, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct MacCall { + #[map(x.segments.iter().map(|rustc_ast::ast::PathSegment{ident, ..}| ident.as_str().into()).collect())] + pub path: Path, + pub args: DelimArgs, +} + +/// Reflects [`rustc_ast::tokenstream::TokenStream`] as a plain +/// string. If you need to reshape that into Rust tokens or construct, +/// please use, e.g., `syn`. +pub type TokenStream = String; + +#[cfg(feature = "rustc")] +impl<'t, S> SInto for rustc_ast::tokenstream::TokenStream { + fn sinto(&self, _: &S) -> String { + rustc_ast_pretty::pprust::tts_to_string(self) + } +} diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs new file mode 100644 index 000000000..fdedf0597 --- /dev/null +++ b/frontend/exporter/src/types/ty.rs @@ -0,0 +1,1435 @@ +//! Copies of the relevant type-level types. These are semantically-rich representations of +//! type-level concepts such as types and trait references. +use crate::prelude::*; +use crate::sinto_as_usize; +use crate::sinto_todo; +use std::sync::Arc; + +#[cfg(feature = "rustc")] +use rustc_middle::ty; + +/// Generic container for decorating items with a type, a span, +/// attributes and other meta-data. +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Decorated { + pub ty: Ty, + pub span: Span, + pub contents: Box, + pub hir_id: Option<(usize, usize)>, + pub attributes: Vec, +} + +/// Reflects [`rustc_middle::infer::canonical::CanonicalTyVarKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalTyVarKind, state: S as gstate)] +pub enum CanonicalTyVarKind { + General(UniverseIndex), + Int, + Float, +} + +sinto_as_usize!(rustc_middle::ty, UniverseIndex); + +/// Reflects [`rustc_middle::ty::ParamTy`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ParamTy, state: S as gstate)] +pub struct ParamTy { + pub index: u32, + pub name: Symbol, +} + +/// Reflects [`rustc_middle::ty::ParamConst`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(, from: rustc_middle::ty::ParamConst, state: S as gstate)] +pub struct ParamConst { + pub index: u32, + pub name: Symbol, +} + +/// A predicate without `Self`, for use in `dyn Trait`. +/// +/// Reflects [`rustc_middle::ty::ExistentialPredicate`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ExistentialPredicate<'tcx>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ExistentialPredicate { + /// E.g. `From`. Note that this isn't `T: From` with a given `T`, this is just + /// `From`. Could be written `?: From`. + Trait(ExistentialTraitRef), + /// E.g. `Iterator::Item = u64`. Could be written `::Item = u64`. + Projection(ExistentialProjection), + /// E.g. `Send`. + AutoTrait(DefId), +} + +/// Reflects [`rustc_type_ir::ExistentialTraitRef`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_type_ir::ExistentialTraitRef>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ExistentialTraitRef { + pub def_id: DefId, + pub args: Vec, +} + +/// Reflects [`rustc_type_ir::ExistentialProjection`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_type_ir::ExistentialProjection>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ExistentialProjection { + pub def_id: DefId, + pub args: Vec, + pub term: Term, +} + +/// Reflects [`rustc_middle::ty::DynKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(, from: rustc_middle::ty::DynKind, state: S as _s)] +pub enum DynKind { + Dyn, + DynStar, +} + +/// Reflects [`rustc_middle::ty::BoundTyKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTyKind, state: S as gstate)] +pub enum BoundTyKind { + Anon, + Param(DefId, Symbol), +} + +/// Reflects [`rustc_middle::ty::BoundTy`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTy, state: S as gstate)] +pub struct BoundTy { + pub var: BoundVar, + pub kind: BoundTyKind, +} + +sinto_as_usize!(rustc_middle::ty, BoundVar); + +/// Reflects [`rustc_middle::ty::BoundRegionKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegionKind, state: S as gstate)] +pub enum BoundRegionKind { + BrAnon, + BrNamed(DefId, Symbol), + BrEnv, +} + +/// Reflects [`rustc_middle::ty::BoundRegion`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegion, state: S as gstate)] +pub struct BoundRegion { + pub var: BoundVar, + pub kind: BoundRegionKind, +} + +/// Reflects [`rustc_middle::ty::PlaceholderRegion`] +pub type PlaceholderRegion = Placeholder; +/// Reflects [`rustc_middle::ty::PlaceholderConst`] +pub type PlaceholderConst = Placeholder; +/// Reflects [`rustc_middle::ty::PlaceholderType`] +pub type PlaceholderType = Placeholder; + +/// Reflects [`rustc_middle::ty::Placeholder`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Placeholder { + pub universe: UniverseIndex, + pub bound: T, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> + for rustc_middle::ty::Placeholder +{ + fn sinto(&self, s: &S) -> Placeholder { + Placeholder { + universe: self.universe.sinto(s), + bound: self.bound.sinto(s), + } + } +} + +/// Reflects [`rustc_middle::infer::canonical::Canonical`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct Canonical { + pub max_universe: UniverseIndex, + pub variables: Vec, + pub value: T, +} +/// Reflects [`rustc_middle::ty::CanonicalUserType`] +pub type CanonicalUserType = Canonical; + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> + for rustc_middle::infer::canonical::Canonical<'tcx, T> +{ + fn sinto(&self, s: &S) -> Canonical { + Canonical { + max_universe: self.max_universe.sinto(s), + variables: self.variables.iter().map(|v| v.kind.sinto(s)).collect(), + value: self.value.sinto(s), + } + } +} + +/// Reflects [`rustc_middle::infer::canonical::CanonicalVarKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::infer::canonical::CanonicalVarKind>, state: S as gstate)] +pub enum CanonicalVarInfo { + Ty(CanonicalTyVarKind), + PlaceholderTy(PlaceholderType), + Region(UniverseIndex), + PlaceholderRegion(PlaceholderRegion), + Const(UniverseIndex), + PlaceholderConst(PlaceholderConst), + Effect, +} + +/// Reflects [`rustc_middle::ty::UserSelfTy`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserSelfTy<'tcx>, state: S as gstate)] +pub struct UserSelfTy { + pub impl_def_id: DefId, + pub self_ty: Ty, +} + +/// Reflects [`rustc_middle::ty::UserArgs`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserArgs<'tcx>, state: S as gstate)] +pub struct UserArgs { + pub args: Vec, + pub user_self_ty: Option, +} + +/// Reflects [`rustc_middle::ty::UserType`]: this is currently +/// disabled, and everything is printed as debug in the +/// [`UserType::Todo`] variant. +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserType<'tcx>, state: S as _s)] +pub enum UserType { + // TODO: for now, we don't use user types at all. + // We disable it for now, since it cause the following to fail: + // + // pub const MY_VAL: u16 = 5; + // pub type Alias = MyStruct; // Using the literal 5, it goes through + // + // pub struct MyStruct {} + // + // impl MyStruct { + // pub const MY_CONST: u16 = VAL; + // } + // + // pub fn do_something() -> u32 { + // u32::from(Alias::MY_CONST) + // } + // + // In this case, we get a [rustc_middle::ty::ConstKind::Bound] in + // [do_something], which we are not able to translate. + // See: https://github.com/hacspec/hax/pull/209 + + // Ty(Ty), + // TypeOf(DefId, UserArgs), + #[todo] + Todo(String), +} + +/// Reflects [`rustc_middle::ty::VariantDiscr`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::VariantDiscr, state: S as gstate)] +pub enum DiscriminantDefinition { + Explicit(DefId), + Relative(u32), +} + +/// Reflects [`rustc_middle::ty::util::Discr`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::util::Discr<'tcx>, state: S as gstate)] +pub struct DiscriminantValue { + pub val: u128, + pub ty: Ty, +} + +/// Reflects [`rustc_middle::ty::Visibility`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Visibility { + Public, + Restricted(Id), +} + +#[cfg(feature = "rustc")] +impl, U> SInto> for rustc_middle::ty::Visibility { + fn sinto(&self, s: &S) -> Visibility { + use rustc_middle::ty::Visibility as T; + match self { + T::Public => Visibility::Public, + T::Restricted(id) => Visibility::Restricted(id.sinto(s)), + } + } +} + +/// Reflects [`rustc_middle::ty::FieldDef`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct FieldDef { + pub did: DefId, + /// Field definition of [tuple + /// structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types) + /// are anonymous, in that case `name` is [`None`]. + pub name: Option, + pub vis: Visibility, + pub ty: Ty, + pub span: Span, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::FieldDef { + fn sinto(&self, s: &S) -> FieldDef { + let tcx = s.base().tcx; + let ty = { + let generics = rustc_middle::ty::GenericArgs::identity_for_item(tcx, self.did); + self.ty(tcx, generics).sinto(s) + }; + let name = { + let name = self.name.sinto(s); + let is_user_provided = { + // SH: Note that the only way I found of checking if the user wrote the name or if it + // is just an integer generated by rustc is by checking if it is just made of + // numerals... + name.parse::().is_err() + }; + is_user_provided.then_some(name) + }; + + FieldDef { + did: self.did.sinto(s), + name, + vis: self.vis.sinto(s), + ty, + span: tcx.def_span(self.did).sinto(s), + } + } +} + +/// Reflects [`rustc_middle::ty::VariantDef`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct VariantDef { + pub def_id: DefId, + pub ctor: Option<(CtorKind, DefId)>, + pub name: Symbol, + pub discr_def: DiscriminantDefinition, + pub discr_val: DiscriminantValue, + /// The definitions of the fields on this variant. In case of + /// [tuple + /// structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types), + /// the fields are anonymous, otherwise fields are named. + pub fields: Vec, + /// Span of the definition of the variant + pub span: Span, +} + +#[cfg(feature = "rustc")] +impl VariantDef { + fn sfrom<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + def: &ty::VariantDef, + discr_val: ty::util::Discr<'tcx>, + ) -> Self { + VariantDef { + def_id: def.def_id.sinto(s), + ctor: def.ctor.sinto(s), + name: def.name.sinto(s), + discr_def: def.discr.sinto(s), + discr_val: discr_val.sinto(s), + fields: def.fields.raw.sinto(s), + span: s.base().tcx.def_span(def.def_id).sinto(s), + } + } +} + +/// Reflects [`rustc_middle::ty::EarlyParamRegion`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::EarlyParamRegion, state: S as gstate)] +pub struct EarlyParamRegion { + pub index: u32, + pub name: Symbol, +} + +/// Reflects [`rustc_middle::ty::LateParamRegion`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::LateParamRegion, state: S as gstate)] +pub struct LateParamRegion { + pub scope: DefId, + pub bound_region: BoundRegionKind, +} + +/// Reflects [`rustc_middle::ty::RegionKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::RegionKind<'tcx>, state: S as gstate)] +pub enum RegionKind { + ReEarlyParam(EarlyParamRegion), + ReBound(DebruijnIndex, BoundRegion), + ReLateParam(LateParamRegion), + ReStatic, + ReVar(RegionVid), + RePlaceholder(PlaceholderRegion), + ReErased, + ReError(ErrorGuaranteed), +} + +sinto_as_usize!(rustc_middle::ty, DebruijnIndex); +sinto_as_usize!(rustc_middle::ty, RegionVid); + +/// Reflects [`rustc_middle::ty::Region`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Region<'tcx>, state: S as s)] +pub struct Region { + #[value(self.kind().sinto(s))] + pub kind: RegionKind, +} + +/// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericArgKind<'tcx>, state: S as s)] +pub enum GenericArg { + Lifetime(Region), + Type(Ty), + Const(ConstantExpr), +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::GenericArg<'tcx> { + fn sinto(&self, s: &S) -> GenericArg { + self.unpack().sinto(s) + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto> + for rustc_middle::ty::GenericArgsRef<'tcx> +{ + fn sinto(&self, s: &S) -> Vec { + self.iter().map(|v| v.unpack().sinto(s)).collect() + } +} + +/// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitIntType, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum LitIntType { + Signed(IntTy), + Unsigned(UintTy), + Unsuffixed, +} + +/// Reflects partially [`rustc_middle::ty::InferTy`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S>, from: rustc_middle::ty::InferTy, state: S as gstate)] +pub enum InferTy { + #[custom_arm(FROM_TYPE::TyVar(..) => TO_TYPE::TyVar,)] + TyVar, /*TODO?*/ + #[custom_arm(FROM_TYPE::IntVar(..) => TO_TYPE::IntVar,)] + IntVar, /*TODO?*/ + #[custom_arm(FROM_TYPE::FloatVar(..) => TO_TYPE::FloatVar,)] + FloatVar, /*TODO?*/ + FreshTy(u32), + FreshIntTy(u32), + FreshFloatTy(u32), +} + +/// Reflects [`rustc_type_ir::IntTy`] +#[derive(AdtInto)] +#[args(, from: rustc_type_ir::IntTy, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum IntTy { + Isize, + I8, + I16, + I32, + I64, + I128, +} + +/// Reflects [`rustc_type_ir::FloatTy`] +#[derive(AdtInto)] +#[args(, from: rustc_type_ir::FloatTy, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum FloatTy { + F16, + F32, + F64, + F128, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S> SInto for rustc_ast::ast::FloatTy { + fn sinto(&self, _: &S) -> FloatTy { + use rustc_ast::ast::FloatTy as T; + match self { + T::F16 => FloatTy::F16, + T::F32 => FloatTy::F32, + T::F64 => FloatTy::F64, + T::F128 => FloatTy::F128, + } + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S> SInto for rustc_ast::ast::IntTy { + fn sinto(&self, _: &S) -> IntTy { + use rustc_ast::ast::IntTy as T; + match self { + T::Isize => IntTy::Isize, + T::I8 => IntTy::I8, + T::I16 => IntTy::I16, + T::I32 => IntTy::I32, + T::I64 => IntTy::I64, + T::I128 => IntTy::I128, + } + } +} +#[cfg(feature = "rustc")] +impl<'tcx, S> SInto for rustc_ast::ast::UintTy { + fn sinto(&self, _: &S) -> UintTy { + use rustc_ast::ast::UintTy as T; + match self { + T::Usize => UintTy::Usize, + T::U8 => UintTy::U8, + T::U16 => UintTy::U16, + T::U32 => UintTy::U32, + T::U64 => UintTy::U64, + T::U128 => UintTy::U128, + } + } +} + +/// Reflects [`rustc_type_ir::UintTy`] +#[derive(AdtInto)] +#[args(, from: rustc_type_ir::UintTy, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Copy, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum UintTy { + Usize, + U8, + U16, + U32, + U64, + U128, +} + +impl ToString for IntTy { + fn to_string(&self) -> String { + use IntTy::*; + match self { + Isize => "isize".to_string(), + I8 => "i8".to_string(), + I16 => "i16".to_string(), + I32 => "i32".to_string(), + I64 => "i64".to_string(), + I128 => "i128".to_string(), + } + } +} + +impl ToString for UintTy { + fn to_string(&self) -> String { + use UintTy::*; + match self { + Usize => "usize".to_string(), + U8 => "u8".to_string(), + U16 => "u16".to_string(), + U32 => "u32".to_string(), + U64 => "u64".to_string(), + U128 => "u128".to_string(), + } + } +} + +/// Reflects [`rustc_middle::ty::TypeAndMut`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TypeAndMut<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct TypeAndMut { + pub ty: Box, + pub mutbl: Mutability, +} + +#[cfg(feature = "rustc")] +impl> SInto> for rustc_middle::ty::List { + fn sinto(&self, s: &S) -> Vec { + self.iter().map(|x| x.sinto(s)).collect() + } +} + +/// Reflects [`rustc_middle::ty::GenericParamDef`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericParamDef, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct GenericParamDef { + pub name: Symbol, + pub def_id: DefId, + pub index: u32, + pub pure_wrt_drop: bool, + #[value( + match self.kind { + ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, + ty::GenericParamDefKind::Type { has_default, synthetic } => GenericParamDefKind::Type { has_default, synthetic }, + ty::GenericParamDefKind::Const { has_default, is_host_effect, .. } => { + let ty = s.base().tcx.type_of(self.def_id).instantiate_identity().sinto(s); + GenericParamDefKind::Const { has_default, is_host_effect, ty } + }, + } + )] + pub kind: GenericParamDefKind, +} + +/// Reflects [`rustc_middle::ty::GenericParamDefKind`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum GenericParamDefKind { + Lifetime, + Type { + has_default: bool, + synthetic: bool, + }, + Const { + has_default: bool, + is_host_effect: bool, + ty: Ty, + }, +} + +/// Reflects [`rustc_middle::ty::Generics`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Generics, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct TyGenerics { + pub parent: Option, + pub parent_count: usize, + #[from(own_params)] + pub params: Vec, + // pub param_def_id_to_index: FxHashMap, + pub has_self: bool, + pub has_late_bound_regions: Option, +} + +/// This type merges the information from +/// `rustc_type_ir::AliasKind` and `rustc_middle::ty::AliasTy` +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Alias { + pub kind: AliasKind, + pub args: Vec, + pub def_id: DefId, +} + +/// Reflects [`rustc_middle::ty::AliasKind`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AliasKind { + /// The projection of a trait type: `>::Type<...>` + Projection { + /// The `impl Trait for Ty` in `Ty: Trait<..., Type = U>`. + impl_expr: ImplExpr, + /// The `Type` in `Ty: Trait<..., Type = U>`. + assoc_item: AssocItem, + }, + /// An associated type in an inherent impl. + Inherent, + /// An `impl Trait` opaque type. + Opaque { + /// The real type hidden inside this opaque type. + hidden_ty: Ty, + }, + /// A type alias that references opaque types. Likely to always be normalized away. + Weak, +} + +#[cfg(feature = "rustc")] +impl Alias { + #[tracing::instrument(level = "trace", skip(s))] + fn from<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + alias_kind: &rustc_type_ir::AliasTyKind, + alias_ty: &rustc_middle::ty::AliasTy<'tcx>, + ) -> TyKind { + let tcx = s.base().tcx; + use rustc_type_ir::AliasTyKind as RustAliasKind; + let kind = match alias_kind { + RustAliasKind::Projection => { + let trait_ref = alias_ty.trait_ref(tcx); + // In a case like: + // ``` + // impl Trait for Result + // where + // for<'a> &'a Result: IntoIterator, + // for<'a> <&'a Result as IntoIterator>::Item: Copy, + // {} + // ``` + // the `&'a Result as IntoIterator` trait ref has escaping bound variables + // yet we dont have a binder around (could even be several). Binding this correctly + // is therefore difficult. Since our trait resolution ignores lifetimes anyway, we + // just erase them. See also https://github.com/hacspec/hax/issues/747. + let trait_ref = crate::traits::erase_and_norm(tcx, s.param_env(), trait_ref); + AliasKind::Projection { + assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), + impl_expr: solve_trait(s, ty::Binder::dummy(trait_ref)), + } + } + RustAliasKind::Inherent => AliasKind::Inherent, + RustAliasKind::Opaque => { + // Reveal the underlying `impl Trait` type. + let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, alias_ty.args); + AliasKind::Opaque { + hidden_ty: ty.sinto(s), + } + } + RustAliasKind::Weak => AliasKind::Weak, + }; + TyKind::Alias(Alias { + kind, + args: alias_ty.args.sinto(s), + def_id: alias_ty.def_id.sinto(s), + }) + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { + fn sinto(&self, s: &S) -> Box { + Box::new(self.sinto(s)) + } +} + +/// Reflects [`rustc_middle::ty::Ty`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Ty { + pub kind: Arc, +} + +impl Ty { + pub fn kind(&self) -> &TyKind { + self.kind.as_ref() + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { + fn sinto(&self, s: &S) -> Ty { + if let Some(ty) = s.with_cache(|cache| cache.tys.get(self).cloned()) { + return ty; + } + let ty = Ty { + kind: Arc::new(self.kind().sinto(s)), + }; + s.with_cache(|cache| cache.tys.insert(*self, ty.clone())); + ty + } +} + +/// Reflects [`rustc_middle::ty::TyKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TyKind<'tcx>, state: S as state)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum TyKind { + Bool, + Char, + Int(IntTy), + Uint(UintTy), + Float(FloatTy), + + #[custom_arm( + rustc_middle::ty::TyKind::FnPtr(sig) => arrow_of_sig(sig, state), + rustc_middle::ty::TyKind::FnDef(def, generics) => { + let tcx = state.base().tcx; + arrow_of_sig(&tcx.fn_sig(*def).instantiate(tcx, generics), state) + }, + FROM_TYPE::Closure (_defid, generics) => { + let sig = generics.as_closure().sig(); + let sig = state.base().tcx.signature_unclosure(sig, rustc_hir::Safety::Safe); + arrow_of_sig(&sig, state) + }, + )] + /// Reflects [`rustc_middle::ty::TyKind::FnPtr`], [`rustc_middle::ty::TyKind::FnDef`] and [`rustc_middle::ty::TyKind::Closure`] + Arrow(Box), + + #[custom_arm( + rustc_middle::ty::TyKind::Adt(adt_def, generics) => { + let def_id = adt_def.did().sinto(state); + let generic_args: Vec = generics.sinto(state); + let trait_refs = solve_item_traits(state, adt_def.did(), generics, None); + TyKind::Adt { def_id, generic_args, trait_refs } + }, + )] + Adt { + /// Reflects [`rustc_middle::ty::TyKind::Adt`]'s substitutions + generic_args: Vec, + /// Predicates required by the type, e.g. `T: Sized` for `Option` or `B: 'a + ToOwned` + /// for `Cow<'a, B>`. + trait_refs: Vec, + def_id: DefId, + }, + Foreign(DefId), + Str, + Array(Box, #[map(Box::new(x.sinto(state)))] Box), + Slice(Box), + RawPtr(Box, Mutability), + Ref(Region, Box, Mutability), + Dynamic(Vec>, Region, DynKind), + Coroutine(DefId, Vec), + Never, + Tuple(Vec), + #[custom_arm( + rustc_middle::ty::TyKind::Alias(alias_kind, alias_ty) => { + Alias::from(state, alias_kind, alias_ty) + }, + )] + Alias(Alias), + Param(ParamTy), + Bound(DebruijnIndex, BoundTy), + Placeholder(PlaceholderType), + Infer(InferTy), + #[custom_arm(rustc_middle::ty::TyKind::Error(..) => TyKind::Error,)] + Error, + #[todo] + Todo(String), +} + +/// Reflects [`rustc_middle::ty::Variance`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::ty::Variance, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum Variance { + Covariant, + Invariant, + Contravariant, + Bivariant, +} + +/// Reflects [`rustc_middle::ty::CanonicalUserTypeAnnotation`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CanonicalUserTypeAnnotation<'tcx>, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct CanonicalUserTypeAnnotation { + pub user_ty: CanonicalUserType, + pub span: Span, + pub inferred_ty: Ty, +} + +/// Reflects [`rustc_middle::ty::AdtKind`] +#[derive_group(Serializers)] +#[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AdtKind, state: S as _s)] +pub enum AdtKind { + Struct, + Union, + Enum, +} + +// This comes from MIR +// TODO: add the generics and the predicates +/// Reflects [`rustc_middle::ty::AdtDef`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct AdtDef { + pub did: DefId, + pub adt_kind: AdtKind, + pub variants: IndexVec, + pub flags: AdtFlags, + pub repr: ReprOptions, +} + +sinto_todo!(rustc_middle::ty, AdtFlags); + +/// Reflects [`rustc_middle::ty::ReprOptions`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ReprOptions, state: S as s)] +pub struct ReprOptions { + pub int: Option, + #[value({ + use crate::rustc_middle::ty::util::IntTypeExt; + self.discr_type().to_ty(s.base().tcx).sinto(s) + })] + pub typ: Ty, + pub align: Option, + pub pack: Option, + pub flags: ReprFlags, + pub field_shuffle_seed: u64, +} + +sinto_todo!(rustc_abi, IntegerType); +sinto_todo!(rustc_abi, ReprFlags); +sinto_todo!(rustc_abi, Align); + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtDef<'tcx> { + fn sinto(&self, s: &S) -> AdtDef { + let variants = self + .variants() + .iter_enumerated() + .map(|(variant_idx, variant)| { + let discr = if self.is_enum() { + self.discriminant_for_variant(s.base().tcx, variant_idx) + } else { + // Structs and unions have a single variant. + assert_eq!(variant_idx.index(), 0); + rustc_middle::ty::util::Discr { + val: 0, + ty: s.base().tcx.types.isize, + } + }; + VariantDef::sfrom(s, variant, discr) + }) + .collect(); + AdtDef { + did: self.did().sinto(s), + adt_kind: self.adt_kind().sinto(s), + variants, + flags: self.flags().sinto(s), + repr: self.repr().sinto(s), + } + } +} + +/// Reflects [`rustc_middle::ty::adjustment::PointerCoercion`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::ty::adjustment::PointerCoercion, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum PointerCoercion { + ReifyFnPointer, + UnsafeFnPointer, + ClosureFnPointer(Safety), + MutToConstPointer, + ArrayToPointer, + Unsize, +} + +sinto_todo!(rustc_middle::ty, ScalarInt); + +/// Reflects [`rustc_middle::ty::FnSig`] +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::FnSig<'tcx>, state: S as s)] +pub struct TyFnSig { + #[value(self.inputs().sinto(s))] + pub inputs: Vec, + #[value(self.output().sinto(s))] + pub output: Ty, + pub c_variadic: bool, + pub safety: Safety, + pub abi: Abi, +} + +/// Reflects [`rustc_middle::ty::PolyFnSig`] +pub type PolyFnSig = Binder; + +/// Reflects [`rustc_middle::ty::TraitRef`] +#[derive_group(Serializers)] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitRef<'tcx>, state: S as tcx)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct TraitRef { + pub def_id: DefId, + #[from(args)] + /// reflects the `args` field + pub generic_args: Vec, +} + +/// Reflects [`rustc_middle::ty::TraitPredicate`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitPredicate<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct TraitPredicate { + pub trait_ref: TraitRef, + #[map(*x == rustc_middle::ty::PredicatePolarity::Positive)] + #[from(polarity)] + pub is_positive: bool, +} + +/// Reflects [`rustc_middle::ty::OutlivesPredicate`] as a named struct +/// instead of a tuple struct. This is because the script converting +/// JSONSchema types to OCaml doesn't support tuple structs, and this +/// is the only tuple struct in the whole AST. +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct OutlivesPredicate { + pub lhs: T, + pub rhs: Region, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, T, U> SInto> + for rustc_middle::ty::OutlivesPredicate<'tcx, T> +where + T: SInto, +{ + fn sinto(&self, s: &S) -> OutlivesPredicate where { + OutlivesPredicate { + lhs: self.0.sinto(s), + rhs: self.1.sinto(s), + } + } +} + +/// Reflects [`rustc_middle::ty::RegionOutlivesPredicate`] +pub type RegionOutlivesPredicate = OutlivesPredicate; +/// Reflects [`rustc_middle::ty::TypeOutlivesPredicate`] +pub type TypeOutlivesPredicate = OutlivesPredicate; + +/// Reflects [`rustc_middle::ty::Term`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Term { + Ty(Ty), + Const(ConstantExpr), +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Term<'tcx> { + fn sinto(&self, s: &S) -> Term { + use rustc_middle::ty::TermKind; + match self.unpack() { + TermKind::Ty(ty) => Term::Ty(ty.sinto(s)), + TermKind::Const(c) => Term::Const(c.sinto(s)), + } + } +} + +/// Expresses a constraints over an associated type. +/// +/// For instance: +/// ```text +/// fn f>(...) +/// ^^^^^^^^^^ +/// ``` +/// (provided the trait `Foo` has an associated type `S`). +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ProjectionPredicate { + /// The `impl Trait for Ty` in `Ty: Trait<..., Type = U>`. + pub impl_expr: ImplExpr, + /// The `Type` in `Ty: Trait<..., Type = U>`. + pub assoc_item: AssocItem, + /// The type `U` in `Ty: Trait<..., Type = U>`. + pub ty: Ty, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderBinderState<'tcx>> SInto + for rustc_middle::ty::ProjectionPredicate<'tcx> +{ + fn sinto(&self, s: &S) -> ProjectionPredicate { + let tcx = s.base().tcx; + let alias_ty = &self.projection_term.expect_ty(tcx); + let poly_trait_ref = s.binder().rebind(alias_ty.trait_ref(tcx)); + let Term::Ty(ty) = self.term.sinto(s) else { + unreachable!() + }; + ProjectionPredicate { + impl_expr: solve_trait(s, poly_trait_ref), + assoc_item: tcx.associated_item(alias_ty.def_id).sinto(s), + ty, + } + } +} + +/// Reflects [`rustc_middle::ty::ClauseKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderBinderState<'tcx>>, from: rustc_middle::ty::ClauseKind<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ClauseKind { + Trait(TraitPredicate), + RegionOutlives(RegionOutlivesPredicate), + TypeOutlives(TypeOutlivesPredicate), + Projection(ProjectionPredicate), + ConstArgHasType(ConstantExpr, Ty), + WellFormed(GenericArg), + ConstEvaluatable(ConstantExpr), +} + +/// Reflects [`rustc_middle::ty::Clause`] and adds a hash-consed predicate identifier. +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Clause { + pub kind: Binder, + pub id: PredicateId, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clause<'tcx> { + fn sinto(&self, s: &S) -> Clause { + let kind = self.kind().sinto(s); + let id = kind.clone().map(PredicateKind::Clause).predicate_id(); + Clause { kind, id } + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto + for rustc_middle::ty::PolyTraitPredicate<'tcx> +{ + fn sinto(&self, s: &S) -> Clause { + let kind: Binder<_> = self.sinto(s); + let kind: Binder = kind.map(ClauseKind::Trait); + let id = kind.clone().map(PredicateKind::Clause).predicate_id(); + Clause { kind, id } + } +} + +/// Reflects [`rustc_middle::ty::Predicate`] and adds a hash-consed predicate identifier. +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Predicate { + pub kind: Binder, + pub id: PredicateId, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Predicate<'tcx> { + fn sinto(&self, s: &S) -> Predicate { + let kind = self.kind().sinto(s); + let id = kind.predicate_id(); + Predicate { kind, id } + } +} + +/// Reflects [`rustc_middle::ty::BoundVariableKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundVariableKind, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum BoundVariableKind { + Ty(BoundTyKind), + Region(BoundRegionKind), + Const, +} + +/// Reflects [`rustc_middle::ty::Binder`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Binder { + pub value: T, + pub bound_vars: Vec, +} + +impl Binder { + pub fn as_ref(&self) -> Binder<&T> { + Binder { + value: &self.value, + bound_vars: self.bound_vars.clone(), + } + } + + pub fn hax_skip_binder(self) -> T { + self.value + } + + pub fn hax_skip_binder_ref(&self) -> &T { + &self.value + } + + pub fn map(self, f: impl FnOnce(T) -> U) -> Binder { + Binder { + value: f(self.value), + bound_vars: self.bound_vars, + } + } + + pub fn inner_mut(&mut self) -> &mut T { + &mut self.value + } + + pub fn rebind(&self, value: U) -> Binder { + self.as_ref().map(|_| value) + } +} + +/// Reflects [`rustc_middle::ty::GenericPredicates`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericPredicates<'tcx>, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct GenericPredicates { + pub parent: Option, + // FIXME: Switch from `Predicate` to `Clause` (will require correct handling of binders). + #[value(self.predicates.iter().map(|(clause, span)| (clause.as_predicate().sinto(s), span.sinto(s))).collect())] + pub predicates: Vec<(Predicate, Span)>, +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto> + for rustc_middle::ty::Binder<'tcx, T1> +where + T1: SInto, T2>, +{ + fn sinto(&self, s: &S) -> Binder { + let bound_vars = self.bound_vars().sinto(s); + let value = { + let under_binder_s = &State { + base: s.base(), + owner_id: s.owner_id(), + binder: self.as_ref().map_bound(|_| ()), + thir: (), + mir: (), + }; + self.as_ref().skip_binder().sinto(under_binder_s) + }; + Binder { value, bound_vars } + } +} + +/// Reflects [`rustc_middle::ty::SubtypePredicate`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::SubtypePredicate<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct SubtypePredicate { + pub a_is_expected: bool, + pub a: Ty, + pub b: Ty, +} + +/// Reflects [`rustc_middle::ty::CoercePredicate`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CoercePredicate<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct CoercePredicate { + pub a: Ty, + pub b: Ty, +} + +/// Reflects [`rustc_middle::ty::AliasRelationDirection`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AliasRelationDirection, state: S as _tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AliasRelationDirection { + Equate, + Subtype, +} + +/// Reflects [`rustc_middle::ty::ClosureArgs`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: ty::ClosureArgs>, state: S as s)] +#[derive(Clone, Debug, JsonSchema)] +#[derive_group(Serializers)] +pub struct ClosureArgs { + #[value(self.kind().sinto(s))] + pub kind: ClosureKind, + #[value(self.parent_args().sinto(s))] + pub parent_args: Vec, + #[value(self.sig().sinto(s))] + pub sig: PolyFnSig, + #[value(self.upvar_tys().sinto(s))] + pub upvar_tys: Vec, +} + +/// Reflects [`rustc_middle::ty::ClosureKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ClosureKind, state: S as _tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ClosureKind { + Fn, + FnMut, + FnOnce, +} + +sinto_todo!(rustc_middle::ty, NormalizesTo<'tcx>); + +/// Reflects [`rustc_middle::ty::PredicateKind`] +#[derive(AdtInto)] +#[args(<'tcx, S: UnderBinderState<'tcx>>, from: rustc_middle::ty::PredicateKind<'tcx>, state: S as tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum PredicateKind { + Clause(ClauseKind), + ObjectSafe(DefId), + Subtype(SubtypePredicate), + Coerce(CoercePredicate), + ConstEquate(ConstantExpr, ConstantExpr), + Ambiguous, + AliasRelate(Term, Term, AliasRelationDirection), + NormalizesTo(NormalizesTo), +} + +/// Reflects [`rustc_middle::ty::ImplSubject`] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ImplSubject { + Trait { + /// The trait that is implemented by this impl block. + trait_pred: TraitPredicate, + /// The `ImplExpr`s required to satisfy the predicates on the trait declaration. E.g.: + /// ```ignore + /// trait Foo: Bar {} + /// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`. + /// ``` + required_impl_exprs: Vec, + }, + Inherent(Ty), +} + +#[cfg(feature = "rustc")] +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<'tcx> { + fn sinto(&self, s: &S) -> ImplSubject { + let tcx = s.base().tcx; + match self { + ty::ImplSubject::Inherent(ty) => ImplSubject::Inherent(ty.sinto(s)), + ty::ImplSubject::Trait(trait_ref) => { + // Also record the polarity. + let polarity = tcx.impl_polarity(s.owner_id()); + let trait_pred = TraitPredicate { + trait_ref: trait_ref.sinto(s), + is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive), + }; + let required_impl_exprs = + solve_item_traits(s, trait_ref.def_id, trait_ref.args, None); + ImplSubject::Trait { + trait_pred, + required_impl_exprs, + } + } + } + } +} + +#[cfg(feature = "rustc")] +fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( + s: &S, + item: &ty::AssocItem, +) -> AssocItemContainer { + let container_id = item.container_id(s.base().tcx); + match item.container { + ty::AssocItemContainer::TraitContainer => AssocItemContainer::TraitContainer { + trait_id: container_id.sinto(s), + }, + ty::AssocItemContainer::ImplContainer => { + if let Some(implemented_trait_item) = item.trait_item_def_id { + AssocItemContainer::TraitImplContainer { + impl_id: container_id.sinto(s), + implemented_trait: s + .base() + .tcx + .trait_of_item(implemented_trait_item) + .unwrap() + .sinto(s), + implemented_trait_item: implemented_trait_item.sinto(s), + overrides_default: s.base().tcx.defaultness(implemented_trait_item).has_value(), + } + } else { + AssocItemContainer::InherentImplContainer { + impl_id: container_id.sinto(s), + } + } + } + } +} + +/// Reflects [`rustc_middle::ty::AssocItem`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::AssocItem, state: S as s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct AssocItem { + pub def_id: DefId, + pub name: Symbol, + pub kind: AssocKind, + #[value(get_container_for_assoc_item(s, self))] + pub container: AssocItemContainer, + /// Whether this item has a value (e.g. this is `false` for trait methods without default + /// implementations). + #[value(self.defaultness(s.base().tcx).has_value())] + pub has_value: bool, + pub fn_has_self_parameter: bool, + pub opt_rpitit_info: Option, +} + +/// Reflects [`rustc_middle::ty::ImplTraitInTraitData`] +#[derive(AdtInto)] +#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::ImplTraitInTraitData, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum ImplTraitInTraitData { + Trait { + fn_def_id: DefId, + opaque_def_id: DefId, + }, + Impl { + fn_def_id: DefId, + }, +} + +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AssocItemContainer { + TraitContainer { + trait_id: DefId, + }, + TraitImplContainer { + impl_id: DefId, + implemented_trait: DefId, + implemented_trait_item: DefId, + /// Whether the corresponding trait item had a default (and therefore this one overrides + /// it). + overrides_default: bool, + }, + InherentImplContainer { + impl_id: DefId, + }, +} + +/// Reflects [`rustc_middle::ty::AssocKind`] +#[derive(AdtInto)] +#[args(, from: rustc_middle::ty::AssocKind, state: S as _tcx)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AssocKind { + Const, + Fn, + Type, +} From 7b1ac561dcf406667e80e8305b9186f4c87e7b3d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Oct 2024 13:55:14 +0200 Subject: [PATCH 102/253] Use shorter paths --- frontend/exporter/src/types/hir.rs | 257 ++++++++++++------------- frontend/exporter/src/types/thir.rs | 137 +++++++------- frontend/exporter/src/types/ty.rs | 283 ++++++++++++++-------------- 3 files changed, 329 insertions(+), 348 deletions(-) diff --git a/frontend/exporter/src/types/hir.rs b/frontend/exporter/src/types/hir.rs index 102b24991..6b6f184d6 100644 --- a/frontend/exporter/src/types/hir.rs +++ b/frontend/exporter/src/types/hir.rs @@ -5,13 +5,17 @@ use crate::prelude::*; use crate::sinto_todo; +#[cfg(feature = "rustc")] +use rustc_ast::ast; +#[cfg(feature = "rustc")] +use rustc_hir as hir; #[cfg(feature = "rustc")] use rustc_middle::ty; -/// Reflects [`rustc_hir::hir_id::HirId`] +/// Reflects [`hir::hir_id::HirId`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::hir_id::HirId, state: S as gstate)] +#[args(<'tcx, S: BaseState<'tcx>>, from: hir::hir_id::HirId, state: S as gstate)] pub struct HirId { owner: DefId, local_id: usize, @@ -20,25 +24,25 @@ pub struct HirId { // TODO: If not working: See original #[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>> SInto for rustc_hir::hir_id::OwnerId { +impl<'tcx, S: BaseState<'tcx>> SInto for hir::hir_id::OwnerId { fn sinto(&self, s: &S) -> DefId { self.to_def_id().sinto(s) } } -/// Reflects [`rustc_ast::ast::LitFloatType`] +/// Reflects [`ast::LitFloatType`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitFloatType, state: S as gstate)] +#[args(<'tcx, S: BaseState<'tcx>>, from: ast::LitFloatType, state: S as gstate)] pub enum LitFloatType { Suffixed(FloatTy), Unsuffixed, } -/// Reflects [`rustc_hir::Movability`] +/// Reflects [`hir::Movability`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S>, from: rustc_hir::Movability, state: S as _s)] +#[args(<'tcx, S>, from: hir::Movability, state: S as _s)] pub enum Movability { Static, Movable, @@ -47,36 +51,36 @@ pub enum Movability { pub type Mutability = bool; #[cfg(feature = "rustc")] -impl SInto for rustc_hir::Mutability { +impl SInto for hir::Mutability { fn sinto(&self, _s: &S) -> Mutability { match self { - rustc_hir::Mutability::Mut => true, - _ => false, + Self::Mut => true, + Self::Not => false, } } } -/// Reflects [`rustc_hir::def::CtorKind`] +/// Reflects [`hir::def::CtorKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_hir::def::CtorKind, state: S as _s)] +#[args(, from: hir::def::CtorKind, state: S as _s)] pub enum CtorKind { Fn, Const, } -/// Reflects [`rustc_hir::def::CtorOf`] +/// Reflects [`hir::def::CtorOf`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(, from: rustc_hir::def::CtorOf, state: S as _s)] +#[args(, from: hir::def::CtorOf, state: S as _s)] pub enum CtorOf { Struct, Variant, } -/// Reflects [`rustc_hir::RangeEnd`] +/// Reflects [`hir::RangeEnd`] #[derive(AdtInto)] -#[args(, from: rustc_hir::RangeEnd, state: S as _s)] +#[args(, from: hir::RangeEnd, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum RangeEnd { @@ -84,9 +88,9 @@ pub enum RangeEnd { Excluded, } -/// Reflects [`rustc_hir::Safety`] +/// Reflects [`hir::Safety`] #[derive(AdtInto)] -#[args(, from: rustc_hir::Safety, state: S as _s)] +#[args(, from: hir::Safety, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Safety { @@ -94,9 +98,9 @@ pub enum Safety { Safe, } -/// Reflects [`rustc_hir::ImplicitSelfKind`] +/// Reflects [`hir::ImplicitSelfKind`] #[derive(AdtInto)] -#[args(, from: rustc_hir::ImplicitSelfKind, state: S as _s)] +#[args(, from: hir::ImplicitSelfKind, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum ImplicitSelfKind { @@ -107,10 +111,10 @@ pub enum ImplicitSelfKind { None, } -/// Reflects [`rustc_hir::FnDecl`] +/// Reflects [`hir::FnDecl`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnDecl<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::FnDecl<'tcx>, state: S as tcx)] pub struct FnDecl { pub inputs: Vec, pub output: FnRetTy, @@ -119,20 +123,20 @@ pub struct FnDecl { pub lifetime_elision_allowed: bool, } -/// Reflects [`rustc_hir::FnSig`] +/// Reflects [`hir::FnSig`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnSig<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::FnSig<'tcx>, state: S as tcx)] pub struct FnSig { pub header: FnHeader, pub decl: FnDecl, pub span: Span, } -/// Reflects [`rustc_hir::FnHeader`] +/// Reflects [`hir::FnHeader`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::FnHeader, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::FnHeader, state: S as tcx)] pub struct FnHeader { pub safety: Safety, pub constness: Constness, @@ -154,8 +158,8 @@ pub struct FnDef { } #[cfg(feature = "rustc")] -impl<'x: 'tcx, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x> { - fn sinto(self: &rustc_hir::Ty<'x>, s: &S) -> Ty { +impl<'x: 'tcx, 'tcx, S: UnderOwnerState<'tcx>> SInto for hir::Ty<'x> { + fn sinto(self: &hir::Ty<'x>, s: &S) -> Ty { // **Important:** // We need a local id here, and we get it from the owner id, which must // be local. It is safe to do so, because if we have access to a HIR ty, @@ -167,9 +171,9 @@ impl<'x: 'tcx, 'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::Ty<'x } } -/// Reflects [`rustc_hir::UseKind`] +/// Reflects [`hir::UseKind`] #[derive(AdtInto)] -#[args(, from: rustc_hir::UseKind, state: S as _s)] +#[args(, from: hir::UseKind, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum UseKind { @@ -178,9 +182,9 @@ pub enum UseKind { ListStem, } -/// Reflects [`rustc_hir::IsAuto`] +/// Reflects [`hir::IsAuto`] #[derive(AdtInto)] -#[args(, from: rustc_hir::IsAuto, state: S as _s)] +#[args(, from: hir::IsAuto, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum IsAuto { @@ -188,9 +192,9 @@ pub enum IsAuto { No, } -/// Reflects [`rustc_hir::Defaultness`] +/// Reflects [`hir::Defaultness`] #[derive(AdtInto)] -#[args(, from: rustc_hir::Defaultness, state: S as tcx)] +#[args(, from: hir::Defaultness, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum Defaultness { @@ -198,9 +202,9 @@ pub enum Defaultness { Final, } -/// Reflects [`rustc_hir::ImplPolarity`] +/// Reflects [`hir::ImplPolarity`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ImplPolarity, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::ImplPolarity, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum ImplPolarity { @@ -208,9 +212,9 @@ pub enum ImplPolarity { Negative(Span), } -/// Reflects [`rustc_hir::Constness`] +/// Reflects [`hir::Constness`] #[derive(AdtInto)] -#[args(, from: rustc_hir::Constness, state: S as _s)] +#[args(, from: hir::Constness, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum Constness { @@ -218,9 +222,9 @@ pub enum Constness { NotConst, } -/// Reflects [`rustc_hir::Generics`] +/// Reflects [`hir::Generics`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Generics<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::Generics<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Generics { @@ -233,9 +237,7 @@ pub struct Generics { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> - for rustc_hir::ImplItemRef -{ +impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> for hir::ImplItemRef { fn sinto(&self, s: &S) -> ImplItem { let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; let impl_item = tcx.hir().impl_item(self.id); @@ -244,7 +246,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> } } -/// Reflects [`rustc_hir::ParamName`] +/// Reflects [`hir::ParamName`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum ParamName { @@ -253,9 +255,9 @@ pub enum ParamName { Error, } -/// Reflects [`rustc_hir::LifetimeParamKind`] +/// Reflects [`hir::LifetimeParamKind`] #[derive(AdtInto)] -#[args(, from: rustc_hir::LifetimeParamKind, state: S as _s)] +#[args(, from: hir::LifetimeParamKind, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum LifetimeParamKind { @@ -264,10 +266,10 @@ pub enum LifetimeParamKind { Error, } -/// Reflects [`rustc_hir::AnonConst`] +/// Reflects [`hir::AnonConst`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AnonConst, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::AnonConst, state: S as s)] pub struct AnonConst { pub hir_id: HirId, pub def_id: GlobalIdent, @@ -277,29 +279,29 @@ pub struct AnonConst { pub body: Body, } -/// Reflects [`rustc_hir::ConstArg`] +/// Reflects [`hir::ConstArg`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArg<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::ConstArg<'tcx>, state: S as s)] pub struct ConstArg { pub hir_id: HirId, pub kind: ConstArgKind, pub is_desugared_from_effects: bool, } -/// Reflects [`rustc_hir::ConstArgKind`] +/// Reflects [`hir::ConstArgKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::ConstArgKind<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::ConstArgKind<'tcx>, state: S as s)] pub enum ConstArgKind { Path(QPath), Anon(AnonConst), } -/// Reflects [`rustc_hir::GenericParamKind`] +/// Reflects [`hir::GenericParamKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParamKind<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::GenericParamKind<'tcx>, state: S as tcx)] pub enum GenericParamKind { Lifetime { kind: LifetimeParamKind, @@ -323,22 +325,22 @@ pub enum GenericParamKind { }, } -/// Reflects [`rustc_hir::GenericParam`] +/// Reflects [`hir::GenericParam`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::GenericParam<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::GenericParam<'tcx>, state: S as s)] pub struct GenericParam { pub hir_id: HirId, pub def_id: GlobalIdent, #[map(match x { - rustc_hir::ParamName::Plain(loc_ident) => + hir::ParamName::Plain(loc_ident) => ParamName::Plain(LocalIdent { name: loc_ident.as_str().to_string(), id: self.hir_id.sinto(s) }), - rustc_hir::ParamName::Fresh => + hir::ParamName::Fresh => ParamName::Fresh, - rustc_hir::ParamName::Error => + hir::ParamName::Error => ParamName::Error, })] pub name: ParamName, @@ -350,10 +352,10 @@ pub struct GenericParam { attributes: Vec, } -/// Reflects [`rustc_hir::ImplItem`] +/// Reflects [`hir::ImplItem`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItem<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::ImplItem<'tcx>, state: S as s)] pub struct ImplItem { pub ident: Ident, pub owner_id: DefId, @@ -367,18 +369,18 @@ pub struct ImplItem { pub attributes: ItemAttributes, } -/// Reflects [`rustc_hir::ImplItemKind`], inlining the body of the items. +/// Reflects [`hir::ImplItemKind`], inlining the body of the items. #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ImplItemKind<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::ImplItemKind<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum ImplItemKind { Const(Ty, Body), - #[custom_arm(rustc_hir::ImplItemKind::Fn(sig, body) => { + #[custom_arm(hir::ImplItemKind::Fn(sig, body) => { ImplItemKind::Fn(make_fn_def::(sig, body, s)) },)] Fn(FnDef), - #[custom_arm(rustc_hir::ImplItemKind::Type(t) => { + #[custom_arm(hir::ImplItemKind::Type(t) => { let parent_bounds = { let (tcx, owner_id) = (s.base().tcx, s.owner_id()); let assoc_item = tcx.opt_associated_item(owner_id).unwrap(); @@ -402,9 +404,9 @@ pub enum ImplItemKind { }, } -/// Reflects [`rustc_hir::AssocItemKind`] +/// Reflects [`hir::AssocItemKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::AssocItemKind, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::AssocItemKind, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum AssocItemKind { @@ -413,9 +415,9 @@ pub enum AssocItemKind { Type, } -/// Reflects [`rustc_hir::Impl`]. +/// Reflects [`hir::Impl`]. #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Impl<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::Impl<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Impl { @@ -452,9 +454,9 @@ pub struct Impl { pub parent_bounds: Vec<(Clause, ImplExpr, Span)>, } -/// Reflects [`rustc_hir::IsAsync`] +/// Reflects [`hir::IsAsync`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::IsAsync, state: S as _s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::IsAsync, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum IsAsync { @@ -462,9 +464,9 @@ pub enum IsAsync { NotAsync, } -/// Reflects [`rustc_hir::FnRetTy`] +/// Reflects [`hir::FnRetTy`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FnRetTy<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::FnRetTy<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum FnRetTy { @@ -472,10 +474,10 @@ pub enum FnRetTy { Return(Ty), } -/// Reflects [`rustc_hir::VariantData`] +/// Reflects [`hir::VariantData`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::VariantData<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::VariantData<'tcx>, state: S as tcx)] pub enum VariantData { Struct { fields: Vec, @@ -486,7 +488,7 @@ pub enum VariantData { } #[cfg(feature = "rustc")] -impl SInto for rustc_ast::ast::Recovered { +impl SInto for ast::Recovered { fn sinto(&self, _s: &S) -> bool { match self { Self::Yes(_) => true, @@ -495,9 +497,9 @@ impl SInto for rustc_ast::ast::Recovered { } } -/// Reflects [`rustc_hir::FieldDef`] +/// Reflects [`hir::FieldDef`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::FieldDef<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::FieldDef<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct HirFieldDef { @@ -511,9 +513,9 @@ pub struct HirFieldDef { attributes: Vec, } -/// Reflects [`rustc_hir::Variant`] +/// Reflects [`hir::Variant`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::Variant<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::Variant<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Variant { @@ -538,9 +540,9 @@ pub struct Variant { pub attributes: Vec, } -/// Reflects [`rustc_hir::UsePath`] +/// Reflects [`hir::UsePath`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::UsePath<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::UsePath<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct UsePath { @@ -550,9 +552,9 @@ pub struct UsePath { pub segments: Vec, #[value(self.segments.iter().last().and_then(|segment| { match s.base().tcx.hir_node_by_def_id(segment.hir_id.owner.def_id) { - rustc_hir::Node::Item(rustc_hir::Item { + hir::Node::Item(hir::Item { ident, - kind: rustc_hir::ItemKind::Use(_, _), + kind: hir::ItemKind::Use(_, _), .. }) if ident.name.to_ident_string() != "" => Some(ident.name.to_ident_string()), _ => None, @@ -561,9 +563,9 @@ pub struct UsePath { pub rename: Option, } -/// Reflects [`rustc_hir::def::Res`] +/// Reflects [`hir::def::Res`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::Res, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::def::Res, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum Res { @@ -584,9 +586,9 @@ pub enum Res { Err, } -/// Reflects [`rustc_hir::PrimTy`] +/// Reflects [`hir::PrimTy`] #[derive(AdtInto)] -#[args(, from: rustc_hir::PrimTy, state: S as s)] +#[args(, from: hir::PrimTy, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum PrimTy { @@ -598,9 +600,9 @@ pub enum PrimTy { Char, } -/// Reflects [`rustc_hir::def::NonMacroAttrKind`] +/// Reflects [`hir::def::NonMacroAttrKind`] #[derive(AdtInto)] -#[args(, from: rustc_hir::def::NonMacroAttrKind, state: S as s)] +#[args(, from: hir::def::NonMacroAttrKind, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum NonMacroAttrKind { @@ -610,9 +612,9 @@ pub enum NonMacroAttrKind { DeriveHelperCompat, } -/// Reflects [`rustc_hir::PathSegment`] +/// Reflects [`hir::PathSegment`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::PathSegment<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::PathSegment<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct PathSegment { @@ -624,9 +626,9 @@ pub struct PathSegment { pub infer_args: bool, } -/// Reflects [`rustc_hir::ItemKind`] +/// Reflects [`hir::ItemKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ItemKind<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::ItemKind<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum ItemKind { @@ -637,7 +639,7 @@ pub enum ItemKind { Static(Ty, Mutability, Body), Const(Ty, Generics, Body), #[custom_arm( - rustc_hir::ItemKind::Fn(sig, generics, body) => { + hir::ItemKind::Fn(sig, generics, body) => { ItemKind::Fn(generics.sinto(s), make_fn_def::(sig, body, s)) } )] @@ -688,38 +690,38 @@ pub enum ItemKind { pub type EnumDef = Vec>; -/// Reflects [`rustc_hir::TraitItemKind`] +/// Reflects [`hir::TraitItemKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItemKind<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::TraitItemKind<'tcx>, state: S as tcx)] #[derive(Clone, Debug, JsonSchema)] #[derive_group(Serializers)] pub enum TraitItemKind { Const(Ty, Option), #[custom_arm( - rustc_hir::TraitItemKind::Fn(sig, rustc_hir::TraitFn::Required(id)) => { + hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(id)) => { TraitItemKind::RequiredFn(sig.sinto(tcx), id.sinto(tcx)) } )] - /// Reflects a required [`rustc_hir::TraitItemKind::Fn`] + /// Reflects a required [`hir::TraitItemKind::Fn`] RequiredFn(FnSig, Vec), #[custom_arm( - rustc_hir::TraitItemKind::Fn(sig, rustc_hir::TraitFn::Provided(body)) => { + hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)) => { TraitItemKind::ProvidedFn(sig.sinto(tcx), make_fn_def::(sig, body, tcx)) } )] - /// Reflects a provided [`rustc_hir::TraitItemKind::Fn`] + /// Reflects a provided [`hir::TraitItemKind::Fn`] ProvidedFn(FnSig, FnDef), #[custom_arm( - rustc_hir::TraitItemKind::Type(b, ty) => { + hir::TraitItemKind::Type(b, ty) => { TraitItemKind::Type(b.sinto(tcx), ty.map(|t| t.sinto(tcx))) } )] Type(GenericBounds, Option), } -/// Reflects [`rustc_hir::TraitItem`] +/// Reflects [`hir::TraitItem`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::TraitItem<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::TraitItem<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct TraitItem { @@ -735,18 +737,14 @@ pub struct TraitItem { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> - for rustc_hir::EnumDef<'tcx> -{ +impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto> for hir::EnumDef<'tcx> { fn sinto(&self, s: &S) -> EnumDef { self.variants.iter().map(|v| v.sinto(s)).collect() } } #[cfg(feature = "rustc")] -impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> - for rustc_hir::TraitItemRef -{ +impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> for hir::TraitItemRef { fn sinto(&self, s: &S) -> TraitItem { let s = with_owner_id(s.base(), (), (), self.id.owner_id.to_def_id()); let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; @@ -755,9 +753,7 @@ impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> } #[cfg(feature = "rustc")] -impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> - for rustc_hir::Mod<'a> -{ +impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> for hir::Mod<'a> { fn sinto(&self, s: &S) -> Vec> { inline_macro_invocations(self.item_ids.iter().copied(), s) // .iter() @@ -766,9 +762,9 @@ impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> } } -/// Reflects [`rustc_hir::ForeignItemKind`] +/// Reflects [`hir::ForeignItemKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItemKind<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::ForeignItemKind<'tcx>, state: S as tcx)] #[derive(Clone, Debug, JsonSchema)] #[derive_group(Serializers)] pub enum ForeignItemKind { @@ -777,9 +773,9 @@ pub enum ForeignItemKind { Type, } -/// Reflects [`rustc_hir::ForeignItem`] +/// Reflects [`hir::ForeignItem`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::ForeignItem<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::ForeignItem<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct ForeignItem { @@ -791,18 +787,16 @@ pub struct ForeignItem { } #[cfg(feature = "rustc")] -impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> - for rustc_hir::ForeignItemRef -{ +impl<'a, S: UnderOwnerState<'a>, Body: IsBody> SInto> for hir::ForeignItemRef { fn sinto(&self, s: &S) -> ForeignItem { let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; tcx.hir().foreign_item(self.id).sinto(s) } } -/// Reflects [`rustc_hir::OpaqueTy`] +/// Reflects [`hir::OpaqueTy`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: rustc_hir::OpaqueTy<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: hir::OpaqueTy<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct OpaqueTy { @@ -812,7 +806,7 @@ pub struct OpaqueTy { pub in_trait: bool, } -/// Reflects [`rustc_hir::GenericBounds`] +/// Reflects [`hir::GenericBounds`] type GenericBounds = Vec; /// Compute the bounds for the owner registed in the state `s` @@ -826,7 +820,6 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene if let Some(oid) = s.owner_id().as_local() { let hir_id = tcx.local_def_id_to_hir_id(oid); let node = tcx.hir_node(hir_id); - use rustc_hir as hir; matches!( node, hir::Node::TraitItem(hir::TraitItem { @@ -859,15 +852,15 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::GenericBounds<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for hir::GenericBounds<'tcx> { fn sinto(&self, s: &S) -> GenericBounds { region_bounds_at_current_owner(s) } } -/// Reflects [`rustc_hir::OpaqueTyOrigin`] +/// Reflects [`hir::OpaqueTyOrigin`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::OpaqueTyOrigin, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: hir::OpaqueTyOrigin, state: S as tcx)] #[derive(Clone, Debug, JsonSchema)] #[derive_group(Serializers)] pub enum OpaqueTyOrigin { @@ -876,9 +869,9 @@ pub enum OpaqueTyOrigin { TyAlias { in_assoc_ty: bool }, } -/// Reflects [`rustc_ast::ast::MacroDef`] +/// Reflects [`ast::MacroDef`] #[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::MacroDef, state: S as tcx)] +#[args(<'tcx, S: BaseState<'tcx>>, from: ast::MacroDef, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct MacroDef { @@ -886,7 +879,7 @@ pub struct MacroDef { pub macro_rules: bool, } -/// Reflects [`rustc_hir::Item`] (and [`rustc_hir::ItemId`]) +/// Reflects [`hir::Item`] (and [`hir::ItemId`]) #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Item { @@ -900,7 +893,7 @@ pub struct Item { } #[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::Item<'tcx> { +impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for hir::Item<'tcx> { fn sinto(&self, s: &S) -> Item { let name: String = self.ident.name.to_ident_string(); let s = &with_owner_id(s.base(), (), (), self.owner_id.to_def_id()); @@ -921,7 +914,7 @@ impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir: } #[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for rustc_hir::ItemId { +impl<'tcx, S: BaseState<'tcx>, Body: IsBody> SInto> for hir::ItemId { fn sinto(&self, s: &S) -> Item { let tcx: rustc_middle::ty::TyCtxt = s.base().tcx; tcx.hir().item(*self).sinto(s) diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index d2a28379e..4ba169ddf 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -2,19 +2,22 @@ //! information and lightly desugared. use crate::prelude::*; -/// Reflects [`rustc_middle::thir::LogicalOp`] +#[cfg(feature = "rustc")] +use rustc_middle::thir; + +/// Reflects [`thir::LogicalOp`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'a, S>, from: rustc_middle::thir::LogicalOp, state: S as _s)] +#[args(<'a, S>, from: thir::LogicalOp, state: S as _s)] pub enum LogicalOp { And, Or, } -/// Reflects [`rustc_middle::thir::LintLevel`] +/// Reflects [`thir::LintLevel`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'slt, S: UnderOwnerState<'slt> + HasThir<'slt>>, from: rustc_middle::thir::LintLevel, state: S as gstate)] +#[args(<'slt, S: UnderOwnerState<'slt> + HasThir<'slt>>, from: thir::LintLevel, state: S as gstate)] pub enum LintLevel { Inherited, Explicit(HirId), @@ -22,8 +25,8 @@ pub enum LintLevel { #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::FruInfo<'tcx>, state: S as gstate)] -/// Field Record Update (FRU) informations, this reflects [`rustc_middle::thir::FruInfo`] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::FruInfo<'tcx>, state: S as gstate)] +/// Field Record Update (FRU) informations, this reflects [`thir::FruInfo`] pub struct FruInfo { /// The base, e.g. `Foo {x: 1, .. base}` pub base: Expr, @@ -38,7 +41,7 @@ pub struct FieldExpr { pub value: Expr, } -/// Reflects [`rustc_middle::thir::AdtExpr`] +/// Reflects [`thir::AdtExpr`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct AdtExpr { @@ -49,7 +52,7 @@ pub struct AdtExpr { } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr<'tcx> { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::AdtExpr<'tcx> { fn sinto(&self, s: &S) -> AdtExpr { let variants = self.adt_def.variants(); let variant: &rustc_middle::ty::VariantDef = &variants[self.variant_index]; @@ -69,7 +72,7 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::AdtExpr } } -/// Reflects [`rustc_middle::thir::LocalVarId`] +/// Reflects [`thir::LocalVarId`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct LocalIdent { @@ -78,7 +81,7 @@ pub struct LocalIdent { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir::LocalVarId { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for thir::LocalVarId { fn sinto(&self, s: &S) -> LocalIdent { LocalIdent { name: s @@ -94,10 +97,10 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::thir } } -/// Reflects [`rustc_middle::thir::BlockSafety`] +/// Reflects [`thir::BlockSafety`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S>, from: rustc_middle::thir::BlockSafety, state: S as _s)] +#[args(<'tcx, S>, from: thir::BlockSafety, state: S as _s)] pub enum BlockSafety { Safe, BuiltinUnsafe, @@ -105,10 +108,10 @@ pub enum BlockSafety { ExplicitUnsafe, } -/// Reflects [`rustc_middle::thir::Block`] +/// Reflects [`thir::Block`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Block, state: S as gstate)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::Block, state: S as gstate)] pub struct Block { pub targeted_by_break: bool, pub region_scope: Scope, @@ -118,9 +121,9 @@ pub struct Block { pub safety_mode: BlockSafety, } -/// Reflects [`rustc_middle::thir::Stmt`] +/// Reflects [`thir::Stmt`] #[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Stmt<'tcx>, state: S as s)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::Stmt<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Stmt { @@ -128,31 +131,31 @@ pub struct Stmt { } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::BlockId { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::BlockId { fn sinto(&self, s: &S) -> Block { s.thir().blocks[*self].sinto(s) } } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::StmtId { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::StmtId { fn sinto(&self, s: &S) -> Stmt { s.thir().stmts[*self].sinto(s) } } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::Expr<'tcx> { fn sinto(&self, s: &S) -> Expr { let (hir_id, attributes) = self.hir_id_and_attributes(s); let hir_id = hir_id.map(|hir_id| hir_id.index()); let unrolled = self.unroll_scope(s); - let rustc_middle::thir::Expr { span, kind, ty, .. } = unrolled; + let thir::Expr { span, kind, ty, .. } = unrolled; let contents = match macro_invocation_of_span(span, s).map(ExprKind::MacroInvokation) { Some(contents) => contents, None => match kind { // Introduce intermediate `Cast` from `T` to `U` when casting from a `#[repr(T)]` enum to `U` - rustc_middle::thir::ExprKind::Cast { source } => { + thir::ExprKind::Cast { source } => { if let rustc_middle::ty::TyKind::Adt(adt, _) = s.thir().exprs[source].ty.kind() { let tcx = s.base().tcx; @@ -180,13 +183,13 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> kind.sinto(s) } } - rustc_middle::thir::ExprKind::NonHirLiteral { lit, .. } => { + thir::ExprKind::NonHirLiteral { lit, .. } => { let cexpr: ConstantExpr = (ConstantExprKind::Literal(scalar_int_to_constant_literal(s, lit, ty))) .decorate(ty.sinto(s), span.sinto(s)); return cexpr.into(); } - rustc_middle::thir::ExprKind::ZstLiteral { .. } => match ty.kind() { + thir::ExprKind::ZstLiteral { .. } => match ty.kind() { rustc_middle::ty::TyKind::FnDef(def, _generics) => { /* TODO: translate generics let tcx = s.base().tcx; @@ -238,7 +241,7 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> } } }, - rustc_middle::thir::ExprKind::Field { + thir::ExprKind::Field { lhs, variant_index, name, @@ -293,27 +296,25 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Expr<'tcx> } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ExprId { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::ExprId { fn sinto(&self, s: &S) -> Expr { s.thir().exprs[*self].sinto(s) } } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::Pat<'tcx> { fn sinto(&self, s: &S) -> Pat { - let rustc_middle::thir::Pat { span, kind, ty } = self; + let thir::Pat { span, kind, ty } = self; let contents = match kind { - rustc_middle::thir::PatKind::Leaf { subpatterns } => match ty.kind() { - rustc_middle::ty::TyKind::Adt(adt_def, args) => { - (rustc_middle::thir::PatKind::Variant { - adt_def: *adt_def, - args, - variant_index: rustc_target::abi::VariantIdx::from_usize(0), - subpatterns: subpatterns.clone(), - }) - .sinto(s) - } + thir::PatKind::Leaf { subpatterns } => match ty.kind() { + rustc_middle::ty::TyKind::Adt(adt_def, args) => (thir::PatKind::Variant { + adt_def: *adt_def, + args, + variant_index: rustc_target::abi::VariantIdx::from_usize(0), + subpatterns: subpatterns.clone(), + }) + .sinto(s), rustc_middle::ty::TyKind::Tuple(..) => PatKind::Tuple { subpatterns: subpatterns .iter() @@ -340,15 +341,15 @@ impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::Pat<'tcx> { } #[cfg(feature = "rustc")] -impl<'tcx, S: ExprState<'tcx>> SInto for rustc_middle::thir::ArmId { +impl<'tcx, S: ExprState<'tcx>> SInto for thir::ArmId { fn sinto(&self, s: &S) -> Arm { s.thir().arms[*self].sinto(s) } } -/// Reflects [`rustc_middle::thir::StmtKind`] +/// Reflects [`thir::StmtKind`] #[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::StmtKind<'tcx>, state: S as gstate)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::StmtKind<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum StmtKind { @@ -369,9 +370,9 @@ pub enum StmtKind { }, } -/// Reflects [`rustc_middle::thir::Ascription`] +/// Reflects [`thir::Ascription`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::Ascription<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: thir::Ascription<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Ascription { @@ -379,9 +380,9 @@ pub struct Ascription { pub variance: Variance, } -/// Reflects [`rustc_middle::thir::PatRange`] +/// Reflects [`thir::PatRange`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRange<'tcx>, state: S as state)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: thir::PatRange<'tcx>, state: S as state)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct PatRange { @@ -390,9 +391,9 @@ pub struct PatRange { pub end: RangeEnd, } -/// Reflects [`rustc_middle::thir::PatRangeBoundary`] +/// Reflects [`thir::PatRangeBoundary`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: rustc_middle::thir::PatRangeBoundary<'tcx>, state: S as state)] +#[args(<'tcx, S: UnderOwnerState<'tcx> + HasThir<'tcx>>, from: thir::PatRangeBoundary<'tcx>, state: S as state)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum PatRangeBoundary { @@ -411,12 +412,12 @@ pub struct FieldPat { pub type Pat = Decorated; -/// Reflects [`rustc_middle::thir::PatKind`] +/// Reflects [`thir::PatKind`] #[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::PatKind<'tcx>, state: S as gstate)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::PatKind<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] -#[append(rustc_middle::thir::PatKind::Leaf {..} => fatal!(gstate, "PatKind::Leaf: should never come up"),)] +#[append(thir::PatKind::Leaf {..} => fatal!(gstate, "PatKind::Leaf: should never come up"),)] pub enum PatKind { Wild, AscribeUserType { @@ -424,7 +425,7 @@ pub enum PatKind { subpattern: Pat, }, #[custom_arm( - rustc_middle::thir::PatKind::Binding {name, mode, var, ty, subpattern, is_primary} => { + thir::PatKind::Binding {name, mode, var, ty, subpattern, is_primary} => { let local_ctx = gstate.base().local_ctx; local_ctx.borrow_mut().vars.insert(*var, name.to_string()); PatKind::Binding { @@ -500,9 +501,9 @@ pub enum PatKind { Error(ErrorGuaranteed), } -/// Reflects [`rustc_middle::thir::Arm`] +/// Reflects [`thir::Arm`] #[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Arm<'tcx>, state: S as gstate)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::Arm<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Arm { @@ -516,9 +517,9 @@ pub struct Arm { attributes: Vec, } -/// Reflects [`rustc_middle::thir::Param`] +/// Reflects [`thir::Param`] #[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::Param<'tcx>, state: S as s)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::Param<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct Param { @@ -537,19 +538,19 @@ pub struct Param { pub type ThirBody = Expr; pub type Expr = Decorated; -/// Reflects [`rustc_middle::thir::ExprKind`] +/// Reflects [`thir::ExprKind`] #[derive(AdtInto)] -#[args(<'tcx, S: ExprState<'tcx>>, from: rustc_middle::thir::ExprKind<'tcx>, state: S as gstate)] +#[args(<'tcx, S: ExprState<'tcx>>, from: thir::ExprKind<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] #[append( - rustc_middle::thir::ExprKind::Scope {..} => { + thir::ExprKind::Scope {..} => { fatal!(gstate, "Scope should have been eliminated at this point"); }, - rustc_middle::thir::ExprKind::Field {..} => { + thir::ExprKind::Field {..} => { fatal!(gstate, "Field should have been eliminated at this point"); }, - rustc_middle::thir::ExprKind::NonHirLiteral {..} => { + thir::ExprKind::NonHirLiteral {..} => { fatal!(gstate, "NonHirLiteral should have been eliminated at this point"); }, )] @@ -861,36 +862,28 @@ pub trait ExprKindExt<'tcx> { &self, s: &S, ) -> (Option, Vec); - fn unroll_scope + HasThir<'tcx>>( - &self, - s: &S, - ) -> rustc_middle::thir::Expr<'tcx>; + fn unroll_scope + HasThir<'tcx>>(&self, s: &S) -> thir::Expr<'tcx>; } #[cfg(feature = "rustc")] -impl<'tcx> ExprKindExt<'tcx> for rustc_middle::thir::Expr<'tcx> { +impl<'tcx> ExprKindExt<'tcx> for thir::Expr<'tcx> { fn hir_id_and_attributes>( &self, s: &S, ) -> (Option, Vec) { match &self.kind { - rustc_middle::thir::ExprKind::Scope { + thir::ExprKind::Scope { region_scope: scope, .. } => attribute_from_scope(s, scope), _ => (None, vec![]), } } - fn unroll_scope + HasThir<'tcx>>( - &self, - s: &S, - ) -> rustc_middle::thir::Expr<'tcx> { + fn unroll_scope + HasThir<'tcx>>(&self, s: &S) -> thir::Expr<'tcx> { // TODO: when we see a loop, we should lookup its label! label is actually a scope id // we remove scopes here, whence the TODO match self.kind { - rustc_middle::thir::ExprKind::Scope { value, .. } => { - s.thir().exprs[value].unroll_scope(s) - } + thir::ExprKind::Scope { value, .. } => s.thir().exprs[value].unroll_scope(s), _ => self.clone(), } } diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index fdedf0597..4ab346098 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -32,19 +32,19 @@ pub enum CanonicalTyVarKind { sinto_as_usize!(rustc_middle::ty, UniverseIndex); -/// Reflects [`rustc_middle::ty::ParamTy`] +/// Reflects [`ty::ParamTy`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ParamTy, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::ParamTy, state: S as gstate)] pub struct ParamTy { pub index: u32, pub name: Symbol, } -/// Reflects [`rustc_middle::ty::ParamConst`] +/// Reflects [`ty::ParamConst`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(, from: rustc_middle::ty::ParamConst, state: S as gstate)] +#[args(, from: ty::ParamConst, state: S as gstate)] pub struct ParamConst { pub index: u32, pub name: Symbol, @@ -52,9 +52,9 @@ pub struct ParamConst { /// A predicate without `Self`, for use in `dyn Trait`. /// -/// Reflects [`rustc_middle::ty::ExistentialPredicate`] +/// Reflects [`ty::ExistentialPredicate`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ExistentialPredicate<'tcx>, state: S as state)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::ExistentialPredicate<'tcx>, state: S as state)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ExistentialPredicate { @@ -88,28 +88,28 @@ pub struct ExistentialProjection { pub term: Term, } -/// Reflects [`rustc_middle::ty::DynKind`] +/// Reflects [`ty::DynKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(, from: rustc_middle::ty::DynKind, state: S as _s)] +#[args(, from: ty::DynKind, state: S as _s)] pub enum DynKind { Dyn, DynStar, } -/// Reflects [`rustc_middle::ty::BoundTyKind`] +/// Reflects [`ty::BoundTyKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTyKind, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::BoundTyKind, state: S as gstate)] pub enum BoundTyKind { Anon, Param(DefId, Symbol), } -/// Reflects [`rustc_middle::ty::BoundTy`] +/// Reflects [`ty::BoundTy`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundTy, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::BoundTy, state: S as gstate)] pub struct BoundTy { pub var: BoundVar, pub kind: BoundTyKind, @@ -117,33 +117,33 @@ pub struct BoundTy { sinto_as_usize!(rustc_middle::ty, BoundVar); -/// Reflects [`rustc_middle::ty::BoundRegionKind`] +/// Reflects [`ty::BoundRegionKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegionKind, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::BoundRegionKind, state: S as gstate)] pub enum BoundRegionKind { BrAnon, BrNamed(DefId, Symbol), BrEnv, } -/// Reflects [`rustc_middle::ty::BoundRegion`] +/// Reflects [`ty::BoundRegion`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundRegion, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::BoundRegion, state: S as gstate)] pub struct BoundRegion { pub var: BoundVar, pub kind: BoundRegionKind, } -/// Reflects [`rustc_middle::ty::PlaceholderRegion`] +/// Reflects [`ty::PlaceholderRegion`] pub type PlaceholderRegion = Placeholder; -/// Reflects [`rustc_middle::ty::PlaceholderConst`] +/// Reflects [`ty::PlaceholderConst`] pub type PlaceholderConst = Placeholder; -/// Reflects [`rustc_middle::ty::PlaceholderType`] +/// Reflects [`ty::PlaceholderType`] pub type PlaceholderType = Placeholder; -/// Reflects [`rustc_middle::ty::Placeholder`] +/// Reflects [`ty::Placeholder`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Placeholder { @@ -153,7 +153,7 @@ pub struct Placeholder { #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, T: SInto, U> SInto> - for rustc_middle::ty::Placeholder + for ty::Placeholder { fn sinto(&self, s: &S) -> Placeholder { Placeholder { @@ -171,7 +171,7 @@ pub struct Canonical { pub variables: Vec, pub value: T, } -/// Reflects [`rustc_middle::ty::CanonicalUserType`] +/// Reflects [`ty::CanonicalUserType`] pub type CanonicalUserType = Canonical; #[cfg(feature = "rustc")] @@ -201,30 +201,30 @@ pub enum CanonicalVarInfo { Effect, } -/// Reflects [`rustc_middle::ty::UserSelfTy`] +/// Reflects [`ty::UserSelfTy`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserSelfTy<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::UserSelfTy<'tcx>, state: S as gstate)] pub struct UserSelfTy { pub impl_def_id: DefId, pub self_ty: Ty, } -/// Reflects [`rustc_middle::ty::UserArgs`] +/// Reflects [`ty::UserArgs`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserArgs<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::UserArgs<'tcx>, state: S as gstate)] pub struct UserArgs { pub args: Vec, pub user_self_ty: Option, } -/// Reflects [`rustc_middle::ty::UserType`]: this is currently +/// Reflects [`ty::UserType`]: this is currently /// disabled, and everything is printed as debug in the /// [`UserType::Todo`] variant. #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::UserType<'tcx>, state: S as _s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::UserType<'tcx>, state: S as _s)] pub enum UserType { // TODO: for now, we don't use user types at all. // We disable it for now, since it cause the following to fail: @@ -242,7 +242,7 @@ pub enum UserType { // u32::from(Alias::MY_CONST) // } // - // In this case, we get a [rustc_middle::ty::ConstKind::Bound] in + // In this case, we get a [ty::ConstKind::Bound] in // [do_something], which we are not able to translate. // See: https://github.com/hacspec/hax/pull/209 @@ -252,25 +252,25 @@ pub enum UserType { Todo(String), } -/// Reflects [`rustc_middle::ty::VariantDiscr`] +/// Reflects [`ty::VariantDiscr`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::VariantDiscr, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::VariantDiscr, state: S as gstate)] pub enum DiscriminantDefinition { Explicit(DefId), Relative(u32), } -/// Reflects [`rustc_middle::ty::util::Discr`] +/// Reflects [`ty::util::Discr`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::util::Discr<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::util::Discr<'tcx>, state: S as gstate)] pub struct DiscriminantValue { pub val: u128, pub ty: Ty, } -/// Reflects [`rustc_middle::ty::Visibility`] +/// Reflects [`ty::Visibility`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum Visibility { @@ -279,9 +279,9 @@ pub enum Visibility { } #[cfg(feature = "rustc")] -impl, U> SInto> for rustc_middle::ty::Visibility { +impl, U> SInto> for ty::Visibility { fn sinto(&self, s: &S) -> Visibility { - use rustc_middle::ty::Visibility as T; + use ty::Visibility as T; match self { T::Public => Visibility::Public, T::Restricted(id) => Visibility::Restricted(id.sinto(s)), @@ -289,7 +289,7 @@ impl, U> SInto> for rustc_middle::ty::Visibil } } -/// Reflects [`rustc_middle::ty::FieldDef`] +/// Reflects [`ty::FieldDef`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct FieldDef { @@ -304,11 +304,11 @@ pub struct FieldDef { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::FieldDef { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::FieldDef { fn sinto(&self, s: &S) -> FieldDef { let tcx = s.base().tcx; let ty = { - let generics = rustc_middle::ty::GenericArgs::identity_for_item(tcx, self.did); + let generics = ty::GenericArgs::identity_for_item(tcx, self.did); self.ty(tcx, generics).sinto(s) }; let name = { @@ -332,7 +332,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Fi } } -/// Reflects [`rustc_middle::ty::VariantDef`] +/// Reflects [`ty::VariantDef`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct VariantDef { @@ -369,28 +369,28 @@ impl VariantDef { } } -/// Reflects [`rustc_middle::ty::EarlyParamRegion`] +/// Reflects [`ty::EarlyParamRegion`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::EarlyParamRegion, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::EarlyParamRegion, state: S as gstate)] pub struct EarlyParamRegion { pub index: u32, pub name: Symbol, } -/// Reflects [`rustc_middle::ty::LateParamRegion`] +/// Reflects [`ty::LateParamRegion`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::LateParamRegion, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::LateParamRegion, state: S as gstate)] pub struct LateParamRegion { pub scope: DefId, pub bound_region: BoundRegionKind, } -/// Reflects [`rustc_middle::ty::RegionKind`] +/// Reflects [`ty::RegionKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::RegionKind<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::RegionKind<'tcx>, state: S as gstate)] pub enum RegionKind { ReEarlyParam(EarlyParamRegion), ReBound(DebruijnIndex, BoundRegion), @@ -405,19 +405,19 @@ pub enum RegionKind { sinto_as_usize!(rustc_middle::ty, DebruijnIndex); sinto_as_usize!(rustc_middle::ty, RegionVid); -/// Reflects [`rustc_middle::ty::Region`] +/// Reflects [`ty::Region`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Region<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::Region<'tcx>, state: S as s)] pub struct Region { #[value(self.kind().sinto(s))] pub kind: RegionKind, } -/// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] +/// Reflects both [`ty::GenericArg`] and [`ty::GenericArgKind`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericArgKind<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::GenericArgKind<'tcx>, state: S as s)] pub enum GenericArg { Lifetime(Region), Type(Ty), @@ -425,22 +425,20 @@ pub enum GenericArg { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::GenericArg<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::GenericArg<'tcx> { fn sinto(&self, s: &S) -> GenericArg { self.unpack().sinto(s) } } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto> - for rustc_middle::ty::GenericArgsRef<'tcx> -{ +impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for ty::GenericArgsRef<'tcx> { fn sinto(&self, s: &S) -> Vec { self.iter().map(|v| v.unpack().sinto(s)).collect() } } -/// Reflects both [`rustc_middle::ty::GenericArg`] and [`rustc_middle::ty::GenericArgKind`] +/// Reflects both [`ty::GenericArg`] and [`ty::GenericArgKind`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: rustc_ast::ast::LitIntType, state: S as gstate)] #[derive_group(Serializers)] @@ -451,10 +449,10 @@ pub enum LitIntType { Unsuffixed, } -/// Reflects partially [`rustc_middle::ty::InferTy`] +/// Reflects partially [`ty::InferTy`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S>, from: rustc_middle::ty::InferTy, state: S as gstate)] +#[args(<'tcx, S>, from: ty::InferTy, state: S as gstate)] pub enum InferTy { #[custom_arm(FROM_TYPE::TyVar(..) => TO_TYPE::TyVar,)] TyVar, /*TODO?*/ @@ -577,9 +575,9 @@ impl ToString for UintTy { } } -/// Reflects [`rustc_middle::ty::TypeAndMut`] +/// Reflects [`ty::TypeAndMut`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TypeAndMut<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::TypeAndMut<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TypeAndMut { @@ -588,15 +586,15 @@ pub struct TypeAndMut { } #[cfg(feature = "rustc")] -impl> SInto> for rustc_middle::ty::List { +impl> SInto> for ty::List { fn sinto(&self, s: &S) -> Vec { self.iter().map(|x| x.sinto(s)).collect() } } -/// Reflects [`rustc_middle::ty::GenericParamDef`] +/// Reflects [`ty::GenericParamDef`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericParamDef, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::GenericParamDef, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct GenericParamDef { @@ -617,7 +615,7 @@ pub struct GenericParamDef { pub kind: GenericParamDefKind, } -/// Reflects [`rustc_middle::ty::GenericParamDefKind`] +/// Reflects [`ty::GenericParamDefKind`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum GenericParamDefKind { @@ -633,9 +631,9 @@ pub enum GenericParamDefKind { }, } -/// Reflects [`rustc_middle::ty::Generics`] +/// Reflects [`ty::Generics`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::Generics, state: S as state)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::Generics, state: S as state)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct TyGenerics { @@ -649,7 +647,7 @@ pub struct TyGenerics { } /// This type merges the information from -/// `rustc_type_ir::AliasKind` and `rustc_middle::ty::AliasTy` +/// `rustc_type_ir::AliasKind` and `ty::AliasTy` #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Alias { @@ -658,7 +656,7 @@ pub struct Alias { pub def_id: DefId, } -/// Reflects [`rustc_middle::ty::AliasKind`] +/// Reflects [`ty::AliasKind`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AliasKind { @@ -686,7 +684,7 @@ impl Alias { fn from<'tcx, S: UnderOwnerState<'tcx>>( s: &S, alias_kind: &rustc_type_ir::AliasTyKind, - alias_ty: &rustc_middle::ty::AliasTy<'tcx>, + alias_ty: &ty::AliasTy<'tcx>, ) -> TyKind { let tcx = s.base().tcx; use rustc_type_ir::AliasTyKind as RustAliasKind; @@ -730,13 +728,13 @@ impl Alias { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Box { Box::new(self.sinto(s)) } } -/// Reflects [`rustc_middle::ty::Ty`] +/// Reflects [`ty::Ty`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Ty { @@ -750,7 +748,7 @@ impl Ty { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { if let Some(ty) = s.with_cache(|cache| cache.tys.get(self).cloned()) { return ty; @@ -763,9 +761,9 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> } } -/// Reflects [`rustc_middle::ty::TyKind`] +/// Reflects [`ty::TyKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TyKind<'tcx>, state: S as state)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::TyKind<'tcx>, state: S as state)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum TyKind { @@ -776,8 +774,8 @@ pub enum TyKind { Float(FloatTy), #[custom_arm( - rustc_middle::ty::TyKind::FnPtr(sig) => arrow_of_sig(sig, state), - rustc_middle::ty::TyKind::FnDef(def, generics) => { + ty::TyKind::FnPtr(sig) => arrow_of_sig(sig, state), + ty::TyKind::FnDef(def, generics) => { let tcx = state.base().tcx; arrow_of_sig(&tcx.fn_sig(*def).instantiate(tcx, generics), state) }, @@ -787,11 +785,11 @@ pub enum TyKind { arrow_of_sig(&sig, state) }, )] - /// Reflects [`rustc_middle::ty::TyKind::FnPtr`], [`rustc_middle::ty::TyKind::FnDef`] and [`rustc_middle::ty::TyKind::Closure`] + /// Reflects [`ty::TyKind::FnPtr`], [`ty::TyKind::FnDef`] and [`ty::TyKind::Closure`] Arrow(Box), #[custom_arm( - rustc_middle::ty::TyKind::Adt(adt_def, generics) => { + ty::TyKind::Adt(adt_def, generics) => { let def_id = adt_def.did().sinto(state); let generic_args: Vec = generics.sinto(state); let trait_refs = solve_item_traits(state, adt_def.did(), generics, None); @@ -799,7 +797,7 @@ pub enum TyKind { }, )] Adt { - /// Reflects [`rustc_middle::ty::TyKind::Adt`]'s substitutions + /// Reflects [`ty::TyKind::Adt`]'s substitutions generic_args: Vec, /// Predicates required by the type, e.g. `T: Sized` for `Option` or `B: 'a + ToOwned` /// for `Cow<'a, B>`. @@ -817,7 +815,7 @@ pub enum TyKind { Never, Tuple(Vec), #[custom_arm( - rustc_middle::ty::TyKind::Alias(alias_kind, alias_ty) => { + ty::TyKind::Alias(alias_kind, alias_ty) => { Alias::from(state, alias_kind, alias_ty) }, )] @@ -826,15 +824,15 @@ pub enum TyKind { Bound(DebruijnIndex, BoundTy), Placeholder(PlaceholderType), Infer(InferTy), - #[custom_arm(rustc_middle::ty::TyKind::Error(..) => TyKind::Error,)] + #[custom_arm(ty::TyKind::Error(..) => TyKind::Error,)] Error, #[todo] Todo(String), } -/// Reflects [`rustc_middle::ty::Variance`] +/// Reflects [`ty::Variance`] #[derive(AdtInto)] -#[args(, from: rustc_middle::ty::Variance, state: S as _s)] +#[args(, from: ty::Variance, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum Variance { @@ -844,9 +842,9 @@ pub enum Variance { Bivariant, } -/// Reflects [`rustc_middle::ty::CanonicalUserTypeAnnotation`] +/// Reflects [`ty::CanonicalUserTypeAnnotation`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CanonicalUserTypeAnnotation<'tcx>, state: S as gstate)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::CanonicalUserTypeAnnotation<'tcx>, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct CanonicalUserTypeAnnotation { @@ -855,10 +853,10 @@ pub struct CanonicalUserTypeAnnotation { pub inferred_ty: Ty, } -/// Reflects [`rustc_middle::ty::AdtKind`] +/// Reflects [`ty::AdtKind`] #[derive_group(Serializers)] #[derive(AdtInto, Copy, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AdtKind, state: S as _s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::AdtKind, state: S as _s)] pub enum AdtKind { Struct, Union, @@ -867,7 +865,7 @@ pub enum AdtKind { // This comes from MIR // TODO: add the generics and the predicates -/// Reflects [`rustc_middle::ty::AdtDef`] +/// Reflects [`ty::AdtDef`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub struct AdtDef { @@ -880,10 +878,10 @@ pub struct AdtDef { sinto_todo!(rustc_middle::ty, AdtFlags); -/// Reflects [`rustc_middle::ty::ReprOptions`] +/// Reflects [`ty::ReprOptions`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ReprOptions, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::ReprOptions, state: S as s)] pub struct ReprOptions { pub int: Option, #[value({ @@ -902,7 +900,7 @@ sinto_todo!(rustc_abi, ReprFlags); sinto_todo!(rustc_abi, Align); #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtDef<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::AdtDef<'tcx> { fn sinto(&self, s: &S) -> AdtDef { let variants = self .variants() @@ -913,7 +911,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtD } else { // Structs and unions have a single variant. assert_eq!(variant_idx.index(), 0); - rustc_middle::ty::util::Discr { + ty::util::Discr { val: 0, ty: s.base().tcx.types.isize, } @@ -931,9 +929,9 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::AdtD } } -/// Reflects [`rustc_middle::ty::adjustment::PointerCoercion`] +/// Reflects [`ty::adjustment::PointerCoercion`] #[derive(AdtInto)] -#[args(, from: rustc_middle::ty::adjustment::PointerCoercion, state: S as gstate)] +#[args(, from: ty::adjustment::PointerCoercion, state: S as gstate)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum PointerCoercion { @@ -947,10 +945,10 @@ pub enum PointerCoercion { sinto_todo!(rustc_middle::ty, ScalarInt); -/// Reflects [`rustc_middle::ty::FnSig`] +/// Reflects [`ty::FnSig`] #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::FnSig<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::FnSig<'tcx>, state: S as s)] pub struct TyFnSig { #[value(self.inputs().sinto(s))] pub inputs: Vec, @@ -961,13 +959,13 @@ pub struct TyFnSig { pub abi: Abi, } -/// Reflects [`rustc_middle::ty::PolyFnSig`] +/// Reflects [`ty::PolyFnSig`] pub type PolyFnSig = Binder; -/// Reflects [`rustc_middle::ty::TraitRef`] +/// Reflects [`ty::TraitRef`] #[derive_group(Serializers)] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitRef<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::TraitRef<'tcx>, state: S as tcx)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TraitRef { pub def_id: DefId, @@ -976,19 +974,19 @@ pub struct TraitRef { pub generic_args: Vec, } -/// Reflects [`rustc_middle::ty::TraitPredicate`] +/// Reflects [`ty::TraitPredicate`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::TraitPredicate<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::TraitPredicate<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct TraitPredicate { pub trait_ref: TraitRef, - #[map(*x == rustc_middle::ty::PredicatePolarity::Positive)] + #[map(*x == ty::PredicatePolarity::Positive)] #[from(polarity)] pub is_positive: bool, } -/// Reflects [`rustc_middle::ty::OutlivesPredicate`] as a named struct +/// Reflects [`ty::OutlivesPredicate`] as a named struct /// instead of a tuple struct. This is because the script converting /// JSONSchema types to OCaml doesn't support tuple structs, and this /// is the only tuple struct in the whole AST. @@ -1001,7 +999,7 @@ pub struct OutlivesPredicate { #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>, T, U> SInto> - for rustc_middle::ty::OutlivesPredicate<'tcx, T> + for ty::OutlivesPredicate<'tcx, T> where T: SInto, { @@ -1013,12 +1011,12 @@ where } } -/// Reflects [`rustc_middle::ty::RegionOutlivesPredicate`] +/// Reflects [`ty::RegionOutlivesPredicate`] pub type RegionOutlivesPredicate = OutlivesPredicate; -/// Reflects [`rustc_middle::ty::TypeOutlivesPredicate`] +/// Reflects [`ty::TypeOutlivesPredicate`] pub type TypeOutlivesPredicate = OutlivesPredicate; -/// Reflects [`rustc_middle::ty::Term`] +/// Reflects [`ty::Term`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Term { @@ -1027,9 +1025,9 @@ pub enum Term { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Term<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Term<'tcx> { fn sinto(&self, s: &S) -> Term { - use rustc_middle::ty::TermKind; + use ty::TermKind; match self.unpack() { TermKind::Ty(ty) => Term::Ty(ty.sinto(s)), TermKind::Const(c) => Term::Const(c.sinto(s)), @@ -1058,7 +1056,7 @@ pub struct ProjectionPredicate { #[cfg(feature = "rustc")] impl<'tcx, S: UnderBinderState<'tcx>> SInto - for rustc_middle::ty::ProjectionPredicate<'tcx> + for ty::ProjectionPredicate<'tcx> { fn sinto(&self, s: &S) -> ProjectionPredicate { let tcx = s.base().tcx; @@ -1075,9 +1073,9 @@ impl<'tcx, S: UnderBinderState<'tcx>> SInto } } -/// Reflects [`rustc_middle::ty::ClauseKind`] +/// Reflects [`ty::ClauseKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderBinderState<'tcx>>, from: rustc_middle::ty::ClauseKind<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderBinderState<'tcx>>, from: ty::ClauseKind<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ClauseKind { @@ -1090,7 +1088,7 @@ pub enum ClauseKind { ConstEvaluatable(ConstantExpr), } -/// Reflects [`rustc_middle::ty::Clause`] and adds a hash-consed predicate identifier. +/// Reflects [`ty::Clause`] and adds a hash-consed predicate identifier. #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Clause { @@ -1099,7 +1097,7 @@ pub struct Clause { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clause<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Clause<'tcx> { fn sinto(&self, s: &S) -> Clause { let kind = self.kind().sinto(s); let id = kind.clone().map(PredicateKind::Clause).predicate_id(); @@ -1108,9 +1106,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Clau } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto - for rustc_middle::ty::PolyTraitPredicate<'tcx> -{ +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::PolyTraitPredicate<'tcx> { fn sinto(&self, s: &S) -> Clause { let kind: Binder<_> = self.sinto(s); let kind: Binder = kind.map(ClauseKind::Trait); @@ -1119,7 +1115,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto } } -/// Reflects [`rustc_middle::ty::Predicate`] and adds a hash-consed predicate identifier. +/// Reflects [`ty::Predicate`] and adds a hash-consed predicate identifier. #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Predicate { @@ -1128,7 +1124,7 @@ pub struct Predicate { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Predicate<'tcx> { +impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Predicate<'tcx> { fn sinto(&self, s: &S) -> Predicate { let kind = self.kind().sinto(s); let id = kind.predicate_id(); @@ -1136,9 +1132,9 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::P } } -/// Reflects [`rustc_middle::ty::BoundVariableKind`] +/// Reflects [`ty::BoundVariableKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::BoundVariableKind, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::BoundVariableKind, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum BoundVariableKind { @@ -1147,7 +1143,7 @@ pub enum BoundVariableKind { Const, } -/// Reflects [`rustc_middle::ty::Binder`] +/// Reflects [`ty::Binder`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Binder { @@ -1187,9 +1183,9 @@ impl Binder { } } -/// Reflects [`rustc_middle::ty::GenericPredicates`] +/// Reflects [`ty::GenericPredicates`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::GenericPredicates<'tcx>, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::GenericPredicates<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct GenericPredicates { @@ -1200,8 +1196,7 @@ pub struct GenericPredicates { } #[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto> - for rustc_middle::ty::Binder<'tcx, T1> +impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto> for ty::Binder<'tcx, T1> where T1: SInto, T2>, { @@ -1221,9 +1216,9 @@ where } } -/// Reflects [`rustc_middle::ty::SubtypePredicate`] +/// Reflects [`ty::SubtypePredicate`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::SubtypePredicate<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::SubtypePredicate<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct SubtypePredicate { @@ -1232,9 +1227,9 @@ pub struct SubtypePredicate { pub b: Ty, } -/// Reflects [`rustc_middle::ty::CoercePredicate`] +/// Reflects [`ty::CoercePredicate`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::CoercePredicate<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::CoercePredicate<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct CoercePredicate { @@ -1242,9 +1237,9 @@ pub struct CoercePredicate { pub b: Ty, } -/// Reflects [`rustc_middle::ty::AliasRelationDirection`] +/// Reflects [`ty::AliasRelationDirection`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::AliasRelationDirection, state: S as _tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::AliasRelationDirection, state: S as _tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AliasRelationDirection { @@ -1252,7 +1247,7 @@ pub enum AliasRelationDirection { Subtype, } -/// Reflects [`rustc_middle::ty::ClosureArgs`] +/// Reflects [`ty::ClosureArgs`] #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: ty::ClosureArgs>, state: S as s)] #[derive(Clone, Debug, JsonSchema)] @@ -1268,9 +1263,9 @@ pub struct ClosureArgs { pub upvar_tys: Vec, } -/// Reflects [`rustc_middle::ty::ClosureKind`] +/// Reflects [`ty::ClosureKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ClosureKind, state: S as _tcx)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::ClosureKind, state: S as _tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ClosureKind { @@ -1281,9 +1276,9 @@ pub enum ClosureKind { sinto_todo!(rustc_middle::ty, NormalizesTo<'tcx>); -/// Reflects [`rustc_middle::ty::PredicateKind`] +/// Reflects [`ty::PredicateKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderBinderState<'tcx>>, from: rustc_middle::ty::PredicateKind<'tcx>, state: S as tcx)] +#[args(<'tcx, S: UnderBinderState<'tcx>>, from: ty::PredicateKind<'tcx>, state: S as tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum PredicateKind { @@ -1297,7 +1292,7 @@ pub enum PredicateKind { NormalizesTo(NormalizesTo), } -/// Reflects [`rustc_middle::ty::ImplSubject`] +/// Reflects [`ty::ImplSubject`] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ImplSubject { @@ -1325,7 +1320,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<' let polarity = tcx.impl_polarity(s.owner_id()); let trait_pred = TraitPredicate { trait_ref: trait_ref.sinto(s), - is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive), + is_positive: matches!(polarity, ty::ImplPolarity::Positive), }; let required_impl_exprs = solve_item_traits(s, trait_ref.def_id, trait_ref.args, None); @@ -1370,9 +1365,9 @@ fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( } } -/// Reflects [`rustc_middle::ty::AssocItem`] +/// Reflects [`ty::AssocItem`] #[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::AssocItem, state: S as s)] +#[args(<'tcx, S: BaseState<'tcx>>, from: ty::AssocItem, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct AssocItem { @@ -1389,9 +1384,9 @@ pub struct AssocItem { pub opt_rpitit_info: Option, } -/// Reflects [`rustc_middle::ty::ImplTraitInTraitData`] +/// Reflects [`ty::ImplTraitInTraitData`] #[derive(AdtInto)] -#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_middle::ty::ImplTraitInTraitData, state: S as _s)] +#[args(<'tcx, S: BaseState<'tcx>>, from: ty::ImplTraitInTraitData, state: S as _s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum ImplTraitInTraitData { @@ -1423,9 +1418,9 @@ pub enum AssocItemContainer { }, } -/// Reflects [`rustc_middle::ty::AssocKind`] +/// Reflects [`ty::AssocKind`] #[derive(AdtInto)] -#[args(, from: rustc_middle::ty::AssocKind, state: S as _tcx)] +#[args(, from: ty::AssocKind, state: S as _tcx)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AssocKind { From dd31010ae7f125d1f2a16a5304789a5ef7086ac8 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Oct 2024 17:22:00 +0200 Subject: [PATCH 103/253] Remove unused definitions and discard `token` submodule --- frontend/exporter/src/types/hir.rs | 37 ++++++ frontend/exporter/src/types/mod.rs | 2 - frontend/exporter/src/types/tokens.rs | 156 -------------------------- 3 files changed, 37 insertions(+), 158 deletions(-) delete mode 100644 frontend/exporter/src/types/tokens.rs diff --git a/frontend/exporter/src/types/hir.rs b/frontend/exporter/src/types/hir.rs index 6b6f184d6..5abeab8cd 100644 --- a/frontend/exporter/src/types/hir.rs +++ b/frontend/exporter/src/types/hir.rs @@ -869,6 +869,43 @@ pub enum OpaqueTyOrigin { TyAlias { in_assoc_ty: bool }, } +/// Reflects [`rustc_ast::tokenstream::TokenStream`] as a plain +/// string. If you need to reshape that into Rust tokens or construct, +/// please use, e.g., `syn`. +pub type TokenStream = String; + +#[cfg(feature = "rustc")] +impl<'t, S> SInto for rustc_ast::tokenstream::TokenStream { + fn sinto(&self, _: &S) -> String { + rustc_ast_pretty::pprust::tts_to_string(self) + } +} + +/// Reflects [`rustc_ast::token::Delimiter`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::token::Delimiter, state: S as _s)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Delimiter { + Parenthesis, + Brace, + Bracket, + Invisible, +} + +/// Reflects [`rustc_ast::ast::DelimArgs`] +#[derive(AdtInto)] +#[args(, from: rustc_ast::ast::DelimArgs, state: S as gstate)] +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct DelimArgs { + pub dspan: DelimSpan, + pub delim: Delimiter, + pub tokens: TokenStream, +} + +sinto_todo!(rustc_ast::tokenstream, DelimSpan); + /// Reflects [`ast::MacroDef`] #[derive(AdtInto)] #[args(<'tcx, S: BaseState<'tcx>>, from: ast::MacroDef, state: S as tcx)] diff --git a/frontend/exporter/src/types/mod.rs b/frontend/exporter/src/types/mod.rs index 2ff6b8f6c..f2ebcdf78 100644 --- a/frontend/exporter/src/types/mod.rs +++ b/frontend/exporter/src/types/mod.rs @@ -10,7 +10,6 @@ mod new; pub(crate) mod serialize_int; mod span; mod thir; -mod tokens; mod ty; pub use def_id::*; @@ -21,5 +20,4 @@ pub use mir_traits::*; pub use new::*; pub use span::*; pub use thir::*; -pub use tokens::*; pub use ty::*; diff --git a/frontend/exporter/src/types/tokens.rs b/frontend/exporter/src/types/tokens.rs deleted file mode 100644 index 4b1764738..000000000 --- a/frontend/exporter/src/types/tokens.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Copies of types related to tokens and syntax representation of rust, as well as macros. -use crate::prelude::*; - -/// Reflects [`rustc_ast::token::Delimiter`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::token::Delimiter, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Delimiter { - Parenthesis, - Brace, - Bracket, - Invisible, -} - -/// Reflects [`rustc_ast::tokenstream::TokenTree`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::TokenTree, state: S as s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum TokenTree { - Token(Token, Spacing), - Delimited(DelimSpan, DelimSpacing, Delimiter, TokenStream), -} - -sinto_todo!(rustc_ast::tokenstream, DelimSpan); -sinto_todo!(rustc_ast::tokenstream, DelimSpacing); - -/// Reflects [`rustc_ast::tokenstream::Spacing`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::tokenstream::Spacing, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Spacing { - Alone, - Joint, - JointHidden, -} - -/// Reflects [`rustc_ast::token::BinOpToken`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::token::BinOpToken, state: S as _s)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum BinOpToken { - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - And, - Or, - Shl, - Shr, -} - -/// Reflects [`rustc_ast::token::TokenKind`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::TokenKind, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum TokenKind { - Eq, - Lt, - Le, - EqEq, - Ne, - Ge, - Gt, - AndAnd, - OrOr, - Not, - Tilde, - BinOp(BinOpToken), - BinOpEq(BinOpToken), - At, - Dot, - DotDot, - DotDotDot, - DotDotEq, - Comma, - Semi, - Colon, - RArrow, - LArrow, - FatArrow, - Pound, - Dollar, - Question, - SingleQuote, - OpenDelim(Delimiter), - CloseDelim(Delimiter), - // Literal(l: Lit), - Ident(Symbol, bool), - Lifetime(Symbol), - // Interpolated(n: Nonterminal), - // DocComment(k: CommentKind, ats: AttrStyle, s: Symbol), - Eof, - #[todo] - Todo(String), -} - -#[cfg(feature = "rustc")] -impl SInto for rustc_ast::token::IdentIsRaw { - fn sinto(&self, _s: &S) -> bool { - match self { - Self::Yes => true, - Self::No => false, - } - } -} - -/// Reflects [`rustc_ast::token::Token`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::token::Token, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Token { - pub kind: TokenKind, - pub span: Span, -} - -/// Reflects [`rustc_ast::ast::DelimArgs`] -#[derive(AdtInto)] -#[args(, from: rustc_ast::ast::DelimArgs, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct DelimArgs { - pub dspan: DelimSpan, - pub delim: Delimiter, - pub tokens: TokenStream, -} - -/// Reflects [`rustc_ast::ast::MacCall`] -#[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_ast::ast::MacCall, state: S as gstate)] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct MacCall { - #[map(x.segments.iter().map(|rustc_ast::ast::PathSegment{ident, ..}| ident.as_str().into()).collect())] - pub path: Path, - pub args: DelimArgs, -} - -/// Reflects [`rustc_ast::tokenstream::TokenStream`] as a plain -/// string. If you need to reshape that into Rust tokens or construct, -/// please use, e.g., `syn`. -pub type TokenStream = String; - -#[cfg(feature = "rustc")] -impl<'t, S> SInto for rustc_ast::tokenstream::TokenStream { - fn sinto(&self, _: &S) -> String { - rustc_ast_pretty::pprust::tts_to_string(self) - } -} From 34aea74d9c4faebc38b3af4fdf6587ae9abd5159 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Oct 2024 17:26:18 +0200 Subject: [PATCH 104/253] Remove now useless `get_params_info` --- frontend/exporter/src/types/mir.rs | 3 +- frontend/exporter/src/types/mir_traits.rs | 123 ---------------------- frontend/exporter/src/types/mod.rs | 4 - 3 files changed, 1 insertion(+), 129 deletions(-) delete mode 100644 frontend/exporter/src/types/mir_traits.rs diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 444110720..a5f232aab 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -383,10 +383,9 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H // } // ``` // The generics for `insert` are `` for the impl and `` for the method. - let params_info = get_params_info(s, container_def_id); - let num_container_generics = params_info.num_generic_params; match assoc.container { rustc_middle::ty::AssocItemContainer::TraitContainer => { + let num_container_generics = tcx.generics_of(container_def_id).own_params.len(); // Retrieve the trait information let impl_expr = self_clause_for_item(s, &assoc, generics).unwrap(); // Return only the method generics; the trait generics are included in `impl_expr`. diff --git a/frontend/exporter/src/types/mir_traits.rs b/frontend/exporter/src/types/mir_traits.rs deleted file mode 100644 index fa2fa5f1e..000000000 --- a/frontend/exporter/src/types/mir_traits.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::prelude::*; - -/// We use this to store information about the parameters in parent blocks. -/// This is necessary because when querying the generics of a definition, -/// rustc gives us *all* the generics used in this definition, including -/// those coming from the outer impl block. -/// -/// For instance: -/// ```text -/// impl Foo { -/// ^^^ -/// outer block generics -/// fn bar(...) { ... } -/// ^^^ -/// generics local to the function bar -/// } -/// ``` -/// -/// `TyCtxt.generics_of(bar)` gives us: `[T, U]`. -/// -/// We however sometimes need to make a distinction between those two kinds -/// of generics, in particular when manipulating trait instances. For instance: -/// -/// ```text -/// impl Foo for Bar { -/// fn baz(...) { ... } -/// } -/// -/// fn test(...) { -/// // Here: -/// x.baz(...); -/// // We should refer to this call as: -/// // > Foo::baz(...) -/// // -/// // If baz hadn't been a method implementation of a trait, -/// // we would have refered to it as: -/// // > baz(...) -/// // -/// // The reason is that with traits, we refer to the whole -/// // trait implementation (as if it were a structure), then -/// // pick a specific method inside (as if projecting a field -/// // from a structure). -/// } -/// ``` -/// -/// **Remark**: Rust only allows refering to the generics of the **immediately** -/// outer block. For this reason, when we need to store the information about -/// the generics of the outer block(s), we need to do it only for one level -/// (this definitely makes things simpler). -/// **Additional remark**: it is not possible to directly write an impl block -/// or a trait definition inside an impl/trait block. However it is possible -/// to define an impl/trait inside a function, which can itself be inside a -/// block, leading to nested impl blocks. -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema)] -pub struct ParamsInfo { - /// The total number of generic parameters (regions + types + consts). - /// We do not consider the trait clauses as generic parameters. - pub num_generic_params: usize, - pub num_region_params: usize, - pub num_type_params: usize, - pub num_const_generic_params: usize, - pub num_trait_clauses: usize, - pub num_regions_outlive: usize, - pub num_types_outlive: usize, - pub num_trait_type_constraints: usize, -} - -/// Compute the parameters information for a definition. See [ParamsInfo]. -pub fn get_params_info<'tcx, S: BaseState<'tcx> + HasOwnerId>( - s: &S, - def_id: rustc_hir::def_id::DefId, -) -> ParamsInfo { - let tcx = s.base().tcx; - - // Compute the number of generics - let mut num_region_params = 0; - let mut num_type_params = 0; - let mut num_const_generic_params = 0; - let mut num_regions_outlive = 0; - let mut num_types_outlive = 0; - let mut num_trait_type_constraints = 0; - - let generics = tcx.generics_of(def_id); - let num_generic_params = generics.own_params.len(); - use rustc_middle::ty::GenericParamDefKind; - for param in &generics.own_params { - match param.kind { - GenericParamDefKind::Lifetime => num_region_params += 1, - GenericParamDefKind::Type { .. } => num_type_params += 1, - GenericParamDefKind::Const { .. } => num_const_generic_params += 1, - } - } - - // Compute the number of trait clauses - let mut num_trait_clauses = 0; - // **IMPORTANT**: we do NOT want to [TyCtxt::predicates_of]. - // If we use [TyCtxt::predicates_of] on a trait `Foo`, we get an - // additional predicate `Self : Foo` (i.e., the trait requires itself), - // which is not what we want. - let preds = tcx.predicates_defined_on(def_id); - for (pred, _) in preds.predicates { - use rustc_middle::ty::ClauseKind; - match &pred.kind().skip_binder() { - ClauseKind::Trait(_) => num_trait_clauses += 1, - ClauseKind::RegionOutlives(_) => num_regions_outlive += 1, - ClauseKind::TypeOutlives(_) => num_types_outlive += 1, - ClauseKind::Projection(_) => num_trait_type_constraints += 1, - _ => (), - } - } - - ParamsInfo { - num_generic_params, - num_region_params, - num_type_params, - num_const_generic_params, - num_trait_clauses, - num_regions_outlive, - num_types_outlive, - num_trait_type_constraints, - } -} diff --git a/frontend/exporter/src/types/mod.rs b/frontend/exporter/src/types/mod.rs index f2ebcdf78..e70f2ce3c 100644 --- a/frontend/exporter/src/types/mod.rs +++ b/frontend/exporter/src/types/mod.rs @@ -4,8 +4,6 @@ mod def_id; mod hir; mod mir; -#[cfg(feature = "rustc")] -mod mir_traits; mod new; pub(crate) mod serialize_int; mod span; @@ -15,8 +13,6 @@ mod ty; pub use def_id::*; pub use hir::*; pub use mir::*; -#[cfg(feature = "rustc")] -pub use mir_traits::*; pub use new::*; pub use span::*; pub use thir::*; From 0751cb7ed545049b9818322428aeac98e71184aa Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 09:15:13 +0200 Subject: [PATCH 105/253] fix(frontend): this was reverted by mistake --- frontend/exporter/src/rustc_utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index ce0bd95ba..96de95f7c 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -26,7 +26,6 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( variant_index: rustc_target::abi::VariantIdx, s: &S, ) -> VariantInformations { - s_assert!(s, !adt_def.is_union() || *CORE_EXTRACTION_MODE); fn is_named<'s, I: std::iter::Iterator + Clone>(it: I) -> bool { it.clone() .any(|field| field.name.to_ident_string().parse::().is_err()) From 6d244f4a4e04707988c55c2d54d92fc9a48a43ae Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Wed, 23 Oct 2024 14:00:40 +0200 Subject: [PATCH 106/253] Handle ProVerif replacements for `fn` --- engine/backends/proverif/proverif_backend.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index ee03faa8b..0c00477d5 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -751,7 +751,11 @@ module Make (Options : OPTS) : MAKE = struct end let filter_crate_functions (items : AST.item list) = - List.filter ~f:(fun item -> [%matches? Fn _] item.v) items + List.filter + ~f:(fun item -> + [%matches? Fn _] item.v + || [%matches? Quote { origin = { item_kind = `Fn; _ }; _ }] item.v) + items let is_process_read : attrs -> bool = Attr_payloads.payloads From 8141f6f648f84a41de78e50f792fa4e81dd1cc0d Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 13:51:58 +0200 Subject: [PATCH 107/253] feat: deduplicate types in haxmeta and JSON --- Cargo.lock | 41 +- Cargo.toml | 1 - cli/driver/src/exporter.rs | 16 +- cli/subcommands/src/cargo_hax.rs | 45 ++- engine/bin/lib.ml | 43 ++- engine/lib/concrete_ident/concrete_ident.ml | 10 +- engine/lib/import_thir.ml | 7 +- engine/lib/import_thir.mli | 2 +- engine/names/extract/Cargo.toml | 1 - .../ocaml_of_json_schema.js | 43 ++- frontend/exporter/Cargo.toml | 1 - frontend/exporter/adt-into/src/lib.rs | 6 +- frontend/exporter/options/Cargo.toml | 1 - frontend/exporter/src/body.rs | 2 +- frontend/exporter/src/id_table.rs | 363 ++++++++++++++++++ frontend/exporter/src/lib.rs | 1 + frontend/exporter/src/prelude.rs | 1 + frontend/exporter/src/state.rs | 20 +- frontend/exporter/src/traits.rs | 6 +- frontend/exporter/src/types/copied.rs | 73 +--- frontend/exporter/src/types/new/full_def.rs | 4 +- hax-types/Cargo.toml | 3 +- hax-types/src/cli_options/extension.rs | 5 +- hax-types/src/cli_options/mod.rs | 7 + hax-types/src/driver_api.rs | 19 +- 25 files changed, 570 insertions(+), 151 deletions(-) create mode 100644 frontend/exporter/src/id_table.rs diff --git a/Cargo.lock b/Cargo.lock index 8462089a3..c46631bc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,25 +98,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "bincode" -version = "2.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" -dependencies = [ - "bincode_derive", - "serde", -] - -[[package]] -name = "bincode_derive" -version = "2.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" -dependencies = [ - "virtue", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -512,7 +493,6 @@ dependencies = [ name = "hax-engine-names-extract" version = "0.1.0-alpha.1" dependencies = [ - "bincode", "hax-adt-into", "hax-engine-names", "serde", @@ -524,7 +504,6 @@ dependencies = [ name = "hax-frontend-exporter" version = "0.1.0-alpha.1" dependencies = [ - "bincode", "extension-traits", "hax-adt-into", "hax-frontend-exporter-options", @@ -541,7 +520,6 @@ dependencies = [ name = "hax-frontend-exporter-options" version = "0.1.0-alpha.1" dependencies = [ - "bincode", "hax-adt-into", "schemars", "serde", @@ -620,7 +598,6 @@ name = "hax-types" version = "0.1.0-alpha.1" dependencies = [ "annotate-snippets", - "bincode", "clap", "colored", "hax-adt-into", @@ -630,7 +607,9 @@ dependencies = [ "path-clean", "schemars", "serde", + "serde-brief", "serde_json", + "tracing", "zstd", ] @@ -1256,6 +1235,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-brief" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3ebe2a279beb0833037245a36adbbf71239fdaefc0f670122aff9922bcaf0b" +dependencies = [ + "serde", + "tracing", +] + [[package]] name = "serde-jsonlines" version = "0.5.0" @@ -1645,12 +1634,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "virtue" -version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" - [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 90ca24953..ceca15b72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,6 @@ quote = "1.0.32" proc-macro2 = "1.0.66" cargo_metadata = "0.15" colored = "2" -bincode = "2.0.0-rc.3" annotate-snippets = "0.11" # Crates in this repository diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index d9e767530..da6cec19f 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -134,12 +134,13 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( hax_frontend_exporter::ImplInfos, )>, Vec>, + hax_frontend_exporter::id_table::Table, ) { use hax_frontend_exporter::WithGlobalCacheExt; let mut state = hax_frontend_exporter::state::State::new(tcx, options.clone()); state.base.macro_infos = Rc::new(macro_calls); for (def_id, thir) in precompute_local_thir_bodies(tcx) { - state.with_item_cache(def_id, |caches| caches.thir = Some(thir)); + state.with_item_cache(def_id, |caches, _| caches.thir = Some(thir)); } let result = hax_frontend_exporter::inline_macro_invocations(tcx.hir().items(), &state); @@ -154,8 +155,15 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( .filter_map(|per_item_cache| per_item_cache.def_id.clone()) .collect() }); + let cache_map = state.with_global_cache(|cache| cache.id_table_session.table().clone()); - (exported_spans, exported_def_ids, impl_infos, result) + ( + exported_spans, + exported_def_ids, + impl_infos, + result, + cache_map, + ) } /// Collect a map from spans to macro calls @@ -260,7 +268,7 @@ impl Callbacks for ExtractionCallbacks { with_kind_type!( self.body_types.clone(), || { - let (spans, def_ids, impl_infos, items) = + let (spans, def_ids, impl_infos, items, cache_map) = convert_thir(&self.clone().into(), self.macro_calls.clone(), tcx); let files: HashSet = HashSet::from_iter( items @@ -279,7 +287,7 @@ impl Callbacks for ExtractionCallbacks { .collect(), def_ids, }; - haxmeta.write(&mut file); + haxmeta.write(&mut file, cache_map); } ); diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index c3ee00316..d5e1691cb 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -13,6 +13,7 @@ use std::path::PathBuf; use std::process; mod engine_debug_webapp; +use hax_frontend_exporter::id_table; /// Return a toolchain argument to pass to `cargo`: when the correct nightly is /// already present, this is None, otherwise we (1) ensure `rustup` is available @@ -199,6 +200,7 @@ impl HaxMessage { /// Runs `hax-engine` fn run_engine( haxmeta: HaxMeta, + id_table: id_table::Table, working_dir: PathBuf, manifest_dir: PathBuf, backend: &BackendOptions<()>, @@ -246,7 +248,9 @@ fn run_engine( }; } - send!(&engine_options); + id_table::WithTable::run(id_table, engine_options, |with_table| { + send!(with_table); + }); let out_dir = backend.output_dir.clone().unwrap_or({ let relative_path: PathBuf = [ @@ -466,26 +470,39 @@ fn run_command(options: &Options, haxmeta_files: Vec) -> boo output_file, kind, include_extra, + use_ids, .. } => { with_kind_type!(kind, || { for EmitHaxMetaMessage { path, .. } in haxmeta_files { - let haxmeta: HaxMeta = HaxMeta::read(fs::File::open(&path).unwrap()); + let (haxmeta, id_table): (HaxMeta, _) = HaxMeta::read(fs::File::open(&path).unwrap()); let dest = output_file.open_or_stdout(); + (if include_extra { - serde_json::to_writer( - dest, - &WithDefIds { - def_ids: haxmeta.def_ids, - impl_infos: haxmeta.impl_infos, - items: haxmeta.items, - comments: haxmeta.comments, - }, - ) + let data = WithDefIds { + def_ids: haxmeta.def_ids, + impl_infos: haxmeta.impl_infos, + items: haxmeta.items, + comments: haxmeta.comments, + }; + if use_ids { + id_table::WithTable::run(id_table, data, |with_table| { + serde_json::to_writer(dest, with_table) + }) + } else { + serde_json::to_writer(dest, &data) + } } else { - serde_json::to_writer(dest, &haxmeta.items) + if use_ids { + id_table::WithTable::run(id_table, haxmeta.items, |with_table| { + serde_json::to_writer(dest, with_table) + }) + } else { + serde_json::to_writer(dest, &haxmeta.items) + } }) .unwrap() + } }); false @@ -508,11 +525,13 @@ fn run_command(options: &Options, haxmeta_files: Vec) -> boo path, } in haxmeta_files { - let haxmeta: HaxMeta = HaxMeta::read(fs::File::open(&path).unwrap()); + let (haxmeta, id_table): (HaxMeta, _) = + HaxMeta::read(fs::File::open(&path).unwrap()); error = error || run_engine( haxmeta, + id_table, working_dir, manifest_dir, &backend, diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index efa2d60ed..bbab16f5e 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -140,10 +140,51 @@ let run (options : Types.engine_options) : Types.output = debug_json = None; } +(** Shallow parses a `id_table::Node` (or a raw `T`) JSON *) +let parse_id_table_node (json : Yojson.Safe.t) : + (int64 * Yojson.Safe.t) list option * Yojson.Safe.t = + let expect_assoc = function + | `Assoc alist -> Some (List.Assoc.find ~equal:[%eq: string] alist) + | _ -> None + in + let expect_uint64 = function + | `Intlit str -> Some (Int64.of_string str) + | `Int id -> Some (Int.to_int64 id) + | _ -> None + in + (let* assoc = expect_assoc json in + let* table = assoc "table" in + let* value = assoc "value" in + let table = + match table with + | `List json_list -> json_list + | _ -> failwith "parse_cached: `map` is supposed to be a list" + in + let table = + List.map + ~f:(function + | `List [ id; `Assoc [ (_, contents) ] ] -> + let id = + expect_uint64 id + |> Option.value_exn ~message:"parse_cached: id: expected int64" + in + (id, contents) + | _ -> failwith "parse_cached: expected a list of size two") + table + in + Some (Some table, value)) + |> Option.value ~default:(None, json) + (** Entrypoint of the engine. Assumes `Hax_io.init` was called. *) let main () = let options = - Hax_io.read_json () |> Option.value_exn |> Types.parse_engine_options + let table, json = + Hax_io.read_json () |> Option.value_exn |> parse_id_table_node + in + table |> Option.value ~default:[] + |> List.iter ~f:(fun (id, json) -> + Hashtbl.add_exn Types.cache_map ~key:id ~data:(`JSON json)); + Types.parse_engine_options json in Printexc.record_backtrace true; let result = diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index 1508d11a5..e367d7037 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -266,7 +266,7 @@ module View = struct open Utils let simple_ty_to_string ~(namespace : Imported.def_id) : - Types.ty -> string option = + Types.node_for__ty_kind -> string option = let escape = let re = Re.Pcre.regexp "_((?:e_)*)of_" in let f group = "_e_" ^ Re.Group.get group 1 ^ "of_" in @@ -284,8 +284,8 @@ module View = struct last.data |> Imported.of_def_path_item |> string_of_def_path_item |> Option.map ~f:escape in - let arity0 (ty : Types.ty) = - match ty.Types.kind with + let arity0 (ty : Types.node_for__ty_kind) = + match ty.Types.value with | Bool -> Some "bool" | Char -> Some "char" | Str -> Some "str" @@ -310,8 +310,8 @@ module View = struct | _ -> None in let apply left right = left ^ "_of_" ^ right in - let rec arity1 (ty : Types.ty) = - match ty.kind with + let rec arity1 (ty : Types.node_for__ty_kind) = + match ty.value with | Slice sub -> arity1 sub |> Option.map ~f:(apply "slice") | Ref (_, sub, _) -> arity1 sub |> Option.map ~f:(apply "ref") | Adt { def_id; generic_args = [ Type arg ]; _ } -> diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index ac7e305db..26bb7967a 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -10,6 +10,7 @@ module Thir = struct type generic_param = generic_param_for__decorated_for__expr_kind type generic_param_kind = generic_param_kind_for__decorated_for__expr_kind type trait_item = trait_item_for__decorated_for__expr_kind + type ty = node_for__ty_kind end open! Prelude @@ -385,7 +386,7 @@ end) : EXPR = struct in (* if there is no expression & the last expression is ⊥, just use that *) let lift_last_statement_as_expr_if_possible expr stmts (ty : Thir.ty) = - match (ty.kind, expr, List.drop_last stmts, List.last stmts) with + match (ty.value, expr, List.drop_last stmts, List.last stmts) with | ( Thir.Never, None, Some stmts, @@ -980,7 +981,7 @@ end) : EXPR = struct ("Pointer, with [cast] being " ^ [%show: Thir.pointer_coercion] cast) and c_ty (span : Thir.span) (ty : Thir.ty) : ty = - match ty.kind with + match ty.value with | Bool -> TBool | Char -> TChar | Int k -> TInt (c_int_ty k) @@ -1278,7 +1279,7 @@ include struct let is_core_item = false end) - let import_ty : Types.span -> Types.ty -> Ast.Rust.ty = c_ty + let import_ty : Types.span -> Types.node_for__ty_kind -> Ast.Rust.ty = c_ty let import_trait_ref : Types.span -> Types.trait_ref -> Ast.Rust.trait_goal = c_trait_ref diff --git a/engine/lib/import_thir.mli b/engine/lib/import_thir.mli index 70bff0423..42a5f2184 100644 --- a/engine/lib/import_thir.mli +++ b/engine/lib/import_thir.mli @@ -1,4 +1,4 @@ -val import_ty : Types.span -> Types.ty -> Ast.Rust.ty +val import_ty : Types.span -> Types.node_for__ty_kind -> Ast.Rust.ty val import_trait_ref : Types.span -> Types.trait_ref -> Ast.Rust.trait_goal val import_clause : diff --git a/engine/names/extract/Cargo.toml b/engine/names/extract/Cargo.toml index c6f9dacb6..22604c874 100644 --- a/engine/names/extract/Cargo.toml +++ b/engine/names/extract/Cargo.toml @@ -16,7 +16,6 @@ serde_json.workspace = true hax-engine-names.workspace = true hax-adt-into.workspace = true tempfile.version = "3.9" -bincode.workspace = true [features] default = ["extract_names_mode"] diff --git a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js index 0f9082802..cb0c0fa67 100644 --- a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js +++ b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js @@ -537,9 +537,12 @@ function run(str){ let impl = `include struct [@@@warning "-A"]`; - let items = Object.entries(definitions).map( - ([name, def]) => export_definition(name, def) - ).filter(x => x instanceof Object); + let items = Object.entries(definitions) + .map(([name, def]) => + [name == 'Node_for_TyKind' ? 'node_for_ty_kind_generated' : name, def]) + .map( + ([name, def]) => export_definition(name, def) + ).filter(x => x instanceof Object); let derive_items = ['show', 'eq']; @@ -568,14 +571,48 @@ open ParseError ).join('\nand ') + derive_clause ); + impl += ` +and node_for__ty_kind = node_for_ty_kind_generated + +let cache_map: (int64, ${"[ `TyKind of ty_kind | `JSON of Yojson.Safe.t ]"}) Base.Hashtbl.t = Base.Hashtbl.create (module Base.Int64) + +`; impl += (''); impl += ('let rec ' + items.map(({name, type, parse}) => `parse_${name} (o: Yojson.Safe.t): ${name} = ${parse}` ).join('\nand ')); + impl += ` +and parse_node_for__ty_kind (o: Yojson.Safe.t): node_for__ty_kind = match o with + | \`Assoc alist -> begin + let id = match List.assoc "cache_id" alist with + | \`Int id -> Base.Int.to_int64 id + | \`Intlit lit -> (try Base.Int64.of_string lit with | _ -> failwith ("Base.Int64.of_string failed for " ^ lit)) + | bad_json -> failwith ("parse_node_for__ty_kind: id was expected to be an int, got: " ^ Yojson.Safe.pretty_to_string bad_json ^ "\n\n\nfull json: " ^ Yojson.Safe.pretty_to_string o) + in + match List.assoc_opt "value" alist with + | Some json when (match json with \`Null -> false | _ -> true) -> + let value = parse_ty_kind json in + {value; id} + | _ -> + let value = match Base.Hashtbl.find cache_map id with + | None -> failwith ("parse_node_for__ty_kind: failed to lookup id " ^ Base.Int64.to_string id) + | Some (\`TyKind v) -> v + | Some (\`JSON json) -> + let v = parse_ty_kind json in + Base.Hashtbl.set cache_map ~key:id ~data:(\`TyKind v); + v + in {value; id} + end + | _ -> failwith "parse_node_for__ty_kind: expected Assoc" +`; impl += (''); impl += ('let rec ' + items.map(({name, type, parse, to_json}) => `to_json_${name} (o: ${name}): Yojson.Safe.t = ${to_json}` ).join('\nand ')); + impl += ` +and to_json_node_for__ty_kind {value; id} = to_json_node_for_ty_kind_generated {value; id} +`; + return impl + ' \n end'; } diff --git a/frontend/exporter/Cargo.toml b/frontend/exporter/Cargo.toml index a9ed2b247..35ed4c09a 100644 --- a/frontend/exporter/Cargo.toml +++ b/frontend/exporter/Cargo.toml @@ -23,7 +23,6 @@ tracing.workspace = true paste = "1.0.11" extension-traits = "1.0.1" lazy_static = "1.4.0" -bincode.workspace = true [features] default = ["rustc"] diff --git a/frontend/exporter/adt-into/src/lib.rs b/frontend/exporter/adt-into/src/lib.rs index 2d0a115f5..573855e78 100644 --- a/frontend/exporter/adt-into/src/lib.rs +++ b/frontend/exporter/adt-into/src/lib.rs @@ -443,10 +443,7 @@ fn drop_generics(type_path: syn::TypePath) -> syn::TypePath { /// and we don't want a whole crate only for that helper. /// /// This proc macro defines some groups of derive clauses that -/// we reuse all the time. This is particularly interesting for -/// serializers and deserializers: today we use `bincode` and -/// `serde`, but maybe we will want to move to something else -/// in the future. +/// we reuse all the time. #[proc_macro_attribute] pub fn derive_group( attr: proc_macro::TokenStream, @@ -460,7 +457,6 @@ pub fn derive_group( .map(|group| match group { "Serializers" => quote! { #[derive(::serde::Serialize, ::serde::Deserialize)] - #[derive(::bincode::Encode, ::bincode::Decode)] }, _ => { errors.push(quote! { diff --git a/frontend/exporter/options/Cargo.toml b/frontend/exporter/options/Cargo.toml index a8f04c553..c8c5a8b1e 100644 --- a/frontend/exporter/options/Cargo.toml +++ b/frontend/exporter/options/Cargo.toml @@ -14,4 +14,3 @@ serde.workspace = true serde_json.workspace = true schemars.workspace = true hax-adt-into.workspace = true -bincode.workspace = true diff --git a/frontend/exporter/src/body.rs b/frontend/exporter/src/body.rs index 77c27e0c1..c9774ccaf 100644 --- a/frontend/exporter/src/body.rs +++ b/frontend/exporter/src/body.rs @@ -22,7 +22,7 @@ mod module { rustc_middle::thir::ExprId, ) { let tcx = s.base().tcx; - s.with_item_cache(did.to_def_id(), |caches| { + s.with_item_cache(did.to_def_id(), |caches, _| { let msg = || fatal!(s[tcx.def_span(did)], "THIR not found for {:?}", did); caches.thir.as_ref().unwrap_or_else(msg).clone() }) diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs new file mode 100644 index 000000000..1279ceb42 --- /dev/null +++ b/frontend/exporter/src/id_table.rs @@ -0,0 +1,363 @@ +/// This module provides a notion of table, identifiers and nodes. A +/// `Node` is a `Arc` bundled with a unique identifier such that +/// there exists an entry in a table for that identifier. +/// +/// The type `WithTable` bundles a table with a value of type +/// `T`. That value of type `T` may hold an arbitrary number of +/// `Node<_>`s. In the context of a `WithTable`, the type `Node<_>` +/// serializes and deserializes using a table as a state. In this +/// case, serializing a `Node` produces only an identifier, without +/// any data of type `U`. Deserializing a `Node` under a +/// `WithTable` will recover `U` data from the table held by +/// `WithTable`. +/// +/// Serde is not designed for stateful (de)serialization. There is no +/// way of deriving `serde::de::DeserializeSeed` systematically. This +/// module thus makes use of global state to achieve serialization and +/// deserialization. This modules provides an API that hides this +/// global state. +use crate::prelude::*; +use std::sync::{atomic::Ordering, Arc, LazyLock, Mutex}; + +/// Unique IDs in a ID table. +#[derive_group(Serializers)] +#[derive(Default, Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[serde(transparent)] +pub struct Id { + id: u32, +} + +/// A session providing fresh IDs for ID table. +#[derive(Default, Debug)] +pub struct Session { + next_id: Id, + table: Table, +} + +impl Session { + pub fn table(&self) -> &Table { + &self.table + } +} + +/// The different types of values one can store in an ID table. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum Value { + Ty(Arc), +} + +/// A node is a bundle of an ID with a value. +#[derive(Deserialize, Serialize, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[serde(into = "serde_repr::NodeRepr")] +#[serde(try_from = "serde_repr::NodeRepr")] +pub struct Node { + id: Id, + value: Arc, +} + +/// Manual implementation of `Clone` that doesn't require a `Clone` +/// bound on `T`. +impl Clone for Node { + fn clone(&self) -> Self { + Self { + id: self.id.clone(), + value: self.value.clone(), + } + } +} + +/// A table is a map from IDs to `Value`s. When serialized, we +/// represent a table as a *sorted* vector. Indeed, the values stored +/// in the table might reference each other, without cycle, so the +/// order matters. +#[derive(Default, Debug, Clone, Deserialize, Serialize)] +#[serde(into = "serde_repr::SortedIdValuePairs")] +#[serde(from = "serde_repr::SortedIdValuePairs")] +pub struct Table(HashMap); + +impl Table { + pub(super) fn insert(&mut self, cache_id: Id, value: Arc) + where + T: SupportedType, + { + self.0.insert(cache_id, T::to_types(value)); + } + pub(super) fn get(&self, cache_id: &Id) -> Option>> + where + T: SupportedType, + { + self.0.get(cache_id).map(T::from_types) + } +} +impl SupportedType for TyKind { + fn to_types(value: Arc) -> Value { + Value::Ty(value) + } + fn from_types(t: &Value) -> Option> { + match t { + Value::Ty(value) => Some(value.clone()), + } + } +} + +/// A value encodable in the enum `Value` +pub trait SupportedType: std::fmt::Debug { + fn to_types(value: Arc) -> Value; + fn from_types(t: &Value) -> Option>; +} + +impl Session { + fn fresh_id(&mut self) -> Id { + let id = self.next_id.id; + self.next_id.id += 1; + Id { id } + } +} + +impl Node { + pub fn new(value: T, session: &mut Session) -> Self { + let id = session.fresh_id(); + let kind = Arc::new(value); + session.table.insert(id.clone(), kind.clone()); + Self { id, value: kind } + } + pub fn inner(&self) -> Arc { + self.value.clone() + } + + pub fn kind(&self) -> &T { + self.value.as_ref() + } +} + +/// Wrapper for a type `T` that creates a bundle containing both a ID +/// table and a value `T`. That value may contains `Node` values +/// inside it. Serializing `WithTable` will serialize IDs only, +/// skipping values. Deserialization of a `WithTable` will +/// automatically use the table and IDs to reconstruct skipped values. +#[derive(Serialize, Debug)] +pub struct WithTable { + table: Table, + value: T, +} + +/// The state used for deserialization: a table. +static DESERIALIZATION_STATE: LazyLock> = + LazyLock::new(|| Mutex::new(Table::default())); +static DESERIALIZATION_STATE_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); + +/// The mode of serialization: should `Node` ship values of type `T` or not? +static SERIALIZATION_MODE_USE_IDS: std::sync::atomic::AtomicBool = + std::sync::atomic::AtomicBool::new(false); + +fn serialize_use_id() -> bool { + SERIALIZATION_MODE_USE_IDS.load(Ordering::Relaxed) +} + +impl WithTable { + /// Runs `f` with a `WithTable` created out of `map` and + /// `value`. Any serialization of values of type `Node<_>` will + /// skip the field `value`. + pub fn run(map: Table, value: T, f: impl FnOnce(&Self) -> R) -> R { + if serialize_use_id() { + panic!("CACHE_MAP_LOCK: only one WithTable serialization can occur at a time (nesting is forbidden)") + } + SERIALIZATION_MODE_USE_IDS.store(true, Ordering::Relaxed); + let result = f(&Self { table: map, value }); + SERIALIZATION_MODE_USE_IDS.store(false, Ordering::Relaxed); + result + } + pub fn destruct(self) -> (T, Table) { + let Self { value, table: map } = self; + (value, map) + } +} + +/// Helper function that makes sure no nested deserializations occur. +fn full_id_deserialization(f: impl FnOnce() -> T) -> T { + let _lock = *DESERIALIZATION_STATE_LOCK.lock().expect("CACHE_MAP_LOCK: only one WithTable deserialization can occur at a time (nesting is forbidden)"); + let result = f(); + result +} + +/// The deserializer of `WithTable` is special. First, we need to continuously +impl<'de, T: Deserialize<'de>> serde::Deserialize<'de> for WithTable { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::{self, Deserialize, MapAccess, SeqAccess, Visitor}; + use std::fmt; + use std::marker::PhantomData; + #[derive(Deserialize, Debug)] + #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Table, + Value, + } + + struct WithTableVisitor(PhantomData); + + impl<'de, T: Deserialize<'de>> Visitor<'de> for WithTableVisitor { + type Value = WithTable; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct WithTable") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let (table, value) = + full_id_deserialization::>(|| { + let previous = std::mem::take(&mut *DESERIALIZATION_STATE.lock().unwrap()); + // Deserializing `Node`s populates `DESERIALIZATION_STATE`: the table + // is already constructed in `DESERIALIZATION_STATE`, we discard it below. + let _: Table = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let value = seq.next_element::().and_then(|inner| { + inner.ok_or_else(|| de::Error::invalid_length(1, &self)) + }); + let table = std::mem::replace( + &mut *DESERIALIZATION_STATE.lock().unwrap(), + previous, + ); + let value = value?; + Ok((table, value)) + })?; + Ok(Self::Value { table, value }) + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let (table, value) = full_id_deserialization::>( + || { + let (table_key, table): (Field, Table) = map + .next_entry()? + .ok_or(de::Error::custom("Expected field `table` *first*"))?; + if !matches!(table_key, Field::Table) { + Err(de::Error::custom("Expected field `table` *first*"))? + } + let previous = + std::mem::replace(&mut *DESERIALIZATION_STATE.lock().unwrap(), table); + + let value_result = map.next_entry::().and_then(|inner| { + inner.ok_or_else(|| { + de::Error::custom("Expected field `value`, got something else? Seems like the type is wrong.") + }) + }); + let table = std::mem::replace( + &mut *DESERIALIZATION_STATE.lock().unwrap(), + previous, + ); + let (value_key, value) = value_result?; + if !matches!(value_key, Field::Value) { + Err(de::Error::custom(&format!( + "Expected field `value`, found {:#?}", + value_key + )))? + } + if let Some(field) = map.next_key()? { + Err(de::Error::unknown_field(field, &["nothing left"]))? + } + Ok((table, value)) + }, + )?; + Ok(Self::Value { table, value }) + } + } + + const FIELDS: &[&str] = &["table", "value"]; + let r = deserializer.deserialize_struct("WithTable", FIELDS, WithTableVisitor(PhantomData)); + r + } +} + +/// Defines representations for various types when serializing or/and +/// deserializing via serde +mod serde_repr { + use super::*; + + #[derive(Serialize, Deserialize, JsonSchema, Debug)] + pub(super) struct NodeRepr { + cache_id: Id, + value: Option>, + } + + #[derive(Serialize)] + pub(super) struct Pair(Id, Value); + pub(super) type SortedIdValuePairs = Vec; + + impl Into> for Node { + fn into(self) -> NodeRepr { + let value = if serialize_use_id() { + None + } else { + Some(self.value.clone()) + }; + let cache_id = self.id; + NodeRepr { value, cache_id } + } + } + + impl TryFrom> for Node { + type Error = serde::de::value::Error; + + fn try_from(cached: NodeRepr) -> Result { + use serde::de::Error; + let map = DESERIALIZATION_STATE.lock().unwrap(); + let id = cached.cache_id; + let kind = if let Some(kind) = cached.value { + kind + } else { + map.get(&id) + .ok_or_else(|| { + Self::Error::custom(&format!( + "Stateful deserialization failed for id {:?}: not found in cache", + id + )) + })? + .ok_or_else(|| { + Self::Error::custom(&format!( + "Stateful deserialization failed for id {:?}: wrong type", + id + )) + })? + }; + Ok(Self { value: kind, id }) + } + } + + impl<'de> serde::Deserialize<'de> for Pair { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let (id, v) = <(Id, Value)>::deserialize(deserializer)?; + DESERIALIZATION_STATE + .lock() + .unwrap() + .0 + .insert(id.clone(), v.clone()); + Ok(Pair(id, v)) + } + } + + impl Into for Table { + fn into(self) -> SortedIdValuePairs { + let mut vec: Vec<_> = self.0.into_iter().map(|(x, y)| Pair(x, y)).collect(); + vec.sort_by_key(|o| o.0.clone()); + vec + } + } + + impl From for Table { + fn from(t: SortedIdValuePairs) -> Self { + Self(HashMap::from_iter(t.into_iter().map(|Pair(x, y)| (x, y)))) + } + } +} diff --git a/frontend/exporter/src/lib.rs b/frontend/exporter/src/lib.rs index 35aefe101..90a68a4f5 100644 --- a/frontend/exporter/src/lib.rs +++ b/frontend/exporter/src/lib.rs @@ -49,6 +49,7 @@ cfg_feature_rustc! { mod body; mod constant_utils; +pub mod id_table; mod types; mod index_vec; diff --git a/frontend/exporter/src/prelude.rs b/frontend/exporter/src/prelude.rs index c7fd69104..f9be0d4e3 100644 --- a/frontend/exporter/src/prelude.rs +++ b/frontend/exporter/src/prelude.rs @@ -7,6 +7,7 @@ pub use std::rc::Rc; pub use crate::body::*; pub use crate::constant_utils::*; +pub use crate::id_table; pub use crate::index_vec::*; pub use crate::traits::*; pub use crate::types::*; diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index cb3aa5254..b150f27f1 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -126,6 +126,8 @@ mod types { pub spans: HashMap, /// Per-item cache. pub per_item: HashMap>, + /// A ID table session, providing fresh IDs. + pub id_table_session: id_table::Session, } /// Per-item cache @@ -319,8 +321,17 @@ pub trait WithGlobalCacheExt<'tcx>: BaseState<'tcx> { } /// Access the cache for a given item. You must not call `sinto` within this function as this /// will likely result in `BorrowMut` panics. - fn with_item_cache(&self, def_id: RDefId, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { - self.with_global_cache(|cache| f(cache.per_item.entry(def_id).or_default())) + fn with_item_cache( + &self, + def_id: RDefId, + f: impl FnOnce(&mut ItemCache<'tcx>, &mut id_table::Session) -> T, + ) -> T { + self.with_global_cache(|cache| { + f( + cache.per_item.entry(def_id).or_default(), + &mut cache.id_table_session, + ) + }) } } impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {} @@ -328,7 +339,10 @@ impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {} pub trait WithItemCacheExt<'tcx>: UnderOwnerState<'tcx> { /// Access the cache for the current item. You must not call `sinto` within this function as /// this will likely result in `BorrowMut` panics. - fn with_cache(&self, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { + fn with_cache( + &self, + f: impl FnOnce(&mut ItemCache<'tcx>, &mut id_table::Session) -> T, + ) -> T { self.with_item_cache(self.owner_id(), f) } } diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 0799cad29..28d68083e 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -152,10 +152,10 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) { + if let Some(impl_expr) = s.with_cache(|cache, _| cache.impl_exprs.get(&trait_ref).cloned()) { return impl_expr; } - let resolved = s.with_cache(|cache| { + let resolved = s.with_cache(|cache, _| { cache .predicate_searcher .get_or_insert_with(|| PredicateSearcher::new_for_owner(s.base().tcx, s.owner_id())) @@ -165,7 +165,7 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), }; - s.with_cache(|cache| cache.impl_exprs.insert(trait_ref, impl_expr.clone())); + s.with_cache(|cache, _| cache.impl_exprs.insert(trait_ref, impl_expr.clone())); impl_expr } diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index aba6f4fbf..12a221483 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use std::sync::Arc; #[cfg(feature = "rustc")] use rustc_middle::ty; @@ -38,11 +37,11 @@ pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) #[cfg(feature = "rustc")] impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { fn sinto(&self, s: &S) -> DefId { - if let Some(def_id) = s.with_item_cache(*self, |cache| cache.def_id.clone()) { + if let Some(def_id) = s.with_item_cache(*self, |cache, _| cache.def_id.clone()) { return def_id; } let def_id = translate_def_id(s, *self); - s.with_item_cache(*self, |cache| cache.def_id = Some(def_id.clone())); + s.with_item_cache(*self, |cache, _| cache.def_id = Some(def_id.clone())); def_id } } @@ -910,49 +909,6 @@ pub struct Span { // expn_backtrace: Vec, } -/// We need to define manual `impl`s of `Span`: we want to skip the -/// field `rust_span_data`. The derive macros from `bincode` don't -/// allow that, see https://github.com/bincode-org/bincode/issues/452. -const _: () = { - impl bincode::Encode for Span { - fn encode( - &self, - encoder: &mut E, - ) -> core::result::Result<(), bincode::error::EncodeError> { - bincode::Encode::encode(&self.lo, encoder)?; - bincode::Encode::encode(&self.hi, encoder)?; - bincode::Encode::encode(&self.filename, encoder)?; - Ok(()) - } - } - - impl bincode::Decode for Span { - fn decode( - decoder: &mut D, - ) -> core::result::Result { - Ok(Self { - lo: bincode::Decode::decode(decoder)?, - hi: bincode::Decode::decode(decoder)?, - filename: bincode::Decode::decode(decoder)?, - rust_span_data: None, - }) - } - } - - impl<'de> bincode::BorrowDecode<'de> for Span { - fn borrow_decode>( - decoder: &mut D, - ) -> core::result::Result { - Ok(Self { - lo: bincode::BorrowDecode::borrow_decode(decoder)?, - hi: bincode::BorrowDecode::borrow_decode(decoder)?, - filename: bincode::BorrowDecode::borrow_decode(decoder)?, - rust_span_data: None, - }) - } - } -}; - const _: () = { // `rust_span_data` is a metadata that should *not* be taken into // account while hashing or comparing @@ -1832,29 +1788,20 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty< } /// Reflects [`rustc_middle::ty::Ty`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Ty { - pub kind: Arc, -} - -impl Ty { - pub fn kind(&self) -> &TyKind { - self.kind.as_ref() - } -} +pub type Ty = id_table::Node; #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { - if let Some(ty) = s.with_cache(|cache| cache.tys.get(self).cloned()) { + if let Some(ty) = s.with_cache(|cache, _| cache.tys.get(self).cloned()) { return ty; } - let ty = Ty { - kind: Arc::new(self.kind().sinto(s)), - }; - s.with_cache(|cache| cache.tys.insert(*self, ty.clone())); - ty + let ty_kind: TyKind = self.kind().sinto(s); + s.with_cache(|cache, seed| { + let ty = id_table::Node::new(ty_kind, seed); + cache.tys.insert(*self, ty.clone()); + ty + }) } } diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index b060de84a..4c9042215 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -33,7 +33,7 @@ pub struct FullDef { #[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { fn sinto(&self, s: &S) -> Arc { - if let Some(full_def) = s.with_item_cache(*self, |cache| cache.full_def.clone()) { + if let Some(full_def) = s.with_item_cache(*self, |cache, _| cache.full_def.clone()) { return full_def; } let tcx = s.base().tcx; @@ -65,7 +65,7 @@ impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { kind, }; let full_def: Arc = Arc::new(full_def); - s.with_item_cache(*self, |cache| cache.full_def = Some(full_def.clone())); + s.with_item_cache(*self, |cache, _| cache.full_def = Some(full_def.clone())); full_def } } diff --git a/hax-types/Cargo.toml b/hax-types/Cargo.toml index 37f39615e..52d2c981e 100644 --- a/hax-types/Cargo.toml +++ b/hax-types/Cargo.toml @@ -21,7 +21,8 @@ colored.workspace = true serde_json.workspace = true annotate-snippets.workspace = true hax-adt-into.workspace = true -bincode.workspace = true +tracing.workspace = true +serde-brief ={ version = "*", features = ["std", "alloc"]} zstd = "0.13.1" [features] diff --git a/hax-types/src/cli_options/extension.rs b/hax-types/src/cli_options/extension.rs index efed466c6..fa1084dc5 100644 --- a/hax-types/src/cli_options/extension.rs +++ b/hax-types/src/cli_options/extension.rs @@ -14,14 +14,11 @@ macro_rules! trait_alias { trait_alias!( ExtensionPoint = - bincode::Decode - + bincode::Encode - + std::fmt::Debug + std::fmt::Debug + for<'a> serde::Deserialize<'a> + serde::Serialize + JsonSchema + Clone - + for<'a> bincode::BorrowDecode<'a> ); trait_alias!(SubcommandExtensionPoint = ExtensionPoint + clap::Subcommand); diff --git a/hax-types/src/cli_options/mod.rs b/hax-types/src/cli_options/mod.rs index 75b771966..4f275606a 100644 --- a/hax-types/src/cli_options/mod.rs +++ b/hax-types/src/cli_options/mod.rs @@ -378,6 +378,13 @@ pub enum Command { )] kind: Vec, + /// By default, `cargo hax json` outputs a JSON where every + /// piece of information is inlined. This however creates very + /// large JSON files. This flag enables the use of unique IDs + /// and outputs a map from IDs to actual objects. + #[arg(long)] + use_ids: bool, + /// Whether to include extra informations about `DefId`s. #[arg(short = 'E', long = "include-extra", default_value = "false")] include_extra: bool, diff --git a/hax-types/src/driver_api.rs b/hax-types/src/driver_api.rs index cf64d1158..51eb86bbc 100644 --- a/hax-types/src/driver_api.rs +++ b/hax-types/src/driver_api.rs @@ -30,19 +30,26 @@ pub struct HaxMeta { pub comments: Vec<(hax_frontend_exporter::Span, String)>, } +use hax_frontend_exporter::id_table; + impl HaxMeta where - Body: bincode::Encode + bincode::Decode, + Body: serde::Serialize + for<'de> serde::Deserialize<'de>, { - pub fn write(self, write: &mut impl std::io::Write) { + #[tracing::instrument(level = "trace", skip(self, write, id_table))] + pub fn write(self, write: &mut impl std::io::Write, id_table: id_table::Table) { let mut write = zstd::stream::write::Encoder::new(write, 0).unwrap(); - bincode::encode_into_std_write(self, &mut write, bincode::config::standard()).unwrap(); - write.finish().unwrap(); + + id_table::WithTable::run(id_table, self, |with_table| { + serde_brief::to_writer(with_table, &mut write).unwrap(); + write.finish().unwrap(); + }) } - pub fn read(reader: impl std::io::Read) -> Self { + #[tracing::instrument(level = "trace", skip(reader))] + pub fn read(reader: impl std::io::Read) -> (Self, id_table::Table) { let reader = zstd::stream::read::Decoder::new(reader).unwrap(); let reader = std::io::BufReader::new(reader); - bincode::decode_from_reader(reader, bincode::config::standard()).unwrap() + id_table::WithTable::destruct(serde_brief::from_reader(reader).unwrap()) } } From a357a0e01526705a70524254677f121a4fc9842d Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Wed, 23 Oct 2024 14:02:02 +0200 Subject: [PATCH 108/253] Implement handling of `opaque_type` in PV --- engine/backends/proverif/proverif_backend.ml | 35 ++++++++++++-------- examples/proverif-psk/src/lib.rs | 20 +++++------ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 0c00477d5..5b6608aef 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -603,23 +603,30 @@ module Make (Options : OPTS) : MAKE = struct (string "let x = construct_fail() in " ^^ print#default_value type_name_doc) in - - if is_struct then - let struct_constructor = List.hd variants in - match struct_constructor with - | None -> empty - | Some constructor -> - type_line ^^ hardline ^^ to_bitstring_converter_line - ^^ hardline ^^ from_bitstring_converter_line ^^ hardline - ^^ default_line ^^ hardline ^^ err_line ^^ hardline - ^^ fun_and_reduc name constructor - else + let default_lines = type_line ^^ hardline ^^ to_bitstring_converter_line ^^ hardline ^^ from_bitstring_converter_line ^^ hardline ^^ default_line ^^ hardline ^^ err_line ^^ hardline - ^^ separate_map hardline - (fun variant -> fun_and_reduc name variant) - variants + in + let destructor_lines = + if is_struct then + let struct_constructor = List.hd variants in + match struct_constructor with + | None -> empty + | Some constructor -> fun_and_reduc name constructor + else + separate_map hardline + (fun variant -> fun_and_reduc name variant) + variants + in + if + Attrs.find_unique_attr item.attrs + ~f: + ([%eq: Types.ha_payload] OpaqueType + >> Fn.flip Option.some_if ()) + |> Option.is_some + then default_lines + else default_lines ^^ destructor_lines | Quote { quote; _ } -> print#quote quote | _ -> empty diff --git a/examples/proverif-psk/src/lib.rs b/examples/proverif-psk/src/lib.rs index 643077181..13be5bdc0 100644 --- a/examples/proverif-psk/src/lib.rs +++ b/examples/proverif-psk/src/lib.rs @@ -1,15 +1,10 @@ use hax_lib as hax; use libcrux::aead::{self, Algorithm}; -#[hax::proverif::replace("type $:{Message}. -const $:{Message}_default_value: $:{Message}. -letfun $:{Message}_default() = - $:{Message}_default_value. -letfun $:{Message}_err() = - let x = construct_fail() in $:{Message}_default_value.")] +#[hax::opaque_type] pub struct Message(aead::Tag, Vec); -#[hax::proverif::replace("type $:{KeyIv}.")] +#[hax::opaque_type] pub struct KeyIv(libcrux::aead::Key, libcrux::aead::Iv); const AEAD_KEY_NONCE: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305) @@ -44,7 +39,7 @@ impl From for Error { } } -#[hax::pv_constructor] // or cleaner with `proverif::replace()`? +#[hax::pv_constructor] fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { let key_iv_bytes = libcrux::hkdf::expand(libcrux::hkdf::Algorithm::Sha256, ikm, info, AEAD_KEY_NONCE)?; @@ -68,8 +63,9 @@ fn serialize_key_iv(key_iv: &KeyIv) -> Vec { result } - -#[hax::proverif::replace("reduc forall k: ${KeyIv}; ${deserialize_key_iv}(${serialize_key_iv}(k)) = k.")] +#[hax::proverif::replace( + "reduc forall k: $:{KeyIv}; ${deserialize_key_iv}(${serialize_key_iv}(k)) = k." +)] fn deserialize_key_iv(bytes: &[u8]) -> Result { let iv = aead::Iv::new(&bytes[..12])?; let key = aead::Key::from_slice(Algorithm::Chacha20Poly1305, &bytes[12..])?; @@ -83,7 +79,9 @@ pub fn encrypt(key_iv: &KeyIv, message: &[u8]) -> Result { Ok(Message(tag, ctxt)) } -#[hax::proverif::replace("reduc forall m: bitstring, k: $:{KeyIv}; ${decrypt}(k, ${encrypt}(k, m)) = m.")] +#[hax::proverif::replace( + "reduc forall m: bitstring, k: $:{KeyIv}; ${decrypt}(k, ${encrypt}(k, m)) = m." +)] fn decrypt(key_iv: &KeyIv, message: Message) -> Result, Error> { libcrux::aead::decrypt_detached( &key_iv.0, From 6cf361ed3967cca8e1f036344c981a2751ff7769 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Wed, 23 Oct 2024 14:14:57 +0200 Subject: [PATCH 109/253] Reorganize and simplify PV example --- examples/proverif-psk/src/lib.rs | 40 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/examples/proverif-psk/src/lib.rs b/examples/proverif-psk/src/lib.rs index 13be5bdc0..7ce191a69 100644 --- a/examples/proverif-psk/src/lib.rs +++ b/examples/proverif-psk/src/lib.rs @@ -1,12 +1,6 @@ use hax_lib as hax; use libcrux::aead::{self, Algorithm}; -#[hax::opaque_type] -pub struct Message(aead::Tag, Vec); - -#[hax::opaque_type] -pub struct KeyIv(libcrux::aead::Key, libcrux::aead::Iv); - const AEAD_KEY_NONCE: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305) + Algorithm::nonce_size(Algorithm::Chacha20Poly1305); @@ -15,6 +9,7 @@ const AEAD_KEY_LENGTH: usize = Algorithm::key_size(Algorithm::Chacha20Poly1305); const EMPTY_AAD: &[u8; 0] = b""; const RESPONSE_KEY_CONTEXT: &[u8; 12] = b"response-key"; +/* Type definitions */ #[derive(Debug)] pub enum Error { CryptoError, @@ -39,20 +34,14 @@ impl From for Error { } } -#[hax::pv_constructor] -fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { - let key_iv_bytes = - libcrux::hkdf::expand(libcrux::hkdf::Algorithm::Sha256, ikm, info, AEAD_KEY_NONCE)?; - - let (key_bytes, iv_bytes) = key_iv_bytes.split_at(AEAD_KEY_LENGTH); - let key = - libcrux::aead::Key::from_slice(libcrux::aead::Algorithm::Chacha20Poly1305, key_bytes)?; +#[hax::opaque_type] +pub struct Message(aead::Tag, Vec); - let iv = libcrux::aead::Iv(iv_bytes.try_into()?); - Ok(KeyIv(key, iv)) -} +#[hax::opaque_type] +pub struct KeyIv(libcrux::aead::Key, libcrux::aead::Iv); -#[hax::proverif::replace("fun ${serialize_key_iv} ($:{KeyIv}): bitstring.")] +/* Wire formats */ +#[hax::pv_constructor] fn serialize_key_iv(key_iv: &KeyIv) -> Vec { let mut result = Vec::new(); result.extend_from_slice(key_iv.1 .0.as_ref()); @@ -72,6 +61,20 @@ fn deserialize_key_iv(bytes: &[u8]) -> Result { Ok(KeyIv(key, iv)) } +/* Cryptographic functions */ +#[hax::pv_constructor] +fn derive_key_iv(ikm: &[u8], info: &[u8]) -> Result { + let key_iv_bytes = + libcrux::hkdf::expand(libcrux::hkdf::Algorithm::Sha256, ikm, info, AEAD_KEY_NONCE)?; + + let (key_bytes, iv_bytes) = key_iv_bytes.split_at(AEAD_KEY_LENGTH); + let key = + libcrux::aead::Key::from_slice(libcrux::aead::Algorithm::Chacha20Poly1305, key_bytes)?; + + let iv = libcrux::aead::Iv(iv_bytes.try_into()?); + Ok(KeyIv(key, iv)) +} + #[hax::proverif::replace("fun ${encrypt} ($:{KeyIv}, bitstring): $:{Message}.")] pub fn encrypt(key_iv: &KeyIv, message: &[u8]) -> Result { let (tag, ctxt) = @@ -93,6 +96,7 @@ fn decrypt(key_iv: &KeyIv, message: Message) -> Result, Error> { .map_err(|_| Error::CryptoError) } +/* Protocol */ pub fn initiate(ikm: &[u8], psk: &KeyIv) -> Result<(Message, KeyIv), Error> { let response_key_iv = derive_key_iv(ikm, RESPONSE_KEY_CONTEXT)?; From ffec8f4c3712341f1bf3e276d7bf10279ec88367 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 14:28:33 +0200 Subject: [PATCH 110/253] fix(id_table): do not hash `id` in `Node<_>`s --- frontend/exporter/src/id_table.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index 1279ceb42..e7caf3ab0 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -17,7 +17,10 @@ /// deserialization. This modules provides an API that hides this /// global state. use crate::prelude::*; -use std::sync::{atomic::Ordering, Arc, LazyLock, Mutex}; +use std::{ + hash::{Hash, Hasher}, + sync::{atomic::Ordering, Arc, LazyLock, Mutex}, +}; /// Unique IDs in a ID table. #[derive_group(Serializers)] @@ -47,7 +50,7 @@ pub enum Value { } /// A node is a bundle of an ID with a value. -#[derive(Deserialize, Serialize, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Deserialize, Serialize, Debug, JsonSchema, PartialEq, Eq, PartialOrd, Ord)] #[serde(into = "serde_repr::NodeRepr")] #[serde(try_from = "serde_repr::NodeRepr")] pub struct Node { @@ -55,6 +58,15 @@ pub struct Node { value: Arc, } +/// Hax relies on hashes being deterministic for predicates +/// ids. Identifiers are not deterministic: we implement hash for +/// `Node` manually, discarding the field `id`. +impl Hash for Node { + fn hash(&self, state: &mut H) { + self.value.as_ref().hash(state); + } +} + /// Manual implementation of `Clone` that doesn't require a `Clone` /// bound on `T`. impl Clone for Node { From 2c5aaa2f99115ff1acde4de3ce88cd05c27e77c0 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 14:50:54 +0200 Subject: [PATCH 111/253] fix(exporter/id_table): revert `with_[item_]cache` API: no `table::Session` --- cli/driver/src/exporter.rs | 2 +- frontend/exporter/src/body.rs | 2 +- frontend/exporter/src/state.rs | 18 +++--------------- frontend/exporter/src/traits.rs | 6 +++--- frontend/exporter/src/types/copied.rs | 12 +++++++----- frontend/exporter/src/types/new/full_def.rs | 4 ++-- 6 files changed, 17 insertions(+), 27 deletions(-) diff --git a/cli/driver/src/exporter.rs b/cli/driver/src/exporter.rs index da6cec19f..96adfabb2 100644 --- a/cli/driver/src/exporter.rs +++ b/cli/driver/src/exporter.rs @@ -140,7 +140,7 @@ fn convert_thir<'tcx, Body: hax_frontend_exporter::IsBody>( let mut state = hax_frontend_exporter::state::State::new(tcx, options.clone()); state.base.macro_infos = Rc::new(macro_calls); for (def_id, thir) in precompute_local_thir_bodies(tcx) { - state.with_item_cache(def_id, |caches, _| caches.thir = Some(thir)); + state.with_item_cache(def_id, |caches| caches.thir = Some(thir)); } let result = hax_frontend_exporter::inline_macro_invocations(tcx.hir().items(), &state); diff --git a/frontend/exporter/src/body.rs b/frontend/exporter/src/body.rs index c9774ccaf..77c27e0c1 100644 --- a/frontend/exporter/src/body.rs +++ b/frontend/exporter/src/body.rs @@ -22,7 +22,7 @@ mod module { rustc_middle::thir::ExprId, ) { let tcx = s.base().tcx; - s.with_item_cache(did.to_def_id(), |caches, _| { + s.with_item_cache(did.to_def_id(), |caches| { let msg = || fatal!(s[tcx.def_span(did)], "THIR not found for {:?}", did); caches.thir.as_ref().unwrap_or_else(msg).clone() }) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index b150f27f1..09a56ef05 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -321,17 +321,8 @@ pub trait WithGlobalCacheExt<'tcx>: BaseState<'tcx> { } /// Access the cache for a given item. You must not call `sinto` within this function as this /// will likely result in `BorrowMut` panics. - fn with_item_cache( - &self, - def_id: RDefId, - f: impl FnOnce(&mut ItemCache<'tcx>, &mut id_table::Session) -> T, - ) -> T { - self.with_global_cache(|cache| { - f( - cache.per_item.entry(def_id).or_default(), - &mut cache.id_table_session, - ) - }) + fn with_item_cache(&self, def_id: RDefId, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { + self.with_global_cache(|cache| f(cache.per_item.entry(def_id).or_default())) } } impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {} @@ -339,10 +330,7 @@ impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {} pub trait WithItemCacheExt<'tcx>: UnderOwnerState<'tcx> { /// Access the cache for the current item. You must not call `sinto` within this function as /// this will likely result in `BorrowMut` panics. - fn with_cache( - &self, - f: impl FnOnce(&mut ItemCache<'tcx>, &mut id_table::Session) -> T, - ) -> T { + fn with_cache(&self, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T { self.with_item_cache(self.owner_id(), f) } } diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 28d68083e..0799cad29 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -152,10 +152,10 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( crate::warning!(s, "{}", msg) } }; - if let Some(impl_expr) = s.with_cache(|cache, _| cache.impl_exprs.get(&trait_ref).cloned()) { + if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) { return impl_expr; } - let resolved = s.with_cache(|cache, _| { + let resolved = s.with_cache(|cache| { cache .predicate_searcher .get_or_insert_with(|| PredicateSearcher::new_for_owner(s.base().tcx, s.owner_id())) @@ -165,7 +165,7 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( Ok(x) => x.sinto(s), Err(e) => crate::fatal!(s, "{}", e), }; - s.with_cache(|cache, _| cache.impl_exprs.insert(trait_ref, impl_expr.clone())); + s.with_cache(|cache| cache.impl_exprs.insert(trait_ref, impl_expr.clone())); impl_expr } diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 12a221483..59d11b755 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -37,11 +37,11 @@ pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) #[cfg(feature = "rustc")] impl<'s, S: BaseState<'s>> SInto for rustc_hir::def_id::DefId { fn sinto(&self, s: &S) -> DefId { - if let Some(def_id) = s.with_item_cache(*self, |cache, _| cache.def_id.clone()) { + if let Some(def_id) = s.with_item_cache(*self, |cache| cache.def_id.clone()) { return def_id; } let def_id = translate_def_id(s, *self); - s.with_item_cache(*self, |cache, _| cache.def_id = Some(def_id.clone())); + s.with_item_cache(*self, |cache| cache.def_id = Some(def_id.clone())); def_id } } @@ -1793,12 +1793,14 @@ pub type Ty = id_table::Node; #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { fn sinto(&self, s: &S) -> Ty { - if let Some(ty) = s.with_cache(|cache, _| cache.tys.get(self).cloned()) { + if let Some(ty) = s.with_cache(|cache| cache.tys.get(self).cloned()) { return ty; } let ty_kind: TyKind = self.kind().sinto(s); - s.with_cache(|cache, seed| { - let ty = id_table::Node::new(ty_kind, seed); + s.with_global_cache(|cache| { + let table_session = &mut cache.id_table_session; + let cache = cache.per_item.entry(s.owner_id()).or_default(); + let ty = id_table::Node::new(ty_kind, table_session); cache.tys.insert(*self, ty.clone()); ty }) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 4c9042215..b060de84a 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -33,7 +33,7 @@ pub struct FullDef { #[cfg(feature = "rustc")] impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { fn sinto(&self, s: &S) -> Arc { - if let Some(full_def) = s.with_item_cache(*self, |cache, _| cache.full_def.clone()) { + if let Some(full_def) = s.with_item_cache(*self, |cache| cache.full_def.clone()) { return full_def; } let tcx = s.base().tcx; @@ -65,7 +65,7 @@ impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { kind, }; let full_def: Arc = Arc::new(full_def); - s.with_item_cache(*self, |cache, _| cache.full_def = Some(full_def.clone())); + s.with_item_cache(*self, |cache| cache.full_def = Some(full_def.clone())); full_def } } From 05cf9a9bbc6d76ae44ebc04e98fd5028c160c677 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 15:01:18 +0200 Subject: [PATCH 112/253] refactor(exporter/Ty): re-introduce a struct `Ty` --- frontend/exporter/src/id_table.rs | 8 ++------ frontend/exporter/src/types/copied.rs | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index e7caf3ab0..705e7b1a6 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -133,12 +133,8 @@ impl Node { session.table.insert(id.clone(), kind.clone()); Self { id, value: kind } } - pub fn inner(&self) -> Arc { - self.value.clone() - } - - pub fn kind(&self) -> &T { - self.value.as_ref() + pub fn inner(&self) -> &Arc { + &self.value } } diff --git a/frontend/exporter/src/types/copied.rs b/frontend/exporter/src/types/copied.rs index 59d11b755..7445824ae 100644 --- a/frontend/exporter/src/types/copied.rs +++ b/frontend/exporter/src/types/copied.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use std::sync::Arc; #[cfg(feature = "rustc")] use rustc_middle::ty; @@ -1788,7 +1789,22 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto> for rustc_middle::ty::Ty< } /// Reflects [`rustc_middle::ty::Ty`] -pub type Ty = id_table::Node; +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[serde(transparent)] +pub struct Ty { + pub(crate) kind: id_table::Node, +} + +impl Ty { + pub fn inner(&self) -> &Arc { + self.kind.inner() + } + + pub fn kind(&self) -> &TyKind { + self.inner().as_ref() + } +} #[cfg(feature = "rustc")] impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> { @@ -1800,7 +1816,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> s.with_global_cache(|cache| { let table_session = &mut cache.id_table_session; let cache = cache.per_item.entry(s.owner_id()).or_default(); - let ty = id_table::Node::new(ty_kind, table_session); + let kind = id_table::Node::new(ty_kind, table_session); + let ty = Ty { kind }; cache.tys.insert(*self, ty.clone()); ty }) From 8a326cedb56e3842a4306383460f294ddc3822dd Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 23 Oct 2024 15:10:37 +0200 Subject: [PATCH 113/253] Avoid bundling use items. --- engine/lib/dependencies.ml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index a4952b4eb..1b4337419 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -393,7 +393,14 @@ module Make (F : Features.T) = struct in let mut_rec_bundles = let mod_graph_cycles = ModGraph.of_items items |> ModGraph.cycles in - let bundles = ItemGraph.CyclicDep.of_mod_sccs items mod_graph_cycles in + let non_use_items = + List.filter + ~f:(fun item -> match item.v with Use _ -> false | _ -> true) + items + in + let bundles = + ItemGraph.CyclicDep.of_mod_sccs non_use_items mod_graph_cycles + in let f = List.filter_map ~f:from_ident in List.map ~f bundles in From f3c97464441cc187b557a3cdbd02232bfc908468 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 15:11:00 +0200 Subject: [PATCH 114/253] fix(exporter/id_table): keep the MutexGuard around, and use `try_lock` --- frontend/exporter/src/id_table.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index 705e7b1a6..161d0142f 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -19,7 +19,7 @@ use crate::prelude::*; use std::{ hash::{Hash, Hasher}, - sync::{atomic::Ordering, Arc, LazyLock, Mutex}, + sync::{atomic::Ordering, Arc, LazyLock, Mutex, MutexGuard}, }; /// Unique IDs in a ID table. @@ -183,7 +183,7 @@ impl WithTable { /// Helper function that makes sure no nested deserializations occur. fn full_id_deserialization(f: impl FnOnce() -> T) -> T { - let _lock = *DESERIALIZATION_STATE_LOCK.lock().expect("CACHE_MAP_LOCK: only one WithTable deserialization can occur at a time (nesting is forbidden)"); + let _lock: MutexGuard<_> = DESERIALIZATION_STATE_LOCK.try_lock().expect("CACHE_MAP_LOCK: only one WithTable deserialization can occur at a time (nesting is forbidden)"); let result = f(); result } From 330dd94fc87feaacf066c2c578c934863d2c8b1f Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 15:17:18 +0200 Subject: [PATCH 115/253] doc(exporter/id_table): fix comment --- frontend/exporter/src/id_table.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index 161d0142f..9a1eff91f 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -188,7 +188,11 @@ fn full_id_deserialization(f: impl FnOnce() -> T) -> T { result } -/// The deserializer of `WithTable` is special. First, we need to continuously +/// The deserializer of `WithTable` is special. We first decode the +/// table in order: each `(Id, Value)` pair of the table populates the +/// global table state found in `DESERIALIZATION_STATE`. Only then we +/// can decode the value itself, knowing `DESERIALIZATION_STATE` is +/// complete. impl<'de, T: Deserialize<'de>> serde::Deserialize<'de> for WithTable { fn deserialize(deserializer: D) -> Result where From 25ea3c52e39088711c82cb16f6b00e022af754da Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 16:13:48 +0200 Subject: [PATCH 116/253] refactor(exporter/id_table): intro. `HeterogeneousMap` --- frontend/exporter/src/id_table.rs | 112 ++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index 9a1eff91f..451a362f2 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -49,11 +49,22 @@ pub enum Value { Ty(Arc), } +impl SupportedType for TyKind { + fn to_types(value: Arc) -> Value { + Value::Ty(value) + } + fn from_types(t: &Value) -> Option> { + match t { + Value::Ty(value) => Some(value.clone()), + } + } +} + /// A node is a bundle of an ID with a value. #[derive(Deserialize, Serialize, Debug, JsonSchema, PartialEq, Eq, PartialOrd, Ord)] #[serde(into = "serde_repr::NodeRepr")] #[serde(try_from = "serde_repr::NodeRepr")] -pub struct Node { +pub struct Node> { id: Id, value: Arc, } @@ -61,7 +72,7 @@ pub struct Node { /// Hax relies on hashes being deterministic for predicates /// ids. Identifiers are not deterministic: we implement hash for /// `Node` manually, discarding the field `id`. -impl Hash for Node { +impl + Hash> Hash for Node { fn hash(&self, state: &mut H) { self.value.as_ref().hash(state); } @@ -69,7 +80,7 @@ impl Hash for Node { /// Manual implementation of `Clone` that doesn't require a `Clone` /// bound on `T`. -impl Clone for Node { +impl> Clone for Node { fn clone(&self) -> Self { Self { id: self.id.clone(), @@ -85,38 +96,59 @@ impl Clone for Node { #[derive(Default, Debug, Clone, Deserialize, Serialize)] #[serde(into = "serde_repr::SortedIdValuePairs")] #[serde(from = "serde_repr::SortedIdValuePairs")] -pub struct Table(HashMap); - -impl Table { - pub(super) fn insert(&mut self, cache_id: Id, value: Arc) - where - T: SupportedType, - { - self.0.insert(cache_id, T::to_types(value)); - } - pub(super) fn get(&self, cache_id: &Id) -> Option>> - where - T: SupportedType, - { - self.0.get(cache_id).map(T::from_types) - } -} -impl SupportedType for TyKind { - fn to_types(value: Arc) -> Value { - Value::Ty(value) +pub struct Table(HeterogeneousMap); + +mod heterogeneous_map { + //! This module provides an heterogenous map that can store types + //! that implement the trait `SupportedType`. + + use std::collections::HashMap; + use std::hash::Hash; + use std::sync::Arc; + #[derive(Clone, Debug)] + /// An heterogenous map is a map from `Key` to `Value`. It provide + /// the methods `insert` and `get` for any type `T` that + /// implements `SupportedType`. + pub struct HeterogeneousMap(HashMap); + + impl Default for HeterogeneousMap { + fn default() -> Self { + Self(HashMap::default()) + } } - fn from_types(t: &Value) -> Option> { - match t { - Value::Ty(value) => Some(value.clone()), + + impl HeterogeneousMap { + pub(super) fn insert(&mut self, key: Id, vKeyue: Arc) + where + T: SupportedType, + { + self.insert_raw_value(key, T::to_types(value)); + } + pub(super) fn insert_raw_value(&mut self, key: Key, value: Value) { + self.0.insert(key, value); + } + pub(super) fn from_iter(it: impl Iterator) -> Self { + Self(HashMap::from_iter(it)) + } + pub(super) fn into_iter(self) -> impl Iterator { + self.0.into_iter() + } + pub(super) fn get(&self, key: &Key) -> Option>> + where + T: SupportedType, + { + self.0.get(key).map(T::from_types) } } -} -/// A value encodable in the enum `Value` -pub trait SupportedType: std::fmt::Debug { - fn to_types(value: Arc) -> Value; - fn from_types(t: &Value) -> Option>; + /// A type that can be mapped to `Value` and optionally + /// reconstructed back. + pub trait SupportedType: std::fmt::Debug { + fn to_types(value: Arc) -> Value; + fn from_types(t: &Value) -> Option>; + } } +use heterogeneous_map::*; impl Session { fn fresh_id(&mut self) -> Id { @@ -126,11 +158,11 @@ impl Session { } } -impl Node { +impl> Node { pub fn new(value: T, session: &mut Session) -> Self { let id = session.fresh_id(); let kind = Arc::new(value); - session.table.insert(id.clone(), kind.clone()); + session.table.0.insert(id.clone(), kind.clone()); Self { id, value: kind } } pub fn inner(&self) -> &Arc { @@ -304,7 +336,7 @@ mod serde_repr { pub(super) struct Pair(Id, Value); pub(super) type SortedIdValuePairs = Vec; - impl Into> for Node { + impl> Into> for Node { fn into(self) -> NodeRepr { let value = if serialize_use_id() { None @@ -316,17 +348,19 @@ mod serde_repr { } } - impl TryFrom> for Node { + impl> TryFrom> for Node { type Error = serde::de::value::Error; fn try_from(cached: NodeRepr) -> Result { use serde::de::Error; - let map = DESERIALIZATION_STATE.lock().unwrap(); + let table = DESERIALIZATION_STATE.lock().unwrap(); let id = cached.cache_id; let kind = if let Some(kind) = cached.value { kind } else { - map.get(&id) + table + .0 + .get(&id) .ok_or_else(|| { Self::Error::custom(&format!( "Stateful deserialization failed for id {:?}: not found in cache", @@ -354,7 +388,7 @@ mod serde_repr { .lock() .unwrap() .0 - .insert(id.clone(), v.clone()); + .insert_raw_value(id.clone(), v.clone()); Ok(Pair(id, v)) } } @@ -369,7 +403,9 @@ mod serde_repr { impl From for Table { fn from(t: SortedIdValuePairs) -> Self { - Self(HashMap::from_iter(t.into_iter().map(|Pair(x, y)| (x, y)))) + Self(HeterogeneousMap::from_iter( + t.into_iter().map(|Pair(x, y)| (x, y)), + )) } } } From b1838c2da6c452675d6fd2ac1690162e9e2df78d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Oct 2024 17:45:41 +0200 Subject: [PATCH 117/253] Correctly substitute associated type generics --- frontend/exporter/src/traits/resolution.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 6ff9c3592..cc7ddea04 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -261,6 +261,7 @@ impl<'tcx> PredicateSearcher<'tcx> { .iter() .filter_map(|(clause, _span)| clause.as_trait_clause()) .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) + .map(|trait_ref| EarlyBinder::bind(trait_ref).instantiate(tcx, alias_ty.args)) .map(|trait_ref| self.resolve(&trait_ref, warn)) .collect::>()?; From 5768aae2a7fe814258443393c7a8cd0050f6c875 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 22 Oct 2024 17:56:54 +0200 Subject: [PATCH 118/253] Resolve nested predicates ourselves --- frontend/exporter/src/traits/resolution.rs | 129 +++++++++++---------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index cc7ddea04..9bb5ddc31 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -255,15 +255,8 @@ impl<'tcx> PredicateSearcher<'tcx> { .enumerate(); // Resolve predicates required to mention the item. - let nested_impl_exprs: Vec<_> = tcx - .predicates_defined_on(alias_ty.def_id) - .predicates - .iter() - .filter_map(|(clause, _span)| clause.as_trait_clause()) - .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) - .map(|trait_ref| EarlyBinder::bind(trait_ref).instantiate(tcx, alias_ty.args)) - .map(|trait_ref| self.resolve(&trait_ref, warn)) - .collect::>()?; + let nested_impl_exprs = + self.resolve_item_predicates(alias_ty.def_id, alias_ty.args, warn)?; // Add all the bounds on the corresponding associated item. self.extend(item_bounds.map(|(index, pred)| { @@ -334,41 +327,59 @@ impl<'tcx> PredicateSearcher<'tcx> { let tcx = self.tcx; let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, erased_tref)); + let nested; let atom = match impl_source { Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args: generics, .. - })) => ImplExprAtom::Concrete { - def_id: impl_def_id, - generics, - }, - Ok(ImplSource::Param(_)) => match self - .resolve_local(erased_tref.upcast(self.tcx), warn)? - { - Some(candidate) => { - let path = candidate.path; - let r#trait = candidate.origin.clause.to_poly_trait_ref(); - match candidate.origin.origin { - BoundPredicateOrigin::SelfPred => ImplExprAtom::SelfImpl { r#trait, path }, - BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound { - predicate: candidate.origin.clause.upcast(tcx), - index, - r#trait, - path, - }, - } + })) => { + // Resolve the predicates required by the impl. + nested = self.resolve_item_predicates(impl_def_id, generics, warn)?; + ImplExprAtom::Concrete { + def_id: impl_def_id, + generics, } - None => { - let msg = - format!("Could not find a clause for `{tref:?}` in the item parameters"); - warn(&msg); - ImplExprAtom::Error(msg) + } + Ok(ImplSource::Param(_)) => { + // Mentioning a local clause requires no extra predicates to hold. + nested = vec![]; + match self.resolve_local(erased_tref.upcast(self.tcx), warn)? { + Some(candidate) => { + let path = candidate.path; + let r#trait = candidate.origin.clause.to_poly_trait_ref(); + match candidate.origin.origin { + BoundPredicateOrigin::SelfPred => { + ImplExprAtom::SelfImpl { r#trait, path } + } + BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound { + predicate: candidate.origin.clause.upcast(tcx), + index, + r#trait, + path, + }, + } + } + None => { + let msg = format!( + "Could not find a clause for `{tref:?}` in the item parameters" + ); + warn(&msg); + ImplExprAtom::Error(msg) + } } - }, - Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn, - Ok(ImplSource::Builtin(_, _)) => ImplExprAtom::Builtin { r#trait: *tref }, + } + Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => { + nested = vec![]; + ImplExprAtom::Dyn + } + Ok(ImplSource::Builtin(_, _)) => { + // Builtin impls currently don't need nested predicates. + nested = vec![]; + ImplExprAtom::Builtin { r#trait: *tref } + } Err(e) => { + nested = vec![]; let msg = format!( "Could not find a clause for `{tref:?}` in the current context: `{e:?}`" ); @@ -377,37 +388,33 @@ impl<'tcx> PredicateSearcher<'tcx> { } }; - let nested = match &impl_source { - Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { nested, .. })) => { - // The nested obligations of depth 1 correspond (we hope) to the predicates on the - // relevant impl that need to be satisfied. - nested - .iter() - .filter(|obligation| obligation.recursion_depth == 1) - .filter_map(|obligation| { - obligation.predicate.as_trait_clause().map(|trait_ref| { - self.resolve(&trait_ref.map_bound(|p| p.trait_ref), warn) - }) - }) - .collect::>()? - } - // Nested obligations can happen e.g. for GATs. We ignore these as we resolve local - // clauses ourselves. - Ok(ImplSource::Param(_)) => vec![], - // We ignore the contained obligations here. For example for `(): Send`, the - // obligations contained would be `[(): Send]`, which leads to an infinite loop. There - // might be important obligations here in other cases; we'll have to see if that comes - // up. - Ok(ImplSource::Builtin(..)) => vec![], - Err(_) => vec![], - }; - Ok(ImplExpr { r#impl: atom, args: nested, r#trait: *tref, }) } + + /// Resolve the predicates required by the given item. + pub fn resolve_item_predicates( + &mut self, + def_id: DefId, + generics: GenericArgsRef<'tcx>, + // Call back into hax-related code to display a nice warning. + warn: &impl Fn(&str), + ) -> Result>, String> { + let tcx = self.tcx; + tcx.predicates_defined_on(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.as_trait_clause()) + .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) + // Substitute the item generics + .map(|trait_ref| EarlyBinder::bind(trait_ref).instantiate(tcx, generics)) + // Resolve + .map(|trait_ref| self.resolve(&trait_ref, warn)) + .collect() + } } mod copy_paste_from_rustc { From 6e2d78b2d34ab4ea9926960a7c636e2d57f75776 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 23 Oct 2024 11:36:52 +0200 Subject: [PATCH 119/253] Clarify the source of various predicates for each item --- frontend/exporter/src/traits.rs | 53 +++---- frontend/exporter/src/traits/resolution.rs | 35 ++--- frontend/exporter/src/traits/utils.rs | 153 ++++++++++++++------ frontend/exporter/src/types/mir.rs | 9 +- frontend/exporter/src/types/new/full_def.rs | 7 +- 5 files changed, 161 insertions(+), 96 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 0799cad29..23bd9449e 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -5,10 +5,14 @@ mod resolution; #[cfg(feature = "rustc")] mod utils; #[cfg(feature = "rustc")] -pub use utils::erase_and_norm; +pub use utils::{erase_and_norm, implied_predicates, required_predicates, self_predicate}; #[cfg(feature = "rustc")] pub use resolution::PredicateSearcher; +#[cfg(feature = "rustc")] +use rustc_middle::ty; +#[cfg(feature = "rustc")] +use rustc_span::def_id::DefId as RDefId; #[derive(AdtInto)] #[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::PathChunk<'tcx>, state: S as s)] @@ -31,7 +35,7 @@ pub enum ImplExprPathChunk { predicate: Binder, #[value(<_ as SInto<_, Clause>>::sinto(predicate, s).id)] predicate_id: PredicateId, - /// The index of this predicate in the list returned by `tcx.item_bounds`. + /// The index of this predicate in the list returned by `implied_predicates`. index: usize, }, Parent { @@ -39,7 +43,7 @@ pub enum ImplExprPathChunk { predicate: Binder, #[value(<_ as SInto<_, Clause>>::sinto(predicate, s).id)] predicate_id: PredicateId, - /// The index of this predicate in the list returned by `tcx.predicates_of`. + /// The index of this predicate in the list returned by `implied_predicates`. index: usize, }, } @@ -66,8 +70,7 @@ pub enum ImplExprAtom { })] predicate_id: PredicateId, /// The nth (non-self) predicate found for this item. We use predicates from - /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an opaque - /// type, we also append the predicates from `explicit_item_bounds` to this list. + /// `required_predicates` starting from the parentmost item. index: usize, r#trait: Binder, path: Vec, @@ -177,23 +180,25 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( #[tracing::instrument(level = "trace", skip(s), ret)] pub fn solve_item_traits<'tcx, S: UnderOwnerState<'tcx>>( s: &S, - def_id: rustc_hir::def_id::DefId, - generics: rustc_middle::ty::GenericArgsRef<'tcx>, - predicates: Option>, + def_id: RDefId, + generics: ty::GenericArgsRef<'tcx>, + predicates_of: Option, ) -> Vec { let tcx = s.base().tcx; let param_env = s.param_env(); let mut impl_exprs = Vec::new(); - // Lookup the predicates and iter through them: we want to solve all the - // trait requirements. - // IMPORTANT: we use [TyCtxt::predicates_defined_on] and not [TyCtxt::predicated_of] - let predicates = match predicates { - None => tcx.predicates_defined_on(def_id), - Some(preds) => preds, + let predicates_of = predicates_of.unwrap_or(def_id); + // We can't use `required_predicates` alone because this is called to resolve trait implied + // predicates too. + // TODO: stop doing that + let predicates: Vec<_> = match tcx.def_kind(predicates_of) { + rustc_hir::def::DefKind::Trait => implied_predicates(tcx, predicates_of).collect(), + _ => required_predicates(tcx, predicates_of).collect(), }; - for (pred, _) in predicates.predicates { + + for pred in predicates { // Explore only the trait predicates if let Some(trait_clause) = pred.as_trait_clause() { let poly_trait_ref = trait_clause.map_bound(|clause| clause.trait_ref); @@ -220,18 +225,16 @@ pub fn self_clause_for_item<'tcx, S: UnderOwnerState<'tcx>>( assoc: &rustc_middle::ty::AssocItem, generics: rustc_middle::ty::GenericArgsRef<'tcx>, ) -> Option { + use rustc_middle::ty::EarlyBinder; let tcx = s.base().tcx; - // Retrieve the trait let tr_def_id = tcx.trait_of_item(assoc.def_id)?; + // The "self" predicate in the context of the trait. + let self_pred = self_predicate(tcx, tr_def_id).unwrap(); + // Substitute to be in the context of the current item. + let generics = generics.truncate_to(tcx, tcx.generics_of(tr_def_id)); + let self_pred = EarlyBinder::bind(self_pred).instantiate(tcx, generics); - // Create the reference to the trait - use rustc_middle::ty::TraitRef; - let tr_generics = tcx.generics_of(tr_def_id); - let generics = generics.truncate_to(tcx, tr_generics); - let tr_ref = TraitRef::new(tcx, tr_def_id, generics); - let tr_ref = rustc_middle::ty::Binder::dummy(tr_ref); - - // Solve - Some(solve_trait(s, tr_ref)) + // Resolve + Some(solve_trait(s, self_pred)) } diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 9bb5ddc31..877dfad17 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -10,6 +10,8 @@ use rustc_middle::ty::*; use crate::traits::utils::erase_and_norm; +use super::utils::{implied_predicates, required_predicates}; + #[derive(Debug, Clone)] pub enum PathChunk<'tcx> { AssocItem { @@ -26,13 +28,13 @@ pub enum PathChunk<'tcx> { impl_exprs: Vec>, /// The implemented predicate. predicate: PolyTraitPredicate<'tcx>, - /// The index of this predicate in the list returned by `tcx.item_bounds`. + /// The index of this predicate in the list returned by `implied_predicates`. index: usize, }, Parent { /// The implemented predicate. predicate: PolyTraitPredicate<'tcx>, - /// The index of this predicate in the list returned by `tcx.predicates_of`. + /// The index of this predicate in the list returned by `implied_predicates`. index: usize, }, } @@ -49,9 +51,7 @@ pub enum ImplExprAtom<'tcx> { LocalBound { predicate: Predicate<'tcx>, /// The nth (non-self) predicate found for this item. We use predicates from - /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an - /// opaque type, we also append the predicates from `explicit_item_bounds` to this - /// list. + /// `required_predicates` starting from the parentmost item. index: usize, r#trait: PolyTraitRef<'tcx>, path: Path<'tcx>, @@ -92,8 +92,7 @@ pub enum BoundPredicateOrigin { /// don't add it for trait implementations, should we?). SelfPred, /// The nth (non-self) predicate found for this item. We use predicates from - /// `tcx.predicates_defined_on` starting from the parentmost item. If the item is an opaque - /// type, we also append the predicates from `explicit_item_bounds` to this list. + /// `required_predicates` starting from the parentmost item. Item(usize), } @@ -132,12 +131,10 @@ fn parents_trait_predicates<'tcx>( pred: PolyTraitPredicate<'tcx>, ) -> Vec> { let self_trait_ref = pred.to_poly_trait_ref(); - tcx.predicates_of(pred.def_id()) - .predicates - .iter() + implied_predicates(tcx, pred.def_id()) // Substitute with the `self` args so that the clause makes sense in the // outside context. - .map(|(clause, _span)| clause.instantiate_supertrait(tcx, self_trait_ref)) + .map(|clause| clause.instantiate_supertrait(tcx, self_trait_ref)) .filter_map(|pred| pred.as_trait_clause()) .collect() } @@ -245,13 +242,11 @@ impl<'tcx> PredicateSearcher<'tcx> { return Ok(()); }; - // The bounds that the associated type must validate. - let item_bounds = tcx - // TODO: `item_bounds` can contain parent traits, we don't want them - .item_bounds(alias_ty.def_id) - .instantiate(tcx, alias_ty.args) - .iter() + // The bounds that hold on the associated type. + let item_bounds = implied_predicates(tcx, alias_ty.def_id) .filter_map(|pred| pred.as_trait_clause()) + // Substitute the item generics + .map(|pred| EarlyBinder::bind(pred).instantiate(tcx, alias_ty.args)) .enumerate(); // Resolve predicates required to mention the item. @@ -404,10 +399,8 @@ impl<'tcx> PredicateSearcher<'tcx> { warn: &impl Fn(&str), ) -> Result>, String> { let tcx = self.tcx; - tcx.predicates_defined_on(def_id) - .predicates - .into_iter() - .filter_map(|(pred, _)| pred.as_trait_clause()) + required_predicates(tcx, def_id) + .filter_map(|clause| clause.as_trait_clause()) .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) // Substitute the item generics .map(|trait_ref| EarlyBinder::bind(trait_ref).instantiate(tcx, generics)) diff --git a/frontend/exporter/src/traits/utils.rs b/frontend/exporter/src/traits/utils.rs index f2e0e1f07..90dd131cc 100644 --- a/frontend/exporter/src/traits/utils.rs +++ b/frontend/exporter/src/traits/utils.rs @@ -1,32 +1,42 @@ +//! Each item can involve three kinds of predicates: +//! - input aka required predicates: the predicates required to mention the item. These are usually `where` +//! clauses (or equivalent) on the item: +//! ```ignore +//! struct Foo { ... } +//! trait Foo where T: Clone { ... } +//! fn function() where I: Iterator, I::Item: Clone { ... } +//! ``` +//! - output aka implied predicates: the predicates that are implied by the presence of this item in a +//! signature. This is mostly trait parent predicates: +//! ```ignore +//! trait Foo: Clone { ... } +//! fn bar() { +//! // from `T: Foo` we can deduce `T: Clone` +//! } +//! ``` +//! This could also include implied predicates such as `&'a T` implying `T: 'a` but we don't +//! consider these. +//! - "self" predicate: that's the special `Self: Trait` predicate in scope within a trait +//! declaration or implementation for trait `Trait`. +//! +//! Note that within a given item the polarity is reversed: input predicates are the ones that can +//! be assumed to hold and output predicates must be proven to hold. The "self" predicate is both +//! assumed and proven within an impl block, and just assumed within a trait declaration block. +//! +//! The current implementation considers all predicates on traits to be outputs, which has the +//! benefit of reducing the size of signatures. Moreover, the rules on which bounds are required vs +//! implied are subtle. We may change this if this proves to be a problem. use rustc_hir::def::DefKind; use rustc_middle::ty::*; +use rustc_span::def_id::DefId; -/// Just like `TyCtxt::predicates_of`, but in the case of a trait or impl item or closures, -/// also includes the predicates defined on the parents. Also this returns the special -/// `Self` clause separately. -pub fn predicates_of_or_above<'tcx>( +/// The predicates that must hold to mention this item. +pub fn required_predicates<'tcx>( tcx: TyCtxt<'tcx>, - did: rustc_span::def_id::DefId, -) -> ( - Vec>, - Option>, -) { + def_id: DefId, +) -> impl Iterator> { use DefKind::*; - let def_kind = tcx.def_kind(did); - - let (mut predicates, mut self_pred) = match def_kind { - // These inherit some predicates from their parent. - AssocTy | AssocFn | AssocConst | Closure => { - let parent = tcx.parent(did); - predicates_of_or_above(tcx, parent) - } - _ => (vec![], None), - }; - - match def_kind { - // Don't list the predicates of traits, we already list the `Self` clause from - // which we can resolve anything needed. - Trait => {} + match tcx.def_kind(def_id) { AssocConst | AssocFn | AssocTy @@ -40,29 +50,84 @@ pub fn predicates_of_or_above<'tcx>( | Struct | TraitAlias | TyAlias - | Union => { - // Only these kinds may reasonably have predicates; we have to filter - // otherwise calling `predicates_defined_on` may ICE. - predicates.extend( - tcx.predicates_defined_on(did) - .predicates - .iter() - .filter_map(|(clause, _span)| clause.as_trait_clause()), - ); - } - _ => {} + | Union => Some( + tcx.predicates_defined_on(def_id) + .predicates + .iter() + .map(|(clause, _span)| *clause), + ), + // We consider all predicates on traits to be outputs + Trait => None, + // `predicates_defined_on ICEs on other def kinds. + _ => None, } + .into_iter() + .flatten() +} - // Add the extra `Self: Trait` predicate. - match def_kind { - Trait => { - // Add the special `Self: Trait` clause. - // Copied from the code of `tcx.predicates_of()`. - let self_clause: Clause<'_> = TraitRef::identity(tcx, did).upcast(tcx); - self_pred = Some(self_clause.as_trait_clause().unwrap()); - } - _ => {} +/// The special "self" predicate on a trait. +pub fn self_predicate<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option> { + use DefKind::*; + match tcx.def_kind(def_id) { + // Copied from the code of `tcx.predicates_of()`. + Trait => Some(Binder::dummy(TraitRef::identity(tcx, def_id))), + _ => None, + } +} + +/// The predicates that can be deduced from the presence of this item in a signature. We only +/// consider predicates implied by traits here, not implied bounds such as `&'a T` implying `T: +/// 'a`. +pub fn implied_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> impl Iterator> { + use DefKind::*; + match tcx.def_kind(def_id) { + // We consider all predicates on traits to be outputs + Trait => tcx + .predicates_defined_on(def_id) + .predicates + .iter() + .map(|(clause, _span)| *clause) + .collect::>(), + AssocTy => tcx + // TODO: `item_bounds` contains parent traits, use `explicit_item_bounds` instead. + .item_bounds(def_id) + .instantiate_identity() + .iter() + .collect(), + _ => vec![], } + .into_iter() +} + +/// Accumulates the `required_predicates` of this item and its parents, starting from the parents. +/// Also returns the special `Self` clause separately. +pub fn predicates_of_or_above<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> ( + Vec>, + Option>, +) { + use DefKind::*; + let def_kind = tcx.def_kind(def_id); + + let (mut predicates, self_pred) = match def_kind { + // These inherit some predicates from their parent. + AssocTy | AssocFn | AssocConst | Closure => { + let parent = tcx.parent(def_id); + predicates_of_or_above(tcx, parent) + } + _ => { + let self_pred = self_predicate(tcx, def_id).map(|clause| clause.upcast(tcx)); + (vec![], self_pred) + } + }; + + predicates + .extend(required_predicates(tcx, def_id).filter_map(|clause| clause.as_trait_clause())); (predicates, self_pred) } diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index a5f232aab..830675e84 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -978,15 +978,14 @@ pub enum AggregateKind { let closure = generics.as_closure(); let sig = closure.sig().sinto(s); - // Solve the trait obligations. Note that we solve the parent + // Solve the predicates from the parent (i.e., the function which calls the closure). let tcx = s.base().tcx; let parent_generics = closure.parent_args(); let generics = tcx.mk_args(parent_generics); - // Retrieve the predicates from the parent (i.e., the function which calls - // the closure). - let predicates = tcx.predicates_defined_on(tcx.generics_of(rust_id).parent.unwrap()); + // TODO: does this handle nested closures? + let parent = tcx.generics_of(rust_id).parent.unwrap(); + let trait_refs = solve_item_traits(s, *rust_id, generics, Some(parent)); - let trait_refs = solve_item_traits(s, *rust_id, generics, Some(predicates)); AggregateKind::Closure(def_id, parent_generics.sinto(s), trait_refs, sig) })] Closure(DefId, Vec, Vec, PolyFnSig), diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index b060de84a..f2fcdc1ae 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -115,7 +115,12 @@ pub enum FullDefKind { #[value({ use ty::Upcast; let tcx = s.base().tcx; - let pred: ty::TraitPredicate = ty::TraitRef::identity(tcx, s.owner_id()).upcast(tcx); + let pred: ty::TraitPredicate = + crate::traits::self_predicate(tcx, s.owner_id()) + .unwrap() + .no_bound_vars() + .unwrap() + .upcast(tcx); pred.sinto(s) })] self_predicate: TraitPredicate, From e077543070bb4522187b6a458f860b66e3495c35 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 23 Oct 2024 12:11:39 +0200 Subject: [PATCH 120/253] Simplify `solve_item_traits` --- frontend/exporter/src/constant_utils.rs | 2 +- frontend/exporter/src/traits.rs | 48 ++++++++++--------------- frontend/exporter/src/types/mir.rs | 8 ++--- frontend/exporter/src/types/thir.rs | 2 +- frontend/exporter/src/types/ty.rs | 5 ++- 5 files changed, 27 insertions(+), 38 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 4da2ab29a..483598d0c 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -433,7 +433,7 @@ mod rustc { // Solve the trait obligations let parent_def_id = tcx.parent(ucv.def); - let trait_refs = solve_item_traits(s, parent_def_id, ucv.args, None); + let trait_refs = solve_item_traits(s, parent_def_id, ucv.args); // Convert let id = ucv.def.sinto(s); diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 23bd9449e..92976db5f 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -172,50 +172,40 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( impl_expr } -/// Solve the trait obligations for a specific item use (for example, a method call, an ADT, etc.). -/// -/// [predicates]: optional predicates, in case we want to solve custom predicates (instead of the -/// ones returned by [TyCtxt::predicates_defined_on]. +/// Solve the trait obligations for a specific item use (for example, a method call, an ADT, etc.) +/// in the current context. #[cfg(feature = "rustc")] #[tracing::instrument(level = "trace", skip(s), ret)] pub fn solve_item_traits<'tcx, S: UnderOwnerState<'tcx>>( s: &S, def_id: RDefId, generics: ty::GenericArgsRef<'tcx>, - predicates_of: Option, ) -> Vec { let tcx = s.base().tcx; let param_env = s.param_env(); - let mut impl_exprs = Vec::new(); - - let predicates_of = predicates_of.unwrap_or(def_id); // We can't use `required_predicates` alone because this is called to resolve trait implied // predicates too. // TODO: stop doing that - let predicates: Vec<_> = match tcx.def_kind(predicates_of) { - rustc_hir::def::DefKind::Trait => implied_predicates(tcx, predicates_of).collect(), - _ => required_predicates(tcx, predicates_of).collect(), + let predicates: Vec<_> = match tcx.def_kind(def_id) { + rustc_hir::def::DefKind::Trait => implied_predicates(tcx, def_id).collect(), + _ => required_predicates(tcx, def_id).collect(), }; - for pred in predicates { - // Explore only the trait predicates - if let Some(trait_clause) = pred.as_trait_clause() { - let poly_trait_ref = trait_clause.map_bound(|clause| clause.trait_ref); - // Apply the substitution - let poly_trait_ref = - rustc_middle::ty::EarlyBinder::bind(poly_trait_ref).instantiate(tcx, generics); - // Warning: this erases regions. We don't really have a way to normalize without - // erasing regions, but this may cause problems in trait solving if there are trait - // impls that include `'static` lifetimes. - let poly_trait_ref = tcx - .try_normalize_erasing_regions(param_env, poly_trait_ref) - .unwrap_or(poly_trait_ref); - let impl_expr = solve_trait(s, poly_trait_ref); - impl_exprs.push(impl_expr); - } - } - impl_exprs + predicates + .into_iter() + .filter_map(|clause| clause.as_trait_clause()) + .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) + // Substitute the item generics + .map(|trait_ref| ty::EarlyBinder::bind(trait_ref).instantiate(tcx, generics)) + // We unfortunately don't have a way to normalize without erasing regions. + .map(|trait_ref| { + tcx.try_normalize_erasing_regions(param_env, trait_ref) + .unwrap_or(trait_ref) + }) + // Resolve + .map(|trait_ref| solve_trait(s, trait_ref)) + .collect() } /// Retrieve the `Self: Trait` clause for a trait associated item. diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 830675e84..b16188e97 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -315,7 +315,7 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H // fn foo(...) // ^^^ // ``` - let mut trait_refs = solve_item_traits(s, def_id, generics, None); + let mut trait_refs = solve_item_traits(s, def_id, generics); // Check if this is a trait method call: retrieve the trait source if // it is the case (i.e., where does the method come from? Does it refer @@ -397,7 +397,7 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H let container_generics = tcx.generics_of(container_def_id); let container_generics = generics.truncate_to(tcx, container_generics); let container_trait_refs = - solve_item_traits(s, container_def_id, container_generics, None); + solve_item_traits(s, container_def_id, container_generics); trait_refs.extend(container_trait_refs); (generics.sinto(s), Option::None) } @@ -950,7 +950,7 @@ pub enum AggregateKind { Tuple, #[custom_arm(rustc_middle::mir::AggregateKind::Adt(def_id, vid, generics, annot, fid) => { let adt_kind = s.base().tcx.adt_def(def_id).adt_kind().sinto(s); - let trait_refs = solve_item_traits(s, *def_id, generics, None); + let trait_refs = solve_item_traits(s, *def_id, generics); AggregateKind::Adt( def_id.sinto(s), vid.sinto(s), @@ -984,7 +984,7 @@ pub enum AggregateKind { let generics = tcx.mk_args(parent_generics); // TODO: does this handle nested closures? let parent = tcx.generics_of(rust_id).parent.unwrap(); - let trait_refs = solve_item_traits(s, *rust_id, generics, Some(parent)); + let trait_refs = solve_item_traits(s, parent, generics); AggregateKind::Closure(def_id, parent_generics.sinto(s), trait_refs, sig) })] diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index 4ba169ddf..79e159324 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -589,7 +589,7 @@ pub enum ExprKind { Some((impl_expr, assoc_generics)) })(); generic_args = translated_generics; - bounds_impls = solve_item_traits(gstate, *def_id, generics, None); + bounds_impls = solve_item_traits(gstate, *def_id, generics); Expr { contents, span: e.span.sinto(gstate), diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index 4ab346098..343d9bd13 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -792,7 +792,7 @@ pub enum TyKind { ty::TyKind::Adt(adt_def, generics) => { let def_id = adt_def.did().sinto(state); let generic_args: Vec = generics.sinto(state); - let trait_refs = solve_item_traits(state, adt_def.did(), generics, None); + let trait_refs = solve_item_traits(state, adt_def.did(), generics); TyKind::Adt { def_id, generic_args, trait_refs } }, )] @@ -1322,8 +1322,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<' trait_ref: trait_ref.sinto(s), is_positive: matches!(polarity, ty::ImplPolarity::Positive), }; - let required_impl_exprs = - solve_item_traits(s, trait_ref.def_id, trait_ref.args, None); + let required_impl_exprs = solve_item_traits(s, trait_ref.def_id, trait_ref.args); ImplSubject::Trait { trait_pred, required_impl_exprs, From 72084c2257107582955ef3598b90fcd177bf02de Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 23 Oct 2024 15:58:37 +0200 Subject: [PATCH 121/253] Rework `initial_search_predicates` --- frontend/exporter/src/traits/resolution.rs | 60 +++++++++++++++------- frontend/exporter/src/traits/utils.rs | 34 +----------- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 877dfad17..5ce6643bb 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -5,10 +5,11 @@ use itertools::Itertools; use std::collections::{hash_map::Entry, HashMap}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::*; -use crate::traits::utils::erase_and_norm; +use crate::{self_predicate, traits::utils::erase_and_norm}; use super::utils::{implied_predicates, required_predicates}; @@ -102,27 +103,50 @@ pub struct AnnotatedTraitPred<'tcx> { pub clause: PolyTraitPredicate<'tcx>, } -/// The predicates to use as a starting point for resolving trait references within this -/// item. This is just like `TyCtxt::predicates_of`, but in the case of a trait or impl -/// item or closures, also includes the predicates defined on the parents. +/// The predicates to use as a starting point for resolving trait references within this item. This +/// includes the "self" predicate if applicable and the `required_predicates` of this item and all +/// its parents, numbered starting from the parents. fn initial_search_predicates<'tcx>( tcx: TyCtxt<'tcx>, - did: rustc_span::def_id::DefId, + def_id: rustc_span::def_id::DefId, ) -> Vec> { - let (predicates, self_pred) = super::utils::predicates_of_or_above(tcx, did); - let predicates = predicates - .into_iter() - .enumerate() - .map(|(i, clause)| AnnotatedTraitPred { - origin: BoundPredicateOrigin::Item(i), - clause, - }); - let self_pred = self_pred.map(|clause| AnnotatedTraitPred { - origin: BoundPredicateOrigin::SelfPred, - clause, - }); + fn acc_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: rustc_span::def_id::DefId, + predicates: &mut Vec>, + pred_id: &mut usize, + ) { + use DefKind::*; + match tcx.def_kind(def_id) { + // These inherit some predicates from their parent. + AssocTy | AssocFn | AssocConst | Closure => { + let parent = tcx.parent(def_id); + acc_predicates(tcx, parent, predicates, pred_id); + } + Trait => { + let self_pred = self_predicate(tcx, def_id).unwrap().upcast(tcx); + predicates.push(AnnotatedTraitPred { + origin: BoundPredicateOrigin::SelfPred, + clause: self_pred, + }) + } + _ => {} + } + predicates.extend(required_predicates(tcx, def_id).filter_map(|clause| { + clause.as_trait_clause().map(|clause| { + let id = *pred_id; + *pred_id += 1; + AnnotatedTraitPred { + origin: BoundPredicateOrigin::Item(id), + clause, + } + }) + })); + } - self_pred.into_iter().chain(predicates).collect() + let mut predicates = vec![]; + acc_predicates(tcx, def_id, &mut predicates, &mut 0); + predicates } #[tracing::instrument(level = "trace", skip(tcx))] diff --git a/frontend/exporter/src/traits/utils.rs b/frontend/exporter/src/traits/utils.rs index 90dd131cc..244692303 100644 --- a/frontend/exporter/src/traits/utils.rs +++ b/frontend/exporter/src/traits/utils.rs @@ -34,7 +34,7 @@ use rustc_span::def_id::DefId; pub fn required_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> impl Iterator> { +) -> impl Iterator> + DoubleEndedIterator { use DefKind::*; match tcx.def_kind(def_id) { AssocConst @@ -81,7 +81,7 @@ pub fn self_predicate<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> impl Iterator> { +) -> impl Iterator> + DoubleEndedIterator { use DefKind::*; match tcx.def_kind(def_id) { // We consider all predicates on traits to be outputs @@ -102,36 +102,6 @@ pub fn implied_predicates<'tcx>( .into_iter() } -/// Accumulates the `required_predicates` of this item and its parents, starting from the parents. -/// Also returns the special `Self` clause separately. -pub fn predicates_of_or_above<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, -) -> ( - Vec>, - Option>, -) { - use DefKind::*; - let def_kind = tcx.def_kind(def_id); - - let (mut predicates, self_pred) = match def_kind { - // These inherit some predicates from their parent. - AssocTy | AssocFn | AssocConst | Closure => { - let parent = tcx.parent(def_id); - predicates_of_or_above(tcx, parent) - } - _ => { - let self_pred = self_predicate(tcx, def_id).map(|clause| clause.upcast(tcx)); - (vec![], self_pred) - } - }; - - predicates - .extend(required_predicates(tcx, def_id).filter_map(|clause| clause.as_trait_clause())); - - (predicates, self_pred) -} - /// Erase all regions. Largely copied from `tcx.erase_regions`. pub fn erase_all_regions<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> T where From cd32742dae921163ede0cfa49d8e82a743197810 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 23 Oct 2024 16:48:33 +0200 Subject: [PATCH 122/253] Rework `codegen_select_candidate` a bit --- frontend/exporter/src/traits/resolution.rs | 126 +++++++++------------ 1 file changed, 52 insertions(+), 74 deletions(-) diff --git a/frontend/exporter/src/traits/resolution.rs b/frontend/exporter/src/traits/resolution.rs index 5ce6643bb..f7c67a86b 100644 --- a/frontend/exporter/src/traits/resolution.rs +++ b/frontend/exporter/src/traits/resolution.rs @@ -7,7 +7,9 @@ use std::collections::{hash_map::Entry, HashMap}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::*; +use rustc_trait_selection::traits::ImplSource; use crate::{self_predicate, traits::utils::erase_and_norm}; @@ -344,8 +346,7 @@ impl<'tcx> PredicateSearcher<'tcx> { let erased_tref = erase_and_norm(self.tcx, self.param_env, *tref); let tcx = self.tcx; - let impl_source = - copy_paste_from_rustc::codegen_select_candidate(tcx, (self.param_env, erased_tref)); + let impl_source = shallow_resolve_trait_ref(tcx, self.param_env, erased_tref); let nested; let atom = match impl_source { Ok(ImplSource::UserDefined(ImplSourceUserDefinedData { @@ -434,84 +435,61 @@ impl<'tcx> PredicateSearcher<'tcx> { } } -mod copy_paste_from_rustc { +/// Attempts to resolve an obligation to an `ImplSource`. The result is a shallow `ImplSource` +/// resolution, meaning that we do not resolve all nested obligations on the impl. Note that type +/// check should guarantee to us that all nested obligations *could be* resolved if we wanted to. +/// +/// This expects that `trait_ref` is fully normalized. +/// +/// This is based on `rustc_traits::codegen::codegen_select_candidate` in rustc. +pub fn shallow_resolve_trait_ref<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + trait_ref: PolyTraitRef<'tcx>, +) -> Result, CodegenObligationError> { use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::CodegenObligationError; - use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; - use rustc_trait_selection::error_reporting::InferCtxtErrorExt; + use rustc_middle::ty::TypeVisitableExt; use rustc_trait_selection::traits::{ - Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, - Unimplemented, + Obligation, ObligationCause, ObligationCtxt, SelectionContext, Unimplemented, + }; + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); + + let selection = match selcx.poly_select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(_) => return Err(CodegenObligationError::FulfillmentError), }; - /// Attempts to resolve an obligation to an `ImplSource`. The result is - /// a shallow `ImplSource` resolution, meaning that we do not - /// (necessarily) resolve all nested obligations on the impl. Note - /// that type check should guarantee to us that all nested - /// obligations *could be* resolved if we wanted to. - /// - /// This also expects that `trait_ref` is fully normalized. - pub fn codegen_select_candidate<'tcx>( - tcx: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), - ) -> Result, CodegenObligationError> { - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); - - let selection = match selcx.poly_select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => return Err(CodegenObligationError::Ambiguity), - Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), - Err(e) => { - panic!( - "Encountered error `{:?}` selecting `{:?}` during codegen", - e, trait_ref - ) - } - }; - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. - let ocx = ObligationCtxt::new(&infcx); - let impl_source = selection.map(|obligation| { - ocx.register_obligation(obligation.clone()); - obligation - }); - - // In principle, we only need to do this so long as `impl_source` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - // `rustc_monomorphize::collector` assumes there are no type errors. - // Cycle errors are the only post-monomorphization errors possible; emit them now so - // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. - for err in errors { - if let ScrubbedTraitError::Cycle(cycle) = err { - infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); - } - } - return Err(CodegenObligationError::FulfillmentError); - } - - let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = infcx.tcx.erase_regions(impl_source); + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. + let ocx = ObligationCtxt::new(&infcx); + let impl_source = selection.map(|obligation| { + ocx.register_obligation(obligation.clone()); + () + }); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + return Err(CodegenObligationError::FulfillmentError); + } - if impl_source.has_infer() { - // Unused lifetimes on an impl get replaced with inference vars, but never resolved, - // causing the return value of a query to contain inference vars. We do not have a concept - // for this and will in fact ICE in stable hashing of the return value. So bail out instead. - infcx.tcx.dcx().has_errors().unwrap(); - return Err(CodegenObligationError::FulfillmentError); - } + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = tcx.erase_regions(impl_source); - Ok(impl_source) + if impl_source.has_infer() { + // Unused lifetimes on an impl get replaced with inference vars, but never resolved. + return Err(CodegenObligationError::FulfillmentError); } + + Ok(impl_source) } From 3a7806288e89fed292645c9a2c1d0e093007d325 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 23 Oct 2024 16:49:17 +0200 Subject: [PATCH 123/253] Remove unused macro --- frontend/exporter/src/utils.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/frontend/exporter/src/utils.rs b/frontend/exporter/src/utils.rs index 73843e7ce..16f46ed29 100644 --- a/frontend/exporter/src/utils.rs +++ b/frontend/exporter/src/utils.rs @@ -147,12 +147,3 @@ mod s_expect_impls { } } } - -macro_rules! s_assert { - ($s:ident, $assertion:expr) => {{ - if !($assertion) { - fatal!($s, "assertion failed: {}", stringify!($assertion)) - } - }}; -} -pub(crate) use s_assert; From c975b44798df5b9a1d37f06da824b249a88c75cd Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 23 Oct 2024 14:44:37 +0200 Subject: [PATCH 124/253] Feature gating for return/break/continue. --- engine/backends/coq/coq/coq_backend.ml | 1 + .../backends/coq/ssprove/ssprove_backend.ml | 4 +- .../backends/easycrypt/easycrypt_backend.ml | 1 + engine/backends/fstar/fstar_backend.ml | 6 +- engine/backends/proverif/proverif_backend.ml | 2 +- engine/lib/ast.ml | 17 +- engine/lib/ast_utils.ml | 3 +- engine/lib/diagnostics.ml | 2 +- engine/lib/features.ml | 2 + engine/lib/import_thir.ml | 2 +- .../phase_drop_return_break_continue.ml | 275 ++++++++++-------- .../phase_drop_return_break_continue.mli | 20 +- .../lib/phases/phase_functionalize_loops.ml | 91 +++--- .../lib/phases/phase_functionalize_loops.mli | 1 + engine/lib/phases/phase_local_mutation.ml | 5 +- .../phase_reconstruct_for_index_loops.ml | 1 - .../lib/phases/phase_reconstruct_for_loops.ml | 3 +- .../phases/phase_reconstruct_while_loops.ml | 3 +- engine/lib/phases/phase_reject.ml | 23 +- .../lib/phases/phase_rewrite_control_flow.ml | 31 +- engine/lib/side_effect_utils.ml | 10 +- engine/lib/subtype.ml | 29 +- 22 files changed, 259 insertions(+), 273 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 34338363f..0e6e8afb5 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -41,6 +41,7 @@ module SubtypeToInputLanguage and type for_index_loop = Features.Off.for_index_loop and type quote = Features.Off.quote and type state_passing_loop = Features.Off.state_passing_loop + and type fold_like_loop = Features.Off.fold_like_loop and type dyn = Features.Off.dyn and type match_guard = Features.Off.match_guard and type trait_item_default = Features.Off.trait_item_default diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index d4db317a9..f2ef39f44 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -18,6 +18,7 @@ include include On.While_loop include On.For_index_loop include On.State_passing_loop + include On.Fold_like_loop end) (struct let backend = Diagnostics.Backend.SSProve @@ -63,6 +64,7 @@ struct include Features.SUBTYPE.On.While_loop include Features.SUBTYPE.On.For_index_loop include Features.SUBTYPE.On.State_passing_loop + include Features.SUBTYPE.On.Fold_like_loop end) let metadata = Phase_utils.Metadata.make (Reject (NotInBackendLang backend)) @@ -1117,7 +1119,7 @@ struct }; label; witness; - control_flow = false; + control_flow = None; }; typ = e.typ; span = e.span; diff --git a/engine/backends/easycrypt/easycrypt_backend.ml b/engine/backends/easycrypt/easycrypt_backend.ml index ac3c74f50..9afc210a3 100644 --- a/engine/backends/easycrypt/easycrypt_backend.ml +++ b/engine/backends/easycrypt/easycrypt_backend.ml @@ -53,6 +53,7 @@ module RejectNotEC (FA : Features.T) = struct let monadic_binding = reject let arbitrary_lhs = reject let state_passing_loop = reject + let fold_like_loop = reject let nontrivial_lhs = reject let block = reject let for_loop = reject diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 2ac2ab8e0..7ebf2b3c7 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -42,6 +42,7 @@ module SubtypeToInputLanguage and type while_loop = Features.Off.while_loop and type for_index_loop = Features.Off.for_index_loop and type state_passing_loop = Features.Off.state_passing_loop + and type fold_like_loop = Features.Off.fold_like_loop and type match_guard = Features.Off.match_guard and type trait_item_default = Features.Off.trait_item_default) = struct @@ -1741,11 +1742,8 @@ module TransformToInputLanguage = |> Phases.Local_mutation |> Phases.Rewrite_control_flow |> Phases.Drop_return_break_continue - |> Phases.Reject.Continue - |> Phases.Reject.EarlyExit - |> Phases.Reject.QuestionMark - |> Phases.Reject.Break |> Phases.Functionalize_loops + |> Phases.Reject.Question_mark |> Phases.Reject.As_pattern |> Phases.Traits_specs |> Phases.Simplify_hoisting diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 3ec1552a1..b11884e22 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -75,6 +75,7 @@ struct let lifetime = reject let monadic_action = reject let monadic_binding = reject + let fold_like_loop = reject let block = reject let dyn = reject let match_guard = reject @@ -902,7 +903,6 @@ module TransformToInputLanguage = |> Phases.Trivialize_assign_lhs |> Side_effect_utils.Hoist |> Phases.Simplify_match_return - |> Phases.Drop_return_break_continue |> Phases.Local_mutation |> Phases.Reject.Continue |> Phases.Reject.Dyn diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 1bacf1e32..4bb5e2a50 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -217,6 +217,7 @@ functor and pat = { p : pat'; span : span; typ : ty } and field_pat = { field : global_ident; pat : pat } + and cf_kind = BreakOnly | BreakOrReturn and expr' = (* pure fragment *) @@ -262,7 +263,7 @@ functor body : expr; kind : loop_kind; state : loop_state option; - control_flow : bool; + control_flow : (cf_kind * F.fold_like_loop) option; label : string option; witness : F.loop; } @@ -313,23 +314,13 @@ functor and loop_kind = | UnconditionalLoop - | WhileLoop of { - condition : expr; - has_return : bool; - witness : F.while_loop; - } - | ForLoop of { - pat : pat; - it : expr; - has_return : bool; - witness : F.for_loop; - } + | WhileLoop of { condition : expr; witness : F.while_loop } + | ForLoop of { pat : pat; it : expr; witness : F.for_loop } | ForIndexLoop of { start : expr; end_ : expr; var : local_ident; var_typ : ty; - has_return : bool; witness : F.for_index_loop; } diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 4f4f81490..703dee7e0 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -1013,9 +1013,10 @@ module Make (F : Features.T) = struct Break e -> (Break (e, acc)) Continue -> (continue (acc)) *) - let make_control_flow_expr ~(span : span) ~(break_type : ty) + let make_control_flow_expr ~(span : span) ~(break_type : ty option) ~(return_type : ty option) ~(acc : expr) ?(e : expr = unit_expr span) (cf : [ `Return | `Break | `Continue ]) = + let break_type = Option.value ~default:unit_typ break_type in match cf with | `Return -> let continue_type = make_tuple_typ [ break_type; acc.typ ] in diff --git a/engine/lib/diagnostics.ml b/engine/lib/diagnostics.ml index 590b0aabe..1a1889544 100644 --- a/engine/lib/diagnostics.ml +++ b/engine/lib/diagnostics.ml @@ -53,7 +53,7 @@ module Phase = struct | TraitsSpecs | SimplifyMatchReturn | SimplifyHoisting - | DropNeedlessReturns + | DropReturnBreakContinue | TransformHaxLibInline | NewtypeAsRefinement | DummyA diff --git a/engine/lib/features.ml b/engine/lib/features.ml index 22a4a3909..9040d8192 100644 --- a/engine/lib/features.ml +++ b/engine/lib/features.ml @@ -4,6 +4,7 @@ loop, for_index_loop, while_loop, state_passing_loop, + fold_like_loop, continue, break, mutable_variable, @@ -40,6 +41,7 @@ module Rust = struct include Off.Monadic_action include Off.Monadic_binding include Off.State_passing_loop + include Off.Fold_like_loop include Off.Quote end diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index d940972c7..c099fd899 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -585,7 +585,7 @@ end) : EXPR = struct state = None; label = None; witness = W.loop; - control_flow = false; + control_flow = None; } | Match { scrutinee; arms } -> let scrutinee = c_expr scrutinee in diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index 339f38bdc..b1c57586a 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -7,128 +7,157 @@ open! Prelude -module Make (F : Features.T) = - Phase_utils.MakeMonomorphicPhase - (F) - (struct - let phase_id = Diagnostics.Phase.DropNeedlessReturns - - open Ast.Make (F) - module U = Ast_utils.Make (F) - module Visitors = Ast_visitors.Make (F) - - module Error = Phase_utils.MakeError (struct - let ctx = Diagnostics.Context.Phase phase_id +module%inlined_contents Make (F : Features.T) = struct + open Ast + module FA = F + + module FB = struct + include F + include Features.On.Fold_like_loop + include Features.Off.Early_exit + include Features.Off.Break + include Features.Off.Continue + end + + include + Phase_utils.MakeBase (F) (FB) + (struct + let phase_id = Diagnostics.Phase.DropReturnBreakContinue end) - type loop_info = { return_type : ty option; break_type : ty } - - let has_return = - object (_self) - inherit [_] Visitors.reduce as super - method zero = { return_type = None; break_type = U.unit_typ } - - method plus li1 li2 = - { - return_type = - (match (li1.return_type, li2.return_type) with - | Some t, _ | _, Some t -> Some t - | _ -> None); - break_type = - (if [%eq: ty] li1.break_type U.unit_typ then li2.break_type - else li1.break_type); - } - - method! visit_expr' () e = - match e with - | Return { e; _ } -> - { return_type = Some e.typ; break_type = U.unit_typ } - | Break { e; _ } -> { return_type = None; break_type = e.typ } - (* We should avoid catching returns and breaks of a nested - loops as they could have different types. *) - | Loop _ -> { return_type = None; break_type = U.unit_typ } - | _ -> super#visit_expr' () e - end - - let visitor = - object (self) - inherit [_] Visitors.map as _super - - method! visit_expr (in_loop : (loop_info * ty) option) e = - match (e, in_loop) with - | { e = Return { e; _ }; _ }, None -> e - (* we know [e] is on an exit position: the return is - thus useless, we can skip it *) - | { e = Let { monadic = None; lhs; rhs; body }; _ }, _ -> - let body = self#visit_expr in_loop body in - { - e with - e = Let { monadic = None; lhs; rhs; body }; - typ = body.typ; - } - (* If a let expression is an exit node, then it's body - is as well *) - | { e = Match { scrutinee; arms }; _ }, _ -> - let arms = List.map ~f:(self#visit_arm in_loop) arms in - let typ = - match arms with - | { arm; _ } :: _ -> arm.body.typ - | [] -> e.typ - in - { e with e = Match { scrutinee; arms }; typ } - | { e = If { cond; then_; else_ }; _ }, _ -> - let then_ = self#visit_expr in_loop then_ in - let else_ = Option.map ~f:(self#visit_expr in_loop) else_ in - { e with e = If { cond; then_; else_ }; typ = then_.typ } - | ( { e = Return { e; _ }; span; _ }, - Some ({ return_type; break_type }, acc_type) ) -> - U.make_control_flow_expr ~return_type ~span ~break_type ~e - ~acc:{ e with typ = acc_type } `Return - | ( { e = Break { e; acc = Some (_, acc); _ }; span; _ }, - Some ({ return_type; break_type }, _) ) -> - U.make_control_flow_expr ~return_type ~span ~break_type ~e ~acc - `Break - | ( { e = Continue { acc = Some (_, acc); _ }; span; _ }, - Some ({ return_type; break_type }, _) ) -> - U.make_control_flow_expr ~return_type ~span ~break_type ~acc - `Continue - | { span; _ }, Some ({ return_type; break_type }, _) -> - U.make_control_flow_expr ~return_type ~span ~break_type ~acc:e - `Continue - | _ -> e - (** The invariant here is that [visit_expr] is called only - on expressions that are on exit positions. [visit_expr] - is first called on root expressions, which are (by - definition) exit nodes. Then, [visit_expr] itself makes - recursive calls to sub expressions that are themselves - in exit nodes. **) - end - - let loop_visitor = - object (_self) - inherit [_] Visitors.map as super - - method! visit_expr () e = - match e.e with - | Loop ({ body; control_flow; _ } as loop) when control_flow -> - let acc_type = - match e.typ with - | TApp { ident; args = [ GType _; GType continue_type ] } - when Ast.Global_ident.equal ident - (Ast.Global_ident.of_name Type - Core__ops__control_flow__ControlFlow) -> - continue_type - | _ -> e.typ - in - let body = - visitor#visit_expr - (Some (has_return#visit_expr () body, acc_type)) - body - in - super#visit_expr () { e with e = Loop { loop with body } } - | _ -> super#visit_expr () e - end - - let ditems = - List.map ~f:(visitor#visit_item None >> loop_visitor#visit_item ()) - end) + module Implem : ImplemT.T = struct + let metadata = metadata + + module UA = Ast_utils.Make (F) + module UB = Ast_utils.Make (FB) + + module S = struct + include Features.SUBTYPE.Id + end + + (* break_type is "by default" unit since there always is a (possibly implicit) break type *) + type loop_info = { return_type : A.ty option; break_type : A.ty option } + + let has_return = + let module Visitors = Ast_visitors.Make (F) in + object (self) + inherit [_] Visitors.reduce as super + method zero = { return_type = None; break_type = None } + + method plus li1 li2 = + { + return_type = Option.first_some li1.return_type li2.return_type; + break_type = Option.first_some li1.break_type li2.break_type; + } + + method! visit_expr' () e = + match e with + | Return { e; _ } -> { return_type = Some e.typ; break_type = None } + | Break { e; _ } -> { return_type = None; break_type = Some e.typ } + (* We should avoid catching breaks of a nested + loops as they could have different types. *) + | Loop { body; _ } -> + { + return_type = (self#visit_expr () body).return_type; + break_type = None; + } + | _ -> super#visit_expr' () e + end + + let visitor = + let module Visitors = Ast_visitors.Make (F) in + object (self) + inherit [_] Visitors.map as _super + + method! visit_expr (in_loop : (loop_info * A.ty) option) e = + let span = e.span in + match (e.e, in_loop) with + | Return { e; _ }, None -> e + (* we know [e] is on an exit position: the return is + thus useless, we can skip it *) + | Let { monadic = None; lhs; rhs; body }, _ -> + let body = self#visit_expr in_loop body in + { + e with + e = Let { monadic = None; lhs; rhs; body }; + typ = body.typ; + } + (* If a let expression is an exit node, then it's body + is as well *) + | Match { scrutinee; arms }, _ -> + let arms = List.map ~f:(self#visit_arm in_loop) arms in + let typ = + match arms with { arm; _ } :: _ -> arm.body.typ | [] -> e.typ + in + { e with e = Match { scrutinee; arms }; typ } + | If { cond; then_; else_ }, _ -> + let then_ = self#visit_expr in_loop then_ in + let else_ = Option.map ~f:(self#visit_expr in_loop) else_ in + { e with e = If { cond; then_; else_ }; typ = then_.typ } + | Return { e; _ }, Some ({ return_type; break_type }, acc_type) -> + UA.make_control_flow_expr ~return_type ~span ~break_type ~e + ~acc:{ e with typ = acc_type } `Return + | ( Break { e; acc = Some (_, acc); _ }, + Some ({ return_type; break_type }, _) ) -> + UA.make_control_flow_expr ~return_type ~span ~break_type ~e ~acc + `Break + | ( Continue { acc = Some (_, acc); _ }, + Some ({ return_type; break_type }, _) ) -> + UA.make_control_flow_expr ~return_type ~span ~break_type ~acc + `Continue + | _, Some ({ return_type; break_type }, _) -> + UA.make_control_flow_expr ~return_type ~span ~break_type ~acc:e + `Continue + | _ -> e + (** The invariant here is that [visit_expr] is called only + on expressions that are on exit positions. [visit_expr] + is first called on root expressions, which are (by + definition) exit nodes. Then, [visit_expr] itself makes + recursive calls to sub expressions that are themselves + in exit nodes. **) + end + + [%%inline_defs dmutability + dsafety_kind] + + let rec dexpr' (span : span) (expr : A.expr') : B.expr' = + match expr with + | [%inline_arms "dexpr'.*" - Return - Break - Continue - Loop] -> auto + | Return _ | Break _ | Continue _ -> + Error.raise { kind = NonTrivialAndMutFnInput (*TODO Correct*); span } + | Loop { body; kind; state; label; witness; _ } -> + let control_flow_type = has_return#visit_expr () body in + let control_flow = + match control_flow_type with + | { return_type = Some _; _ } -> + Some (B.BreakOrReturn, Features.On.fold_like_loop) + | { break_type = Some _; _ } -> + Some (BreakOnly, Features.On.fold_like_loop) + | _ -> None + in + let acc_type = + match body.typ with + | TApp { ident; args = [ GType _; GType continue_type ] } + when Ast.Global_ident.equal ident + (Ast.Global_ident.of_name Type + Core__ops__control_flow__ControlFlow) -> + continue_type + | _ -> body.typ + in + let body = + visitor#visit_expr (Some (control_flow_type, acc_type)) body + |> dexpr + in + let kind = dloop_kind span kind in + let state = Option.map ~f:(dloop_state span) state in + Loop { body; control_flow; kind; state; label; witness } + [@@inline_ands bindings_of dexpr - dexpr'] + + [%%inline_defs "Item.*" - ditems] + + let ditems (items : A.item list) : B.item list = + List.concat_map items ~f:(visitor#visit_item None >> ditem) + end + + include Implem +end +[@@add "subtype.ml"] diff --git a/engine/lib/phases/phase_drop_return_break_continue.mli b/engine/lib/phases/phase_drop_return_break_continue.mli index fc3df33f5..b4e2d6d39 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.mli +++ b/engine/lib/phases/phase_drop_return_break_continue.mli @@ -5,4 +5,22 @@ and thus eliminate all `return`s. Inside loops it rewrites `return`, wrapper that will be handled by the specific fold operators introduced by phase `FunctionalizeLoops`. *) -module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE +module Make (F : Features.T) : sig + include module type of struct + module FA = F + + module FB = struct + include F + include Features.On.Fold_like_loop + include Features.Off.Early_exit + include Features.Off.Break + include Features.Off.Continue + end + + module A = Ast.Make (F) + module B = Ast.Make (FB) + module ImplemT = Phase_utils.MakePhaseImplemT (A) (B) + end + + include ImplemT.T +end diff --git a/engine/lib/phases/phase_functionalize_loops.ml b/engine/lib/phases/phase_functionalize_loops.ml index 3af6eadf6..28b3dff86 100644 --- a/engine/lib/phases/phase_functionalize_loops.ml +++ b/engine/lib/phases/phase_functionalize_loops.ml @@ -16,6 +16,7 @@ struct include Features.Off.While_loop include Features.Off.For_index_loop include Features.Off.State_passing_loop + include Features.Off.Fold_like_loop include Features.Off.Continue include Features.Off.Early_exit include Features.Off.Break @@ -43,18 +44,6 @@ struct invariant : (B.pat * B.expr) option; } - let has_cf = - object (_self) - inherit [_] Visitors.reduce as super - method zero = false - method plus = ( || ) - - method! visit_expr' () e = - match e with - | Return _ | Break _ | Continue _ -> true - | _ -> super#visit_expr' () e - end - let extract_loop_invariant (body : B.expr) : body_and_invariant = match body.e with | Let @@ -140,43 +129,48 @@ struct Some (ChunksExact { size; slice }) else None - let fn_args_of_iterator (has_cf : bool) (has_return : bool) (it : iterator) - : (Concrete_ident.name * B.expr list * B.ty) option = + let fn_args_of_iterator (cf : A.cf_kind option) (it : iterator) : + (Concrete_ident.name * B.expr list * B.ty) option = let open Concrete_ident_generated in let usize = B.TInt { size = SSize; signedness = Unsigned } in match it with | Enumerate (ChunksExact { size; slice }) -> let fold_op = - if has_return then - Rust_primitives__hax__folds__fold_enumerated_chunked_slice_return - else if has_cf then - Rust_primitives__hax__folds__fold_enumerated_chunked_slice_cf - else Rust_primitives__hax__folds__fold_enumerated_chunked_slice + match cf with + | Some BreakOrReturn -> + Rust_primitives__hax__folds__fold_enumerated_chunked_slice_return + | Some BreakOnly -> + Rust_primitives__hax__folds__fold_enumerated_chunked_slice_cf + | None -> Rust_primitives__hax__folds__fold_enumerated_chunked_slice in Some (fold_op, [ size; slice ], usize) | Enumerate (Slice slice) -> let fold_op = - if has_return then - Rust_primitives__hax__folds__fold_enumerated_slice_return - else if has_cf then - Rust_primitives__hax__folds__fold_enumerated_slice_cf - else Rust_primitives__hax__folds__fold_enumerated_slice + match cf with + | Some BreakOrReturn -> + Rust_primitives__hax__folds__fold_enumerated_slice_return + | Some BreakOnly -> + Rust_primitives__hax__folds__fold_enumerated_slice_cf + | None -> Rust_primitives__hax__folds__fold_enumerated_slice in Some (fold_op, [ slice ], usize) | StepBy { n; it = Range { start; end_ } } -> let fold_op = - if has_return then - Rust_primitives__hax__folds__fold_range_step_by_return - else if has_cf then - Rust_primitives__hax__folds__fold_range_step_by_cf - else Rust_primitives__hax__folds__fold_range_step_by + match cf with + | Some BreakOrReturn -> + Rust_primitives__hax__folds__fold_range_step_by_return + | Some BreakOnly -> + Rust_primitives__hax__folds__fold_range_step_by_cf + | None -> Rust_primitives__hax__folds__fold_range_step_by in Some (fold_op, [ start; end_; n ], start.typ) | Range { start; end_ } -> let fold_op = - if has_return then Rust_primitives__hax__folds__fold_range_return - else if has_cf then Rust_primitives__hax__folds__fold_range_cf - else Rust_primitives__hax__folds__fold_range + match cf with + | Some BreakOrReturn -> + Rust_primitives__hax__folds__fold_range_return + | Some BreakOnly -> Rust_primitives__hax__folds__fold_range_cf + | None -> Rust_primitives__hax__folds__fold_range in Some (fold_op, [ start; end_ ], start.typ) | _ -> None @@ -191,7 +185,7 @@ struct | Loop { body; - kind = ForLoop { it; pat; has_return; _ }; + kind = ForLoop { it; pat; _ }; state = Some _ as state; control_flow; _; @@ -199,9 +193,9 @@ struct | Loop { body; - kind = ForLoop { it; pat; has_return = true as has_return; _ }; + kind = ForLoop { it; pat; _ }; state; - control_flow; + control_flow = Some (BreakOrReturn, _) as control_flow; _; } -> let bpat, init = @@ -216,11 +210,9 @@ struct let it = dexpr it in let pat = dpat pat in let fn : B.expr = UB.make_closure [ bpat; pat ] body body.span in + let cf = Option.map ~f:fst control_flow in let f, kind, args = - match - as_iterator it - |> Option.bind ~f:(fn_args_of_iterator control_flow has_return) - with + match as_iterator it |> Option.bind ~f:(fn_args_of_iterator cf) with | Some (f, args, typ) -> (* TODO what happens if there is control flow? *) let invariant : B.expr = @@ -234,9 +226,11 @@ struct (f, Concrete_ident.Kind.Value, args @ [ invariant; init; fn ]) | None -> let fold : Concrete_ident.name = - if has_return then Rust_primitives__hax__folds__fold_return - else if control_flow then Rust_primitives__hax__folds__fold_cf - else Core__iter__traits__iterator__Iterator__fold + match cf with + | Some BreakOrReturn -> + Rust_primitives__hax__folds__fold_return + | Some BreakOnly -> Rust_primitives__hax__folds__fold_cf + | None -> Core__iter__traits__iterator__Iterator__fold in (fold, AssociatedItem Value, [ it; init; fn ]) in @@ -244,7 +238,7 @@ struct | Loop { body; - kind = WhileLoop { condition; has_return; _ }; + kind = WhileLoop { condition; _ }; state = Some _ as state; control_flow; _; @@ -252,9 +246,9 @@ struct | Loop { body; - kind = WhileLoop { condition; has_return = true as has_return; _ }; + kind = WhileLoop { condition; _ }; state; - control_flow; + control_flow = Some (BreakOrReturn, _) as control_flow; _; } -> let bpat, init = @@ -277,9 +271,10 @@ struct ~span:body.span in let fold_operator : Concrete_ident.name = - if has_return then Rust_primitives__hax__while_loop_return - else if control_flow then Rust_primitives__hax__while_loop_cf - else Rust_primitives__hax__while_loop + match control_flow with + | Some (BreakOrReturn, _) -> Rust_primitives__hax__while_loop_return + | Some (BreakOnly, _) -> Rust_primitives__hax__while_loop_cf + | None -> Rust_primitives__hax__while_loop in UB.call ~kind:(AssociatedItem Value) fold_operator [ condition; init; body ] span (dty span expr.typ) diff --git a/engine/lib/phases/phase_functionalize_loops.mli b/engine/lib/phases/phase_functionalize_loops.mli index ccfbe9c15..a27824364 100644 --- a/engine/lib/phases/phase_functionalize_loops.mli +++ b/engine/lib/phases/phase_functionalize_loops.mli @@ -15,6 +15,7 @@ module Make include Features.Off.For_loop include Features.Off.For_index_loop include Features.Off.State_passing_loop + include Features.Off.Fold_like_loop end module A = Ast.Make (F) diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index 7a36f2155..8d1a42d98 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -259,7 +259,7 @@ struct span = expr.span; typ = e.typ; } - | Loop { body; kind; state; label; witness; control_flow } -> + | Loop { body; kind; state; label; witness; _ } -> let variables_to_output = s.expr_level in (* [adapt]: should we reorder shadowings? *) let observable_mutations, adapt = @@ -326,7 +326,8 @@ struct let typ = List.map ~f:snd observable_mutations |> UB.make_tuple_typ in let loop : B.expr = { - e = Loop { body; kind; state; label; witness; control_flow }; + e = + Loop { body; kind; state; label; witness; control_flow = None }; typ; span; } diff --git a/engine/lib/phases/phase_reconstruct_for_index_loops.ml b/engine/lib/phases/phase_reconstruct_for_index_loops.ml index cc433a864..4ecdfceca 100644 --- a/engine/lib/phases/phase_reconstruct_for_index_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_index_loops.ml @@ -84,7 +84,6 @@ module%inlined_contents Make (FA : Features.T) = struct end_ = dexpr end_; var; var_typ = dty span typ; - has_return = false; witness = Features.On.for_index_loop; } | [%inline_arms "dloop_kind.*"] -> auto diff --git a/engine/lib/phases/phase_reconstruct_for_loops.ml b/engine/lib/phases/phase_reconstruct_for_loops.ml index 57cc7c852..b5e0fb960 100644 --- a/engine/lib/phases/phase_reconstruct_for_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_loops.ml @@ -251,12 +251,11 @@ struct it = dexpr it; pat = dpat pat; witness = Features.On.for_loop; - has_return = false; }; state = Option.map ~f:(dloop_state expr.span) state; label; witness = S.loop expr.span witness; - control_flow = false; + control_flow = None; }; span = expr.span; typ = UB.unit_typ; diff --git a/engine/lib/phases/phase_reconstruct_while_loops.ml b/engine/lib/phases/phase_reconstruct_while_loops.ml index 3edd09036..b95181bcf 100644 --- a/engine/lib/phases/phase_reconstruct_while_loops.ml +++ b/engine/lib/phases/phase_reconstruct_while_loops.ml @@ -91,12 +91,11 @@ module%inlined_contents Make (FA : Features.T) = struct { condition = dexpr condition; witness = Features.On.while_loop; - has_return = false; }; state = Option.map ~f:(dloop_state expr.span) state; label; witness = S.loop expr.span witness; - control_flow = false; + control_flow = None; }; span = expr.span; typ = UB.unit_typ; diff --git a/engine/lib/phases/phase_reject.ml b/engine/lib/phases/phase_reject.ml index 434fb02cd..4e314e915 100644 --- a/engine/lib/phases/phase_reject.ml +++ b/engine/lib/phases/phase_reject.ml @@ -41,25 +41,7 @@ end module _ (FA : Features.T) : Phase_utils.PHASE = Continue (FA) -module Break (FA : Features.T) = struct - module FB = struct - include FA - include Features.Off.Break - end - - include - Feature_gate.Make (FA) (FB) - (struct - module A = FA - module B = FB - include Feature_gate.DefaultSubtype - - let break = reject - let metadata = make_metadata Break - end) -end - -module QuestionMark (FA : Features.T) = struct +module Question_mark (FA : Features.T) = struct module FB = struct include FA include Features.Off.Question_mark @@ -77,8 +59,7 @@ module QuestionMark (FA : Features.T) = struct end) end -module _ (FA : Features.T) : Phase_utils.PHASE = Continue (FA) -module _ (FA : Features.T) : Phase_utils.PHASE = Break (FA) +module _ (FA : Features.T) : Phase_utils.PHASE = Question_mark (FA) module RawOrMutPointer (FA : Features.T) = struct module FB = struct diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 820b41b2b..07cdcda52 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -71,20 +71,6 @@ module Make (F : Features.T) = U.make_control_flow_type ~continue_type:loop.typ ~break_type:return_type in - let loop = - match loop.e with - | Loop ({ kind; _ } as loop_info) -> - let kind = - match kind with - | ForLoop for_loop -> - ForLoop { for_loop with has_return = true } - | WhileLoop while_loop -> - WhileLoop { while_loop with has_return = true } - | _ -> kind - in - { loop with e = Loop { loop_info with kind } } - | _ -> loop - in let loop = { loop with typ } in let span = loop.span in let id = U.fresh_local_ident_in [] "ret" in @@ -113,19 +99,10 @@ module Make (F : Features.T) = | _ when not (has_return#visit_expr true e) -> e | Loop loop -> let return_inside = has_return#visit_expr false loop.body in - let control_flow = - return_inside || loop_has_cf#visit_expr () loop.body - in let loop_expr = { e with - e = - Loop - { - loop with - body = self#visit_expr true loop.body; - control_flow; - }; + e = Loop { loop with body = self#visit_expr true loop.body }; } in if return_inside then @@ -174,11 +151,7 @@ module Make (F : Features.T) = rhs with e = Loop - { - loop with - control_flow = true; - body = self#visit_expr true loop.body; - }; + { loop with body = self#visit_expr true loop.body }; } in U.make_lets stmts_before diff --git a/engine/lib/side_effect_utils.ml b/engine/lib/side_effect_utils.ml index 3fb874fe2..77343161b 100644 --- a/engine/lib/side_effect_utils.ml +++ b/engine/lib/side_effect_utils.ml @@ -305,12 +305,10 @@ struct HoistSeq.many env kind_state (fun l effects -> let kind = match (l, kind) with - | ( condition :: ([ _ ] | []), - WhileLoop { witness; has_return; _ } ) -> - WhileLoop { condition; has_return; witness } - | ( it :: ([ _ ] | []), - ForLoop { pat; witness; has_return; _ } ) -> - ForLoop { pat; witness; has_return; it } + | condition :: ([ _ ] | []), WhileLoop { witness; _ } -> + WhileLoop { condition; witness } + | it :: ([ _ ] | []), ForLoop { pat; witness; _ } -> + ForLoop { pat; witness; it } | ([ _ ] | []), UnconditionalLoop -> UnconditionalLoop | _, ForIndexLoop _ -> . | _ -> HoistSeq.err_hoist_invariant e.span Stdlib.__LOC__ diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index 6698e045e..63e223201 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -243,7 +243,14 @@ struct kind = dloop_kind span kind; state = Option.map ~f:(dloop_state span) state; label; - control_flow; + control_flow = + Option.map + ~f: + ((function + | A.BreakOnly -> B.BreakOnly + | A.BreakOrReturn -> B.BreakOrReturn) + *** S.fold_like_loop span) + control_flow; witness = S.loop span witness; } | Break { e; acc; label; witness } -> @@ -308,29 +315,19 @@ struct and dloop_kind (span : span) (k : A.loop_kind) : B.loop_kind = match k with | UnconditionalLoop -> UnconditionalLoop - | WhileLoop { condition; witness; has_return } -> + | WhileLoop { condition; witness } -> WhileLoop - { - condition = dexpr condition; - has_return; - witness = S.while_loop span witness; - } - | ForLoop { it; pat; has_return; witness } -> + { condition = dexpr condition; witness = S.while_loop span witness } + | ForLoop { it; pat; witness } -> ForLoop - { - it = dexpr it; - pat = dpat pat; - has_return; - witness = S.for_loop span witness; - } - | ForIndexLoop { start; end_; var; var_typ; has_return; witness } -> + { it = dexpr it; pat = dpat pat; witness = S.for_loop span witness } + | ForIndexLoop { start; end_; var; var_typ; witness } -> ForIndexLoop { start = dexpr start; end_ = dexpr end_; var; var_typ = dty span var_typ; - has_return; witness = S.for_index_loop span witness; } From beb2e151c05ebe86c27a3a3cc92650a2670083f2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 23 Oct 2024 17:21:49 +0200 Subject: [PATCH 125/253] Split `solve_item_traits` in two --- frontend/exporter/src/constant_utils.rs | 2 +- frontend/exporter/src/traits.rs | 36 ++++++++++++++++++------- frontend/exporter/src/types/mir.rs | 8 +++--- frontend/exporter/src/types/thir.rs | 2 +- frontend/exporter/src/types/ty.rs | 5 ++-- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 483598d0c..867ac44f7 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -433,7 +433,7 @@ mod rustc { // Solve the trait obligations let parent_def_id = tcx.parent(ucv.def); - let trait_refs = solve_item_traits(s, parent_def_id, ucv.args); + let trait_refs = solve_item_required_traits(s, parent_def_id, ucv.args); // Convert let id = ucv.def.sinto(s); diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 92976db5f..fc162289c 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -176,24 +176,40 @@ pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>( /// in the current context. #[cfg(feature = "rustc")] #[tracing::instrument(level = "trace", skip(s), ret)] -pub fn solve_item_traits<'tcx, S: UnderOwnerState<'tcx>>( +pub fn solve_item_required_traits<'tcx, S: UnderOwnerState<'tcx>>( s: &S, def_id: RDefId, generics: ty::GenericArgsRef<'tcx>, +) -> Vec { + let predicates = required_predicates(s.base().tcx, def_id); + solve_item_traits_inner(s, generics, predicates) +} + +/// Solve the trait obligations for implementing a trait (or for trait associated type bounds) in +/// the current context. +#[cfg(feature = "rustc")] +#[tracing::instrument(level = "trace", skip(s), ret)] +pub fn solve_item_implied_traits<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + def_id: RDefId, + generics: ty::GenericArgsRef<'tcx>, +) -> Vec { + let predicates = implied_predicates(s.base().tcx, def_id); + solve_item_traits_inner(s, generics, predicates) +} + +/// Apply the given generics to the provided clauses and resolve the trait references in the +/// current context. +#[cfg(feature = "rustc")] +fn solve_item_traits_inner<'tcx, S: UnderOwnerState<'tcx>>( + s: &S, + generics: ty::GenericArgsRef<'tcx>, + predicates: impl Iterator>, ) -> Vec { let tcx = s.base().tcx; let param_env = s.param_env(); - // We can't use `required_predicates` alone because this is called to resolve trait implied - // predicates too. - // TODO: stop doing that - let predicates: Vec<_> = match tcx.def_kind(def_id) { - rustc_hir::def::DefKind::Trait => implied_predicates(tcx, def_id).collect(), - _ => required_predicates(tcx, def_id).collect(), - }; - predicates - .into_iter() .filter_map(|clause| clause.as_trait_clause()) .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) // Substitute the item generics diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index b16188e97..11b230421 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -315,7 +315,7 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H // fn foo(...) // ^^^ // ``` - let mut trait_refs = solve_item_traits(s, def_id, generics); + let mut trait_refs = solve_item_required_traits(s, def_id, generics); // Check if this is a trait method call: retrieve the trait source if // it is the case (i.e., where does the method come from? Does it refer @@ -397,7 +397,7 @@ pub(crate) fn get_function_from_def_id_and_generics<'tcx, S: BaseState<'tcx> + H let container_generics = tcx.generics_of(container_def_id); let container_generics = generics.truncate_to(tcx, container_generics); let container_trait_refs = - solve_item_traits(s, container_def_id, container_generics); + solve_item_required_traits(s, container_def_id, container_generics); trait_refs.extend(container_trait_refs); (generics.sinto(s), Option::None) } @@ -950,7 +950,7 @@ pub enum AggregateKind { Tuple, #[custom_arm(rustc_middle::mir::AggregateKind::Adt(def_id, vid, generics, annot, fid) => { let adt_kind = s.base().tcx.adt_def(def_id).adt_kind().sinto(s); - let trait_refs = solve_item_traits(s, *def_id, generics); + let trait_refs = solve_item_required_traits(s, *def_id, generics); AggregateKind::Adt( def_id.sinto(s), vid.sinto(s), @@ -984,7 +984,7 @@ pub enum AggregateKind { let generics = tcx.mk_args(parent_generics); // TODO: does this handle nested closures? let parent = tcx.generics_of(rust_id).parent.unwrap(); - let trait_refs = solve_item_traits(s, parent, generics); + let trait_refs = solve_item_required_traits(s, parent, generics); AggregateKind::Closure(def_id, parent_generics.sinto(s), trait_refs, sig) })] diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index 79e159324..a7c991bbd 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -589,7 +589,7 @@ pub enum ExprKind { Some((impl_expr, assoc_generics)) })(); generic_args = translated_generics; - bounds_impls = solve_item_traits(gstate, *def_id, generics); + bounds_impls = solve_item_required_traits(gstate, *def_id, generics); Expr { contents, span: e.span.sinto(gstate), diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index 343d9bd13..7f55155ef 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -792,7 +792,7 @@ pub enum TyKind { ty::TyKind::Adt(adt_def, generics) => { let def_id = adt_def.did().sinto(state); let generic_args: Vec = generics.sinto(state); - let trait_refs = solve_item_traits(state, adt_def.did(), generics); + let trait_refs = solve_item_required_traits(state, adt_def.did(), generics); TyKind::Adt { def_id, generic_args, trait_refs } }, )] @@ -1322,7 +1322,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<' trait_ref: trait_ref.sinto(s), is_positive: matches!(polarity, ty::ImplPolarity::Positive), }; - let required_impl_exprs = solve_item_traits(s, trait_ref.def_id, trait_ref.args); + let required_impl_exprs = + solve_item_implied_traits(s, trait_ref.def_id, trait_ref.args); ImplSubject::Trait { trait_pred, required_impl_exprs, From 32ae13658728453f0db5fdf4d3d69c00f529de55 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 23 Oct 2024 17:28:05 +0200 Subject: [PATCH 126/253] refactor(exporter/id_table): simplify a lot `WithTable` deserializer Thanks @nadrieril! --- engine/bin/lib.ml | 54 +++++++------- frontend/exporter/src/id_table.rs | 113 +++++------------------------- 2 files changed, 45 insertions(+), 122 deletions(-) diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index bbab16f5e..ce415c260 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -142,38 +142,36 @@ let run (options : Types.engine_options) : Types.output = (** Shallow parses a `id_table::Node` (or a raw `T`) JSON *) let parse_id_table_node (json : Yojson.Safe.t) : - (int64 * Yojson.Safe.t) list option * Yojson.Safe.t = - let expect_assoc = function - | `Assoc alist -> Some (List.Assoc.find ~equal:[%eq: string] alist) - | _ -> None - in + (int64 * Yojson.Safe.t) list * Yojson.Safe.t = let expect_uint64 = function | `Intlit str -> Some (Int64.of_string str) | `Int id -> Some (Int.to_int64 id) | _ -> None in - (let* assoc = expect_assoc json in - let* table = assoc "table" in - let* value = assoc "value" in - let table = - match table with - | `List json_list -> json_list - | _ -> failwith "parse_cached: `map` is supposed to be a list" - in - let table = - List.map - ~f:(function - | `List [ id; `Assoc [ (_, contents) ] ] -> - let id = - expect_uint64 id - |> Option.value_exn ~message:"parse_cached: id: expected int64" - in - (id, contents) - | _ -> failwith "parse_cached: expected a list of size two") - table - in - Some (Some table, value)) - |> Option.value ~default:(None, json) + let table, value = + match json with + | `List [ table; value ] -> (table, value) + | _ -> failwith "parse_id_table_node: expected a tuple at top-level" + in + let table = + match table with + | `List json_list -> json_list + | _ -> failwith "parse_id_table_node: `map` is supposed to be a list" + in + let table = + List.map + ~f:(function + | `List [ id; `Assoc [ (_, contents) ] ] -> + let id = + expect_uint64 id + |> Option.value_exn + ~message:"parse_id_table_node: id: expected int64" + in + (id, contents) + | _ -> failwith "parse_id_table_node: expected a list of size two") + table + in + (table, value) (** Entrypoint of the engine. Assumes `Hax_io.init` was called. *) let main () = @@ -181,7 +179,7 @@ let main () = let table, json = Hax_io.read_json () |> Option.value_exn |> parse_id_table_node in - table |> Option.value ~default:[] + table |> List.iter ~f:(fun (id, json) -> Hashtbl.add_exn Types.cache_map ~key:id ~data:(`JSON json)); Types.parse_engine_options json diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index d80517d2e..70f503d0b 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -175,7 +175,7 @@ impl> Node { /// inside it. Serializing `WithTable` will serialize IDs only, /// skipping values. Deserialization of a `WithTable` will /// automatically use the table and IDs to reconstruct skipped values. -#[derive(Serialize, Debug)] +#[derive(Debug)] pub struct WithTable { table: Table, value: T, @@ -213,11 +213,14 @@ impl WithTable { } } -/// Helper function that makes sure no nested deserializations occur. -fn full_id_deserialization(f: impl FnOnce() -> T) -> T { - let _lock: MutexGuard<_> = DESERIALIZATION_STATE_LOCK.try_lock().expect("CACHE_MAP_LOCK: only one WithTable deserialization can occur at a time (nesting is forbidden)"); - let result = f(); - result +impl Serialize for WithTable { + fn serialize(&self, serializer: S) -> Result { + let mut ts = serializer.serialize_tuple_struct("WithTable", 2)?; + use serde::ser::SerializeTupleStruct; + ts.serialize_field(&self.table)?; + ts.serialize_field(&self.value)?; + ts.end() + } } /// The deserializer of `WithTable` is special. We first decode the @@ -230,94 +233,13 @@ impl<'de, T: Deserialize<'de>> serde::Deserialize<'de> for WithTable { where D: serde::Deserializer<'de>, { - use serde::de::{self, Deserialize, MapAccess, SeqAccess, Visitor}; - use std::fmt; - use std::marker::PhantomData; - #[derive(Deserialize, Debug)] - #[serde(field_identifier, rename_all = "lowercase")] - enum Field { - Table, - Value, - } - - struct WithTableVisitor(PhantomData); - - impl<'de, T: Deserialize<'de>> Visitor<'de> for WithTableVisitor { - type Value = WithTable; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("struct WithTable") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let (table, value) = - full_id_deserialization::>(|| { - let previous = std::mem::take(&mut *DESERIALIZATION_STATE.lock().unwrap()); - // Deserializing `Node`s populates `DESERIALIZATION_STATE`: the table - // is already constructed in `DESERIALIZATION_STATE`, we discard it below. - let _: Table = seq - .next_element()? - .ok_or_else(|| de::Error::invalid_length(0, &self))?; - let value = seq.next_element::().and_then(|inner| { - inner.ok_or_else(|| de::Error::invalid_length(1, &self)) - }); - let table = std::mem::replace( - &mut *DESERIALIZATION_STATE.lock().unwrap(), - previous, - ); - let value = value?; - Ok((table, value)) - })?; - Ok(Self::Value { table, value }) - } - - fn visit_map(self, mut map: V) -> Result - where - V: MapAccess<'de>, - { - let (table, value) = full_id_deserialization::>( - || { - let (table_key, table): (Field, Table) = map - .next_entry()? - .ok_or(de::Error::custom("Expected field `table` *first*"))?; - if !matches!(table_key, Field::Table) { - Err(de::Error::custom("Expected field `table` *first*"))? - } - let previous = - std::mem::replace(&mut *DESERIALIZATION_STATE.lock().unwrap(), table); - - let value_result = map.next_entry::().and_then(|inner| { - inner.ok_or_else(|| { - de::Error::custom("Expected field `value`, got something else? Seems like the type is wrong.") - }) - }); - let table = std::mem::replace( - &mut *DESERIALIZATION_STATE.lock().unwrap(), - previous, - ); - let (value_key, value) = value_result?; - if !matches!(value_key, Field::Value) { - Err(de::Error::custom(&format!( - "Expected field `value`, found {:#?}", - value_key - )))? - } - if let Some(field) = map.next_key()? { - Err(de::Error::unknown_field(field, &["nothing left"]))? - } - Ok((table, value)) - }, - )?; - Ok(Self::Value { table, value }) - } - } - - const FIELDS: &[&str] = &["table", "value"]; - let r = deserializer.deserialize_struct("WithTable", FIELDS, WithTableVisitor(PhantomData)); - r + let _lock: MutexGuard<_> = DESERIALIZATION_STATE_LOCK.try_lock().expect("CACHE_MAP_LOCK: only one WithTable deserialization can occur at a time (nesting is forbidden)"); + use serde_repr::WithTableRepr; + let previous = std::mem::take(&mut *DESERIALIZATION_STATE.lock().unwrap()); + let with_table_repr = WithTableRepr::deserialize(deserializer); + *DESERIALIZATION_STATE.lock().unwrap() = previous; + let WithTableRepr(table, value) = with_table_repr?; + Ok(Self { table, value }) } } @@ -336,6 +258,9 @@ mod serde_repr { pub(super) struct Pair(Id, Value); pub(super) type SortedIdValuePairs = Vec; + #[derive(Serialize, Deserialize)] + pub(super) struct WithTableRepr(pub(super) Table, pub(super) T); + impl> Into> for Node { fn into(self) -> NodeRepr { let value = if serialize_use_id() { From 8af502401a745a524e3226f11c5da730101e5e93 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 23 Oct 2024 17:40:04 +0200 Subject: [PATCH 127/253] Move constrol flow builders to Ast_builders. --- engine/lib/ast_builder.ml | 160 ++++++++++++++++++ engine/lib/ast_utils.ml | 127 -------------- .../phase_drop_return_break_continue.ml | 8 +- .../lib/phases/phase_rewrite_control_flow.ml | 33 ++-- 4 files changed, 174 insertions(+), 154 deletions(-) diff --git a/engine/lib/ast_builder.ml b/engine/lib/ast_builder.ml index 851477048..d6bbefe09 100644 --- a/engine/lib/ast_builder.ml +++ b/engine/lib/ast_builder.ml @@ -22,6 +22,24 @@ module Make (F : Features.T) = struct let ty_tuple_or_id : ty list -> ty = function | [ ty ] -> ty | types -> ty_tuple types + + let ty_control_flow ~(continue_type : ty) ~(break_type : ty) : ty = + TApp + { + ident = Global_ident.of_name Type Core__ops__control_flow__ControlFlow; + args = [ GType break_type; GType continue_type ]; + } + + let ty_cf_return ~(acc_type : ty) ~(break_type : ty) + ~(return_type : ty option) : ty = + let break_type = ty_tuple [ break_type; acc_type ] in + match return_type with + | Some ret_ty -> + let break_type = + ty_control_flow ~break_type:ret_ty ~continue_type:break_type + in + ty_control_flow ~break_type ~continue_type:acc_type + | None -> ty_control_flow ~break_type ~continue_type:acc_type end include NoSpan @@ -29,10 +47,148 @@ module Make (F : Features.T) = struct module Explicit = struct let ty_unit : ty = TApp { ident = `TupleType 0; args = [] } let expr_unit = expr_GlobalVar (`TupleCons 0) ~typ:ty_unit + + let expr_tuple ~(span : span) (tuple : expr list) = + let len = List.length tuple in + let fields = List.mapi ~f:(fun i x -> (`TupleField (i, len), x)) tuple in + let typ = NoSpan.ty_tuple @@ List.map ~f:(fun { typ; _ } -> typ) tuple in + expr_Construct ~span ~typ ~constructor:(`TupleCons len) ~is_record:false + ~is_struct:true ~fields ~base:None + let pat_PBinding ~typ = pat_PBinding ~inner_typ:typ ~typ let arm ~span arm_pat ?(guard = None) body = { arm = { arm_pat; body; guard }; span } + + let pat_Constructor_CF ~(span : span) ~(typ : ty) + (cf : [ `Break | `Continue ]) (pat : pat) = + match cf with + | `Break -> + { + p = + PConstruct + { + name = + Global_ident.of_name + (Constructor { is_struct = false }) + Core__ops__control_flow__ControlFlow__Break; + args = + [ + { + field = + Global_ident.of_name Field + Core__ops__control_flow__ControlFlow__Break__0; + pat; + }; + ]; + is_record = false; + is_struct = false; + }; + typ; + span; + } + | `Continue -> + { + p = + PConstruct + { + name = + Global_ident.of_name + (Constructor { is_struct = false }) + Core__ops__control_flow__ControlFlow__Continue; + args = + [ + { + field = + Global_ident.of_name Field + Core__ops__control_flow__ControlFlow__Continue__0; + pat; + }; + ]; + is_record = false; + is_struct = false; + }; + typ; + span; + } + + let call_Constructor' (constructor : global_ident) is_struct + (args : expr list) span ret_typ = + let mk_field = + let len = List.length args in + fun n -> `TupleField (len, n) + in + let fields = List.mapi ~f:(fun i arg -> (mk_field i, arg)) args in + { + e = + Construct + { constructor; is_record = false; is_struct; fields; base = None }; + typ = ret_typ; + span; + } + + let call_Constructor (constructor_name : Concrete_ident.name) + (is_struct : bool) (args : expr list) span ret_typ = + call_Constructor' + (`Concrete + (Concrete_ident.of_name (Constructor { is_struct }) constructor_name)) + is_struct args span ret_typ + + let expr'_Constructor_CF ~(span : span) ~(break_type : ty) + ?(continue_type : ty = ty_unit) (cf : [ `Break | `Continue ]) (e : expr) + = + let typ = NoSpan.ty_control_flow ~continue_type ~break_type in + match cf with + | `Break -> + call_Constructor Core__ops__control_flow__ControlFlow__Break false + [ e ] span typ + | `Continue -> + call_Constructor Core__ops__control_flow__ControlFlow__Continue false + [ e ] span typ + + (* We use the following encoding of return, break and continue in the `ControlFlow` enum: + Return e -> Break (Break e) + Break e -> Break ((Continue(e, acc))) + Continue -> Continue(acc) + + In case there is no return we simplify to: + Break e -> (Break (e, acc)) + Continue -> (continue (acc)) + *) + let expr_Constructor_CF ~(span : span) ~(break_type : ty option) + ~(return_type : ty option) ~(acc : expr) ?(e : expr = expr_unit ~span) + (cf : [ `Return | `Break | `Continue ]) = + let break_type = Option.value ~default:ty_unit break_type in + match cf with + | `Return -> + let continue_type = NoSpan.ty_tuple [ break_type; acc.typ ] in + let inner = + expr'_Constructor_CF ~break_type:e.typ ~continue_type ~span `Break e + in + expr'_Constructor_CF ~span ~break_type:inner.typ + ~continue_type:acc.typ `Break inner + | `Break -> + let tuple = expr_tuple ~span [ e; acc ] in + let inner = + match return_type with + | Some ret_typ -> + expr'_Constructor_CF ~span ~break_type:ret_typ + ~continue_type:tuple.typ `Continue tuple + | None -> tuple + in + expr'_Constructor_CF ~span ~break_type:inner.typ + ~continue_type:acc.typ `Break inner + | `Continue -> + let break_type = + let tuple_type = NoSpan.ty_tuple [ break_type; acc.typ ] in + match return_type with + | Some ret_typ -> + NoSpan.ty_control_flow ~break_type:ret_typ + ~continue_type:tuple_type + | None -> tuple_type + in + expr'_Constructor_CF ~span ~break_type ~continue_type:acc.typ + `Continue acc end include Explicit @@ -44,6 +200,10 @@ module Make (F : Features.T) = struct let pat_PBinding = Explicit.pat_PBinding ~span let expr_unit = expr_unit ~span + let expr_tuple = expr_tuple ~span + let pat_Constructor_CF = pat_Constructor_CF ~span + let expr'_Constructor_CF = expr'_Constructor_CF ~span + let expr_Constructor_CF = expr_Constructor_CF ~span let arm ?(guard = None) = arm ~span ?guard end diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 703dee7e0..d8e072ac6 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -922,133 +922,6 @@ module Make (F : Features.T) = struct let e = Closure { params; body; captures = [] } in { e; typ = TArrow (List.map ~f:(fun p -> p.typ) params, body.typ); span } - let make_control_flow_type ~(continue_type : ty) ~(break_type : ty) : ty = - TApp - { - ident = Global_ident.of_name Type Core__ops__control_flow__ControlFlow; - args = [ GType break_type; GType continue_type ]; - } - - let make_cf_return_type ~(acc_type : ty) ~(break_type : ty) - ~(return_type : ty option) : ty = - let break_type = make_tuple_typ [ break_type; acc_type ] in - match return_type with - | Some ret_ty -> - let break_type = - make_control_flow_type ~break_type:ret_ty ~continue_type:break_type - in - make_control_flow_type ~break_type ~continue_type:acc_type - | None -> make_control_flow_type ~break_type ~continue_type:acc_type - - let make_control_flow_pat ~(span : span) ~(typ : ty) - (cf : [ `Break | `Continue ]) (pat : pat) = - match cf with - | `Break -> - { - p = - PConstruct - { - name = - Global_ident.of_name - (Constructor { is_struct = false }) - Core__ops__control_flow__ControlFlow__Break; - args = - [ - { - field = - Global_ident.of_name Field - Core__ops__control_flow__ControlFlow__Break__0; - pat; - }; - ]; - is_record = false; - is_struct = false; - }; - typ; - span; - } - | `Continue -> - { - p = - PConstruct - { - name = - Global_ident.of_name - (Constructor { is_struct = false }) - Core__ops__control_flow__ControlFlow__Continue; - args = - [ - { - field = - Global_ident.of_name Field - Core__ops__control_flow__ControlFlow__Continue__0; - pat; - }; - ]; - is_record = false; - is_struct = false; - }; - typ; - span; - } - - let make_control_flow_expr' ~(span : span) ~(break_type : ty) - ?(continue_type : ty = unit_typ) (cf : [ `Break | `Continue ]) (e : expr) - = - let typ = make_control_flow_type ~continue_type ~break_type in - match cf with - | `Break -> - call_Constructor Core__ops__control_flow__ControlFlow__Break false [ e ] - span typ - | `Continue -> - call_Constructor Core__ops__control_flow__ControlFlow__Continue false - [ e ] span typ - - (* We use the following encoding of return, break and continue in the `ControlFlow` enum: - Return e -> Break (Break e) - Break e -> Break ((Continue(e, acc))) - Continue -> Continue(acc) - - In case there is no return we simplify to: - Break e -> (Break (e, acc)) - Continue -> (continue (acc)) - *) - let make_control_flow_expr ~(span : span) ~(break_type : ty option) - ~(return_type : ty option) ~(acc : expr) ?(e : expr = unit_expr span) - (cf : [ `Return | `Break | `Continue ]) = - let break_type = Option.value ~default:unit_typ break_type in - match cf with - | `Return -> - let continue_type = make_tuple_typ [ break_type; acc.typ ] in - let inner = - make_control_flow_expr' ~break_type:e.typ ~continue_type ~span `Break - e - in - make_control_flow_expr' ~span ~break_type:inner.typ - ~continue_type:acc.typ `Break inner - | `Break -> - let tuple = make_tuple_expr ~span [ e; acc ] in - let inner = - match return_type with - | Some ret_typ -> - make_control_flow_expr' ~span ~break_type:ret_typ - ~continue_type:tuple.typ `Continue tuple - | None -> tuple - in - make_control_flow_expr' ~span ~break_type:inner.typ - ~continue_type:acc.typ `Break inner - | `Continue -> - let break_type = - let tuple_type = make_tuple_typ [ break_type; acc.typ ] in - match return_type with - | Some ret_typ -> - make_control_flow_type ~break_type:ret_typ - ~continue_type:tuple_type - | None -> tuple_type - in - make_control_flow_expr' ~span ~break_type ~continue_type:acc.typ - `Continue acc - let string_lit span (s : string) : expr = { span; typ = TStr; e = Literal (String s) } diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index b1c57586a..759125c00 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -95,18 +95,18 @@ module%inlined_contents Make (F : Features.T) = struct let else_ = Option.map ~f:(self#visit_expr in_loop) else_ in { e with e = If { cond; then_; else_ }; typ = then_.typ } | Return { e; _ }, Some ({ return_type; break_type }, acc_type) -> - UA.make_control_flow_expr ~return_type ~span ~break_type ~e + UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~e ~acc:{ e with typ = acc_type } `Return | ( Break { e; acc = Some (_, acc); _ }, Some ({ return_type; break_type }, _) ) -> - UA.make_control_flow_expr ~return_type ~span ~break_type ~e ~acc + UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~e ~acc `Break | ( Continue { acc = Some (_, acc); _ }, Some ({ return_type; break_type }, _) ) -> - UA.make_control_flow_expr ~return_type ~span ~break_type ~acc + UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~acc `Continue | _, Some ({ return_type; break_type }, _) -> - UA.make_control_flow_expr ~return_type ~span ~break_type ~acc:e + UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~acc:e `Continue | _ -> e (** The invariant here is that [visit_expr] is called only diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 07cdcda52..860949501 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -21,17 +21,17 @@ module Make (F : Features.T) = let ctx = Diagnostics.Context.Phase phase_id end) - let has_return = + let has_cf = object (_self) inherit [_] Visitors.reduce as super method zero = false method plus = ( || ) - method! visit_expr' in_loop e = + method! visit_expr' break_continue e = match e with | Return _ -> true - | (Break _ | Continue _) when in_loop -> true - | _ -> super#visit_expr' in_loop e + | (Break _ | Continue _) when break_continue -> true + | _ -> super#visit_expr' break_continue e end let loop_return_type = @@ -46,19 +46,6 @@ module Make (F : Features.T) = | _ -> super#visit_expr' () e end - let loop_has_cf = - object (_self) - inherit [_] Visitors.reduce as super - method zero = false - method plus = ( || ) - - method! visit_expr' () e = - match e with - | Return _ | Break _ | Continue _ -> true - | Loop _ -> false - | _ -> super#visit_expr' () e - end - let rewrite_control_flow = object (self) inherit [_] Visitors.map as super @@ -68,14 +55,14 @@ module Make (F : Features.T) = let return_type, witness = loop_return_type#visit_expr () loop in let typ = - U.make_control_flow_type ~continue_type:loop.typ + U.M.ty_control_flow ~continue_type:loop.typ ~break_type:return_type in let loop = { loop with typ } in let span = loop.span in let id = U.fresh_local_ident_in [] "ret" in let module MS = (val U.M.make span) in - let mk_cf_pat = U.make_control_flow_pat ~span ~typ in + let mk_cf_pat = U.M.pat_Constructor_CF ~span ~typ in let return_expr = let inner_e = MS.expr_LocalVar ~typ:return_type id in match witness with @@ -96,9 +83,9 @@ module Make (F : Features.T) = in match e.e with (* This is supposed to improve performance but it might actually make it worse in some cases *) - | _ when not (has_return#visit_expr true e) -> e + | _ when not (has_cf#visit_expr true e) -> e | Loop loop -> - let return_inside = has_return#visit_expr false loop.body in + let return_inside = has_cf#visit_expr false loop.body in let loop_expr = { e with @@ -138,9 +125,9 @@ module Make (F : Features.T) = let stmts_before, stmt_and_stmts_after = List.split_while stmts ~f:(fun (_, e) -> match e.e with - | (If _ | Match _) when has_return#visit_expr in_loop e -> + | (If _ | Match _) when has_cf#visit_expr in_loop e -> false - | Loop _ when has_return#visit_expr false e -> false + | Loop _ when has_cf#visit_expr false e -> false | Return _ | Break _ | Continue _ -> false | _ -> true) in From 884c5c9d1527a5df16306b652c9fe85d718f2286 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 23 Oct 2024 18:24:50 +0200 Subject: [PATCH 128/253] Fix loops control flow with feature gates. --- .../lib/phases/phase_drop_return_break_continue.ml | 3 ++- engine/lib/phases/phase_rewrite_control_flow.ml | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index 759125c00..d16230b45 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -105,7 +105,8 @@ module%inlined_contents Make (F : Features.T) = struct Some ({ return_type; break_type }, _) ) -> UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~acc `Continue - | _, Some ({ return_type; break_type }, _) -> + | _, Some ({ return_type; break_type }, _) + when Option.is_some return_type || Option.is_some break_type -> UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~acc:e `Continue | _ -> e diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 860949501..2a9a97eb4 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -86,10 +86,16 @@ module Make (F : Features.T) = | _ when not (has_cf#visit_expr true e) -> e | Loop loop -> let return_inside = has_cf#visit_expr false loop.body in + let new_body = self#visit_expr true loop.body in let loop_expr = { e with - e = Loop { loop with body = self#visit_expr true loop.body }; + e = + Loop + { + loop with + body = { new_body with typ = loop.body.typ }; + }; } in if return_inside then @@ -133,12 +139,16 @@ module Make (F : Features.T) = in match stmt_and_stmts_after with | (p, ({ e = Loop loop; _ } as rhs)) :: stmts_after -> + let new_body = self#visit_expr true loop.body in let loop_expr = { rhs with e = Loop - { loop with body = self#visit_expr true loop.body }; + { + loop with + body = { new_body with typ = loop.body.typ }; + }; } in U.make_lets stmts_before From b3eccce8f7db7e4af8f49d13939d8d6505905d8f Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Thu, 24 Oct 2024 08:29:08 +0200 Subject: [PATCH 129/253] added mk_* functions for all types --- .../rust_primitives/Rust_primitives.Integers.fsti | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti index 9a03ba89a..f7810340e 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti @@ -85,6 +85,19 @@ let v (#t:inttype) (x:int_t t) : range_t t = LI.v #t #LI.PUB x [@(strict_on_arguments [0])] val mk_int (#t:inttype) (n:range_t t) : int_t t +let mk_u8 x = mk_int #u8_inttype x +let mk_i8 x = mk_int #i8_inttype x +let mk_u16 x = mk_int #u16_inttype x +let mk_i16 x = mk_int #i16_inttype x +let mk_u32 x = mk_int #u32_inttype x +let mk_i32 x = mk_int #i32_inttype x +let mk_u64 x = mk_int #u64_inttype x +let mk_i64 x = mk_int #i64_inttype x +let mk_u128 x = mk_int #u128_inttype x +let mk_i128 x = mk_int #i128_inttype x +let mk_usize x = mk_int #usize_inttype x +let mk_isize x = mk_int #isize_inttype x + [@(strict_on_arguments [0])] val mk_int_equiv_lemma #t (n:range_t t) : Lemma ( From 646db417e7db0872bbd7d4744d874ce561cd709a Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 22 Oct 2024 11:09:26 +0200 Subject: [PATCH 130/253] feat(engine/ast): add `origin` to quotes --- engine/backends/fstar/fstar_backend.ml | 2 +- engine/backends/proverif/proverif_backend.ml | 2 +- engine/lib/ast.ml | 25 ++++++++++++++++++- engine/lib/ast_utils.ml | 14 +++++++++++ .../deprecated_generic_printer.ml | 2 +- .../generic_printer_template.ml | 3 ++- .../phases/phase_transform_hax_lib_inline.ml | 17 ++++++++++++- engine/lib/print_rust.ml | 2 +- engine/lib/subtype.ml | 2 +- .../generate_from_ast/codegen_visitor.ml | 1 + 10 files changed, 62 insertions(+), 8 deletions(-) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 0ee9c0e93..b4f78f9bc 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1465,7 +1465,7 @@ struct let tcinst = F.term @@ F.AST.Var FStar_Parser_Const.tcinstance_lid in F.decls ~fsti:ctx.interface_mode ~attrs:[ tcinst ] @@ F.AST.TopLevelLet (NoLetQualifier, [ (pat, body) ]) - | Quote quote -> + | Quote { quote; _ } -> let fstar_opts = Attrs.find_unique_attr e.attrs ~f:(function | ItemQuote q -> Some q.fstar_options diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index a69aee227..dddb667e6 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -635,7 +635,7 @@ module Make (Options : OPTS) : MAKE = struct ^^ separate_map hardline (fun variant -> fun_and_reduc name variant) variants - | Quote quote -> print#quote quote + | Quote { quote; _ } -> print#quote quote | _ -> empty method! expr_let : lhs:pat -> rhs:expr -> expr fn = diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 672080ebf..2dcd488ab 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -99,6 +99,29 @@ type literal = type 'mut_witness mutability = Mutable of 'mut_witness | Immutable [@@deriving show, yojson, hash, compare, sexp, hash, eq] +type item_kind = + [ `Fn + | `TyAlias + | `Type + | `IMacroInvokation + | `Trait + | `Impl + | `Alias + | `Use + | `Quote + | `HaxError + | `NotImplementedYet ] +[@@deriving show, yojson, hash, compare, sexp, hash, eq] +(** Describes the (shallow) kind of an item. *) + +type item_quote_origin = { + item_kind : item_kind; + item_ident : concrete_ident; + position : [ `Before | `After | `Replace ]; +} +[@@deriving show, yojson, hash, compare, sexp, hash, eq] +(** From where does a quote item comes from? *) + module Make = functor (F : Features.T) @@ -434,7 +457,7 @@ functor is_external : bool; rename : string option; } - | Quote of quote + | Quote of { quote : quote; origin : item_quote_origin } | HaxError of string | NotImplementedYet diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index db6163882..26e826bbf 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -999,6 +999,20 @@ module Make (F : Features.T) = struct in Some { pat; typ; typ_span = Some span; attrs = [] } + let kind_of_item (item : item) : item_kind = + match item.v with + | Fn _ -> `Fn + | TyAlias _ -> `TyAlias + | Type _ -> `Type + | IMacroInvokation _ -> `IMacroInvokation + | Trait _ -> `Trait + | Impl _ -> `Impl + | Alias _ -> `Alias + | Use _ -> `Use + | Quote _ -> `Quote + | HaxError _ -> `HaxError + | NotImplementedYet -> `NotImplementedYet + let rec expr_of_lhs (span : span) (lhs : lhs) : expr = match lhs with | LhsLocalVar { var; typ } -> { e = LocalVar var; typ; span } diff --git a/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml index 5cd219b4a..3b1c190aa 100644 --- a/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml +++ b/engine/lib/deprecated_generic_printer/deprecated_generic_printer.ml @@ -407,7 +407,7 @@ module Make (F : Features.T) (View : Concrete_ident.VIEW_API) = struct safety ^^ !^"fn" ^^ space ^^ print#concrete_ident name ^^ generics ^^ params ^^ iblock braces (print#expr_at Item_Fn_body body) - | Quote quote -> print#quote quote + | Quote { quote; _ } -> print#quote quote | _ -> string "item not implemented" method generic_param' : generic_param fn = diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 110873754..4470b4164 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -219,7 +219,8 @@ struct method item'_NotImplementedYet = default_document_for "item'_NotImplementedYet" - method item'_Quote ~super:_ _x2 = default_document_for "item'_Quote" + method item'_Quote ~super:_ ~quote:_ ~origin:_ = + default_document_for "item'_Quote" method item'_Trait ~super:_ ~name:_ ~generics:_ ~items:_ ~safety:_ = default_document_for "item'_Trait" diff --git a/engine/lib/phases/phase_transform_hax_lib_inline.ml b/engine/lib/phases/phase_transform_hax_lib_inline.ml index 3005fddaa..c6e8d80a8 100644 --- a/engine/lib/phases/phase_transform_hax_lib_inline.ml +++ b/engine/lib/phases/phase_transform_hax_lib_inline.ml @@ -166,6 +166,7 @@ module%inlined_contents Make (F : Features.T) = struct let before, after = let map_fst = List.map ~f:fst in try + let replace = Attrs.late_skip item.attrs in Attrs.associated_items Attr_payloads.AssocRole.ItemQuote item.attrs |> List.map ~f:(fun assoc_item -> let e : A.expr = @@ -181,7 +182,6 @@ module%inlined_contents Make (F : Features.T) = struct (* ^ (UA.LiftToFullAst.expr e |> Print_rust.pexpr_str) *) ^ [%show: A.expr] e) in - let v : B.item' = Quote quote in let span = e.span in let position, attr = Attrs.find_unique_attr assoc_item.attrs ~f:(function @@ -192,6 +192,21 @@ module%inlined_contents Make (F : Features.T) = struct "Malformed `Quote` item: could not find a \ ItemQuote payload") in + let v : B.item' = + let origin : item_quote_origin = + { + item_kind = UA.kind_of_item item; + item_ident = item.ident; + position = + (if replace then `Replace + else + match position with + | After -> `After + | Before -> `Before); + } + in + Quote { quote; origin } + in let attrs = [ Attr_payloads.to_attr attr assoc_item.span ] in (B.{ v; span; ident = item.ident; attrs }, position)) |> List.partition_tf ~f:(snd >> [%matches? Types.Before]) diff --git a/engine/lib/print_rust.ml b/engine/lib/print_rust.ml index 1fb6f9a78..86506c7ef 100644 --- a/engine/lib/print_rust.ml +++ b/engine/lib/print_rust.ml @@ -592,7 +592,7 @@ module Raw = struct & !"{" & List.map ~f:pimpl_item items |> concat ~sep:!"\n" & !"}" - | Quote quote -> pquote e.span quote & !";" + | Quote { quote; _ } -> pquote e.span quote & !";" | _ -> raise NotImplemented in pattrs e.attrs & pi diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index 0e2c8fbff..831b629dd 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -532,7 +532,7 @@ struct } | Alias { name; item } -> B.Alias { name; item } | Use { path; is_external; rename } -> B.Use { path; is_external; rename } - | Quote quote -> Quote (dquote span quote) + | Quote { quote; origin } -> Quote { quote = dquote span quote; origin } | HaxError e -> B.HaxError e | NotImplementedYet -> B.NotImplementedYet diff --git a/engine/utils/generate_from_ast/codegen_visitor.ml b/engine/utils/generate_from_ast/codegen_visitor.ml index 9a8b62725..e9e65ad24 100644 --- a/engine/utils/generate_from_ast/codegen_visitor.ml +++ b/engine/utils/generate_from_ast/codegen_visitor.ml @@ -233,6 +233,7 @@ let is_allowed_opaque name = "quote"; "float_kind"; "int_kind"; + "item_quote_origin"; ] in List.mem ~equal:String.equal allowlist name From d1787685f254fbc5c0d06c84bcc78136d7b2b8f5 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 09:27:33 +0200 Subject: [PATCH 131/253] Better documentation for return/break/continue. --- engine/lib/ast.ml | 6 +++++ engine/lib/ast_builder.ml | 22 ++++++++++--------- .../phase_drop_return_break_continue.ml | 5 +++-- .../lib/phases/phase_rewrite_control_flow.ml | 3 +-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/engine/lib/ast.ml b/engine/lib/ast.ml index 4bb5e2a50..224d43b4b 100644 --- a/engine/lib/ast.ml +++ b/engine/lib/ast.ml @@ -217,6 +217,12 @@ functor and pat = { p : pat'; span : span; typ : ty } and field_pat = { field : global_ident; pat : pat } + + (* This marker describes what control flow is present in a loop. + It is added by phase `DropReturnBreakContinue` and the + information is used in `FunctionalizeLoops`. We need it because + we replace the control flow nodes of the AST by some encoding + in the `ControlFlow` enum. *) and cf_kind = BreakOnly | BreakOrReturn and expr' = diff --git a/engine/lib/ast_builder.ml b/engine/lib/ast_builder.ml index d6bbefe09..692320e51 100644 --- a/engine/lib/ast_builder.ml +++ b/engine/lib/ast_builder.ml @@ -23,23 +23,26 @@ module Make (F : Features.T) = struct | [ ty ] -> ty | types -> ty_tuple types - let ty_control_flow ~(continue_type : ty) ~(break_type : ty) : ty = + (** This gives the type of a value in the `ControlFlow` enum *) + let ty_cf ~(continue_type : ty) ~(break_type : ty) : ty = TApp { ident = Global_ident.of_name Type Core__ops__control_flow__ControlFlow; args = [ GType break_type; GType continue_type ]; } + (** This gives the type of a value encoded in the `ControlFlow` enum. + In case a `return_type` is provided the encoding is nested: + `return v` is `Break (Break v)` + `break v` is `Break (Continue (v, acc))` *) let ty_cf_return ~(acc_type : ty) ~(break_type : ty) ~(return_type : ty option) : ty = let break_type = ty_tuple [ break_type; acc_type ] in match return_type with | Some ret_ty -> - let break_type = - ty_control_flow ~break_type:ret_ty ~continue_type:break_type - in - ty_control_flow ~break_type ~continue_type:acc_type - | None -> ty_control_flow ~break_type ~continue_type:acc_type + let break_type = ty_cf ~break_type:ret_ty ~continue_type:break_type in + ty_cf ~break_type ~continue_type:acc_type + | None -> ty_cf ~break_type ~continue_type:acc_type end include NoSpan @@ -137,7 +140,7 @@ module Make (F : Features.T) = struct let expr'_Constructor_CF ~(span : span) ~(break_type : ty) ?(continue_type : ty = ty_unit) (cf : [ `Break | `Continue ]) (e : expr) = - let typ = NoSpan.ty_control_flow ~continue_type ~break_type in + let typ = NoSpan.ty_cf ~continue_type ~break_type in match cf with | `Break -> call_Constructor Core__ops__control_flow__ControlFlow__Break false @@ -146,7 +149,7 @@ module Make (F : Features.T) = struct call_Constructor Core__ops__control_flow__ControlFlow__Continue false [ e ] span typ - (* We use the following encoding of return, break and continue in the `ControlFlow` enum: + (** We use the following encoding of return, break and continue in the `ControlFlow` enum: Return e -> Break (Break e) Break e -> Break ((Continue(e, acc))) Continue -> Continue(acc) @@ -183,8 +186,7 @@ module Make (F : Features.T) = struct let tuple_type = NoSpan.ty_tuple [ break_type; acc.typ ] in match return_type with | Some ret_typ -> - NoSpan.ty_control_flow ~break_type:ret_typ - ~continue_type:tuple_type + NoSpan.ty_cf ~break_type:ret_typ ~continue_type:tuple_type | None -> tuple_type in expr'_Constructor_CF ~span ~break_type ~continue_type:acc.typ diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index d16230b45..fbbadc6fc 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -1,4 +1,4 @@ -(* This phase removes `return`s in exit position. Inside loops, +(** This phase removes `return`s in exit position. Inside loops, it replaces `return`, `break` and `continue` (in exit position) by their encoding in the `ControlFlow` enum. It replaces another expression in exit position by an equivalent `continue`. @@ -124,7 +124,8 @@ module%inlined_contents Make (F : Features.T) = struct match expr with | [%inline_arms "dexpr'.*" - Return - Break - Continue - Loop] -> auto | Return _ | Break _ | Continue _ -> - Error.raise { kind = NonTrivialAndMutFnInput (*TODO Correct*); span } + Error.assertion_failure span + "Return/Break/Continue are expected to be gone as this point" | Loop { body; kind; state; label; witness; _ } -> let control_flow_type = has_return#visit_expr () body in let control_flow = diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index 2a9a97eb4..d8c568fc3 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -55,8 +55,7 @@ module Make (F : Features.T) = let return_type, witness = loop_return_type#visit_expr () loop in let typ = - U.M.ty_control_flow ~continue_type:loop.typ - ~break_type:return_type + U.M.ty_cf ~continue_type:loop.typ ~break_type:return_type in let loop = { loop with typ } in let span = loop.span in From 30e2ac35bdca7975d58064e2f173e80177376854 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 10:06:21 +0200 Subject: [PATCH 132/253] Explain the situation with in bundles. --- engine/lib/dependencies.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index 1b4337419..2cbe2a32e 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -393,6 +393,8 @@ module Make (F : Features.T) = struct in let mut_rec_bundles = let mod_graph_cycles = ModGraph.of_items items |> ModGraph.cycles in + (* `Use` items shouldn't be bundled as they have no dependencies + and they have dummy names. *) let non_use_items = List.filter ~f:(fun item -> match item.v with Use _ -> false | _ -> true) From 011c076b8bb1c419e831ee535def51e1a38c6354 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 10:41:55 +0200 Subject: [PATCH 133/253] Fix conflicts. --- engine/lib/ast_builder.ml | 8 ++++---- .../lib/generic_printer/generic_printer_template.ml | 11 ++++++++--- engine/lib/phases/phase_drop_return_break_continue.ml | 4 ++-- engine/lib/phases/phase_local_mutation.ml | 4 ++-- engine/lib/subtype.ml | 4 ++-- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/engine/lib/ast_builder.ml b/engine/lib/ast_builder.ml index 692320e51..a092f9225 100644 --- a/engine/lib/ast_builder.ml +++ b/engine/lib/ast_builder.ml @@ -71,11 +71,11 @@ module Make (F : Features.T) = struct p = PConstruct { - name = + constructor = Global_ident.of_name (Constructor { is_struct = false }) Core__ops__control_flow__ControlFlow__Break; - args = + fields = [ { field = @@ -95,11 +95,11 @@ module Make (F : Features.T) = struct p = PConstruct { - name = + constructor = Global_ident.of_name (Constructor { is_struct = false }) Core__ops__control_flow__ControlFlow__Continue; - args = + fields = [ { field = diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 4470b4164..02386dcf3 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -71,7 +71,7 @@ struct method expr'_Borrow ~super:_ ~kind:_ ~e:_ ~witness:_ = default_document_for "expr'_Borrow" - method expr'_Break ~super:_ ~e:_ ~label:_ ~witness:_ = + method expr'_Break ~super:_ ~e:_ ~acc:_ ~label:_ ~witness:_ = default_document_for "expr'_Break" method expr'_Closure ~super:_ ~params:_ ~body:_ ~captures:_ = @@ -84,7 +84,7 @@ struct method expr'_Construct_tuple ~super:_ ~components:_ = default_document_for "expr'_Construct_tuple" - method expr'_Continue ~super:_ ~e:_ ~label:_ ~witness:_ = + method expr'_Continue ~super:_ ~acc:_ ~label:_ ~witness:_ = default_document_for "expr'_Continue" method expr'_EffectAction ~super:_ ~action:_ ~argument:_ = @@ -105,7 +105,8 @@ struct method expr'_Literal ~super:_ _x2 = default_document_for "expr'_Literal" method expr'_LocalVar ~super:_ _x2 = default_document_for "expr'_LocalVar" - method expr'_Loop ~super:_ ~body:_ ~kind:_ ~state:_ ~label:_ ~witness:_ = + method expr'_Loop ~super:_ ~body:_ ~kind:_ ~state:_ ~control_flow:_ + ~label:_ ~witness:_ = default_document_for "expr'_Loop" method expr'_MacroInvokation ~super:_ ~macro:_ ~args:_ ~witness:_ = @@ -122,6 +123,10 @@ struct method expr'_Return ~super:_ ~e:_ ~witness:_ = default_document_for "expr'_Return" + method cf_kind_BreakOrReturn = + default_document_for "cf_kind_BreakOrReturn" + + method cf_kind_BreakOnly = default_document_for "cf_kind_BreakOnly" method field_pat ~field:_ ~pat:_ = default_document_for "field_pat" method generic_constraint_GCLifetime _x1 _x2 = diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index fbbadc6fc..f9d0c0235 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -97,11 +97,11 @@ module%inlined_contents Make (F : Features.T) = struct | Return { e; _ }, Some ({ return_type; break_type }, acc_type) -> UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~e ~acc:{ e with typ = acc_type } `Return - | ( Break { e; acc = Some (_, acc); _ }, + | ( Break { e; acc = Some (acc, _); _ }, Some ({ return_type; break_type }, _) ) -> UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~e ~acc `Break - | ( Continue { acc = Some (_, acc); _ }, + | ( Continue { acc = Some (acc, _); _ }, Some ({ return_type; break_type }, _) ) -> UA.M.expr_Constructor_CF ~return_type ~span ~break_type ~acc `Continue diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index 8d1a42d98..e4936b7f8 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -244,7 +244,7 @@ struct Break { e = dexpr_same e; - acc = Some (w, local_vars_expr); + acc = Some (local_vars_expr, w); label; witness; }; @@ -255,7 +255,7 @@ struct let w = Features.On.state_passing_loop in let e = local_vars_expr in { - e = Continue { acc = Some (w, e); label; witness }; + e = Continue { acc = Some (e, w); label; witness }; span = expr.span; typ = e.typ; } diff --git a/engine/lib/subtype.ml b/engine/lib/subtype.ml index fa79fe89c..1f9528d49 100644 --- a/engine/lib/subtype.ml +++ b/engine/lib/subtype.ml @@ -257,7 +257,7 @@ struct Break { e = dexpr e; - acc = Option.map ~f:(S.state_passing_loop span *** dexpr) acc; + acc = Option.map ~f:(dexpr *** S.state_passing_loop span) acc; label; witness = (S.break span *** S.loop span) witness; } @@ -273,7 +273,7 @@ struct | Continue { acc; label; witness = w1, w2 } -> Continue { - acc = Option.map ~f:(dexpr *** S.state_passing_loop span) e; + acc = Option.map ~f:(dexpr *** S.state_passing_loop span) acc; label; witness = (S.continue span w1, S.loop span w2); } From cf39d4901b354d232e3a4fc6ff1ff74f3e58c720 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 11:01:21 +0200 Subject: [PATCH 134/253] fix tests --- .../toolchain__cyclic-modules into-fstar.snap | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap index f0b6e249f..2b4320887 100644 --- a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap @@ -32,7 +32,7 @@ module Cyclic_modules.B open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_194616565 {g as g} +include Cyclic_modules.Rec_bundle_805309848 {g as g} ''' "Cyclic_modules.C.fst" = ''' module Cyclic_modules.C @@ -272,8 +272,8 @@ open FStar.Mul include Cyclic_modules.Rec1_same_name.Rec_bundle_213192514 {f91805216 as f} ''' -"Cyclic_modules.Rec_bundle_194616565.fst" = ''' -module Cyclic_modules.Rec_bundle_194616565 +"Cyclic_modules.Rec_bundle_805309848.fst" = ''' +module Cyclic_modules.Rec_bundle_805309848 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul @@ -356,45 +356,43 @@ module Cyclic_modules open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_194616565 {v_DUMMY as v_DUMMY} +include Cyclic_modules.Rec_bundle_805309848 {b as b} -include Cyclic_modules.Rec_bundle_194616565 {b as b} +include Cyclic_modules.Rec_bundle_805309848 {c as c} -include Cyclic_modules.Rec_bundle_194616565 {c as c} +include Cyclic_modules.Rec_bundle_805309848 {d as d} -include Cyclic_modules.Rec_bundle_194616565 {d as d} +include Cyclic_modules.Rec_bundle_805309848 {de as de} -include Cyclic_modules.Rec_bundle_194616565 {de as de} +include Cyclic_modules.Rec_bundle_805309848 {disjoint_cycle_a as disjoint_cycle_a} -include Cyclic_modules.Rec_bundle_194616565 {disjoint_cycle_a as disjoint_cycle_a} +include Cyclic_modules.Rec_bundle_805309848 {disjoint_cycle_b as disjoint_cycle_b} -include Cyclic_modules.Rec_bundle_194616565 {disjoint_cycle_b as disjoint_cycle_b} +include Cyclic_modules.Rec_bundle_805309848 {e as e} -include Cyclic_modules.Rec_bundle_194616565 {e as e} +include Cyclic_modules.Rec_bundle_805309848 {enums_a as enums_a} -include Cyclic_modules.Rec_bundle_194616565 {enums_a as enums_a} +include Cyclic_modules.Rec_bundle_805309848 {enums_b as enums_b} -include Cyclic_modules.Rec_bundle_194616565 {enums_b as enums_b} +include Cyclic_modules.Rec_bundle_805309848 {m1 as m1} -include Cyclic_modules.Rec_bundle_194616565 {m1 as m1} +include Cyclic_modules.Rec_bundle_805309848 {m2 as m2} -include Cyclic_modules.Rec_bundle_194616565 {m2 as m2} +include Cyclic_modules.Rec_bundle_805309848 {v_rec as v_rec} -include Cyclic_modules.Rec_bundle_194616565 {v_rec as v_rec} +include Cyclic_modules.Rec_bundle_805309848 {rec1_same_name as rec1_same_name} -include Cyclic_modules.Rec_bundle_194616565 {rec1_same_name as rec1_same_name} +include Cyclic_modules.Rec_bundle_805309848 {rec2_same_name as rec2_same_name} -include Cyclic_modules.Rec_bundle_194616565 {rec2_same_name as rec2_same_name} +include Cyclic_modules.Rec_bundle_805309848 {std as std} -include Cyclic_modules.Rec_bundle_194616565 {std as std} +include Cyclic_modules.Rec_bundle_805309848 {typ_a as typ_a} -include Cyclic_modules.Rec_bundle_194616565 {typ_a as typ_a} +include Cyclic_modules.Rec_bundle_805309848 {typ_b as typ_b} -include Cyclic_modules.Rec_bundle_194616565 {typ_b as typ_b} +include Cyclic_modules.Rec_bundle_805309848 {f as f} -include Cyclic_modules.Rec_bundle_194616565 {f as f} +include Cyclic_modules.Rec_bundle_805309848 {h as h} -include Cyclic_modules.Rec_bundle_194616565 {h as h} - -include Cyclic_modules.Rec_bundle_194616565 {h2 as h2} +include Cyclic_modules.Rec_bundle_805309848 {h2 as h2} ''' From a443432238e8d7a9de531dcd6539a029f289636f Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Thu, 24 Oct 2024 11:16:17 +0200 Subject: [PATCH 135/253] more conversion functions --- .../Rust_primitives.Integers.fsti | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti index f7810340e..f3678ca9f 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti @@ -98,6 +98,31 @@ let mk_i128 x = mk_int #i128_inttype x let mk_usize x = mk_int #usize_inttype x let mk_isize x = mk_int #isize_inttype x +let from_uint8 (x:FStar.UInt8.t) : u8 = x +let from_int8 (x:FStar.Int8.t) : i8 = x +let from_uint16 (x:FStar.UInt16.t) : u16 = x +let from_int16 (x:FStar.Int16.t) : i16 = x +let from_uint32 (x:FStar.UInt32.t) : u32 = x +let from_int32 (x:FStar.Int32.t) : i32 = x +let from_uint64 (x:FStar.UInt64.t) : u64 = x +let from_int64 (x:FStar.Int64.t) : i64 = x +let from_uint128 (x:FStar.UInt128.t) : u128 = x +let from_int128 (x:FStar.Int128.t) : i128 = x +let from_usize (x:FStar.UInt32.t) : usize = mk_usize (FStar.UInt32.v x) +let from_isize (x:FStar.Int32.t) : isize = mk_isize (FStar.Int32.v x) + +let to_uint8 (x:u8) : FStar.UInt8.t = x +let to_int8 (x:i8) : FStar.Int8.t = x +let to_uint16 (x:u16) : FStar.UInt16.t = x +let to_int16 (x:i16) : FStar.Int16.t = x +let to_uint32 (x:u32) : FStar.UInt32.t = x +let to_int32 (x:i32) : FStar.Int32.t = x +let to_uint64 (x:u64) : FStar.UInt64.t = x +let to_int64 (x:i64) : FStar.Int64.t = x +let to_uint128 (x:u128) : FStar.UInt128.t = x +let to_int128 (x:i128) : FStar.Int128.t = x + + [@(strict_on_arguments [0])] val mk_int_equiv_lemma #t (n:range_t t) : Lemma ( From 8416d9990a0e0a5fd3e38d70e5f02d69e3bf65e9 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Thu, 24 Oct 2024 11:27:44 +0200 Subject: [PATCH 136/253] Formatting --- engine/backends/proverif/proverif_backend.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 166f067d8..872522637 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -872,7 +872,9 @@ let translate m (bo : BackendOptions.t) ~(bundles : AST.item list list) let lib_contents = M.Preamble.print items ^ M.DataTypes.print items ^ M.Letfuns.print items in - let lib_file = Types.{ path = "lib.pvl"; contents = lib_contents; sourcemap = None } in + let lib_file = + Types.{ path = "lib.pvl"; contents = lib_contents; sourcemap = None } + in [ lib_file ] open Phase_utils From f1e9eaf76a58b022d2f72636b9fa4d0585af99b9 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Thu, 24 Oct 2024 11:31:48 +0200 Subject: [PATCH 137/253] Revert "Minimal PV extraction example" This reverts commit 331f81d2ecd0383b59e372c9d56bdf916da763ef. --- examples/Cargo.lock | 35 ++---------- examples/Cargo.toml | 1 - examples/minimal-proverif/Cargo.toml | 8 --- examples/minimal-proverif/Readme.md | 55 ------------------- .../proofs/proverif/extraction/analysis.pv | 33 ----------- examples/minimal-proverif/src/lib.rs | 22 -------- 6 files changed, 6 insertions(+), 148 deletions(-) delete mode 100644 examples/minimal-proverif/Cargo.toml delete mode 100644 examples/minimal-proverif/Readme.md delete mode 100644 examples/minimal-proverif/proofs/proverif/extraction/analysis.pv delete mode 100644 examples/minimal-proverif/src/lib.rs diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 4be61c380..4acf7c2eb 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -188,16 +188,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "duplicate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" -dependencies = [ - "heck", - "proc-macro-error", -] - [[package]] name = "either" version = "1.9.0" @@ -241,16 +231,14 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hax-bounded-integers" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ - "duplicate", "hax-lib", - "paste", ] [[package]] name = "hax-lib" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ "hax-lib-macros", "num-bigint", @@ -259,10 +247,9 @@ dependencies = [ [[package]] name = "hax-lib-macros" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ "hax-lib-macros-types", - "paste", "proc-macro-error", "proc-macro2", "quote", @@ -271,7 +258,7 @@ dependencies = [ [[package]] name = "hax-lib-macros-types" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ "proc-macro2", "quote", @@ -280,12 +267,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hex" version = "0.4.3" @@ -464,10 +445,6 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" -[[package]] -name = "minimal-proverif" -version = "0.1.0" - [[package]] name = "num-bigint" version = "0.4.4" @@ -528,9 +505,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.15" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "ppv-lite86" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 6425df82e..7a79b49ba 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,7 +5,6 @@ members = [ "sha256", "barrett", "kyber_compress", - "minimal-proverif", "proverif-psk" ] resolver = "2" diff --git a/examples/minimal-proverif/Cargo.toml b/examples/minimal-proverif/Cargo.toml deleted file mode 100644 index 69263bbde..000000000 --- a/examples/minimal-proverif/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "minimal-proverif" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/examples/minimal-proverif/Readme.md b/examples/minimal-proverif/Readme.md deleted file mode 100644 index 0907ebbfc..000000000 --- a/examples/minimal-proverif/Readme.md +++ /dev/null @@ -1,55 +0,0 @@ -# A minimal hax ProVerif example - -This crate demonstrates a minimal example of ProVerif extraction using hax. - -The crate provides functions for implementing a simplistic protocol -between an initiator and receiver, which is defined as follows: -``` -Initiator(payload: u8): let message = Ping(payload) - -Initiator -> Responder: message - -Responder: If message was Ping(payload), - let response = Pong(payload) - else abort - -Responder -> Initiator: response - -Initiator: If response was Pong(payload), - return payload - else abort -``` - -The crate does not implement message transport, only the initiator and responder protocol logic. - -## Extracting into ProVerif -To obtain a ProVerif model of the protocol logic functions, run -``` -cargo hax into pro-verif -``` -This will generate a file `./proofs/proverif/extraction/lib.pvl`. - -## Running a Basic Analysis on the Model -We have provided a handwritten file -`./proofs/proverif/extraction/analysis.pv`, which models the protocol -using the extracted functions in `lib.pvl` and uses ProVerif to verify -that initiator and receiver can both complete the protocol. - -To let ProVerif perform the analysis, from the crate root, run: - -``` -proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv -``` - -The expected final output is -``` --------------------------------------------------------------- -Verification summary: - -Query not event(Reach_end_Initiator) is false. - -Query not event(Reach_end_Responder) is false. - --------------------------------------------------------------- -``` - diff --git a/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv b/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv deleted file mode 100644 index dad4b3d45..000000000 --- a/examples/minimal-proverif/proofs/proverif/extraction/analysis.pv +++ /dev/null @@ -1,33 +0,0 @@ -(*****************************************) -(* Top-level process *) -(*****************************************) - -event Reach_end_Initiator. -event Reach_end_Responder. - -query event(Reach_end_Initiator). -query event(Reach_end_Responder). - -let Initiator(payload: nat) = - let ping_message = minimal_proverif__send_ping(payload) in - out(c, ping_message); - - in(c, pong_message: minimal_proverif__t_Message ); - let received_payload = accessor_minimal_proverif__Message__Pong_0(pong_message) in - event Reach_end_Initiator; - 0. - -let Responder() = - in(c, ping_message: minimal_proverif__t_Message ); - let minimal_proverif__Message_Message_Ping_c(received_payload) = ping_message in - let pong_message = minimal_proverif__Message_Message_Pong_c(received_payload) in - out(c, pong_message); - event Reach_end_Responder; - 0. - -process - in(c, payload: nat); - - Initiator(payload) | Responder() - - diff --git a/examples/minimal-proverif/src/lib.rs b/examples/minimal-proverif/src/lib.rs deleted file mode 100644 index 0924433de..000000000 --- a/examples/minimal-proverif/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub enum Message { - Ping(u8), - Pong(u8), -} - -pub fn send_ping(input: u8) -> Message { - Message::Ping(input) -} - -pub fn receive_ping(message: Message) -> Result { - match message { - Message::Ping(payload) => Ok(Message::Pong(payload)), - _ => Err(()), - } -} - -pub fn receive_pong(message: Message) -> Result { - match message { - Message::Pong(payload) => Ok(payload), - _ => Err(()), - } -} From 5d412d065ddff21678061ca1079a75d68804ad96 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Thu, 24 Oct 2024 11:32:30 +0200 Subject: [PATCH 138/253] Update lock --- examples/Cargo.lock | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 4acf7c2eb..d2b20070e 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -188,6 +188,16 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "either" version = "1.9.0" @@ -231,14 +241,16 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hax-bounded-integers" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ + "duplicate", "hax-lib", + "paste", ] [[package]] name = "hax-lib" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros", "num-bigint", @@ -247,9 +259,10 @@ dependencies = [ [[package]] name = "hax-lib-macros" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros-types", + "paste", "proc-macro-error", "proc-macro2", "quote", @@ -258,7 +271,7 @@ dependencies = [ [[package]] name = "hax-lib-macros-types" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "proc-macro2", "quote", @@ -267,6 +280,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex" version = "0.4.3" @@ -505,9 +524,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "ppv-lite86" From 4b7ae0564844bae8c27e192e6a9942e4399d9ff7 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 11:50:48 +0200 Subject: [PATCH 139/253] feat: add a `deny.toml` for licenses --- deny.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 deny.toml diff --git a/deny.toml b/deny.toml new file mode 100644 index 000000000..293de552a --- /dev/null +++ b/deny.toml @@ -0,0 +1,13 @@ +[licenses] +unused-allowed-license = "allow" +allow = [ + "Apache-2.0", + "MIT", + "Unicode-DFS-2016", + "MPL-2.0", + # Licences used in the OCaml dependencies in the engine + "BSD-3-Clause", + "LGPL-2.1", + "LGPL-2.0", + "ISC", +] \ No newline at end of file From e6693557894fda783dcf2bfcdd33465b1fd3921a Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 11:50:24 +0200 Subject: [PATCH 140/253] feat(justfile): add `check-licenses` --- flake.nix | 1 + justfile | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/flake.nix b/flake.nix index 10c622a15..56c892e8c 100644 --- a/flake.nix +++ b/flake.nix @@ -176,6 +176,7 @@ pkgs.openssl.dev pkgs.pkg-config pkgs.rust-analyzer + pkgs.toml2json rustfmt rustc diff --git a/justfile b/justfile index b52f992aa..2414dd5f0 100644 --- a/justfile +++ b/justfile @@ -73,6 +73,27 @@ test-review: (_ensure_command_in_path "cargo-insta" "Insta (https://insta.rs)") | sd '[-](\d+)' '#$1\t is labeled `marked-unimplemented`, but was not found in the code' \ | sd '[+](\d+)' '#$1\t is *not* labeled `marked-unimplemented` or is closed' +# Check that the licenses of every crate and every package are compliant with `deny.toml` +check-licenses: + #!/usr/bin/env bash + just _ensure_command_in_path cargo-deny "cargo-deny (https://embarkstudios.github.io/cargo-deny/)" + just _ensure_command_in_path toml2json "toml2json (https://github.com/woodruffw/toml2json)" + echo "> Check licenses for Rust" + cargo deny check licenses + cd engine + echo "> Check licenses for OCaml" + # initialize opam if needed + opam env >& /dev/null || opam init --no + # pin package `hax-engine` if needed + opam list --required-by=hax-engine --column=name,license: -s >& /dev/null || opam pin . --yes + # Check that every pacakge matches licenses of `deny.toml` + if opam list --required-by=hax-engine --column=name,license: -s \ + | grep -Pvi $(toml2json ../deny.toml| jq '.licenses.allow | join("|")'); then + echo "Some licenses were non compliant to our policy (see `deny.toml`)" + else + echo "licenses ok" + fi + _ensure_command_in_path BINARY NAME: #!/usr/bin/env bash command -v {{BINARY}} &> /dev/null || { From 9801eebfc3e1193fc685ca9dc794202d490adae5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 24 Oct 2024 11:51:20 +0200 Subject: [PATCH 141/253] Fix flake for lorri --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 10c622a15..d9cbe8cf0 100644 --- a/flake.nix +++ b/flake.nix @@ -195,7 +195,7 @@ }; default = pkgs.mkShell { inherit packages inputsFrom LIBCLANG_PATH; - shellHook = ''echo "Commands available: $(ls ${utils}/bin | tr '\n' ' ')"''; + shellHook = ''echo "Commands available: $(ls ${utils}/bin | tr '\n' ' ')" 1>&2''; }; }; } From 2c9600e5308383e80589fe5c9a863f7cba097248 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 14:15:07 +0200 Subject: [PATCH 142/253] refactor(nix): rename `fstar` into `examples` --- examples/.envrc | 2 +- examples/README.md | 2 +- flake.nix | 2 +- proof-libs/fstar-secret-integers/.envrc | 2 +- proof-libs/fstar/.envrc | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/.envrc b/examples/.envrc index 7045e0610..42800cde0 100644 --- a/examples/.envrc +++ b/examples/.envrc @@ -1 +1 @@ -use flake .#fstar +use flake .#examples diff --git a/examples/README.md b/examples/README.md index 462d02101..03aff939f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -15,7 +15,7 @@ First, make sure to have hax installed in PATH. Then: - * With Nix, `nix develop .#fstar` setups a shell automatically for you. + * With Nix, `nix develop .#examples` setups a shell automatically for you. * Without Nix: 1. install F* `v2024.01.13` manually (see https://github.com/FStarLang/FStar/blob/master/INSTALL.md); diff --git a/flake.nix b/flake.nix index 10c622a15..f85f58b4a 100644 --- a/flake.nix +++ b/flake.nix @@ -183,7 +183,7 @@ ]; LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; in { - fstar = pkgs.mkShell { + examples = pkgs.mkShell { inherit inputsFrom LIBCLANG_PATH; HACL_HOME = "${hacl-star}"; shellHook = '' diff --git a/proof-libs/fstar-secret-integers/.envrc b/proof-libs/fstar-secret-integers/.envrc index 7045e0610..42800cde0 100644 --- a/proof-libs/fstar-secret-integers/.envrc +++ b/proof-libs/fstar-secret-integers/.envrc @@ -1 +1 @@ -use flake .#fstar +use flake .#examples diff --git a/proof-libs/fstar/.envrc b/proof-libs/fstar/.envrc index 7045e0610..42800cde0 100644 --- a/proof-libs/fstar/.envrc +++ b/proof-libs/fstar/.envrc @@ -1 +1 @@ -use flake .#fstar +use flake .#examples From 48b58a2ae87b5fdc78f2c969251674ad13b8b4f3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 14:15:31 +0200 Subject: [PATCH 143/253] feat(nix): `example` devshell: add `proverif` --- examples/default.nix | 3 ++- flake.nix | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/default.nix b/examples/default.nix index 74aba3dcd..7daa30ee6 100644 --- a/examples/default.nix +++ b/examples/default.nix @@ -7,6 +7,7 @@ hacl-star, hax-env, jq, + proverif, }: let matches = re: path: !builtins.isNull (builtins.match re path); commonArgs = { @@ -46,5 +47,5 @@ in sed -i "s/make -C limited-order-book/HAX_VANILLA_RUSTC=never make -C limited-order-book/g" Makefile make ''; - buildInputs = [hax hax-env fstar jq]; + buildInputs = [hax hax-env fstar jq proverif]; }) diff --git a/flake.nix b/flake.nix index f85f58b4a..f59f47b97 100644 --- a/flake.nix +++ b/flake.nix @@ -191,7 +191,7 @@ export HAX_PROOF_LIBS_HOME="$HAX_ROOT/proof-libs/fstar" export HAX_LIBS_HOME="$HAX_ROOT/hax-lib" ''; - packages = packages ++ [fstar]; + packages = packages ++ [fstar pkgs.proverif]; }; default = pkgs.mkShell { inherit packages inputsFrom LIBCLANG_PATH; From 18ea362fcd8f4148012f3d81e1db5d610ba59261 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 14:16:01 +0200 Subject: [PATCH 144/253] feat(examples/pv): add makefiels --- examples/Makefile | 1 + examples/proverif-psk/Makefile | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 examples/proverif-psk/Makefile diff --git a/examples/Makefile b/examples/Makefile index 69cb20696..62a6e2d23 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -5,6 +5,7 @@ default: OTHERFLAGS="--lax" make -C sha256 make -C barrett make -C kyber_compress + make -C proverif-psk clean: make -C limited-order-book clean diff --git a/examples/proverif-psk/Makefile b/examples/proverif-psk/Makefile new file mode 100644 index 000000000..37cea0ed4 --- /dev/null +++ b/examples/proverif-psk/Makefile @@ -0,0 +1,8 @@ +check: proofs/proverif/extraction/analysis.pv ./proofs/proverif/extraction/lib.pvl + proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv + +proofs/proverif/extraction/%: + cargo hax into pro-verif + +clean: + rm -f proofs/fstar/extraction/* From ac864077b0be4627bbbbf82e65f2a6bd3cf4981d Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Thu, 24 Oct 2024 15:16:36 +0200 Subject: [PATCH 145/253] Add timeout for PV --- examples/proverif-psk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/proverif-psk/Makefile b/examples/proverif-psk/Makefile index 37cea0ed4..05ae18de5 100644 --- a/examples/proverif-psk/Makefile +++ b/examples/proverif-psk/Makefile @@ -1,5 +1,5 @@ check: proofs/proverif/extraction/analysis.pv ./proofs/proverif/extraction/lib.pvl - proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv + timeout 30 proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv proofs/proverif/extraction/%: cargo hax into pro-verif From 4db6535ed092a1fe6b2376de10fc3b5929154da3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 15:37:45 +0200 Subject: [PATCH 146/253] fix(ci/pv): fitler clean only `*.pvl`, not `*.pv` --- examples/Makefile | 1 + examples/default.nix | 4 ++-- examples/proverif-psk/Makefile | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 62a6e2d23..583193f08 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -13,3 +13,4 @@ clean: make -C sha256 clean make -C barrett clean make -C kyber_compress clean + make -C proverif-psk clean diff --git a/examples/default.nix b/examples/default.nix index 7daa30ee6..007bba6c2 100644 --- a/examples/default.nix +++ b/examples/default.nix @@ -16,8 +16,8 @@ src = craneLib.path ./..; filter = path: type: # We include only certain files. FStar files under the example - # directory are listed out. - ( matches ".*(Makefile|.*[.](rs|toml|lock|diff|fsti?))$" path + # directory are listed out. Same for proverif (*.pvl) files. + ( matches ".*(Makefile|.*[.](rs|toml|lock|diff|fsti?|pvl))$" path && !matches ".*examples/.*[.]fsti?$" path ) || ("directory" == type); }; diff --git a/examples/proverif-psk/Makefile b/examples/proverif-psk/Makefile index 05ae18de5..777350131 100644 --- a/examples/proverif-psk/Makefile +++ b/examples/proverif-psk/Makefile @@ -1,8 +1,9 @@ -check: proofs/proverif/extraction/analysis.pv ./proofs/proverif/extraction/lib.pvl +check: ./proofs/proverif/extraction/lib.pvl timeout 30 proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv + proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv -proofs/proverif/extraction/%: +proofs/proverif/extraction/lib.pvl: cargo hax into pro-verif clean: - rm -f proofs/fstar/extraction/* + rm -f proofs/fstar/extraction/lib.pvl From d13dc2e4f54942c2e95a19a388646b99277412a3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 15:25:06 +0200 Subject: [PATCH 147/253] feat(ci): add a job for licenses --- .github/workflows/licenses.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/licenses.yml diff --git a/.github/workflows/licenses.yml b/.github/workflows/licenses.yml new file mode 100644 index 000000000..914ab0ab7 --- /dev/null +++ b/.github/workflows/licenses.yml @@ -0,0 +1,27 @@ +name: Check licenses + +on: + pull_request: + merge_group: + workflow_dispatch: + push: + branches: [main] + +jobs: + tests: + name: nix-action + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: extractions/setup-just@v1 + - name: Set-up OCaml + uses: ocaml/setup-ocaml@v3 + with: + ocaml-compiler: 5 + - name: Install cargo-deny + run: cargo install cargo-deny + - name: Install cargo-deny + run: cargo install toml2json + - name: Check the licenses + run: just check-licenses + From 1caec6845668d91beecf482683069c8dff724796 Mon Sep 17 00:00:00 2001 From: Jonas Schneider-Bensch Date: Thu, 24 Oct 2024 15:55:52 +0200 Subject: [PATCH 148/253] Makefile fixes --- examples/proverif-psk/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/proverif-psk/Makefile b/examples/proverif-psk/Makefile index 777350131..8e337d064 100644 --- a/examples/proverif-psk/Makefile +++ b/examples/proverif-psk/Makefile @@ -1,9 +1,8 @@ check: ./proofs/proverif/extraction/lib.pvl timeout 30 proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv - proverif -lib ./proofs/proverif/extraction/lib.pvl ./proofs/proverif/extraction/analysis.pv proofs/proverif/extraction/lib.pvl: cargo hax into pro-verif clean: - rm -f proofs/fstar/extraction/lib.pvl + rm -f proofs/proverif/extraction/lib.pvl From f2327c266ac090783fcc53f40140ad6917c400fc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 24 Oct 2024 11:51:51 +0200 Subject: [PATCH 149/253] Upgrade rustc pin --- cli/subcommands/src/cargo_hax.rs | 1 + engine/lib/import_thir.ml | 4 +-- flake.lock | 6 ++-- frontend/exporter/src/constant_utils.rs | 4 +-- frontend/exporter/src/rustc_utils.rs | 8 ----- frontend/exporter/src/state.rs | 2 +- frontend/exporter/src/traits.rs | 4 ++- frontend/exporter/src/traits/utils.rs | 27 +++++++++++++--- frontend/exporter/src/types/hir.rs | 28 ++++++++-------- frontend/exporter/src/types/mir.rs | 18 ++++++++--- frontend/exporter/src/types/new/full_def.rs | 7 ++-- frontend/exporter/src/types/thir.rs | 2 +- frontend/exporter/src/types/ty.rs | 36 +++++++++++++-------- hax-types/src/lib.rs | 1 + rust-toolchain.toml | 2 +- test-harness/src/harness.rs | 1 + 16 files changed, 94 insertions(+), 57 deletions(-) diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index d5e1691cb..a2bf5e666 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -1,3 +1,4 @@ +#![feature(rustc_private)] use annotate_snippets::{Level, Renderer}; use clap::Parser; use colored::Colorize; diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 9e6a699be..f19449c2b 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -644,7 +644,7 @@ end) : EXPR = struct let e' = c_expr arg in let kind = c_borrow_kind e.span kind in Borrow { kind; e = e'; witness = W.reference } - | AddressOf { arg; mutability = mut } -> + | RawBorrow { arg; mutability = mut } -> let e = c_expr arg in AddressOf { @@ -1763,7 +1763,7 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = | Union _ -> unimplemented ~issue_id:998 [ item.span ] "Union types: not supported" | ExternCrate _ | Static _ | Macro _ | Mod _ | ForeignMod _ | GlobalAsm _ - | OpaqueTy _ | TraitAlias _ -> + | TraitAlias _ -> mk NotImplementedYet let import_item ~drop_body (item : Thir.item) : diff --git a/flake.lock b/flake.lock index ba2824fa7..afe019a9f 100644 --- a/flake.lock +++ b/flake.lock @@ -110,11 +110,11 @@ ] }, "locked": { - "lastModified": 1723429325, - "narHash": "sha256-4x/32xTCd+xCwFoI/kKSiCr5LQA2ZlyTRYXKEni5HR8=", + "lastModified": 1729736953, + "narHash": "sha256-Rb6JUop7NRklg0uzcre+A+Ebrn/ZiQPkm4QdKg6/3pw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "65e3dc0fe079fe8df087cd38f1fe6836a0373aad", + "rev": "29b1275740d9283467b8117499ec8cbb35250584", "type": "github" }, "original": { diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 867ac44f7..a8e2afbf6 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -186,7 +186,7 @@ mod rustc { borrow_kind: BorrowKind::Shared, arg: e.into(), }, - MutPtr(e) => ExprKind::AddressOf { + MutPtr(e) => ExprKind::RawBorrow { mutability: true, arg: e.into(), }, @@ -462,7 +462,7 @@ mod rustc { impl<'tcx> ConstantExt<'tcx> for ty::Const<'tcx> { fn eval_constant>(&self, s: &S) -> Option { let (ty, evaluated) = self - .eval(s.base().tcx, s.param_env(), rustc_span::DUMMY_SP) + .eval_valtree(s.base().tcx, s.param_env(), rustc_span::DUMMY_SP) .ok()?; let evaluated = ty::Const::new(s.base().tcx, ty::ConstKind::Value(ty, evaluated)); (&evaluated != self).then_some(evaluated) diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index 96de95f7c..cb24dffca 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -12,14 +12,6 @@ impl<'tcx, T: ty::TypeFoldable>> ty::Binder<'tcx, T> { } } -#[tracing::instrument(skip(s))] -pub(crate) fn arrow_of_sig<'tcx, S: UnderOwnerState<'tcx>>( - sig: &ty::PolyFnSig<'tcx>, - s: &S, -) -> TyKind { - TyKind::Arrow(Box::new(sig.sinto(s))) -} - #[tracing::instrument(skip(s))] pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( adt_def: &ty::AdtDef<'s>, diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 30300f136..7982823e3 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -348,7 +348,7 @@ impl ImplInfos { .impl_trait_ref(did) .map(|trait_ref| trait_ref.instantiate_identity()) .sinto(s), - clauses: tcx.predicates_defined_on(did).predicates.sinto(s), + clauses: predicates_defined_on(tcx, did).predicates.sinto(s), } } } diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index fc162289c..0abd22f5f 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -5,7 +5,9 @@ mod resolution; #[cfg(feature = "rustc")] mod utils; #[cfg(feature = "rustc")] -pub use utils::{erase_and_norm, implied_predicates, required_predicates, self_predicate}; +pub use utils::{ + erase_and_norm, implied_predicates, predicates_defined_on, required_predicates, self_predicate, +}; #[cfg(feature = "rustc")] pub use resolution::PredicateSearcher; diff --git a/frontend/exporter/src/traits/utils.rs b/frontend/exporter/src/traits/utils.rs index 244692303..cc06e573e 100644 --- a/frontend/exporter/src/traits/utils.rs +++ b/frontend/exporter/src/traits/utils.rs @@ -30,6 +30,26 @@ use rustc_hir::def::DefKind; use rustc_middle::ty::*; use rustc_span::def_id::DefId; +/// Returns a list of type predicates for the definition with ID `def_id`, including inferred +/// lifetime constraints. This is the basic list of predicates we use for essentially all items. +pub fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> GenericPredicates<'_> { + let mut result = tcx.explicit_predicates_of(def_id); + let inferred_outlives = tcx.inferred_outlives_of(def_id); + if !inferred_outlives.is_empty() { + let inferred_outlives_iter = inferred_outlives + .iter() + .map(|(clause, span)| ((*clause).upcast(tcx), *span)); + result.predicates = tcx.arena.alloc_from_iter( + result + .predicates + .into_iter() + .copied() + .chain(inferred_outlives_iter), + ); + } + result +} + /// The predicates that must hold to mention this item. pub fn required_predicates<'tcx>( tcx: TyCtxt<'tcx>, @@ -51,14 +71,14 @@ pub fn required_predicates<'tcx>( | TraitAlias | TyAlias | Union => Some( - tcx.predicates_defined_on(def_id) + predicates_defined_on(tcx, def_id) .predicates .iter() .map(|(clause, _span)| *clause), ), // We consider all predicates on traits to be outputs Trait => None, - // `predicates_defined_on ICEs on other def kinds. + // `predicates_defined_on` ICEs on other def kinds. _ => None, } .into_iter() @@ -85,8 +105,7 @@ pub fn implied_predicates<'tcx>( use DefKind::*; match tcx.def_kind(def_id) { // We consider all predicates on traits to be outputs - Trait => tcx - .predicates_defined_on(def_id) + Trait => predicates_defined_on(tcx, def_id) .predicates .iter() .map(|(clause, _span)| *clause) diff --git a/frontend/exporter/src/types/hir.rs b/frontend/exporter/src/types/hir.rs index 5abeab8cd..4287fb190 100644 --- a/frontend/exporter/src/types/hir.rs +++ b/frontend/exporter/src/types/hir.rs @@ -440,9 +440,7 @@ pub struct Impl { let trait_did = tcx.trait_id_of_impl(owner_id); if let Some(trait_did) = trait_did { tcx.explicit_super_predicates_of(trait_did) - .predicates - .iter() - .copied() + .iter_identity_copied() .filter_map(|(clause, span)| super_clause_to_clause_and_impl_expr(s, owner_id, clause, span)) .collect::>() } else { @@ -665,7 +663,6 @@ pub enum ItemKind { Ty, Generics, ), - OpaqueTy(OpaqueTy), Enum( EnumDef, Generics, @@ -768,7 +765,7 @@ impl<'a, 'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto>> #[derive(Clone, Debug, JsonSchema)] #[derive_group(Serializers)] pub enum ForeignItemKind { - Fn(FnDecl, Vec, Generics, Safety), + Fn(FnSig, Vec, Generics), Static(Ty, Mutability, Safety), Type, } @@ -803,7 +800,6 @@ pub struct OpaqueTy { pub generics: Generics, pub bounds: GenericBounds, pub origin: OpaqueTyOrigin, - pub in_trait: bool, } /// Reflects [`hir::GenericBounds`] @@ -825,10 +821,7 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. - }) | hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }), - .. - }) + }) | hir::Node::OpaqueTy(..), ) } else { false @@ -841,7 +834,7 @@ fn region_bounds_at_current_owner<'tcx, S: UnderOwnerState<'tcx>>(s: &S) -> Gene .iter() .collect() } else { - tcx.predicates_defined_on(s.owner_id()) + predicates_defined_on(tcx, s.owner_id()) .predicates .iter() .map(|(x, _span)| x) @@ -864,9 +857,16 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for hir::GenericBou #[derive(Clone, Debug, JsonSchema)] #[derive_group(Serializers)] pub enum OpaqueTyOrigin { - FnReturn(GlobalIdent), - AsyncFn(GlobalIdent), - TyAlias { in_assoc_ty: bool }, + FnReturn { + parent: GlobalIdent, + }, + AsyncFn { + parent: GlobalIdent, + }, + TyAlias { + parent: GlobalIdent, + in_assoc_ty: bool, + }, } /// Reflects [`rustc_ast::tokenstream::TokenStream`] as a plain diff --git a/frontend/exporter/src/types/mir.rs b/frontend/exporter/src/types/mir.rs index 11b230421..ecc4d9d72 100644 --- a/frontend/exporter/src/types/mir.rs +++ b/frontend/exporter/src/types/mir.rs @@ -469,7 +469,7 @@ fn get_function_from_operand<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>( trace!("type: {:?}", ty); trace!("type kind: {:?}", ty.kind()); let sig = match ty.kind() { - rustc_middle::ty::TyKind::FnPtr(sig) => sig, + rustc_middle::ty::TyKind::FnPtr(sig, ..) => sig, _ => unreachable!(), }; trace!("FnPtr: {:?}", sig); @@ -996,12 +996,11 @@ pub enum AggregateKind { #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] -#[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::CastKind, state: S as s)] +#[args(<'tcx, S>, from: rustc_middle::mir::CastKind, state: S as _s)] pub enum CastKind { PointerExposeProvenance, PointerWithExposedProvenance, - PointerCoercion(PointerCoercion), - DynStar, + PointerCoercion(PointerCoercion, CoercionSource), IntToInt, FloatToInt, FloatToFloat, @@ -1011,6 +1010,14 @@ pub enum CastKind { Transmute, } +#[derive_group(Serializers)] +#[derive(AdtInto, Clone, Debug, JsonSchema)] +#[args(<'tcx, S>, from: rustc_middle::mir::CoercionSource, state: S as _s)] +pub enum CoercionSource { + AsCast, + Implicit, +} + #[derive_group(Serializers)] #[derive(AdtInto, Clone, Debug, JsonSchema)] #[args(<'tcx, S: UnderOwnerState<'tcx> + HasMir<'tcx>>, from: rustc_middle::mir::NullOp<'tcx>, state: S as s)] @@ -1035,7 +1042,7 @@ pub enum Rvalue { Repeat(Operand, ConstantExpr), Ref(Region, BorrowKind, Place), ThreadLocalRef(DefId), - AddressOf(Mutability, Place), + RawPtr(Mutability, Place), Len(Place), Cast(CastKind, Operand, Ty), BinaryOp(BinOp, (Operand, Operand)), @@ -1129,6 +1136,7 @@ pub enum ScopeData { Arguments, Destruction, IfThen, + IfThenRescope, Remainder(FirstStatementIndex), } diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index f2fcdc1ae..899f3fc6b 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -308,6 +308,9 @@ pub enum FullDefKind { LifetimeParam, /// A use of `global_asm!`. GlobalAsm, + /// A synthetic coroutine body created by the lowering of a coroutine-closure, such as an async + /// closure. + SyntheticCoroutineBody, } impl FullDef { @@ -425,6 +428,7 @@ fn get_def_visibility<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Option None, } } @@ -473,8 +477,7 @@ fn get_generic_predicates<'tcx, S: UnderOwnerState<'tcx>>( s: &S, def_id: RDefId, ) -> GenericPredicates { - // We use `predicates_defined_on` to skip the implied `Self` clause. - let predicates = s.base().tcx.predicates_defined_on(def_id); + let predicates = predicates_defined_on(s.base().tcx, def_id); let pred_list = normalize_trait_clauses(s, predicates.predicates); GenericPredicates { parent: predicates.parent.sinto(s), diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index a7c991bbd..3c579297a 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -764,7 +764,7 @@ pub enum ExprKind { borrow_kind: BorrowKind, arg: Expr, }, - AddressOf { + RawBorrow { mutability: Mutability, arg: Expr, }, diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index 1e9403df0..8d4c9970a 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -772,7 +772,7 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_middle::ty::Ty<'tcx> /// Reflects [`ty::TyKind`] #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::TyKind<'tcx>, state: S as state)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: ty::TyKind<'tcx>, state: S as s)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum TyKind { @@ -783,15 +783,24 @@ pub enum TyKind { Float(FloatTy), #[custom_arm( - ty::TyKind::FnPtr(sig) => arrow_of_sig(sig, state), + ty::TyKind::FnPtr(tys, header) => { + let sig = tys.map_bound(|tys| ty::FnSig { + inputs_and_output: tys.inputs_and_output, + c_variadic: header.c_variadic, + safety: header.safety, + abi: header.abi, + }); + TyKind::Arrow(Box::new(sig.sinto(s))) + }, ty::TyKind::FnDef(def, generics) => { - let tcx = state.base().tcx; - arrow_of_sig(&tcx.fn_sig(*def).instantiate(tcx, generics), state) + let tcx = s.base().tcx; + let sig = tcx.fn_sig(*def).instantiate(tcx, generics); + TyKind::Arrow(Box::new(sig.sinto(s))) }, - FROM_TYPE::Closure (_defid, generics) => { + ty::TyKind::Closure (_def_id, generics) => { let sig = generics.as_closure().sig(); - let sig = state.base().tcx.signature_unclosure(sig, rustc_hir::Safety::Safe); - arrow_of_sig(&sig, state) + let sig = s.base().tcx.signature_unclosure(sig, rustc_hir::Safety::Safe); + TyKind::Arrow(Box::new(sig.sinto(s))) }, )] /// Reflects [`ty::TyKind::FnPtr`], [`ty::TyKind::FnDef`] and [`ty::TyKind::Closure`] @@ -799,9 +808,9 @@ pub enum TyKind { #[custom_arm( ty::TyKind::Adt(adt_def, generics) => { - let def_id = adt_def.did().sinto(state); - let generic_args: Vec = generics.sinto(state); - let trait_refs = solve_item_required_traits(state, adt_def.did(), generics); + let def_id = adt_def.did().sinto(s); + let generic_args: Vec = generics.sinto(s); + let trait_refs = solve_item_required_traits(s, adt_def.did(), generics); TyKind::Adt { def_id, generic_args, trait_refs } }, )] @@ -815,7 +824,7 @@ pub enum TyKind { }, Foreign(DefId), Str, - Array(Box, #[map(Box::new(x.sinto(state)))] Box), + Array(Box, #[map(Box::new(x.sinto(s)))] Box), Slice(Box), RawPtr(Box, Mutability), Ref(Region, Box, Mutability), @@ -825,7 +834,7 @@ pub enum TyKind { Tuple(Vec), #[custom_arm( ty::TyKind::Alias(alias_kind, alias_ty) => { - Alias::from(state, alias_kind, alias_ty) + Alias::from(s, alias_kind, alias_ty) }, )] Alias(Alias), @@ -949,6 +958,7 @@ pub enum PointerCoercion { ClosureFnPointer(Safety), MutToConstPointer, ArrayToPointer, + DynStar, Unsize, } @@ -1292,7 +1302,7 @@ sinto_todo!(rustc_middle::ty, NormalizesTo<'tcx>); #[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum PredicateKind { Clause(ClauseKind), - ObjectSafe(DefId), + DynCompatible(DefId), Subtype(SubtypePredicate), Coerce(CoercePredicate), ConstEquate(ConstantExpr, ConstantExpr), diff --git a/hax-types/src/lib.rs b/hax-types/src/lib.rs index b59b7b0d0..07129a9bf 100644 --- a/hax-types/src/lib.rs +++ b/hax-types/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(rustc_private)] //! This crate contains the type definitions that are used to communicate between: //! - the command line (the `cargo-hax` binary); //! - the custom rustc driver; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 9d093adde..43384737a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-08-11" +channel = "nightly-2024-10-23" components = [ "rustc-dev", "llvm-tools-preview" , "rust-analysis" , "rust-src" , "rustfmt" ] diff --git a/test-harness/src/harness.rs b/test-harness/src/harness.rs index 6d3c0db90..88753913e 100644 --- a/test-harness/src/harness.rs +++ b/test-harness/src/harness.rs @@ -1,3 +1,4 @@ +#![feature(rustc_private)] mod command_hax_ext; use command_hax_ext::*; use serde_json::{Map, Value}; From 9331cecefc38c005d97d03f1c33138bea32a07ed Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 15:57:15 +0200 Subject: [PATCH 150/253] fix ci --- examples/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/default.nix b/examples/default.nix index 007bba6c2..e4fb8e65d 100644 --- a/examples/default.nix +++ b/examples/default.nix @@ -17,7 +17,7 @@ filter = path: type: # We include only certain files. FStar files under the example # directory are listed out. Same for proverif (*.pvl) files. - ( matches ".*(Makefile|.*[.](rs|toml|lock|diff|fsti?|pvl))$" path + ( matches ".*(Makefile|.*[.](rs|toml|lock|diff|fsti?|pv))$" path && !matches ".*examples/.*[.]fsti?$" path ) || ("directory" == type); }; From ff07699d883ee4bec7626cadbcda514ea6775c2d Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Thu, 24 Oct 2024 16:46:19 +0200 Subject: [PATCH 151/253] bump rlimit --- examples/Cargo.lock | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 61ed48fed..010c0d23f 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -181,6 +181,16 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck", + "proc-macro-error", +] + [[package]] name = "either" version = "1.9.0" @@ -222,14 +232,16 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hax-bounded-integers" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ + "duplicate", "hax-lib", + "paste", ] [[package]] name = "hax-lib" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros", "num-bigint", @@ -238,9 +250,10 @@ dependencies = [ [[package]] name = "hax-lib-macros" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "hax-lib-macros-types", + "paste", "proc-macro-error", "proc-macro2", "quote", @@ -249,7 +262,7 @@ dependencies = [ [[package]] name = "hax-lib-macros-types" -version = "0.1.0-pre.1" +version = "0.1.0-alpha.1" dependencies = [ "proc-macro2", "quote", @@ -258,6 +271,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex" version = "0.4.3" @@ -430,9 +449,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pretty" From f2b95c3df6bc1ae81d4a58edea166add68139cff Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 16:47:45 +0200 Subject: [PATCH 152/253] fix newline --- deny.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deny.toml b/deny.toml index 293de552a..cae10ee5b 100644 --- a/deny.toml +++ b/deny.toml @@ -10,4 +10,4 @@ allow = [ "LGPL-2.1", "LGPL-2.0", "ISC", -] \ No newline at end of file +] From 70d54c9bfd6c942696fba4bea4264f50930d9bc4 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 16:48:53 +0200 Subject: [PATCH 153/253] Fix for constructors passed as closure. --- engine/lib/import_thir.ml | 15 ++++++++++++--- frontend/exporter/src/constant_utils.rs | 10 +++++++++- frontend/exporter/src/rustc_utils.rs | 12 ++++++++++++ frontend/exporter/src/types/thir.rs | 25 +++++++++++++++++++++++-- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index f19449c2b..7af3249f8 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -518,7 +518,7 @@ end) : EXPR = struct let f = let f = c_expr fun' in match (trait, fun'.contents) with - | Some _, GlobalName { id } -> + | Some _, GlobalName { id; _ } -> { f with e = GlobalVar (def_id (AssociatedItem Value) id) } | _ -> f in @@ -638,7 +638,15 @@ end) : EXPR = struct trait = None (* TODO: see issue #328 *); bounds_impls = []; } - | GlobalName { id } -> GlobalVar (def_id Value id) + | GlobalName { id; constructor } -> + let kind = + match constructor with + | Some { kind = Struct _; _ } -> + Concrete_ident.Kind.Constructor { is_struct = true } + | Some _ -> Concrete_ident.Kind.Constructor { is_struct = false } + | None -> Concrete_ident.Kind.Value + in + GlobalVar (def_id kind id) | UpvarRef { var_hir_id = id; _ } -> LocalVar (local_ident Expr id) | Borrow { arg; borrow_kind = kind } -> let e' = c_expr arg in @@ -824,7 +832,8 @@ end) : EXPR = struct Array { fields = List.map ~f:constant_expr_to_expr fields } | Tuple { fields } -> Tuple { fields = List.map ~f:constant_expr_to_expr fields } - | GlobalName { id; _ } -> GlobalName { id } + | GlobalName { id; variant_information; _ } -> + GlobalName { id; constructor = variant_information } | Borrow arg -> Borrow { arg = constant_expr_to_expr arg; borrow_kind = Thir.Shared } | ConstRef { id } -> ConstRef { id } diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index a8e2afbf6..acaa7d0d7 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -62,6 +62,7 @@ pub enum ConstantExprKind { id: GlobalIdent, generics: Vec, trait_refs: Vec, + variant_information: Option, }, /// A trait constant /// @@ -181,7 +182,11 @@ mod rustc { id, generics: _, trait_refs: _, - } => ExprKind::GlobalName { id }, + variant_information, + } => ExprKind::GlobalName { + id, + constructor: variant_information, + }, Borrow(e) => ExprKind::Borrow { borrow_kind: BorrowKind::Shared, arg: e.into(), @@ -288,6 +293,7 @@ mod rustc { id: did.sinto(s), generics: Vec::new(), trait_refs: Vec::new(), + variant_information: None, }, GlobalAlloc::Memory(alloc) => { let values = alloc.inner().get_bytes_unchecked( @@ -442,6 +448,7 @@ mod rustc { id, generics, trait_refs, + variant_information: None, } } } else { @@ -452,6 +459,7 @@ mod rustc { id, generics: vec![], trait_refs: vec![], + variant_information: None, } }; let cv = kind.decorate(ty.sinto(s), span.sinto(s)); diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index cb24dffca..4f3bd539c 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -257,3 +257,15 @@ pub fn inline_macro_invocations<'t, S: BaseState<'t>, Body: IsBody>( }) .collect() } + +pub fn closest_parent_type( + tcx: &ty::TyCtxt, + id: rustc_span::def_id::DefId, +) -> rustc_span::def_id::DefId { + match tcx.def_kind(id) { + rustc_hir::def::DefKind::Union + | rustc_hir::def::DefKind::Struct + | rustc_hir::def::DefKind::Enum => id, + _ => closest_parent_type(tcx, tcx.parent(id)), + } +} diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index 3c579297a..9c2fe9398 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -201,8 +201,27 @@ impl<'tcx, S: ExprState<'tcx>> SInto for thir::Expr<'tcx> { let params: Vec = params.map(|i| tcx.erase_late_bound_regions(i)).collect(); */ + let tcx = s.base().tcx; + let id: DefId = def.clone().sinto(s); + let rustc_id = (&id).into(); + let constructor = if tcx.is_constructor(rustc_id) { + let adt_def = + tcx.adt_def(rustc_utils::closest_parent_type(&tcx, rustc_id)); + let variant_id = tcx.parent(rustc_id); + let variant_index = adt_def.variant_index_with_id(variant_id); + Some(rustc_utils::get_variant_information( + &adt_def, + variant_index, + s, + )) + } else { + None + }; return Expr { - contents: Box::new(ExprKind::GlobalName { id: def.sinto(s) }), + contents: Box::new(ExprKind::GlobalName { + id: def.sinto(s), + constructor, + }), span: self.span.sinto(s), ty: ty.sinto(s), hir_id, @@ -577,7 +596,8 @@ pub enum ExprKind { let (hir_id, attributes) = e.hir_id_and_attributes(gstate); let hir_id = hir_id.map(|hir_id| hir_id.index()); let contents = Box::new(ExprKind::GlobalName { - id: def_id.sinto(gstate) + id: def_id.sinto(gstate), + constructor: None }); let mut translated_generics = generics.sinto(gstate); let tcx = gstate.base().tcx; @@ -755,6 +775,7 @@ pub enum ExprKind { #[disable_mapping] GlobalName { id: GlobalIdent, + constructor: Option, }, UpvarRef { closure_def_id: DefId, From 7f82e378011997434da2cbc3d429374908eba2bd Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 17:03:10 +0200 Subject: [PATCH 154/253] Add tests for constructor as closure. --- tests/Cargo.lock | 6 +++++- tests/Cargo.toml | 1 + tests/constructor-as-closure/Cargo.toml | 9 +++++++++ tests/constructor-as-closure/src/lib.rs | 15 +++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/constructor-as-closure/Cargo.toml create mode 100644 tests/constructor-as-closure/src/lib.rs diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 2c6d55fa9..09cd8e14b 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "abstract_integers" @@ -150,6 +150,10 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "constructor-as-closure" +version = "0.1.0" + [[package]] name = "criterion" version = "0.4.0" diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 10969e04d..df3b03ffa 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -35,5 +35,6 @@ members = [ "guards", "cyclic-modules", "unsafe", + "constructor-as-closure", ] resolver = "2" diff --git a/tests/constructor-as-closure/Cargo.toml b/tests/constructor-as-closure/Cargo.toml new file mode 100644 index 000000000..523a0ff06 --- /dev/null +++ b/tests/constructor-as-closure/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "constructor-as-closure" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[package.metadata.hax-tests] +into."fstar" = { broken = false, snapshot = "stdout", issue_id = "914" } diff --git a/tests/constructor-as-closure/src/lib.rs b/tests/constructor-as-closure/src/lib.rs new file mode 100644 index 000000000..5d11085fe --- /dev/null +++ b/tests/constructor-as-closure/src/lib.rs @@ -0,0 +1,15 @@ +struct Test(i32); +impl Test { + pub fn test(x: Option) -> Option { + x.map(Self) + } +} +pub enum Context { + A(i32), + B(i32), +} +impl Context { + pub fn test(x: Option) -> Option { + x.map(Self::B) + } +} From 5bc769e7ad851c43d4b5219237018b48c26f6997 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 17:18:33 +0200 Subject: [PATCH 155/253] Correct style. --- frontend/exporter/src/rustc_utils.rs | 5 +++-- frontend/exporter/src/types/thir.rs | 13 +++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index 4f3bd539c..8d4c56628 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -258,7 +258,8 @@ pub fn inline_macro_invocations<'t, S: BaseState<'t>, Body: IsBody>( .collect() } -pub fn closest_parent_type( +/// Gets the closest ancestor of `id` that is the id of a type. +pub fn get_closest_parent_type( tcx: &ty::TyCtxt, id: rustc_span::def_id::DefId, ) -> rustc_span::def_id::DefId { @@ -266,6 +267,6 @@ pub fn closest_parent_type( rustc_hir::def::DefKind::Union | rustc_hir::def::DefKind::Struct | rustc_hir::def::DefKind::Enum => id, - _ => closest_parent_type(tcx, tcx.parent(id)), + _ => get_closest_parent_type(tcx, tcx.parent(id)), } } diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index 9c2fe9398..959ea3739 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -190,7 +190,7 @@ impl<'tcx, S: ExprState<'tcx>> SInto for thir::Expr<'tcx> { return cexpr.into(); } thir::ExprKind::ZstLiteral { .. } => match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def, _generics) => { + rustc_middle::ty::TyKind::FnDef(def_id, _generics) => { /* TODO: translate generics let tcx = s.base().tcx; let sig = &tcx.fn_sig(*def).instantiate(tcx, generics); @@ -202,13 +202,10 @@ impl<'tcx, S: ExprState<'tcx>> SInto for thir::Expr<'tcx> { params.map(|i| tcx.erase_late_bound_regions(i)).collect(); */ let tcx = s.base().tcx; - let id: DefId = def.clone().sinto(s); - let rustc_id = (&id).into(); - let constructor = if tcx.is_constructor(rustc_id) { + let constructor = if tcx.is_constructor(*def_id) { let adt_def = - tcx.adt_def(rustc_utils::closest_parent_type(&tcx, rustc_id)); - let variant_id = tcx.parent(rustc_id); - let variant_index = adt_def.variant_index_with_id(variant_id); + tcx.adt_def(rustc_utils::get_closest_parent_type(&tcx, *def_id)); + let variant_index = adt_def.variant_index_with_id(tcx.parent(*def_id)); Some(rustc_utils::get_variant_information( &adt_def, variant_index, @@ -219,7 +216,7 @@ impl<'tcx, S: ExprState<'tcx>> SInto for thir::Expr<'tcx> { }; return Expr { contents: Box::new(ExprKind::GlobalName { - id: def.sinto(s), + id: def_id.sinto(s), constructor, }), span: self.span.sinto(s), From f3c98241eb347326ed9ea5c4d8073097a60b6f1d Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Thu, 24 Oct 2024 17:19:26 +0200 Subject: [PATCH 156/253] Add test snapshot for constructor-as-closure. --- ...in__constructor-as-closure into-fstar.snap | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test-harness/src/snapshots/toolchain__constructor-as-closure into-fstar.snap diff --git a/test-harness/src/snapshots/toolchain__constructor-as-closure into-fstar.snap b/test-harness/src/snapshots/toolchain__constructor-as-closure into-fstar.snap new file mode 100644 index 000000000..6f8919b71 --- /dev/null +++ b/test-harness/src/snapshots/toolchain__constructor-as-closure into-fstar.snap @@ -0,0 +1,46 @@ +--- +source: test-harness/src/harness.rs +expression: snapshot +info: + kind: + Translate: + backend: fstar + info: + name: constructor-as-closure + manifest: constructor-as-closure/Cargo.toml + description: ~ + spec: + optional: false + broken: false + issue_id: ~ + positive: true + snapshot: + stderr: false + stdout: true + include_flag: ~ + backend_options: ~ +--- +exit = 0 + +[stdout] +diagnostics = [] + +[stdout.files] +"Constructor_as_closure.fst" = ''' +module Constructor_as_closure +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_Context = + | Context_A : i32 -> t_Context + | Context_B : i32 -> t_Context + +type t_Test = | Test : i32 -> t_Test + +let impl__Test__test (x: Core.Option.t_Option i32) : Core.Option.t_Option t_Test = + Core.Option.impl__map #i32 #t_Test x Test + +let impl__Context__test (x: Core.Option.t_Option i32) : Core.Option.t_Option t_Context = + Core.Option.impl__map #i32 #t_Context x Context_B +''' From d5ed2867f8359d7cf486b48ff2f87cf7cf369dee Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 17:43:33 +0200 Subject: [PATCH 157/253] fix(pv): fix locally a division by zero occuring in Proverif This division by zero occurs when proverif is ran from a non-TTY. --- examples/default.nix | 7 ++++++- examples/proverif-psk/pv_div_by_zero_fix.diff | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 examples/proverif-psk/pv_div_by_zero_fix.diff diff --git a/examples/default.nix b/examples/default.nix index e4fb8e65d..bd602e515 100644 --- a/examples/default.nix +++ b/examples/default.nix @@ -47,5 +47,10 @@ in sed -i "s/make -C limited-order-book/HAX_VANILLA_RUSTC=never make -C limited-order-book/g" Makefile make ''; - buildInputs = [hax hax-env fstar jq proverif]; + buildInputs = [ + hax hax-env fstar jq + (proverif.overrideDerivation (_: { + patches = [ ./proverif-psk/pv_div_by_zero_fix.diff ]; + })) + ]; }) diff --git a/examples/proverif-psk/pv_div_by_zero_fix.diff b/examples/proverif-psk/pv_div_by_zero_fix.diff new file mode 100644 index 000000000..fec2cf726 --- /dev/null +++ b/examples/proverif-psk/pv_div_by_zero_fix.diff @@ -0,0 +1,13 @@ +diff proverif2.05/src/display.ml proverif2.05/src/display.ml +index c43785ec..2763d907 100644 +--- proverif/src/display.ml ++++ proverif/src/display.ml +@@ -49,7 +49,7 @@ let dynamic_display str = + then display_whitespace (!record_cursor_line - size); + (* If we cannot determine the number of columns, we just assume that the statistics + will fit on one line (the statistics will not be active by default) *) +- let lines = if columns = -1 then 0 else ((max (!record_cursor_line) size) - 1) / columns in ++ let lines = if columns <= 0 then 0 else ((max (!record_cursor_line) size) - 1) / columns in + (* Go to the beginning of the line *) + print_string "\r"; + if lines > 0 then From d663429d6bc1b0cdcb736c5602704ab982d668fa Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 24 Oct 2024 20:19:32 +0200 Subject: [PATCH 158/253] fix: rustc_private #1036 added an unconditional feature(rustc_private) on crate `hax-types`, but we need that to be non-nightly (this is consumed by other crates)! --- hax-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hax-types/src/lib.rs b/hax-types/src/lib.rs index 07129a9bf..167e9ccd9 100644 --- a/hax-types/src/lib.rs +++ b/hax-types/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![cfg_attr(feature = "rustc", feature(rustc_private))] //! This crate contains the type definitions that are used to communicate between: //! - the command line (the `cargo-hax` binary); //! - the custom rustc driver; From 2bb9a043804f3d69492a2d0f4f7be3bbda9f64d5 Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Fri, 25 Oct 2024 10:06:05 +0200 Subject: [PATCH 159/253] fix for conversion functions --- .../Rust_primitives.Integers.fsti | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti b/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti index f3678ca9f..9f1c5b531 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.Integers.fsti @@ -85,18 +85,18 @@ let v (#t:inttype) (x:int_t t) : range_t t = LI.v #t #LI.PUB x [@(strict_on_arguments [0])] val mk_int (#t:inttype) (n:range_t t) : int_t t -let mk_u8 x = mk_int #u8_inttype x -let mk_i8 x = mk_int #i8_inttype x -let mk_u16 x = mk_int #u16_inttype x -let mk_i16 x = mk_int #i16_inttype x -let mk_u32 x = mk_int #u32_inttype x -let mk_i32 x = mk_int #i32_inttype x -let mk_u64 x = mk_int #u64_inttype x -let mk_i64 x = mk_int #i64_inttype x -let mk_u128 x = mk_int #u128_inttype x -let mk_i128 x = mk_int #i128_inttype x -let mk_usize x = mk_int #usize_inttype x -let mk_isize x = mk_int #isize_inttype x +let mk_u8 x = FStar.UInt8.uint_to_t x +let mk_i8 x = FStar.Int8.int_to_t x +let mk_u16 x = FStar.UInt16.uint_to_t x +let mk_i16 x = FStar.Int16.int_to_t x +let mk_u32 x = FStar.UInt32.uint_to_t x +let mk_i32 x = FStar.Int32.int_to_t x +let mk_u64 x = FStar.UInt64.uint_to_t x +let mk_i64 x = FStar.Int64.int_to_t x +let mk_u128 x = FStar.UInt128.uint_to_t x +let mk_i128 x = FStar.Int128.int_to_t x +let mk_usize x = FStar.UInt32.uint_to_t x +let mk_isize x = FStar.Int32.int_to_t x let from_uint8 (x:FStar.UInt8.t) : u8 = x let from_int8 (x:FStar.Int8.t) : i8 = x @@ -108,8 +108,8 @@ let from_uint64 (x:FStar.UInt64.t) : u64 = x let from_int64 (x:FStar.Int64.t) : i64 = x let from_uint128 (x:FStar.UInt128.t) : u128 = x let from_int128 (x:FStar.Int128.t) : i128 = x -let from_usize (x:FStar.UInt32.t) : usize = mk_usize (FStar.UInt32.v x) -let from_isize (x:FStar.Int32.t) : isize = mk_isize (FStar.Int32.v x) +let from_usize (x:FStar.UInt32.t) : usize = mk_int (FStar.UInt32.v x) +let from_isize (x:FStar.Int32.t) : isize = mk_int (FStar.Int32.v x) let to_uint8 (x:u8) : FStar.UInt8.t = x let to_int8 (x:i8) : FStar.Int8.t = x From a58caa895a39098f3b59130a5de9fee4f20b6732 Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Fri, 25 Oct 2024 10:12:26 +0200 Subject: [PATCH 160/253] lock --- examples/Cargo.lock | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 010c0d23f..61ed48fed 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -181,16 +181,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "duplicate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" -dependencies = [ - "heck", - "proc-macro-error", -] - [[package]] name = "either" version = "1.9.0" @@ -232,16 +222,14 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "hax-bounded-integers" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ - "duplicate", "hax-lib", - "paste", ] [[package]] name = "hax-lib" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ "hax-lib-macros", "num-bigint", @@ -250,10 +238,9 @@ dependencies = [ [[package]] name = "hax-lib-macros" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ "hax-lib-macros-types", - "paste", "proc-macro-error", "proc-macro2", "quote", @@ -262,7 +249,7 @@ dependencies = [ [[package]] name = "hax-lib-macros-types" -version = "0.1.0-alpha.1" +version = "0.1.0-pre.1" dependencies = [ "proc-macro2", "quote", @@ -271,12 +258,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hex" version = "0.4.3" @@ -449,9 +430,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.15" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pretty" From f05e71f90f95e6ac7ee55f0dbcfecdcbf228fa6b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 25 Oct 2024 15:58:30 +0200 Subject: [PATCH 161/253] Don't recompute `def_kind` too much --- frontend/exporter/src/types/new/full_def.rs | 30 ++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 899f3fc6b..70e24d78a 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -1,6 +1,8 @@ use crate::prelude::*; use std::sync::Arc; +#[cfg(feature = "rustc")] +use rustc_hir::def::DefKind as RDefKind; #[cfg(feature = "rustc")] use rustc_middle::ty; #[cfg(feature = "rustc")] @@ -38,23 +40,25 @@ impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { } let tcx = s.base().tcx; let def_id = *self; + let def_kind = tcx.def_kind(def_id); let kind = { let state_with_id = with_owner_id(s.base(), (), (), def_id); - tcx.def_kind(def_id).sinto(&state_with_id) + def_kind.sinto(&state_with_id) }; let source_span = def_id.as_local().map(|ldid| tcx.source_span(ldid)); let source_text = source_span .filter(|source_span| source_span.ctxt().is_root()) .and_then(|source_span| tcx.sess.source_map().span_to_snippet(source_span).ok()); + let full_def = FullDef { def_id: self.sinto(s), parent: tcx.opt_parent(def_id).sinto(s), span: tcx.def_span(def_id).sinto(s), source_span: source_span.sinto(s), source_text, - attributes: get_def_attrs(tcx, def_id).sinto(s), - visibility: get_def_visibility(tcx, def_id), + attributes: get_def_attrs(tcx, def_id, def_kind).sinto(s), + visibility: get_def_visibility(tcx, def_id, def_kind), lang_item: s .base() .tcx @@ -395,9 +399,13 @@ impl FullDef { /// Gets the visibility (`pub` or not) of the definition. Returns `None` for defs that don't have a /// meaningful visibility. #[cfg(feature = "rustc")] -fn get_def_visibility<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Option { - use rustc_hir::def::DefKind::*; - match tcx.def_kind(def_id) { +fn get_def_visibility<'tcx>( + tcx: ty::TyCtxt<'tcx>, + def_id: RDefId, + def_kind: RDefKind, +) -> Option { + use RDefKind::*; + match def_kind { AssocConst | AssocFn | Const @@ -435,9 +443,13 @@ fn get_def_visibility<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Option(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> &'tcx [rustc_ast::ast::Attribute] { - use rustc_hir::def::DefKind::*; - match tcx.def_kind(def_id) { +fn get_def_attrs<'tcx>( + tcx: ty::TyCtxt<'tcx>, + def_id: RDefId, + def_kind: RDefKind, +) -> &'tcx [rustc_ast::ast::Attribute] { + use RDefKind::*; + match def_kind { // These kinds cause `get_attrs_unchecked` to panic. ConstParam | LifetimeParam | TyParam => &[], _ => tcx.get_attrs_unchecked(def_id), From 4903478ce32e74d42e228f6ce6fcf3ef541fd235 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 25 Oct 2024 15:58:48 +0200 Subject: [PATCH 162/253] Catch more query panics --- frontend/exporter/src/types/new/full_def.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 70e24d78a..501b498d2 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -54,7 +54,7 @@ impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { let full_def = FullDef { def_id: self.sinto(s), parent: tcx.opt_parent(def_id).sinto(s), - span: tcx.def_span(def_id).sinto(s), + span: get_def_span(tcx, def_id, def_kind).sinto(s), source_span: source_span.sinto(s), source_text, attributes: get_def_attrs(tcx, def_id, def_kind).sinto(s), @@ -396,6 +396,21 @@ impl FullDef { } } +/// Gets the attributes of the definition. +#[cfg(feature = "rustc")] +fn get_def_span<'tcx>( + tcx: ty::TyCtxt<'tcx>, + def_id: RDefId, + def_kind: RDefKind, +) -> rustc_span::Span { + use RDefKind::*; + match def_kind { + // These kinds cause `def_span` to panic. + ForeignMod => rustc_span::DUMMY_SP, + _ => tcx.def_span(def_id), + } +} + /// Gets the visibility (`pub` or not) of the definition. Returns `None` for defs that don't have a /// meaningful visibility. #[cfg(feature = "rustc")] @@ -451,7 +466,7 @@ fn get_def_attrs<'tcx>( use RDefKind::*; match def_kind { // These kinds cause `get_attrs_unchecked` to panic. - ConstParam | LifetimeParam | TyParam => &[], + ConstParam | LifetimeParam | TyParam | ForeignMod => &[], _ => tcx.get_attrs_unchecked(def_id), } } From cb6661c67a922e402efd35efe2f8a005ac25a167 Mon Sep 17 00:00:00 2001 From: Karthikeyan Bhargavan Date: Fri, 25 Oct 2024 18:23:10 +0200 Subject: [PATCH 163/253] count_ones and bool->int --- proof-libs/fstar/core/Core.Num.fsti | 1 + proof-libs/fstar/rust_primitives/Rust_primitives.fst | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/proof-libs/fstar/core/Core.Num.fsti b/proof-libs/fstar/core/Core.Num.fsti index 0f436ec05..7c994c747 100644 --- a/proof-libs/fstar/core/Core.Num.fsti +++ b/proof-libs/fstar/core/Core.Num.fsti @@ -46,6 +46,7 @@ val impl__i16__pow (base: i16) (exponent: u32): result: i16 {v base == 2 /\ v ex val impl__i32__pow (base: i32) (exponent: u32): result: i32 {v base == 2 /\ v exponent <= 16 ==> result == mk_int #Lib.IntTypes.S32 (pow2 (v exponent))} val impl__u8__count_ones: u8 -> r:u32{v r <= 8} +val impl__i32__count_ones: i32 -> r:u32{v r <= 32} val impl__u8__from_str_radix: string -> u32 -> Core.Result.t_Result u8 Core.Num.Error.t_ParseIntError diff --git a/proof-libs/fstar/rust_primitives/Rust_primitives.fst b/proof-libs/fstar/rust_primitives/Rust_primitives.fst index d80eabfde..2037912ef 100644 --- a/proof-libs/fstar/rust_primitives/Rust_primitives.fst +++ b/proof-libs/fstar/rust_primitives/Rust_primitives.fst @@ -35,6 +35,10 @@ instance cast_tc_integers (t:inttype) (t':inttype) : cast_tc (int_t t) (int_t t') = { cast = (fun x -> Rust_primitives.Integers.cast_mod #t #t' x) } +instance cast_tc_bool_integer (t:inttype) + : cast_tc bool (int_t t) + = { cast = (fun x -> if x then Rust_primitives.Integers.mk_int 1 else Rust_primitives.Integers.mk_int 0) } + class unsize_tc source = { output: Type; unsize: source -> output; From 921dd1ba94fa81dec178f698ef24d2e346a3a8b7 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 10:43:35 +0100 Subject: [PATCH 164/253] Revert "Remove unused macro" This reverts commit 3a7806288e89fed292645c9a2c1d0e093007d325. --- frontend/exporter/src/utils.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/exporter/src/utils.rs b/frontend/exporter/src/utils.rs index 16f46ed29..73843e7ce 100644 --- a/frontend/exporter/src/utils.rs +++ b/frontend/exporter/src/utils.rs @@ -147,3 +147,12 @@ mod s_expect_impls { } } } + +macro_rules! s_assert { + ($s:ident, $assertion:expr) => {{ + if !($assertion) { + fatal!($s, "assertion failed: {}", stringify!($assertion)) + } + }}; +} +pub(crate) use s_assert; From 5491ca1d2d3484243f06ec9a5100d9a0cb20cae3 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 28 Oct 2024 10:55:41 +0100 Subject: [PATCH 165/253] Move variant constructors in recursive bundling. --- engine/lib/concrete_ident/concrete_ident.ml | 4 + engine/lib/concrete_ident/concrete_ident.mli | 1 + engine/lib/dependencies.ml | 12 ++- .../toolchain__cyclic-modules into-fstar.snap | 91 ++++++++++++++----- tests/cyclic-modules/src/lib.rs | 20 ++++ 5 files changed, 103 insertions(+), 25 deletions(-) diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index e367d7037..d37d2e642 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -630,6 +630,10 @@ module Create = struct in let path = List.drop_last_exn old.def_id.path @ [ last ] in { old with def_id = { old.def_id with path } } + + let ctor name = + let path = name.def_id.path @ [ { data = Ctor; disambiguator = 0 } ] in + { name with def_id = { name.def_id with path } } end let lookup_raw_impl_info (impl : t) : Types.impl_infos option = diff --git a/engine/lib/concrete_ident/concrete_ident.mli b/engine/lib/concrete_ident/concrete_ident.mli index 8a5e413eb..02eba281b 100644 --- a/engine/lib/concrete_ident/concrete_ident.mli +++ b/engine/lib/concrete_ident/concrete_ident.mli @@ -29,6 +29,7 @@ val to_debug_string : t -> string module Create : sig val fresh_module : from:t list -> t val move_under : new_parent:t -> t -> t + val ctor : t -> t val map_last : f:(string -> string) -> t -> t (** [map_last f ident] applies [f] on the last chunk of [ident]'s diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index 2cbe2a32e..deab19324 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -450,11 +450,19 @@ module Make (F : Features.T) = struct ))) | _ -> [] in - + let variant_and_constructors_renamings = + List.concat_map ~f:variants_renamings renamings + |> List.concat_map ~f:(fun (old_name, new_name) -> + [ + (old_name, new_name); + ( Concrete_ident.Create.ctor old_name, + Concrete_ident.Create.ctor new_name ); + ]) + in let renamings = Map.of_alist_exn (module Concrete_ident) - (renamings @ List.concat_map ~f:variants_renamings renamings) + (renamings @ variant_and_constructors_renamings) in let rename = let renamer _lvl i = Map.find renamings i |> Option.value ~default:i in diff --git a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap index 2b4320887..b1eaee72a 100644 --- a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap @@ -32,7 +32,7 @@ module Cyclic_modules.B open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_805309848 {g as g} +include Cyclic_modules.Rec_bundle_696247411 {g as g} ''' "Cyclic_modules.C.fst" = ''' module Cyclic_modules.C @@ -272,8 +272,8 @@ open FStar.Mul include Cyclic_modules.Rec1_same_name.Rec_bundle_213192514 {f91805216 as f} ''' -"Cyclic_modules.Rec_bundle_805309848.fst" = ''' -module Cyclic_modules.Rec_bundle_805309848 +"Cyclic_modules.Rec_bundle_696247411.fst" = ''' +module Cyclic_modules.Rec_bundle_696247411 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul @@ -350,49 +350,94 @@ include Cyclic_modules.Typ_b.Rec_bundle_546955701 {t_T2Rec as t_T2Rec} include Cyclic_modules.Typ_b.Rec_bundle_546955701 {T2Rec_T2 as T2Rec_T2} ''' +"Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539.fst" = ''' +module Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_Context = + | Context_A : i32 -> t_Context + | Context_B : i32 -> t_Context + +let test (x: Core.Option.t_Option i32) : Core.Option.t_Option t_Context = + Core.Option.impl__map #i32 #t_Context x Context_A + +let h (_: Prims.unit) : t_Context = Context_A 1l <: t_Context + +let f (_: Prims.unit) : t_Context = h () +''' +"Cyclic_modules.Variant_constructor_a.fst" = ''' +module Cyclic_modules.Variant_constructor_a +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 {t_Context as t_Context} + +include Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 {Context_A as Context_A} + +include Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 {Context_B as Context_B} + +include Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 {test as impl__Context__test} + +include Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 {f as f} +''' +"Cyclic_modules.Variant_constructor_b.fst" = ''' +module Cyclic_modules.Variant_constructor_b +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.Variant_constructor_a.Rec_bundle_584097539 {h as h} +''' "Cyclic_modules.fst" = ''' module Cyclic_modules #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_805309848 {b as b} +include Cyclic_modules.Rec_bundle_696247411 {b as b} + +include Cyclic_modules.Rec_bundle_696247411 {c as c} + +include Cyclic_modules.Rec_bundle_696247411 {d as d} -include Cyclic_modules.Rec_bundle_805309848 {c as c} +include Cyclic_modules.Rec_bundle_696247411 {de as de} -include Cyclic_modules.Rec_bundle_805309848 {d as d} +include Cyclic_modules.Rec_bundle_696247411 {disjoint_cycle_a as disjoint_cycle_a} -include Cyclic_modules.Rec_bundle_805309848 {de as de} +include Cyclic_modules.Rec_bundle_696247411 {disjoint_cycle_b as disjoint_cycle_b} -include Cyclic_modules.Rec_bundle_805309848 {disjoint_cycle_a as disjoint_cycle_a} +include Cyclic_modules.Rec_bundle_696247411 {e as e} -include Cyclic_modules.Rec_bundle_805309848 {disjoint_cycle_b as disjoint_cycle_b} +include Cyclic_modules.Rec_bundle_696247411 {enums_a as enums_a} -include Cyclic_modules.Rec_bundle_805309848 {e as e} +include Cyclic_modules.Rec_bundle_696247411 {enums_b as enums_b} -include Cyclic_modules.Rec_bundle_805309848 {enums_a as enums_a} +include Cyclic_modules.Rec_bundle_696247411 {m1 as m1} -include Cyclic_modules.Rec_bundle_805309848 {enums_b as enums_b} +include Cyclic_modules.Rec_bundle_696247411 {m2 as m2} -include Cyclic_modules.Rec_bundle_805309848 {m1 as m1} +include Cyclic_modules.Rec_bundle_696247411 {v_rec as v_rec} -include Cyclic_modules.Rec_bundle_805309848 {m2 as m2} +include Cyclic_modules.Rec_bundle_696247411 {rec1_same_name as rec1_same_name} -include Cyclic_modules.Rec_bundle_805309848 {v_rec as v_rec} +include Cyclic_modules.Rec_bundle_696247411 {rec2_same_name as rec2_same_name} -include Cyclic_modules.Rec_bundle_805309848 {rec1_same_name as rec1_same_name} +include Cyclic_modules.Rec_bundle_696247411 {std as std} -include Cyclic_modules.Rec_bundle_805309848 {rec2_same_name as rec2_same_name} +include Cyclic_modules.Rec_bundle_696247411 {typ_a as typ_a} -include Cyclic_modules.Rec_bundle_805309848 {std as std} +include Cyclic_modules.Rec_bundle_696247411 {typ_b as typ_b} -include Cyclic_modules.Rec_bundle_805309848 {typ_a as typ_a} +include Cyclic_modules.Rec_bundle_696247411 {variant_constructor_a as variant_constructor_a} -include Cyclic_modules.Rec_bundle_805309848 {typ_b as typ_b} +include Cyclic_modules.Rec_bundle_696247411 {variant_constructor_b as variant_constructor_b} -include Cyclic_modules.Rec_bundle_805309848 {f as f} +include Cyclic_modules.Rec_bundle_696247411 {f as f} -include Cyclic_modules.Rec_bundle_805309848 {h as h} +include Cyclic_modules.Rec_bundle_696247411 {h as h} -include Cyclic_modules.Rec_bundle_805309848 {h2 as h2} +include Cyclic_modules.Rec_bundle_696247411 {h2 as h2} ''' diff --git a/tests/cyclic-modules/src/lib.rs b/tests/cyclic-modules/src/lib.rs index 781a1e156..b59be2d80 100644 --- a/tests/cyclic-modules/src/lib.rs +++ b/tests/cyclic-modules/src/lib.rs @@ -146,3 +146,23 @@ pub mod disjoint_cycle_b { super::disjoint_cycle_a::g() } } + +pub mod variant_constructor_a { + pub enum Context { + A(i32), + B(i32), + } + pub fn f() -> Context { + super::variant_constructor_b::h() + } + impl Context { + pub fn test(x: Option) -> Option { + x.map(Self::A) + } + } +} +pub mod variant_constructor_b { + pub fn h() -> super::variant_constructor_a::Context { + super::variant_constructor_a::Context::A(1) + } +} From d01c2d42633aad15588d8e57b3f476ff0ddbb39b Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 10:56:05 +0100 Subject: [PATCH 166/253] fix(exporter/thir): fix #1042 --- frontend/exporter/src/types/thir.rs | 106 +++++++++++++--------------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index 959ea3739..2f742adcb 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -189,74 +189,66 @@ impl<'tcx, S: ExprState<'tcx>> SInto for thir::Expr<'tcx> { .decorate(ty.sinto(s), span.sinto(s)); return cexpr.into(); } - thir::ExprKind::ZstLiteral { .. } => match ty.kind() { - rustc_middle::ty::TyKind::FnDef(def_id, _generics) => { - /* TODO: translate generics - let tcx = s.base().tcx; - let sig = &tcx.fn_sig(*def).instantiate(tcx, generics); - let ret: rustc_middle::ty::Ty = tcx.erase_late_bound_regions(sig.output()); - let inputs = sig.inputs(); - let indexes = inputs.skip_binder().iter().enumerate().map(|(i, _)| i); - let params = indexes.map(|i| inputs.map_bound(|tys| tys[i])); - let params: Vec = - params.map(|i| tcx.erase_late_bound_regions(i)).collect(); - */ - let tcx = s.base().tcx; - let constructor = if tcx.is_constructor(*def_id) { - let adt_def = - tcx.adt_def(rustc_utils::get_closest_parent_type(&tcx, *def_id)); - let variant_index = adt_def.variant_index_with_id(tcx.parent(*def_id)); - Some(rustc_utils::get_variant_information( - &adt_def, - variant_index, - s, - )) - } else { - None + thir::ExprKind::ZstLiteral { .. } => { + if ty.is_phantom_data() { + let rustc_middle::ty::Adt(def, _) = ty.kind() else { + supposely_unreachable_fatal!(s[span], "PhantomDataNotAdt"; {kind, ty}) + }; + let adt_def = AdtExpr { + info: get_variant_information(def, rustc_target::abi::FIRST_VARIANT, s), + user_ty: None, + base: None, + fields: vec![], }; return Expr { - contents: Box::new(ExprKind::GlobalName { - id: def_id.sinto(s), - constructor, - }), + contents: Box::new(ExprKind::Adt(adt_def)), span: self.span.sinto(s), ty: ty.sinto(s), hir_id, attributes, }; } - _ => { - if ty.is_phantom_data() { - let rustc_middle::ty::Adt(def, _) = ty.kind() else { - supposely_unreachable_fatal!(s[span], "PhantomDataNotAdt"; {kind, ty}) - }; - let adt_def = AdtExpr { - info: get_variant_information( - def, - rustc_target::abi::FIRST_VARIANT, - s, - ), - user_ty: None, - base: None, - fields: vec![], - }; - return Expr { - contents: Box::new(ExprKind::Adt(adt_def)), - span: self.span.sinto(s), - ty: ty.sinto(s), - hir_id, - attributes, - }; - } else { - supposely_unreachable!( + let def_id = match ty.kind() { + rustc_middle::ty::Adt(adt_def, generics) => { + // Here, we should only get `struct Name;` structs. + s_assert!(s, adt_def.variants().len() == 1); + s_assert!(s, generics.is_empty()); + adt_def.did() + } + rustc_middle::ty::TyKind::FnDef(def_id, _generics) => *def_id, + ty_kind => { + let ty_kind = ty_kind.sinto(s); + supposely_unreachable_fatal!( s[span], - "ZstLiteral ty≠FnDef(...) or PhantomData"; - {kind, span, ty} + "ZstLiteral ty≠FnDef(...) or PhantomData or naked Struct"; + {kind, span, ty, ty_kind} ); - kind.sinto(s) } - } - }, + }; + let tcx = s.base().tcx; + let constructor = if tcx.is_constructor(def_id) { + let adt_def = + tcx.adt_def(rustc_utils::get_closest_parent_type(&tcx, def_id)); + let variant_index = adt_def.variant_index_with_id(tcx.parent(def_id)); + Some(rustc_utils::get_variant_information( + &adt_def, + variant_index, + s, + )) + } else { + None + }; + return Expr { + contents: Box::new(ExprKind::GlobalName { + id: def_id.sinto(s), + constructor, + }), + span: self.span.sinto(s), + ty: ty.sinto(s), + hir_id, + attributes, + }; + } thir::ExprKind::Field { lhs, variant_index, From ebccec9946dd1db6b2693dc00320b0d55b4a0dea Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 28 Oct 2024 11:47:33 +0100 Subject: [PATCH 167/253] Rename and document Concrete_ident.Create.constructor. --- engine/lib/concrete_ident/concrete_ident.ml | 2 +- engine/lib/concrete_ident/concrete_ident.mli | 5 ++++- engine/lib/dependencies.ml | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index d37d2e642..c5bebf76f 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -631,7 +631,7 @@ module Create = struct let path = List.drop_last_exn old.def_id.path @ [ last ] in { old with def_id = { old.def_id with path } } - let ctor name = + let constructor name = let path = name.def_id.path @ [ { data = Ctor; disambiguator = 0 } ] in { name with def_id = { name.def_id with path } } end diff --git a/engine/lib/concrete_ident/concrete_ident.mli b/engine/lib/concrete_ident/concrete_ident.mli index 02eba281b..e87f71b22 100644 --- a/engine/lib/concrete_ident/concrete_ident.mli +++ b/engine/lib/concrete_ident/concrete_ident.mli @@ -29,7 +29,10 @@ val to_debug_string : t -> string module Create : sig val fresh_module : from:t list -> t val move_under : new_parent:t -> t -> t - val ctor : t -> t + + val constructor : t -> t + (** [constructor ident] adds a [Ctor] to [ident] + this allows to build a constructor from a variant name. *) val map_last : f:(string -> string) -> t -> t (** [map_last f ident] applies [f] on the last chunk of [ident]'s diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index deab19324..7d5570673 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -455,8 +455,8 @@ module Make (F : Features.T) = struct |> List.concat_map ~f:(fun (old_name, new_name) -> [ (old_name, new_name); - ( Concrete_ident.Create.ctor old_name, - Concrete_ident.Create.ctor new_name ); + ( Concrete_ident.Create.constructor old_name, + Concrete_ident.Create.constructor new_name ); ]) in let renamings = From 5c79ab3afdfabef0cb99409e141a73fb90f1785d Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 12:14:59 +0100 Subject: [PATCH 168/253] fix(exporter/thir): fix #1048 --- frontend/exporter/src/types/thir.rs | 17 ++++++----- .../toolchain__functions into-fstar.snap | 28 +++++++++++++++++++ tests/functions/Cargo.toml | 2 +- tests/functions/src/lib.rs | 16 +++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/frontend/exporter/src/types/thir.rs b/frontend/exporter/src/types/thir.rs index 2f742adcb..381620a76 100644 --- a/frontend/exporter/src/types/thir.rs +++ b/frontend/exporter/src/types/thir.rs @@ -579,8 +579,7 @@ pub enum ExprKind { #[map({ let e = gstate.thir().exprs[*fun].unroll_scope(gstate); let (generic_args, r#trait, bounds_impls); - // A function is any expression whose type is something callable - let fun = match ty.kind() { + let fun = match e.ty.kind() { rustc_middle::ty::TyKind::FnDef(def_id, generics) => { let (hir_id, attributes) = e.hir_id_and_attributes(gstate); let hir_id = hir_id.map(|hir_id| hir_id.index()); @@ -613,11 +612,15 @@ pub enum ExprKind { r#trait = None; // A function pointer is not a method e.sinto(gstate) }, - ty_kind => supposely_unreachable_fatal!( - gstate[e.span], - "CallNotTyFnDef"; - {e, ty_kind} - ) + ty_kind => { + let ty_norm: Ty = gstate.base().tcx.normalize_erasing_regions(gstate.param_env(), *ty).sinto(gstate); + let ty_kind_sinto = ty_kind.sinto(gstate); + supposely_unreachable_fatal!( + gstate[e.span], + "CallNotTyFnDef"; + {e, ty_kind, ty_kind_sinto, ty_norm} + ); + } }; TO_TYPE::Call { ty: ty.sinto(gstate), diff --git a/test-harness/src/snapshots/toolchain__functions into-fstar.snap b/test-harness/src/snapshots/toolchain__functions into-fstar.snap index 21a6f688a..df12b8b6e 100644 --- a/test-harness/src/snapshots/toolchain__functions into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__functions into-fstar.snap @@ -26,6 +26,34 @@ exit = 0 diagnostics = [] [stdout.files] +"Functions.Issue_1048_.fst" = ''' +module Functions.Issue_1048_ +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +type t_CallableViaDeref = | CallableViaDeref : t_CallableViaDeref + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl: Core.Ops.Deref.t_Deref t_CallableViaDeref = + { + f_Target = Prims.unit -> bool; + f_deref_pre = (fun (self: t_CallableViaDeref) -> true); + f_deref_post = (fun (self: t_CallableViaDeref) (out: (Prims.unit -> bool)) -> true); + f_deref + = + fun (self: t_CallableViaDeref) -> + fun temp_0_ -> + let _:Prims.unit = temp_0_ in + true + } + +let call_via_deref (_: Prims.unit) : bool = + Core.Ops.Deref.f_deref #t_CallableViaDeref + #FStar.Tactics.Typeclasses.solve + (CallableViaDeref <: t_CallableViaDeref) + () +''' "Functions.fst" = ''' module Functions #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" diff --git a/tests/functions/Cargo.toml b/tests/functions/Cargo.toml index 215bd726c..e430cbdf8 100644 --- a/tests/functions/Cargo.toml +++ b/tests/functions/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" hax-lib = { path = "../../hax-lib" } [package.metadata.hax-tests] -into."fstar+coq" = { snapshot = "stdout" } +into."fstar" = { snapshot = "stdout" } diff --git a/tests/functions/src/lib.rs b/tests/functions/src/lib.rs index f3c4b4801..8d80d6ad1 100644 --- a/tests/functions/src/lib.rs +++ b/tests/functions/src/lib.rs @@ -4,3 +4,19 @@ fn calling_function_pointer() { let f_ptr = f::; f_ptr(); } + +mod issue_1048 { + pub struct CallableViaDeref; + + impl core::ops::Deref for CallableViaDeref { + type Target = fn() -> bool; + + fn deref(&self) -> &Self::Target { + &((|| true) as fn() -> bool) + } + } + + pub fn call_via_deref() -> bool { + CallableViaDeref() + } +} From 26fcf82986f8f924235dbd50a79b2dc5b125b22c Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 14:34:24 +0100 Subject: [PATCH 169/253] feat(exporter/consts): more and better debug informations --- frontend/exporter/src/constant_utils.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index acaa7d0d7..78fb4fbb3 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -215,10 +215,11 @@ mod rustc { } } + #[tracing::instrument(level = "trace", skip(s))] pub(crate) fn scalar_int_to_constant_literal<'tcx, S: UnderOwnerState<'tcx>>( s: &S, x: rustc_middle::ty::ScalarInt, - ty: rustc_middle::ty::Ty, + ty: rustc_middle::ty::Ty<'tcx>, ) -> ConstantLiteral { match ty.kind() { ty::Char => ConstantLiteral::Char( @@ -236,14 +237,19 @@ mod rustc { let v = x.to_uint(x.size()); ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s))) } - _ => fatal!( - s, - "scalar_int_to_constant_literal: the type {:?} is not a literal", - ty - ), + // https://github.com/rust-lang/rust/pull/116930 + _ => { + let ty_sinto: Ty = ty.sinto(s); + supposely_unreachable_fatal!( + s, + "scalar_int_to_constant_literal_ExpectedLiteralType"; + { ty, ty_sinto, x } + ) + } } } + #[tracing::instrument(level = "trace", skip(s))] pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( s: &S, ty: rustc_middle::ty::Ty<'tcx>, @@ -373,6 +379,7 @@ mod rustc { ) } + #[tracing::instrument(level = "trace", skip(s))] fn trait_const_to_constant_expr_kind<'tcx, S: BaseState<'tcx> + HasOwnerId>( s: &S, _const_def_id: rustc_hir::def_id::DefId, @@ -486,6 +493,7 @@ mod rustc { } } impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::Const<'tcx> { + #[tracing::instrument(level = "trace", skip(s))] fn sinto(&self, s: &S) -> ConstantExpr { use rustc_middle::query::Key; let span = self.default_span(s.base().tcx); @@ -515,7 +523,7 @@ mod rustc { } } - // #[tracing::instrument(skip(s))] + #[tracing::instrument(level = "trace", skip(s))] pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( s: &S, valtree: rustc_middle::ty::ValTree<'tcx>, From b9065e5f3c888f2119891d2caeea3d379127cb82 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 15:27:47 +0100 Subject: [PATCH 170/253] fix: cargo fmt --- frontend/exporter/src/constant_utils.rs | 100 ++++++++++++------------ 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 78fb4fbb3..abf960f13 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -531,59 +531,59 @@ mod rustc { span: rustc_span::Span, ) -> ConstantExpr { let kind = match (valtree, ty.kind()) { - (_, ty::Ref(_, inner_ty, _)) => { - ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span)) - } - (ty::ValTree::Branch(valtrees), ty::Str) => ConstantExprKind::Literal( - ConstantLiteral::byte_str(valtrees.iter().map(|x| match x { - ty::ValTree::Leaf(leaf) => leaf.to_u8(), - _ => fatal!(s[span], "Expected a flat list of leaves while translating a str literal, got a arbitrary valtree.") - }).collect(), StrStyle::Cooked)) - , - (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { - let contents: rustc_middle::ty::DestructuredConst = s - .base().tcx - .destructure_const(ty::Const::new_value(s.base().tcx, valtree, ty)); - let fields = contents.fields.iter().copied(); - match ty.kind() { - ty::Array(_, _) => ConstantExprKind::Array { - fields: fields - .map(|field| field.sinto(s)) - .collect(), - }, - ty::Tuple(_) => ConstantExprKind::Tuple { - fields: fields - .map(|field| field.sinto(s)) - .collect(), - }, - ty::Adt(def, _) => { - let variant_idx = contents - .variant - .s_expect(s, "destructed const of adt without variant idx"); - let variant_def = &def.variant(variant_idx); - - ConstantExprKind::Adt{ - info: get_variant_information(def, variant_idx, s), - fields: fields.into_iter() - .zip(&variant_def.fields) - .map(|(value, field)| ConstantFieldExpr { - field: field.did.sinto(s), - value: value.sinto(s), - }) - .collect(), + (_, ty::Ref(_, inner_ty, _)) => { + ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span)) + } + (ty::ValTree::Branch(valtrees), ty::Str) => ConstantExprKind::Literal( + ConstantLiteral::byte_str(valtrees.iter().map(|x| match x { + ty::ValTree::Leaf(leaf) => leaf.to_u8(), + _ => fatal!(s[span], "Expected a flat list of leaves while translating a str literal, got a arbitrary valtree.") + }).collect(), StrStyle::Cooked)) + , + (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { + let contents: rustc_middle::ty::DestructuredConst = s + .base().tcx + .destructure_const(ty::Const::new_value(s.base().tcx, valtree, ty)); + let fields = contents.fields.iter().copied(); + match ty.kind() { + ty::Array(_, _) => ConstantExprKind::Array { + fields: fields + .map(|field| field.sinto(s)) + .collect(), + }, + ty::Tuple(_) => ConstantExprKind::Tuple { + fields: fields + .map(|field| field.sinto(s)) + .collect(), + }, + ty::Adt(def, _) => { + let variant_idx = contents + .variant + .s_expect(s, "destructed const of adt without variant idx"); + let variant_def = &def.variant(variant_idx); + + ConstantExprKind::Adt{ + info: get_variant_information(def, variant_idx, s), + fields: fields.into_iter() + .zip(&variant_def.fields) + .map(|(value, field)| ConstantFieldExpr { + field: field.did.sinto(s), + value: value.sinto(s), + }) + .collect(), + } } + _ => unreachable!(), } - _ => unreachable!(), } - } - (ty::ValTree::Leaf(x), _) => ConstantExprKind::Literal ( - scalar_int_to_constant_literal(s, x, ty) - ), - _ => supposely_unreachable_fatal!( - s[span], "valtree_to_expr"; - {valtree, ty} - ), - }; + (ty::ValTree::Leaf(x), _) => ConstantExprKind::Literal ( + scalar_int_to_constant_literal(s, x, ty) + ), + _ => supposely_unreachable_fatal!( + s[span], "valtree_to_expr"; + {valtree, ty} + ), + }; kind.decorate(ty.sinto(s), span.sinto(s)) } From 68eaa19b6038597f0361026985fef04a35199fbe Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 15:34:08 +0100 Subject: [PATCH 171/253] fix(exporter/constants): support usize casted to raw pointers constants This commit adds support for constants that are usize literals casted to raw pointers. --- engine/lib/import_thir.ml | 2 +- frontend/exporter/src/constant_utils.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 7af3249f8..0fc1dd2de 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -837,7 +837,7 @@ end) : EXPR = struct | Borrow arg -> Borrow { arg = constant_expr_to_expr arg; borrow_kind = Thir.Shared } | ConstRef { id } -> ConstRef { id } - | MutPtr _ | TraitConst _ | FnPtr _ -> + | Cast _ | RawBorrow _ | TraitConst _ | FnPtr _ -> assertion_failure [ span ] "constant_lit_to_lit: TraitConst | FnPtr | MutPtr" | Todo _ -> assertion_failure [ span ] "ConstantExpr::Todo" diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index abf960f13..0a04973d5 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -80,6 +80,13 @@ pub enum ConstantExprKind { Borrow(ConstantExpr), /// A `*mut` pointer to a static mutable variable. MutPtr(ConstantExpr), + /// A cast ` as `, `` is stored as the type of + /// the current constant expression. Currently, this is only used + /// to represent `lit as *mut T` or `lit as *const T`, where `lit` + /// is a `usize` literal. + Cast { + source: ConstantExpr, + }, ConstRef { id: ParamConst, }, @@ -202,6 +209,9 @@ mod rustc { Tuple { fields } => ExprKind::Tuple { fields: fields.into_iter().map(|field| field.into()).collect(), }, + Cast { source } => ExprKind::Cast { + source: source.into(), + }, kind @ (FnPtr { .. } | TraitConst { .. }) => { // SH: I see the `Closure` kind, but it's not the same as function pointer? ExprKind::Todo(format!("FnPtr or TraitConst. kind={:#?}", kind)) @@ -576,6 +586,16 @@ mod rustc { _ => unreachable!(), } } + (ty::ValTree::Leaf(x), ty::RawPtr(_, _)) => { + use crate::rustc_type_ir::inherent::Ty; + let raw_address = x.to_bits_unchecked(); + let uint_ty = UintTy::Usize; + let usize_ty = rustc_middle::ty::Ty::new_usize(s.base().tcx).sinto(s); + let lit = ConstantLiteral::Int(ConstantInt::Uint(raw_address, uint_ty)); + ConstantExprKind::Cast { + source: ConstantExprKind::Literal(lit).decorate(usize_ty, span.sinto(s)) + } + } (ty::ValTree::Leaf(x), _) => ConstantExprKind::Literal ( scalar_int_to_constant_literal(s, x, ty) ), From 06b20714f88259eeb50b6b5d8128205c853086b6 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 15:47:04 +0100 Subject: [PATCH 172/253] refactor(constants): rename `MutPtr` to `RawBorrow` --- frontend/exporter/src/constant_utils.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index 0a04973d5..ede21a233 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -78,8 +78,11 @@ pub enum ConstantExprKind { }, /// A shared reference to a static variable. Borrow(ConstantExpr), - /// A `*mut` pointer to a static mutable variable. - MutPtr(ConstantExpr), + /// A raw borrow (`*const` or `*mut`). + RawBorrow { + mutability: Mutability, + arg: ConstantExpr, + }, /// A cast ` as `, `` is stored as the type of /// the current constant expression. Currently, this is only used /// to represent `lit as *mut T` or `lit as *const T`, where `lit` @@ -198,9 +201,9 @@ mod rustc { borrow_kind: BorrowKind::Shared, arg: e.into(), }, - MutPtr(e) => ExprKind::RawBorrow { - mutability: true, - arg: e.into(), + RawBorrow { mutability, arg } => ExprKind::RawBorrow { + mutability, + arg: arg.into(), }, ConstRef { id } => ExprKind::ConstRef { id }, Array { fields } => ExprKind::Array { @@ -333,7 +336,10 @@ mod rustc { let contents = contents.decorate(inner_ty.sinto(s), cspan.clone()); match ty.kind() { ty::Ref(..) => ConstantExprKind::Borrow(contents), - ty::RawPtr(..) => ConstantExprKind::MutPtr(contents), + ty::RawPtr(_, mutability) => ConstantExprKind::RawBorrow { + arg: contents, + mutability: mutability.sinto(s), + }, _ => unreachable!(), } } From e6f646b0610fed5207a3066bb469135f0264c6bd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 28 Oct 2024 15:48:22 +0100 Subject: [PATCH 173/253] Rename `utils` to `utils::error_macros` --- frontend/exporter/src/{utils.rs => utils/error_macros.rs} | 0 frontend/exporter/src/utils/mod.rs | 2 ++ 2 files changed, 2 insertions(+) rename frontend/exporter/src/{utils.rs => utils/error_macros.rs} (100%) create mode 100644 frontend/exporter/src/utils/mod.rs diff --git a/frontend/exporter/src/utils.rs b/frontend/exporter/src/utils/error_macros.rs similarity index 100% rename from frontend/exporter/src/utils.rs rename to frontend/exporter/src/utils/error_macros.rs diff --git a/frontend/exporter/src/utils/mod.rs b/frontend/exporter/src/utils/mod.rs new file mode 100644 index 000000000..fa174c16c --- /dev/null +++ b/frontend/exporter/src/utils/mod.rs @@ -0,0 +1,2 @@ +mod error_macros; +pub use error_macros::*; From 1ac3c19b7363803fd40fcc6a4dd403bb2fe762a0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 28 Oct 2024 15:49:23 +0100 Subject: [PATCH 174/253] Copy charon's type-generic map --- frontend/exporter/src/utils/mod.rs | 3 ++ frontend/exporter/src/utils/type_map.rs | 52 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 frontend/exporter/src/utils/type_map.rs diff --git a/frontend/exporter/src/utils/mod.rs b/frontend/exporter/src/utils/mod.rs index fa174c16c..3e1fb05ee 100644 --- a/frontend/exporter/src/utils/mod.rs +++ b/frontend/exporter/src/utils/mod.rs @@ -1,2 +1,5 @@ mod error_macros; +mod type_map; + pub use error_macros::*; +pub use type_map::*; diff --git a/frontend/exporter/src/utils/type_map.rs b/frontend/exporter/src/utils/type_map.rs new file mode 100644 index 000000000..f7a3bc3a5 --- /dev/null +++ b/frontend/exporter/src/utils/type_map.rs @@ -0,0 +1,52 @@ +use std::{ + any::{Any, TypeId}, + collections::HashMap, + marker::PhantomData, +}; + +pub trait TypeMappable = Any + Send + Sync; + +/// Defines a mapping from types to types. +pub trait TypeMapper { + type Value: TypeMappable; +} + +/// A map that maps types to values in a generic manner: we store for each type `T` a value of +/// type `M::Value`. +pub struct TypeMap { + data: HashMap>, + phantom: PhantomData, +} + +impl TypeMap { + pub fn get(&self) -> Option<&M::Value> { + self.data + .get(&TypeId::of::()) + // We must be careful to not accidentally cast the box itself as `dyn Any`. + .map(|val: &Box| &**val) + .and_then(|val: &dyn TypeMappable| (val as &dyn Any).downcast_ref()) + } + + pub fn get_mut(&mut self) -> Option<&mut M::Value> { + self.data + .get_mut(&TypeId::of::()) + // We must be careful to not accidentally cast the box itself as `dyn Any`. + .map(|val: &mut Box| &mut **val) + .and_then(|val: &mut dyn TypeMappable| (val as &mut dyn Any).downcast_mut()) + } + + pub fn insert(&mut self, val: M::Value) -> Option>> { + self.data + .insert(TypeId::of::(), Box::new(val)) + .and_then(|val: Box| (val as Box).downcast().ok()) + } +} + +impl Default for TypeMap { + fn default() -> Self { + Self { + data: Default::default(), + phantom: Default::default(), + } + } +} From 88db1131501882c43a6023467331bce7ed94fb43 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 28 Oct 2024 16:15:56 +0100 Subject: [PATCH 175/253] Allow extra where clauses in `AdtInto` derive macro --- frontend/exporter/adt-into/src/lib.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/exporter/adt-into/src/lib.rs b/frontend/exporter/adt-into/src/lib.rs index 573855e78..98c062316 100644 --- a/frontend/exporter/adt-into/src/lib.rs +++ b/frontend/exporter/adt-into/src/lib.rs @@ -18,6 +18,7 @@ struct Options { from: syn::TypePath, state: syn::Ident, state_type: syn::Type, + where_clause: Option, } mod option_parse { use super::*; @@ -29,20 +30,30 @@ mod option_parse { fn parse(input: ParseStream) -> syn::Result { let generics = input.parse()?; input.parse::()?; + input.parse::()?; input.parse::()?; let from = input.parse()?; input.parse::()?; + input.parse::()?; input.parse::()?; let state_type = input.parse()?; input.parse::()?; let state = input.parse()?; + + let mut where_clause = None; + if input.peek(Token![,]) && input.peek2(Token![where]) { + input.parse::()?; + where_clause = Some(input.parse()?); + } + Ok(Options { generics, from, state, state_type, + where_clause, }) } } @@ -291,6 +302,7 @@ pub fn adt_into(input: proc_macro::TokenStream) -> proc_macro::TokenStream { from: from_with_generics, state, state_type, + where_clause, } = parse_attr("args", attrs).expect("An [args] attribute was expected"); let generics = { @@ -388,7 +400,7 @@ pub fn adt_into(input: proc_macro::TokenStream) -> proc_macro::TokenStream { const _ : () = { use #from as FROM_TYPE; use #to as TO_TYPE; - impl #generics SInto<#state_type, #to #to_generics> for #from_with_generics { + impl #generics SInto<#state_type, #to #to_generics> for #from_with_generics #where_clause { #[tracing::instrument(level = "trace", skip(#state))] fn sinto(&self, #state: &#state_type) -> #to #to_generics { tracing::trace!("Enters sinto ({})", stringify!(#from_with_generics)); From 1fcea121b73e92fa328c2a413c95b97007c19d89 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 28 Oct 2024 15:37:48 +0100 Subject: [PATCH 176/253] Include bodies in `FullDef` --- frontend/exporter/src/state.rs | 10 +- frontend/exporter/src/types/new/full_def.rs | 105 ++++++++++++-------- 2 files changed, 71 insertions(+), 44 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 7982823e3..231af1496 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -130,13 +130,19 @@ mod types { pub id_table_session: id_table::Session, } + /// Defines a mapping from types to types, for use with `TypeMap`. + pub struct FullDefMapper {} + impl TypeMapper for FullDefMapper { + type Value = Arc>; + } + /// Per-item cache #[derive(Default)] pub struct ItemCache<'tcx> { /// The translated `DefId`. pub def_id: Option, - /// The translated definition. - pub full_def: Option>, + /// The translated definitions, generic in the body. + pub full_def: TypeMap, /// Cache the `Ty` translations. pub tys: HashMap, Ty>, /// Cache the trait resolution engine for each item. diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 501b498d2..54d82a573 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -11,7 +11,7 @@ use rustc_span::def_id::DefId as RDefId; /// Gathers a lot of definition information about a [`rustc_hir::def_id::DefId`]. #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] -pub struct FullDef { +pub struct FullDef { pub def_id: DefId, /// The enclosing item. pub parent: Option, @@ -29,58 +29,69 @@ pub struct FullDef { pub lang_item: Option, /// If this definition is a diagnostic item, we store the identifier, e.g. `box_new`. pub diagnostic_item: Option, - pub kind: FullDefKind, + pub kind: FullDefKind, } #[cfg(feature = "rustc")] -impl<'tcx, S: BaseState<'tcx>> SInto> for RDefId { - fn sinto(&self, s: &S) -> Arc { - if let Some(full_def) = s.with_item_cache(*self, |cache| cache.full_def.clone()) { - return full_def; - } - let tcx = s.base().tcx; - let def_id = *self; - let def_kind = tcx.def_kind(def_id); - let kind = { - let state_with_id = with_owner_id(s.base(), (), (), def_id); - def_kind.sinto(&state_with_id) - }; +fn translate_full_def<'tcx, S, Body>(s: &S, def_id: RDefId) -> FullDef +where + S: BaseState<'tcx>, + Body: IsBody, +{ + let tcx = s.base().tcx; + let def_kind = tcx.def_kind(def_id); + let kind = { + let state_with_id = with_owner_id(s.base(), (), (), def_id); + def_kind.sinto(&state_with_id) + }; - let source_span = def_id.as_local().map(|ldid| tcx.source_span(ldid)); - let source_text = source_span - .filter(|source_span| source_span.ctxt().is_root()) - .and_then(|source_span| tcx.sess.source_map().span_to_snippet(source_span).ok()); + let source_span = def_id.as_local().map(|ldid| tcx.source_span(ldid)); + let source_text = source_span + .filter(|source_span| source_span.ctxt().is_root()) + .and_then(|source_span| tcx.sess.source_map().span_to_snippet(source_span).ok()); - let full_def = FullDef { - def_id: self.sinto(s), - parent: tcx.opt_parent(def_id).sinto(s), - span: get_def_span(tcx, def_id, def_kind).sinto(s), - source_span: source_span.sinto(s), - source_text, - attributes: get_def_attrs(tcx, def_id, def_kind).sinto(s), - visibility: get_def_visibility(tcx, def_id, def_kind), - lang_item: s - .base() - .tcx - .as_lang_item(def_id) - .map(|litem| litem.name()) - .sinto(s), - diagnostic_item: tcx.get_diagnostic_name(def_id).sinto(s), - kind, - }; - let full_def: Arc = Arc::new(full_def); - s.with_item_cache(*self, |cache| cache.full_def = Some(full_def.clone())); - full_def + FullDef { + def_id: def_id.sinto(s), + parent: tcx.opt_parent(def_id).sinto(s), + span: get_def_span(tcx, def_id, def_kind).sinto(s), + source_span: source_span.sinto(s), + source_text, + attributes: get_def_attrs(tcx, def_id, def_kind).sinto(s), + visibility: get_def_visibility(tcx, def_id, def_kind), + lang_item: s + .base() + .tcx + .as_lang_item(def_id) + .map(|litem| litem.name()) + .sinto(s), + diagnostic_item: tcx.get_diagnostic_name(def_id).sinto(s), + kind, + } +} + +#[cfg(feature = "rustc")] +impl<'tcx, S, Body> SInto>> for RDefId +where + Body: IsBody + TypeMappable, + S: BaseState<'tcx>, +{ + fn sinto(&self, s: &S) -> Arc> { + if let Some(def) = s.with_item_cache(*self, |cache| cache.full_def.get().cloned()) { + return def; + } + let def = Arc::new(translate_full_def(s, *self)); + s.with_item_cache(*self, |cache| cache.full_def.insert(def.clone())); + def } } /// Imbues [`rustc_hir::def::DefKind`] with a lot of extra information. /// Important: the `owner_id()` must be the id of this definition. #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::DefKind, state: S as s)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::DefKind, state: S as s, where Body: IsBody)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] -pub enum FullDefKind { +pub enum FullDefKind { // Type namespace Mod, /// Refers to the struct definition, [`DefKind::Ctor`] refers to its constructor if it exists. @@ -194,6 +205,8 @@ pub enum FullDefKind { inline: InlineAttr, #[value(s.base().tcx.fn_sig(s.owner_id()).instantiate_identity().sinto(s))] sig: PolyFnSig, + #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] + body: Option, }, /// Associated function: `impl MyStruct { fn associated() {} }` or `trait Foo { fn associated() /// {} }` @@ -210,6 +223,8 @@ pub enum FullDefKind { inline: InlineAttr, #[value(s.base().tcx.fn_sig(s.owner_id()).instantiate_identity().sinto(s))] sig: PolyFnSig, + #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] + body: Option, }, /// A closure, coroutine, or coroutine-closure. /// @@ -237,6 +252,8 @@ pub enum FullDefKind { predicates: GenericPredicates, #[value(s.base().tcx.type_of(s.owner_id()).instantiate_identity().sinto(s))] ty: Ty, + #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] + body: Option, }, /// Associated constant: `trait MyTrait { const ASSOC: usize; }` AssocConst { @@ -250,6 +267,8 @@ pub enum FullDefKind { predicates: GenericPredicates, #[value(s.base().tcx.type_of(s.owner_id()).instantiate_identity().sinto(s))] ty: Ty, + #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] + body: Option, }, Static { /// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`. @@ -264,6 +283,8 @@ pub enum FullDefKind { predicates: GenericPredicates, #[value(s.base().tcx.type_of(s.owner_id()).instantiate_identity().sinto(s))] ty: Ty, + #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] + body: Option, }, /// Constant generic parameter: `struct Foo { ... }` ConstParam, @@ -317,13 +338,13 @@ pub enum FullDefKind { SyntheticCoroutineBody, } -impl FullDef { +impl FullDef { #[cfg(feature = "rustc")] pub fn rust_def_id(&self) -> RDefId { (&self.def_id).into() } - pub fn kind(&self) -> &FullDefKind { + pub fn kind(&self) -> &FullDefKind { &self.kind } From 3be504dbd789118599d51756a6e0f4bcbd9d05c3 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Mon, 28 Oct 2024 16:19:07 +0100 Subject: [PATCH 177/253] fix(tests): update snapshots --- .../toolchain__functions into-coq.snap | 28 ++++++++++++++++--- .../toolchain__traits into-fstar.snap | 4 +-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__functions into-coq.snap b/test-harness/src/snapshots/toolchain__functions into-coq.snap index 56ca87c28..29fe45a24 100644 --- a/test-harness/src/snapshots/toolchain__functions into-coq.snap +++ b/test-harness/src/snapshots/toolchain__functions into-coq.snap @@ -20,10 +20,12 @@ info: include_flag: ~ backend_options: ~ --- -exit = 0 - -[stdout] -diagnostics = [] +exit = 1 +[[stdout.diagnostics]] +message = ''' +(Coq backend) something is not implemented yet. +[ty] node typ''' +spans = ['Span { lo: Loc { line: 11, col: 4 }, hi: Loc { line: 17, col: 5 }, filename: Real(LocalPath("functions/src/lib.rs")), rust_span_data: None }'] [stdout.files] "Functions.v" = ''' @@ -36,6 +38,8 @@ Open Scope bool_scope. (*Not implemented yet? todo(item)*) +(*Not implemented yet? todo(item)*) + Definition calling_function_pointer__f (_ : unit) : unit := tt. @@ -44,3 +48,19 @@ Definition calling_function_pointer (_ : unit) : unit := let _ := calling_function_pointer__f tt : unit in tt. ''' +"Functions_Issue_1048_.v" = ''' +(* File automatically generated by Hacspec *) +From Hacspec Require Import Hacspec_Lib MachineIntegers. +From Coq Require Import ZArith. +Import List.ListNotations. +Open Scope Z_scope. +Open Scope bool_scope. + +Record t_CallableViaDeref : Type := { +}. + +(*item error backend*) + +Definition call_via_deref (_ : unit) : bool := + f_deref CallableViaDereft_CallableViaDeref_t tt. +''' diff --git a/test-harness/src/snapshots/toolchain__traits into-fstar.snap b/test-harness/src/snapshots/toolchain__traits into-fstar.snap index 4aaf4ea2f..3ada99292 100644 --- a/test-harness/src/snapshots/toolchain__traits into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__traits into-fstar.snap @@ -387,11 +387,11 @@ let method_caller () class t_SubTrait (v_Self: Type0) (v_TypeArg: Type0) (v_ConstArg: usize) = { - [@@@ FStar.Tactics.Typeclasses.no_method]_super_8779313392680198588:t_Trait v_Self + [@@@ FStar.Tactics.Typeclasses.no_method]_super_11748868061750783190:t_Trait v_Self v_TypeArg v_ConstArg; f_AssocType:Type0; - f_AssocType_6369404467997533198:t_Trait f_AssocType v_TypeArg v_ConstArg + f_AssocType_10469511598065652520:t_Trait f_AssocType v_TypeArg v_ConstArg } ''' "Traits.Interlaced_consts_types.fst" = ''' From 65d93e5f1f8e0128365a08406d6d2f983c2bbd68 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 28 Oct 2024 15:41:51 +0100 Subject: [PATCH 178/253] Avoid wrapping return in a tuple. --- engine/lib/phases/phase_local_mutation.ml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index e4936b7f8..f92c0d985 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -251,6 +251,12 @@ struct span = expr.span; typ = local_vars_expr.typ; } + | Return { e; witness } -> + { + e = Return { e = dexpr_same e; witness }; + span = expr.span; + typ = local_vars_expr.typ; + } | Continue { acc = None; label; witness; _ } -> let w = Features.On.state_passing_loop in let e = local_vars_expr in @@ -354,7 +360,8 @@ struct } else loop | [%inline_arms - "dexpr'.*" - Let - Assign - Closure - Loop - If - Match - Break] -> + "dexpr'.*" - Let - Assign - Closure - Loop - If - Match - Break + - Return] -> map (fun e -> let e' = B.{ e; typ = dty expr.span expr.typ; span = expr.span } From 2729794cab5c1350ba6203e320357ed41e911199 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 28 Oct 2024 16:25:58 +0100 Subject: [PATCH 179/253] Fix return expression. --- engine/lib/phases/phase_local_mutation.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index f92c0d985..b55ebdfc4 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -253,7 +253,7 @@ struct } | Return { e; witness } -> { - e = Return { e = dexpr_same e; witness }; + e = Return { e = dexpr e; witness }; span = expr.span; typ = local_vars_expr.typ; } From 42cc4cc745ca706818147e36ec81c6563f547629 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 06:01:52 +0100 Subject: [PATCH 180/253] feat(frontend/consts): float lits: use strings not bits, more support This commit: - changes the representation of floats for constant literals, instead of storing raw bits with a u128, we store a string representation of the float; - adds support for float in the function `scalar_int_to_constant_literal` Note: this will require a change in Charon. --- frontend/exporter/src/constant_utils.rs | 30 +++++++++++++++++-------- frontend/exporter/src/lib.rs | 1 + 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frontend/exporter/src/constant_utils.rs b/frontend/exporter/src/constant_utils.rs index ede21a233..e35b3e986 100644 --- a/frontend/exporter/src/constant_utils.rs +++ b/frontend/exporter/src/constant_utils.rs @@ -22,9 +22,7 @@ pub enum ConstantInt { pub enum ConstantLiteral { Bool(bool), Char(char), - // Rust floats do not have the Eq or Ord traits due to the presence of NaN - // We instead store their bit representation, which always fits in a u128 - Float(u128, FloatTy), + Float(String, FloatTy), Int(ConstantInt), Str(String, StrStyle), ByteStr(Vec, StrStyle), @@ -173,7 +171,7 @@ mod rustc { } } } - Float(_bits, _ty) => todo!("Converting float literals back to AST"), + Float(f, ty) => LitKind::Float(f, LitFloatType::Suffixed(ty)), ByteStr(raw, str_style) => LitKind::ByteStr(raw, str_style), Str(raw, str_style) => LitKind::Str(raw, str_style), }; @@ -250,7 +248,10 @@ mod rustc { let v = x.to_uint(x.size()); ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s))) } - // https://github.com/rust-lang/rust/pull/116930 + ty::Float(kind) => { + let v = x.to_bits_unchecked(); + bits_and_type_to_float_constant_literal(v, kind.sinto(s)) + } _ => { let ty_sinto: Ty = ty.sinto(s); supposely_unreachable_fatal!( @@ -262,6 +263,18 @@ mod rustc { } } + /// Converts a bit-representation of a float of type `ty` to a constant literal + fn bits_and_type_to_float_constant_literal(bits: u128, ty: FloatTy) -> ConstantLiteral { + use rustc_apfloat::{ieee, Float}; + let string = match &ty { + FloatTy::F16 => ieee::Half::from_bits(bits).to_string(), + FloatTy::F32 => ieee::Single::from_bits(bits).to_string(), + FloatTy::F64 => ieee::Double::from_bits(bits).to_string(), + FloatTy::F128 => ieee::Quad::from_bits(bits).to_string(), + }; + ConstantLiteral::Float(string, ty) + } + #[tracing::instrument(level = "trace", skip(s))] pub(crate) fn scalar_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>( s: &S, @@ -292,10 +305,9 @@ mod rustc { scalar ) }); - ConstantExprKind::Literal(ConstantLiteral::Float( - scalar_int.to_bits_unchecked(), - float_type.sinto(s), - )) + let data = scalar_int.to_bits_unchecked(); + let lit = bits_and_type_to_float_constant_literal(data, float_type.sinto(s)); + ConstantExprKind::Literal(lit) } ty::Ref(_, inner_ty, Mutability::Not) | ty::RawPtr(inner_ty, Mutability::Mut) => { let tcx = s.base().tcx; diff --git a/frontend/exporter/src/lib.rs b/frontend/exporter/src/lib.rs index 90a68a4f5..49afafd0d 100644 --- a/frontend/exporter/src/lib.rs +++ b/frontend/exporter/src/lib.rs @@ -23,6 +23,7 @@ cfg_feature_rustc! { extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; + extern crate rustc_apfloat; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; From 18751758794cebb498cc9af8b42a3b5764d4edab Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 29 Oct 2024 11:14:42 +0100 Subject: [PATCH 181/253] Fix type of return. --- engine/lib/phases/phase_local_mutation.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index b55ebdfc4..4a5dd6d1d 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -255,7 +255,7 @@ struct { e = Return { e = dexpr e; witness }; span = expr.span; - typ = local_vars_expr.typ; + typ = dty expr.span expr.typ; } | Continue { acc = None; label; witness; _ } -> let w = Features.On.state_passing_loop in From 5d33c5bc101d002d9f22e6eea7e79dfcfb1e2f1e Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 29 Oct 2024 11:32:32 +0100 Subject: [PATCH 182/253] Remove attributes on bundle aliases and filter out NotImplementedYet. --- engine/lib/dependencies.ml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index 7d5570673..a54e28eeb 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -383,7 +383,11 @@ module Make (F : Features.T) = struct let aliases = List.map (old_new :: variants_renamings old_new) ~f:(fun (old_ident, new_ident) -> - { item with v = Alias { name = old_ident; item = new_ident } }) + { + item with + v = Alias { name = old_ident; item = new_ident }; + attrs = []; + }) in item' :: aliases @@ -397,7 +401,8 @@ module Make (F : Features.T) = struct and they have dummy names. *) let non_use_items = List.filter - ~f:(fun item -> match item.v with Use _ -> false | _ -> true) + ~f:(fun item -> + match item.v with Use _ | NotImplementedYet -> false | _ -> true) items in let bundles = From 1eadb043e73988dbd8ba35a34c2ba5997d7d67bb Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 29 Oct 2024 11:38:16 +0100 Subject: [PATCH 183/253] Test results for bundling without include of submodules. --- .../toolchain__cyclic-modules into-fstar.snap | 50 +++---------------- 1 file changed, 6 insertions(+), 44 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap index b1eaee72a..3edbdc730 100644 --- a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap @@ -32,7 +32,7 @@ module Cyclic_modules.B open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_696247411 {g as g} +include Cyclic_modules.Rec_bundle_318256792 {g as g} ''' "Cyclic_modules.C.fst" = ''' module Cyclic_modules.C @@ -272,8 +272,8 @@ open FStar.Mul include Cyclic_modules.Rec1_same_name.Rec_bundle_213192514 {f91805216 as f} ''' -"Cyclic_modules.Rec_bundle_696247411.fst" = ''' -module Cyclic_modules.Rec_bundle_696247411 +"Cyclic_modules.Rec_bundle_318256792.fst" = ''' +module Cyclic_modules.Rec_bundle_318256792 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" open Core open FStar.Mul @@ -397,47 +397,9 @@ module Cyclic_modules open Core open FStar.Mul -include Cyclic_modules.Rec_bundle_696247411 {b as b} +include Cyclic_modules.Rec_bundle_318256792 {f as f} -include Cyclic_modules.Rec_bundle_696247411 {c as c} +include Cyclic_modules.Rec_bundle_318256792 {h as h} -include Cyclic_modules.Rec_bundle_696247411 {d as d} - -include Cyclic_modules.Rec_bundle_696247411 {de as de} - -include Cyclic_modules.Rec_bundle_696247411 {disjoint_cycle_a as disjoint_cycle_a} - -include Cyclic_modules.Rec_bundle_696247411 {disjoint_cycle_b as disjoint_cycle_b} - -include Cyclic_modules.Rec_bundle_696247411 {e as e} - -include Cyclic_modules.Rec_bundle_696247411 {enums_a as enums_a} - -include Cyclic_modules.Rec_bundle_696247411 {enums_b as enums_b} - -include Cyclic_modules.Rec_bundle_696247411 {m1 as m1} - -include Cyclic_modules.Rec_bundle_696247411 {m2 as m2} - -include Cyclic_modules.Rec_bundle_696247411 {v_rec as v_rec} - -include Cyclic_modules.Rec_bundle_696247411 {rec1_same_name as rec1_same_name} - -include Cyclic_modules.Rec_bundle_696247411 {rec2_same_name as rec2_same_name} - -include Cyclic_modules.Rec_bundle_696247411 {std as std} - -include Cyclic_modules.Rec_bundle_696247411 {typ_a as typ_a} - -include Cyclic_modules.Rec_bundle_696247411 {typ_b as typ_b} - -include Cyclic_modules.Rec_bundle_696247411 {variant_constructor_a as variant_constructor_a} - -include Cyclic_modules.Rec_bundle_696247411 {variant_constructor_b as variant_constructor_b} - -include Cyclic_modules.Rec_bundle_696247411 {f as f} - -include Cyclic_modules.Rec_bundle_696247411 {h as h} - -include Cyclic_modules.Rec_bundle_696247411 {h2 as h2} +include Cyclic_modules.Rec_bundle_318256792 {h2 as h2} ''' From fe4ac13afdab0271937f7ceebc448b6b1d314479 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 29 Oct 2024 11:59:57 +0100 Subject: [PATCH 184/253] Add module information to `FullDef` --- frontend/exporter/src/types/new/full_def.rs | 42 ++++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 54d82a573..ddfb36573 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -93,7 +93,10 @@ where #[derive(Clone, Debug, JsonSchema)] pub enum FullDefKind { // Type namespace - Mod, + Mod { + #[value(get_mod_children(s.base().tcx, s.owner_id()).sinto(s))] + items: Vec, + }, /// Refers to the struct definition, [`DefKind::Ctor`] refers to its constructor if it exists. Struct { #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] @@ -298,7 +301,10 @@ pub enum FullDefKind { ExternCrate, Use, /// An `extern` block. - ForeignMod, + ForeignMod { + #[value(get_mod_children(s.base().tcx, s.owner_id()).sinto(s))] + items: Vec, + }, /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` AnonConst, /// An inline constant, e.g. `const { 1 + 2 }` @@ -492,6 +498,38 @@ fn get_def_attrs<'tcx>( } } +/// Gets the children of a module. +#[cfg(feature = "rustc")] +fn get_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec { + match def_id.as_local() { + Some(ldid) => match tcx.hir_node_by_def_id(ldid) { + rustc_hir::Node::Crate(m) + | rustc_hir::Node::Item(&rustc_hir::Item { + kind: rustc_hir::ItemKind::Mod(m), + .. + }) => m + .item_ids + .iter() + .map(|item_id| item_id.owner_id.to_def_id()) + .collect(), + + rustc_hir::Node::Item(rustc_hir::Item { + kind: rustc_hir::ItemKind::ForeignMod { items, .. }, + .. + }) => items + .iter() + .map(|foreign_item_ref| foreign_item_ref.id.owner_id.to_def_id()) + .collect(), + node => panic!("DefKind::Module is an unexpected node: {node:?}"), + }, + None => tcx + .module_children(def_id) + .iter() + .map(|child| child.res.def_id()) + .collect(), + } +} + /// This normalizes trait clauses before calling `sinto` on them. This is a bit of a hack required /// by charon for now. We can't normalize all clauses as this would lose region information in /// outlives clauses. From c33892dd4701cc7b3c01377e7297796abe815a34 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 29 Oct 2024 12:09:29 +0100 Subject: [PATCH 185/253] Reorder `FullDefKind` --- frontend/exporter/src/types/new/full_def.rs | 167 +++++++++++--------- 1 file changed, 88 insertions(+), 79 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index ddfb36573..fb0f3ea24 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -92,11 +92,7 @@ where #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum FullDefKind { - // Type namespace - Mod { - #[value(get_mod_children(s.base().tcx, s.owner_id()).sinto(s))] - items: Vec, - }, + // Types /// Refers to the struct definition, [`DefKind::Ctor`] refers to its constructor if it exists. Struct { #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] @@ -122,39 +118,6 @@ pub enum FullDefKind { #[value(s.base().tcx.adt_def(s.owner_id()).sinto(s))] def: AdtDef, }, - /// Refers to the variant definition, [`DefKind::Ctor`] refers to its constructor if it exists. - Variant, - Trait { - #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] - generics: TyGenerics, - #[value(get_generic_predicates(s, s.owner_id()))] - predicates: GenericPredicates, - /// The special `Self: Trait` clause. - #[value({ - use ty::Upcast; - let tcx = s.base().tcx; - let pred: ty::TraitPredicate = - crate::traits::self_predicate(tcx, s.owner_id()) - .unwrap() - .no_bound_vars() - .unwrap() - .upcast(tcx); - pred.sinto(s) - })] - self_predicate: TraitPredicate, - /// Associated items, in definition order. - #[value( - s - .base() - .tcx - .associated_items(s.owner_id()) - .in_definition_order() - .map(|assoc| (assoc, assoc.def_id)) - .collect::>() - .sinto(s) - )] - items: Vec<(AssocItem, Arc)>, - }, /// Type alias: `type Foo = Bar;` TyAlias { #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] @@ -173,8 +136,6 @@ pub enum FullDefKind { }, /// Type from an `extern` block. ForeignTy, - /// Trait alias: `trait IntIterator = Iterator;` - TraitAlias, /// Associated type: `trait MyTrait { type Assoc; }` AssocTy { #[value(s.base().tcx.parent(s.owner_id()).sinto(s))] @@ -195,10 +156,65 @@ pub enum FullDefKind { })] value: Option, }, - /// Type parameter: the `T` in `struct Vec { ... }` - TyParam, + /// Opaque type, aka `impl Trait`. + OpaqueTy, + + // Traits + Trait { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + /// The special `Self: Trait` clause. + #[value({ + use ty::Upcast; + let tcx = s.base().tcx; + let pred: ty::TraitPredicate = + crate::traits::self_predicate(tcx, s.owner_id()) + .unwrap() + .no_bound_vars() + .unwrap() + .upcast(tcx); + pred.sinto(s) + })] + self_predicate: TraitPredicate, + /// Associated items, in definition order. + #[value( + s + .base() + .tcx + .associated_items(s.owner_id()) + .in_definition_order() + .map(|assoc| (assoc, assoc.def_id)) + .collect::>() + .sinto(s) + )] + items: Vec<(AssocItem, Arc)>, + }, + /// Trait alias: `trait IntIterator = Iterator;` + TraitAlias, + Impl { + #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + generics: TyGenerics, + #[value(get_generic_predicates(s, s.owner_id()))] + predicates: GenericPredicates, + #[value(s.base().tcx.impl_subject(s.owner_id()).instantiate_identity().sinto(s))] + impl_subject: ImplSubject, + /// Associated items, in definition order. + #[value( + s + .base() + .tcx + .associated_items(s.owner_id()) + .in_definition_order() + .map(|assoc| (assoc, assoc.def_id)) + .collect::>() + .sinto(s) + )] + items: Vec<(AssocItem, Arc)>, + }, - // Value namespace + // Functions Fn { #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] generics: TyGenerics, @@ -248,6 +264,8 @@ pub enum FullDefKind { })] args: ClosureArgs, }, + + // Constants Const { #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] generics: TyGenerics, @@ -273,6 +291,10 @@ pub enum FullDefKind { #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] body: Option, }, + /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` + AnonConst, + /// An inline constant, e.g. `const { 1 + 2 }` + InlineConst, Static { /// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`. safety: Safety, @@ -289,54 +311,41 @@ pub enum FullDefKind { #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] body: Option, }, - /// Constant generic parameter: `struct Foo { ... }` - ConstParam, - /// Refers to the struct or enum variant's constructor. - Ctor(CtorOf, CtorKind), - // Macro namespace - Macro(MacroKind), - - // Not namespaced (or they are, but we don't treat them so) + // Crates and modules ExternCrate, Use, + Mod { + #[value(get_mod_children(s.base().tcx, s.owner_id()).sinto(s))] + items: Vec, + }, /// An `extern` block. ForeignMod { #[value(get_mod_children(s.base().tcx, s.owner_id()).sinto(s))] items: Vec, }, - /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` - AnonConst, - /// An inline constant, e.g. `const { 1 + 2 }` - InlineConst, - /// Opaque type, aka `impl Trait`. - OpaqueTy, - Impl { - #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] - generics: TyGenerics, - #[value(get_generic_predicates(s, s.owner_id()))] - predicates: GenericPredicates, - #[value(s.base().tcx.impl_subject(s.owner_id()).instantiate_identity().sinto(s))] - impl_subject: ImplSubject, - /// Associated items, in definition order. - #[value( - s - .base() - .tcx - .associated_items(s.owner_id()) - .in_definition_order() - .map(|assoc| (assoc, assoc.def_id)) - .collect::>() - .sinto(s) - )] - items: Vec<(AssocItem, Arc)>, - }, + + // Type-level parameters + /// Type parameter: the `T` in `struct Vec { ... }` + TyParam, + /// Constant generic parameter: `struct Foo { ... }` + ConstParam, + /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` + LifetimeParam, + + // ADT parts + /// Refers to the variant definition, [`DefKind::Ctor`] refers to its constructor if it exists. + Variant, + /// Refers to the struct or enum variant's constructor. + Ctor(CtorOf, CtorKind), /// A field in a struct, enum or union. e.g. /// - `bar` in `struct Foo { bar: u8 }` /// - `Foo::Bar::0` in `enum Foo { Bar(u8) }` Field, - /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` - LifetimeParam, + + // Others + /// Macros + Macro(MacroKind), /// A use of `global_asm!`. GlobalAsm, /// A synthetic coroutine body created by the lowering of a coroutine-closure, such as an async From 192e20cd41e4a9a6a2c9fb0f338da5616b939a67 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 14:47:56 +0100 Subject: [PATCH 186/253] fix(book): fix CSS/JS (we dropped them, but they are useful!) --- book/book.toml | 3 ++- book/default.nix | 1 - book/postprocess.sh | 29 --------------------- book/src/quick_start/intro.md | 10 ++++---- book/static/custom.css | 16 ++++++++++++ book/static/see-fstar-extraction.css | 25 ++++++++++++++++++ book/static/see-fstar-extraction.js | 38 ++++++++++++++++++++++++++++ 7 files changed, 86 insertions(+), 36 deletions(-) delete mode 100755 book/postprocess.sh create mode 100644 book/static/custom.css create mode 100644 book/static/see-fstar-extraction.css create mode 100644 book/static/see-fstar-extraction.js diff --git a/book/book.toml b/book/book.toml index c7377ded6..5c047cb12 100644 --- a/book/book.toml +++ b/book/book.toml @@ -7,4 +7,5 @@ title = "hax" [output.html] mathjax-support = true - +additional-css = ["static/custom.css", "static/see-fstar-extraction.css"] +additional-js = ["static/see-fstar-extraction.js"] diff --git a/book/default.nix b/book/default.nix index 98580862c..a7358b93f 100644 --- a/book/default.nix +++ b/book/default.nix @@ -9,7 +9,6 @@ stdenv.mkDerivation { buildPhase = '' mdbook build mdbook build archive -d ../book/archive - bash ./postprocess.sh ''; installPhase = "mv book $out"; } diff --git a/book/postprocess.sh b/book/postprocess.sh deleted file mode 100755 index 79d4a55ae..000000000 --- a/book/postprocess.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env sh - -# This file replaces `user-checkable` with actual -# checkboxes and adds CSS to the generated HTML. - -for file in $(find . -name '*.html'); do - sed -i 's|user-checkable||g' "$file" -done - -for css in $(find . -name 'general.css'); do - cat >> "$css" <<-EOF -input.user-checkable { - transform: scale(1.5); - margin-right: 8px; - margin-left: 8px; -} - -ul:has(> li > .user-checkable) { - list-style-type: none; - padding: 0; - margin: 0; -} -li:has(> .user-checkable) { - list-style-type: none; - padding: 0; - margin: 0; -} -EOF -done diff --git a/book/src/quick_start/intro.md b/book/src/quick_start/intro.md index 15d42ba26..a5dd82a12 100644 --- a/book/src/quick_start/intro.md +++ b/book/src/quick_start/intro.md @@ -5,9 +5,9 @@ what you are looking for! ## Setup the tools - - **user-checkable** [Install the hax toolchain](https://github.com/hacspec/hax?tab=readme-ov-file#installation). + - [Install the hax toolchain](https://github.com/hacspec/hax?tab=readme-ov-file#installation). 🪄 Running `cargo hax --version` should print some version info. - - **user-checkable** [Install F*](https://github.com/FStarLang/FStar/blob/master/INSTALL.md) *(optional: only if want to run F\*)* + - [Install F*](https://github.com/FStarLang/FStar/blob/master/INSTALL.md) *(optional: only if want to run F\*)* ## Setup the crate you want to verify @@ -16,11 +16,11 @@ what you are looking for! *Note: this part is useful only if you want to run F\*.* - - **user-checkable** Create the folder `proofs/fstar/extraction` folder, right next to the `Cargo.toml` of the crate you want to verify. + - Create the folder `proofs/fstar/extraction` folder, right next to the `Cargo.toml` of the crate you want to verify. 🪄 `mkdir -p proofs/fstar/extraction` - - **user-checkable** Copy [this makefile](https://gist.github.com/W95Psp/4c304132a1f85c5af4e4959dd6b356c3) to `proofs/fstar/extraction/Makefile`. + - Copy [this makefile](https://gist.github.com/W95Psp/4c304132a1f85c5af4e4959dd6b356c3) to `proofs/fstar/extraction/Makefile`. 🪄 `curl -o proofs/fstar/extraction/Makefile https://gist.githubusercontent.com/W95Psp/4c304132a1f85c5af4e4959dd6b356c3/raw/Makefile` - - **user-checkable** Add `hax-lib` as a dependency to your crate, enabled only when using hax. + - Add `hax-lib` as a dependency to your crate, enabled only when using hax. 🪄 `cargo add --target 'cfg(hax)' --git https://github.com/hacspec/hax hax-lib` 🪄 *(`hax-lib` is not mandatory, but this guide assumes it is present)* diff --git a/book/static/custom.css b/book/static/custom.css new file mode 100644 index 000000000..cf40db607 --- /dev/null +++ b/book/static/custom.css @@ -0,0 +1,16 @@ +input.user-checkable { + transform: scale(1.5); + margin-right: 8px; + margin-left: 8px; +} + +ul:has(> li > .user-checkable) { + list-style-type: none; + padding: 0; + margin: 0; +} +li:has(> .user-checkable) { + list-style-type: none; + padding: 0; + margin: 0; +} diff --git a/book/static/see-fstar-extraction.css b/book/static/see-fstar-extraction.css new file mode 100644 index 000000000..f9109499a --- /dev/null +++ b/book/static/see-fstar-extraction.css @@ -0,0 +1,25 @@ +.rust-fstar-wrapper .buttons { + text-align: right; + margin-right: 8px; +} +.rust-fstar-wrapper button { + border: none; + background: none; + padding: 4px 14px; +} +.rust-fstar-wrapper .buttons .fstar-rust-snippet-active { + background: #f6f7f6; + opacity: 1; +} +.rust-fstar-wrapper .buttons button:hover { + opacity: 1; +} +.rust-fstar-wrapper .buttons .fstar-rust-snippet-hidden { + opacity: 0.4; +} +.rust-fstar-wrapper .snippets .snippet.fstar-rust-snippet-hidden { + display: none; +} +.rust-fstar-wrapper .snippets .snippet pre { + margin-top: 0; +} diff --git a/book/static/see-fstar-extraction.js b/book/static/see-fstar-extraction.js new file mode 100644 index 000000000..0dfb76292 --- /dev/null +++ b/book/static/see-fstar-extraction.js @@ -0,0 +1,38 @@ +function installButtons() { + let id = 0; + for(let fst of document.querySelectorAll('pre + pre')) { + let parent = fst.parentElement; + let rust = fst.previousElementSibling; + let w = s => `
${s}
`; + let both = w(rust.outerHTML) + w(fst.outerHTML); + parent.removeChild(rust); + let snippets = document.createElement('div'); + snippets.classList.add('snippets'); + snippets.innerHTML = both; + let buttons = document.createElement('div'); + id++; + buttons.classList.add('buttons'); + buttons.innerHTML = ``; + let mk_active = i => { + [snippets, buttons].map(el => + [...el.children].map((x, j) => { + x.classList[j==i ? 'remove' : 'add']('fstar-rust-snippet-hidden'); + x.classList[j==i ? 'add' : 'remove']('fstar-rust-snippet-active'); + }) + ); + }; + [...buttons.children].map((child, nth) => + (child.onclick = _ => mk_active(nth)) + ); + const RUST = 0; + mk_active(RUST); + + let wrapper = document.createElement('div'); + wrapper.classList.add('rust-fstar-wrapper'); + wrapper.appendChild(buttons); + wrapper.appendChild(snippets); + parent.replaceChild(wrapper, fst); + } +}; + +window.addEventListener("load", installButtons); From 911f8ea025675777345481eb4cac359331cc1f11 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 29 Oct 2024 16:37:22 +0100 Subject: [PATCH 187/253] Compute the impl exprs for an implemented associated type --- frontend/exporter/src/traits.rs | 3 ++- frontend/exporter/src/types/ty.rs | 38 ++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/frontend/exporter/src/traits.rs b/frontend/exporter/src/traits.rs index 0abd22f5f..1ba78515d 100644 --- a/frontend/exporter/src/traits.rs +++ b/frontend/exporter/src/traits.rs @@ -208,12 +208,13 @@ fn solve_item_traits_inner<'tcx, S: UnderOwnerState<'tcx>>( generics: ty::GenericArgsRef<'tcx>, predicates: impl Iterator>, ) -> Vec { + use crate::rustc_middle::ty::ToPolyTraitRef; let tcx = s.base().tcx; let param_env = s.param_env(); predicates .filter_map(|clause| clause.as_trait_clause()) - .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref)) + .map(|clause| clause.to_poly_trait_ref()) // Substitute the item generics .map(|trait_ref| ty::EarlyBinder::bind(trait_ref).instantiate(tcx, generics)) // We unfortunately don't have a way to normalize without erasing regions. diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index 8d4c9970a..72ad7f785 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -1357,23 +1357,34 @@ fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( s: &S, item: &ty::AssocItem, ) -> AssocItemContainer { - let container_id = item.container_id(s.base().tcx); + let tcx = s.base().tcx; + let container_id = item.container_id(tcx); match item.container { ty::AssocItemContainer::TraitContainer => AssocItemContainer::TraitContainer { trait_id: container_id.sinto(s), }, ty::AssocItemContainer::ImplContainer => { if let Some(implemented_trait_item) = item.trait_item_def_id { + // The trait ref that is being implemented by this `impl` block. + let implemented_trait_ref = tcx + .impl_trait_ref(container_id) + .unwrap() + .instantiate_identity(); + + // Resolve required impl exprs for this item. + let item_args = ty::GenericArgs::identity_for_item(tcx, item.def_id); + // Subtlety: we have to add the GAT arguments (if any) to the trait ref arguments. + let args = item_args.rebase_onto(tcx, container_id, implemented_trait_ref.args); + let state_with_id = with_owner_id(s.base(), (), (), item.def_id); + let required_impl_exprs = + solve_item_implied_traits(&state_with_id, implemented_trait_item, args); + AssocItemContainer::TraitImplContainer { impl_id: container_id.sinto(s), - implemented_trait: s - .base() - .tcx - .trait_of_item(implemented_trait_item) - .unwrap() - .sinto(s), + implemented_trait: implemented_trait_ref.def_id.sinto(s), implemented_trait_item: implemented_trait_item.sinto(s), - overrides_default: s.base().tcx.defaultness(implemented_trait_item).has_value(), + overrides_default: tcx.defaultness(implemented_trait_item).has_value(), + required_impl_exprs, } } else { AssocItemContainer::InherentImplContainer { @@ -1431,6 +1442,17 @@ pub enum AssocItemContainer { /// Whether the corresponding trait item had a default (and therefore this one overrides /// it). overrides_default: bool, + /// The `ImplExpr`s required to satisfy the predicates on the associated type. E.g.: + /// ```ignore + /// trait Foo { + /// type Type: Clone, + /// } + /// impl Foo for () { + /// type Type: Arc; // would supply an `ImplExpr` for `Arc: Clone`. + /// } + /// ``` + /// Empty if this item is an associated const or fn. + required_impl_exprs: Vec, }, InherentImplContainer { impl_id: DefId, From 8cfe9d600294ca1258a55f13d8cbc41b0db837f7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 29 Oct 2024 16:57:14 +0100 Subject: [PATCH 188/253] Add constness information to `FullDef` --- frontend/exporter/src/types/new/full_def.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index fb0f3ea24..abdf0c43f 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -222,6 +222,8 @@ pub enum FullDefKind { predicates: GenericPredicates, #[value(s.base().tcx.codegen_fn_attrs(s.owner_id()).inline.sinto(s))] inline: InlineAttr, + #[value(s.base().tcx.constness(s.owner_id()) == rustc_hir::Constness::Const)] + is_const: bool, #[value(s.base().tcx.fn_sig(s.owner_id()).instantiate_identity().sinto(s))] sig: PolyFnSig, #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] @@ -240,6 +242,8 @@ pub enum FullDefKind { predicates: GenericPredicates, #[value(s.base().tcx.codegen_fn_attrs(s.owner_id()).inline.sinto(s))] inline: InlineAttr, + #[value(s.base().tcx.constness(s.owner_id()) == rustc_hir::Constness::Const)] + is_const: bool, #[value(s.base().tcx.fn_sig(s.owner_id()).instantiate_identity().sinto(s))] sig: PolyFnSig, #[value(s.owner_id().as_local().map(|ldid| Body::body(ldid, s)))] @@ -255,6 +259,8 @@ pub enum FullDefKind { /// constant. #[value(s.base().tcx.parent(s.owner_id()).sinto(s))] parent: DefId, + #[value(s.base().tcx.constness(s.owner_id()) == rustc_hir::Constness::Const)] + is_const: bool, #[value({ let fun_type = s.base().tcx.type_of(s.owner_id()).instantiate_identity(); match fun_type.kind() { From 351ae498d39f3d41ba691456c227a32b84a83c0c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 29 Oct 2024 16:59:41 +0100 Subject: [PATCH 189/253] Forgot bodies in recursive `FullDef`s --- frontend/exporter/src/types/new/full_def.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index abdf0c43f..1583b8a21 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -36,7 +36,7 @@ pub struct FullDef { fn translate_full_def<'tcx, S, Body>(s: &S, def_id: RDefId) -> FullDef where S: BaseState<'tcx>, - Body: IsBody, + Body: IsBody + TypeMappable, { let tcx = s.base().tcx; let def_kind = tcx.def_kind(def_id); @@ -88,7 +88,7 @@ where /// Imbues [`rustc_hir::def::DefKind`] with a lot of extra information. /// Important: the `owner_id()` must be the id of this definition. #[derive(AdtInto)] -#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::DefKind, state: S as s, where Body: IsBody)] +#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_hir::def::DefKind, state: S as s, where Body: IsBody + TypeMappable)] #[derive_group(Serializers)] #[derive(Clone, Debug, JsonSchema)] pub enum FullDefKind { @@ -189,7 +189,7 @@ pub enum FullDefKind { .collect::>() .sinto(s) )] - items: Vec<(AssocItem, Arc)>, + items: Vec<(AssocItem, Arc>)>, }, /// Trait alias: `trait IntIterator = Iterator;` TraitAlias, @@ -211,7 +211,7 @@ pub enum FullDefKind { .collect::>() .sinto(s) )] - items: Vec<(AssocItem, Arc)>, + items: Vec<(AssocItem, Arc>)>, }, // Functions From 335d018971a48b0b9aaa582871c01b0d4ac57f5a Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 17:25:03 +0100 Subject: [PATCH 190/253] feat(book): allow F* extraction & TC within the book --- book/book.toml | 8 +- book/src/tutorial/Cargo.lock | 239 ------ book/src/tutorial/Cargo.toml | 10 - book/src/tutorial/Sources.fst | 110 --- book/src/tutorial/data-invariants.md | 48 +- book/src/tutorial/panic-freedom.md | 37 +- book/src/tutorial/properties.md | 74 +- book/src/tutorial/sources.rs | 138 ---- book/theme/ansi_up.js | 7 + book/theme/book.js | 776 ++++++++++++++++++ book/theme/css/chrome.css | 606 ++++++++++++++ book/theme/css/general.css | 234 ++++++ book/theme/css/print.css | 50 ++ book/theme/css/variables.css | 279 +++++++ book/theme/favicon.png | Bin 0 -> 5679 bytes book/theme/favicon.svg | 22 + book/theme/fonts/OPEN-SANS-LICENSE.txt | 202 +++++ book/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt | 93 +++ book/theme/fonts/fonts.css | 100 +++ .../open-sans-v17-all-charsets-300.woff2 | Bin 0 -> 44352 bytes ...open-sans-v17-all-charsets-300italic.woff2 | Bin 0 -> 40656 bytes .../open-sans-v17-all-charsets-600.woff2 | Bin 0 -> 44936 bytes ...open-sans-v17-all-charsets-600italic.woff2 | Bin 0 -> 42120 bytes .../open-sans-v17-all-charsets-700.woff2 | Bin 0 -> 44988 bytes ...open-sans-v17-all-charsets-700italic.woff2 | Bin 0 -> 40800 bytes .../open-sans-v17-all-charsets-800.woff2 | Bin 0 -> 44536 bytes ...open-sans-v17-all-charsets-800italic.woff2 | Bin 0 -> 40812 bytes .../open-sans-v17-all-charsets-italic.woff2 | Bin 0 -> 41076 bytes .../open-sans-v17-all-charsets-regular.woff2 | Bin 0 -> 43236 bytes ...source-code-pro-v11-all-charsets-500.woff2 | Bin 0 -> 59140 bytes book/theme/fstar.js | 82 ++ book/theme/highlight.css | 82 ++ book/theme/highlight.css.old | 82 ++ book/theme/highlight.js | 53 ++ book/theme/index.hbs | 346 ++++++++ book/theme/lz-string.js | 1 + 36 files changed, 3125 insertions(+), 554 deletions(-) delete mode 100644 book/src/tutorial/Cargo.lock delete mode 100644 book/src/tutorial/Cargo.toml delete mode 100644 book/src/tutorial/Sources.fst delete mode 100644 book/src/tutorial/sources.rs create mode 100644 book/theme/ansi_up.js create mode 100644 book/theme/book.js create mode 100644 book/theme/css/chrome.css create mode 100644 book/theme/css/general.css create mode 100644 book/theme/css/print.css create mode 100644 book/theme/css/variables.css create mode 100644 book/theme/favicon.png create mode 100644 book/theme/favicon.svg create mode 100644 book/theme/fonts/OPEN-SANS-LICENSE.txt create mode 100644 book/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt create mode 100644 book/theme/fonts/fonts.css create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-300.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-300italic.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-600.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-600italic.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-700.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-700italic.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-800.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-800italic.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-italic.woff2 create mode 100644 book/theme/fonts/open-sans-v17-all-charsets-regular.woff2 create mode 100644 book/theme/fonts/source-code-pro-v11-all-charsets-500.woff2 create mode 100644 book/theme/fstar.js create mode 100644 book/theme/highlight.css create mode 100644 book/theme/highlight.css.old create mode 100644 book/theme/highlight.js create mode 100644 book/theme/index.hbs create mode 100644 book/theme/lz-string.js diff --git a/book/book.toml b/book/book.toml index 5c047cb12..19d6bf585 100644 --- a/book/book.toml +++ b/book/book.toml @@ -7,5 +7,9 @@ title = "hax" [output.html] mathjax-support = true -additional-css = ["static/custom.css", "static/see-fstar-extraction.css"] -additional-js = ["static/see-fstar-extraction.js"] +additional-css = ["static/custom.css"] +additional-js = ["theme/fstar.js", "theme/lz-string.js", "theme/ansi_up.js"] + +[output.html.playground] +runnable = true +editable = true diff --git a/book/src/tutorial/Cargo.lock b/book/src/tutorial/Cargo.lock deleted file mode 100644 index 9675766ca..000000000 --- a/book/src/tutorial/Cargo.lock +++ /dev/null @@ -1,239 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hax-lib" -version = "0.1.0-pre.1" -source = "git+https://github.com/hacspec/hax#d668de4d17e5ddee3a613068dc30b71353a9db4f" - -[[package]] -name = "hax-lib-macros" -version = "0.1.0-pre.1" -source = "git+https://github.com/hacspec/hax#d668de4d17e5ddee3a613068dc30b71353a9db4f" -dependencies = [ - "hax-lib-macros-types", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "hax-lib-macros-types" -version = "0.1.0-pre.1" -source = "git+https://github.com/hacspec/hax#d668de4d17e5ddee3a613068dc30b71353a9db4f" -dependencies = [ - "proc-macro2", - "quote", - "schemars", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "schemars" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" -dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 1.0.109", -] - -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.52", -] - -[[package]] -name = "serde_derive_internals" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "serde_json" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tutorial-src" -version = "0.1.0" -dependencies = [ - "hax-lib", - "hax-lib-macros", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "uuid" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" -dependencies = [ - "getrandom", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/book/src/tutorial/Cargo.toml b/book/src/tutorial/Cargo.toml deleted file mode 100644 index de5569b89..000000000 --- a/book/src/tutorial/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "tutorial-src" -version = "0.1.0" -edition = "2021" - -[lib] -path = "sources.rs" - -[dependencies] -hax-lib = { git = "https://github.com/hacspec/hax", version = "0.1.0-pre.1" } diff --git a/book/src/tutorial/Sources.fst b/book/src/tutorial/Sources.fst deleted file mode 100644 index cedf378a5..000000000 --- a/book/src/tutorial/Sources.fst +++ /dev/null @@ -1,110 +0,0 @@ -module Tutorial_src -#set-options "--fuel 0 --ifuel 1 --z3rlimit 150" -open Core -open FStar.Mul - -// ANCHOR: F3 -type t_F3 = - | F3_E1 : t_F3 - | F3_E2 : t_F3 - | F3_E3 : t_F3 - -let t_F3_cast_to_repr (x: t_F3) : isize = - match x with - | F3_E1 -> isz 0 - | F3_E2 -> isz 1 - | F3_E3 -> isz 3 -// ANCHOR_END: F3 - -// ANCHOR: barrett -unfold -let t_FieldElement = i32 - -let v_BARRETT_MULTIPLIER: i64 = 20159L - -let v_BARRETT_R: i64 = 67108864L - -let v_BARRETT_SHIFT: i64 = 26L - -let v_FIELD_MODULUS: i32 = 3329l - -let barrett_reduce (value: i32) - : Pure i32 - (requires - (Core.Convert.f_from value <: i64) >=. (Core.Ops.Arith.Neg.neg v_BARRETT_R <: i64) && - (Core.Convert.f_from value <: i64) <=. v_BARRETT_R) - (ensures - fun result -> - let result:i32 = result in - result >. (Core.Ops.Arith.Neg.neg v_FIELD_MODULUS <: i32) && result <. v_FIELD_MODULUS && - (result %! v_FIELD_MODULUS <: i32) =. (value %! v_FIELD_MODULUS <: i32)) = - let t:i64 = (Core.Convert.f_from value <: i64) *! v_BARRETT_MULTIPLIER in - let t:i64 = t +! (v_BARRETT_R >>! 1l <: i64) in - let quotient:i64 = t >>! v_BARRETT_SHIFT in - let quotient:i32 = cast (quotient <: i64) <: i32 in - let sub:i32 = quotient *! v_FIELD_MODULUS in - let _:Prims.unit = Tutorial_src.Math.Lemmas.cancel_mul_mod quotient 3329l in - value -! sub -// ANCHOR_END: barrett - -// ANCHOR: encrypt_decrypt -let decrypt (ciphertext key: u32) : u32 = ciphertext ^. key - -let encrypt (plaintext key: u32) : u32 = plaintext ^. key -// ANCHOR_END: encrypt_decrypt - - - - - - - -// ANCHOR: encrypt_decrypt_identity -let encrypt_decrypt_identity (key plaintext: u32) - : Lemma (requires true) - (ensures (decrypt (encrypt plaintext key <: u32) key <: u32) =. plaintext) = () -// ANCHOR_END: encrypt_decrypt_identity - -// ANCHOR: square -let square (x: u8) : u8 = x *! x -// ANCHOR_END: square - -// ANCHOR: square_ensures -let square_ensures (x: u8) - : Pure u8 - (requires x <. 16uy) - (ensures fun result -> result >=. x) - = x *! x -// ANCHOR_END: square_ensures - -// ANCHOR: square_option -let square_option (x: u8) : Core.Option.t_Option u8 = - if x >=. 16uy - then Core.Option.Option_None <: Core.Option.t_Option u8 - else Core.Option.Option_Some (x *! x) <: Core.Option.t_Option u8 -// ANCHOR_END: square_option - -// ANCHOR: square_requires -let square_requires (x: u8) - : Pure u8 (requires x <. 16uy) (requires fun _ -> True) - = x *! x -// ANCHOR_END: square_requires - -// ANCHOR: F -let v_Q: u16 = 2347us - -type t_F = { f_v:f_v: u16{f_v <. v_Q} } -// ANCHOR_END: F - -// ANCHOR: AddF -[@@ FStar.Tactics.Typeclasses.tcinstance] -let impl: Core.Ops.Arith.t_Add t_F t_F = - { - f_Output = t_F; - f_add_pre = (fun (self: t_F) (rhs: t_F) -> true); - f_add_post = (fun (self: t_F) (rhs: t_F) (out: t_F) -> true); - f_add = fun (self: t_F) (rhs: t_F) -> { - f_v = (self.f_v +! rhs.f_v <: u16) %! v_Q - } <: t_F - } -// ANCHOR_END: AddF diff --git a/book/src/tutorial/data-invariants.md b/book/src/tutorial/data-invariants.md index a6777795f..285413bb2 100644 --- a/book/src/tutorial/data-invariants.md +++ b/book/src/tutorial/data-invariants.md @@ -25,11 +25,12 @@ Rust alone already can solve our representation issues with define the `enum` type `F3` which has only three constructor: `F3` represent exactly the elements of `F₃`, not more, not less. -```rust,noplaypen -{{#include sources.rs:F3}} -``` -```ocaml -{{#include Sources.fst:F3}} +```rust,editable +enum F3 { + E1, + E2, + E3, +} ``` With `F3`, there doesn't exist illegal values at all: we can now @@ -53,11 +54,14 @@ one `u16` field `v`. Notice the refinment annotation on `v`: the extraction of this type `F` via hax will result in a type enforcing `v` small enough. -```rust,noplaypen -{{#include sources.rs:F}} -``` -```ocaml -{{#include Sources.fst:F}} +```rust,editable +pub const Q: u16 = 2347; + +#[hax_lib::attributes] +pub struct F { + #[hax_lib::refine(v < Q)] + pub v: u16, +} ``` In Rust, we can now define functions that operates on type `F`, @@ -65,11 +69,25 @@ assuming they are in bounds with respect to `F₂₃₄₇`: every such assumption will be checked and enforced by the proof assistant. As an example, below is the implementation of the addition for type `F`. -```rust,noplaypen -{{#include sources.rs:AddF}} -``` -```ocaml -{{#include Sources.fst:AddF}} +```rust,editable +# pub const Q: u16 = 2347; +# +# #[hax_lib::attributes] +# pub struct F { +# #[hax_lib::refine(v < Q)] +# pub v: u16, +# } + +use core::ops::Add; + +impl Add for F { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self { + v: (self.v + rhs.v) % Q, + } + } +} ``` Here, F* is able to prove automatically that (1) the addition doesn't diff --git a/book/src/tutorial/panic-freedom.md b/book/src/tutorial/panic-freedom.md index 38d2f2c33..ab996f58d 100644 --- a/book/src/tutorial/panic-freedom.md +++ b/book/src/tutorial/panic-freedom.md @@ -5,15 +5,13 @@ integer. To extract this function to F* using hax, we simply need to run the command `cargo hax into fstar` in the directory of the crate in which the function `square` is defined. -*Note: throughout this tutorial, you can inspect the hax extraction to -F\* for each code Rust snippets, by clicking on the "F\* extraction" -tab.* +*Note: throughout this tutorial, you can edit the snippets of code and +extract to F\* by clicking the play button ( ), or even typecheck it with the button ( ).* -```rust,noplaypen -{{#include sources.rs:square}} -``` -```ocaml -{{#include Sources.fst:square}} +```rust,editable +fn square(x: u8) -> u8 { + x * x +} ``` Though, if we try to verify this function, F* is complaining about a @@ -58,11 +56,14 @@ its input is within `0` and `15`. ### Solution A: reflect the partialness of the function in Rust A first solution is to make `square` return an `Option` instead of a `u8`: -```rust,noplaypen -{{#include sources.rs:square_option}} -``` -```ocaml -{{#include Sources.fst:square_option}} +```rust,editable +fn square_option(x: u8) -> Option { + if x >= 16 { + None + } else { + Some(x * x) + } +} ``` Here, F* is able to prove panic-freedom: calling `square` with any @@ -90,11 +91,11 @@ provdes the `requires` [proc-macro](https://doc.rust-lang.org/reference/procedural-macros.html) which lets user writting pre-conditions directly in Rust. -```rust,noplaypen -{{#include sources.rs:square_requires}} -``` -```ocaml -{{#include Sources.fst:square_requires}} +```rust,editable +#[hax_lib::requires(x < 16)] +fn square_requires(x: u8) -> u8 { + x * x +} ``` With this precondition, F* is able to prove panic freedom. From now diff --git a/book/src/tutorial/properties.md b/book/src/tutorial/properties.md index 5e1a438ab..fb411243e 100644 --- a/book/src/tutorial/properties.md +++ b/book/src/tutorial/properties.md @@ -9,12 +9,12 @@ _return a value_: it will not panic or diverge. We could enrich the contract of `square` with a post-condition about the fact it is a increasing function: -```rust,noplaypen -{{#include sources.rs:square_ensures}} -``` - -```ocaml -{{#include Sources.fst:square_ensures}} +```rust,editable +#[hax_lib::requires(x < 16)] +#[hax_lib::ensures(|result| result >= x)] +fn square_ensures(x: u8) -> u8 { + x * x +} ``` Such a simple post-condition is automatically proven by F\*. The @@ -37,12 +37,30 @@ Given `value` a field element (a `i32` whose absolute value is at most It is easy to write this contract directly as `hax::requires` and `hax::ensures` annotations, as shown in the snippet below. -```rust,noplaypen -{{#include sources.rs:barrett}} -``` +```rust,editable +type FieldElement = i32; +const FIELD_MODULUS: i32 = 3329; +const BARRETT_SHIFT: i64 = 26; +const BARRETT_R: i64 = 0x4000000; // 2^26 +const BARRETT_MULTIPLIER: i64 = 20159; // ⌊(BARRETT_R / FIELD_MODULUS) + 1/2⌋ + +#[hax_lib::requires((i64::from(value) >= -BARRETT_R && i64::from(value) <= BARRETT_R))] +#[hax_lib::ensures(|result| result > -FIELD_MODULUS && result < FIELD_MODULUS + && result % FIELD_MODULUS == value % FIELD_MODULUS)] +fn barrett_reduce(value: i32) -> i32 { + let t = i64::from(value) * BARRETT_MULTIPLIER; + let t = t + (BARRETT_R >> 1); + + let quotient = t >> BARRETT_SHIFT; + let quotient = quotient as i32; -```ocaml -{{#include Sources.fst:barrett}} + let sub = quotient * FIELD_MODULUS; + + // Here a lemma to prove that `(quotient * 3329) % 3329 = 0` + // may have to be called in F*. + + value - sub +} ``` diff --git a/book/theme/fonts/OPEN-SANS-LICENSE.txt b/book/theme/fonts/OPEN-SANS-LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/book/theme/fonts/OPEN-SANS-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/book/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt b/book/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt new file mode 100644 index 000000000..366206f54 --- /dev/null +++ b/book/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/book/theme/fonts/fonts.css b/book/theme/fonts/fonts.css new file mode 100644 index 000000000..858efa598 --- /dev/null +++ b/book/theme/fonts/fonts.css @@ -0,0 +1,100 @@ +/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ +/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ + +/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), + url('open-sans-v17-all-charsets-300.woff2') format('woff2'); +} + +/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; + src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), + url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); +} + +/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); +} + +/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), + url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); +} + +/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('open-sans-v17-all-charsets-600.woff2') format('woff2'); +} + +/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), + url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); +} + +/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), + url('open-sans-v17-all-charsets-700.woff2') format('woff2'); +} + +/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), + url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); +} + +/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), + url('open-sans-v17-all-charsets-800.woff2') format('woff2'); +} + +/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 800; + src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), + url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); +} + +/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 500; + src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); +} diff --git a/book/theme/fonts/open-sans-v17-all-charsets-300.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-300.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9f51be370fa913ce6de2922b580c262c4822b337 GIT binary patch literal 44352 zcmV(;K-<4}Pew8T0RR910Ifg(5dZ)H0f7hr0Ib{q0RR9100000000000000000000 z0000QE*lUWfmQ}!0EY+&fhq})G!YOAg!yQMtSAeP3IG8%0we>R0t6rhgFFYi4Ge-h zTM$x_K;*{m=TyO<(oF`$dr#+gT@uRz<@OP72f1way{Ld4djxa`IG0*=K;{4c|Nq>i zF~-^s+Z{rPn$}0zLzV=G*ddk#MfRZCOSo7Svxg)@O1QTM(GtC{-8am>TkfXJ&}5JO zXokZnNWAaG&x#r1r&DFc3k@sfl$|@RDaX?kWW{EN@TZnHp}gCDd}u9PW@H>gZ142z+QEhtr+J1&#|>KAj6Y2`)3tZkBe+ebjmTS6=W*;+$iHPBB3Un)Qo?6q*dE(P3T9y565vHowfyevYxI9K2P(y z$<_L{@8?J5hBF;TxvX%vUMY{MW;AQOFw;MRE?UNs>(i)Pw#F30SO&%}gA&nV#5ynh z%lr4w|41^EwI78NR7X_&MdMPeXq|gj4oJ6}tzd{4Fvwwq1Zjy_sfS1l0YYgJLOuSa zG~qZt#{MG5VL1;uY?c0qywYwhjn*_`$CiZFZCFDFz-?kG;zz}gkK?(Z;(4Ip0|Y@p zL`0q-DhfWlFW)O~_Uv1l(z*7n%=kiif-51?{(S1>dTz;-%RXz{zW_NG4POWVdSfQ{H?gb&VPWmSuI@as@lXQ zCML+EVq_sv+K31qR)E!rHdbOZcI*#x`rpX1-FQZd2?w2J5+HD^d^xN_9WLUu;R1_>$Sl2l1j{i_PqRoxBKXmEfAv5RRCG~gHz zoRPqp)jl)`>4DtY_ee=+oD0vBlrtv1+}R|)Aj>WYFNl--dsEGJL13vB!x?g=A&fDlOONKn#&pyZ<<^Gt#Y5O9+B{||V8CFK!GIY^G7 ziird-fZ=XPfYkAzOvx!^1&5rvR8_9Zlqy%TZCti4x_G(NsHD}UoUD}Q&&1ywU=hnR zK_eK;d!w1V-89?ZEBgl|7bFMOFTBI&;bU#pwZ9KM5d*ckoOlTrnn@#e=0bxf_LKF$ zd-0Mi4MXYT*CGx?Tq%ZXXdY`yIWWVJf|?K(5DNrL%GP_mZs@nw-vBb}Rw0W;wB!)N z5TjzUSNZXIA7943^nXK*r#Dw9|Mtf&ksu-=h_`Yp9V;Dkh;8<4psUZVb-$?#qp%T! ziAdB1b$5t5hjOzR8iD$*)2$e71R6>Zt8%DEY$Sg2KWN&b4Cqr8h>8`6#((@8#L}XktLaTS zryU~vMx03nNxOB%uQY)H>VL7pz)zP2nhY%8WH@)-0RsdY-07d0c5ee-ah{%=QSM%u z*8so2)#K3GU!m!|?O$6+?&yD~(Fj>ZOxK05BApxGi zJr7YET6WG{j1#TYt(MkW%SPIA4dOUU&zsN+<{}nS6r*LQrr)v8tl?2R`* z6w<>(odO>Dg>%+<`=H~%Re+D2bI267Gb@WPo}vT*tKEȮck{9tEK*~BMoW% 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 literal 0 HcmV?d00001 diff --git a/book/theme/fonts/open-sans-v17-all-charsets-300italic.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-300italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2f545448418cba6668a2e7d49e9616e8c69dfd15 GIT binary patch literal 40656 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 bQBM5)6s%p?oy_T)fR3IrepgG2|qH4K6n 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

D& zKmG7e67!kl#@t`?2092GluuaI?(wqHGc$CxbhOu&-QklBs;yusvX`9XbS$sFoH+FwvSs*$VNBEt-3}x$RNG$?<{E4Ybo(b3OQlfghskNz z9}K5Z3VQ3758HkG0jW@{RIXI$g7RShkH;@~Tu&=BS_r#d@9~%{hig#_2T@|P9H)w? z=gh}5S>q^Cq)p*cpk@GaSXq4sH<14^6;np5c+t|$J9x&lS&Se9UXJl& z`)tC!CGF^PM{9Gle70PoNpUr~Y%X6Z!}+OG>@qySno#@WZs|(!*Vl)pnmp&Xm-VKQ zd#My=>7WO!yH+kA!}m@QP$?RL){Bk$Qv*y2cO;BUYachhU4q|dA!Mv|yd}&v+!gE% z{DqB_ousX_y~Gbfu*tQR**BQz*PQqTVG6mV8#<{f+pRkMaZ3L)vy(`szQ9`Qf3L->DdXY}1dMc^^Csk2NTKs7&QcmZsc@0=Q*+*}0+ubaVYp z?_|MQ3hbnc(VG!jcF*kMaE)V8EC4oZFthXNL(^I^9lZlOJ$lJAO5=PrN|Oa{fGt+^ z86n<5N4dk4So5{kLjS&dhC18h8m3KH)**}vqTFD5^iMTKEbcl&5* zW^QC_D;06l5fzsu|eN0BcF>w|9d0O=b_CFVJ+E}_9y>Lu<@sRBZRB_KQXt_6*y+3*^M zE`8Gx-~2b)<#e>sMPht9=HdY`yV6x{- z64g$bGMR7NOT#uSC|2C5PQzyT^d!Zjg}qSQ?g6h$P4ccGk1(o5QhVy0CTs#8Vc)~9 zOq7?zT_f$!BRru4nCKiVUdJbNGaH|)2T8r+vx5vQZAuho$o6xH5)jXZGCov~fcRfT z&bKQLJ3z=#;>0N62R2Ai419Sb^WkaElLsFHLI;>$2KQ0{9@j2ZT<&_5+_Qnn+unjA znR%4OQ<~yW{LJ??8#ND;4y+f5FkhH;oGaMu*V%`Yil((-`_{i*wzrFu0@>r@;Q!@9 ztG-5C$|o66q0!cO8N3oR-ZuJgm%HhR9u|9gr72nkgf z`o9%BG~SIbmXx=T6}XWG!96o?82ddt~la{g9g5aRjJlk4d!jyanU_J7pF% z77h|AA4MVw=oD5BKVh$ZqKjco|ES*^`7lni8w`M~OOWG;!0pS{gxy|=mLhl`j&hO$ zyh#a7>{8aWnp$JtTk9*E)-=y}7@o8Aa4GKMcm(?Dkj`*yw&d^BbmmXdiwG6W=0S!H zhPH0Do+Bm19r|tQO1}!sqQwXgXJt)nTYP{voU&oA`&wBCy5wXMu+q{aM~Pnu^`Xm% z>~wKZWVqL`FH-T@4e}yAN80yR(3BfT^Ox^K6v1kT9mt8Me)EpvvO~*=Dzl0TbRG>Y z021OhH){SbYUb?JJhVvyjO_=O!9SzJSr7p`)%p3ee#i#M@JWL}?M@`DqCi*ZE@Tjp F{|Bsk2y6fV literal 0 HcmV?d00001 diff --git a/book/theme/fonts/open-sans-v17-all-charsets-600italic.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-600italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c99aabe80340fd88a6aeb5729251e76c9a6f35ec GIT binary patch literal 42120 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 E9}-z&tN;K2 literal 0 HcmV?d00001 diff --git a/book/theme/fonts/open-sans-v17-all-charsets-700.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..421a1ab25fa88105ab776552d7201205f7899841 GIT binary patch literal 44988 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 literal 0 HcmV?d00001 diff --git a/book/theme/fonts/open-sans-v17-all-charsets-700italic.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-700italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..12ce3d20d1ce2288206e8b4f31c20f76452efe37 GIT binary patch literal 40800 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%0DER>;wf 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%0Deo9y(?}8?riQx3p&>dOY zNGwTh_PW&_Qdr$zy%ULyhlWx)VM8XFOazsQ97W%}?ADm8L=UZMtBpKBsbkHkh>!_&Yk^=gzh*3V6@UVyV4OZwt1b7cJ=(dz-fPc zn>e)KFdZs{{c;MnclXvtRwW#K;a#wf z%~mn)yT0@-SaS$Ai0_W-QLK!=kY@}%Ak7P{tEg8`L{9a8N=h-0B9h$n zi29HaZ7JYBus`C<=^y*T1#z-h4; zem>>d4+vO%VLL5V?dx_sYgC)Emnoqq!}_R{fSW^Yw?WEYMx_&=vcp*cLHAc_1A2^o zj3UNN)li3>4)8cyozhg@NE{CU9wem=f3&5i)eP zOn7kbgjv+^d|_3%Mv|E;0TO~Z8b)UIJ%2sl7SC+-!sUCa$9$H8eV36cl+I|EX$Ja?zmlHH36b1xd zhlqbtYldM4Gi6E(?4;jzkVw>@+;cNGW1aRhZnYD=YA1Ts#(K1-ej!ky1OhsnPp^}- zPt|l-9Z*gV;ZHYN$&&6MFlZ(%N6kF4q<2)__fy3$~XlZ1uHK7AiSCr<-x1hHpg zxkvq)Wt`b;@PmR%0#4D@174IDTNYOzp z6(@5N5_n>bVwC=mH)xOLLq$h8IQMp2z|7%;KOe;?`{*CfzI)G_WN)@^eEc0ow=x_= z(X3aCZ@H(cA5PExW5%0sQ1*ngzQDH}`wa;_%4v^FqO%!Q`-Vcb=V%l@(l6s-v0^L1 zjm;ddMLfa4eqb23y|pJ#D=>+>0T^-*SBVbLJb zlLL`|p#SdI9%an8yCf=q$3iGErnD*${SfEgZ2QyT>ozs;G77t2BQD>`tik2Zh%mTf z&kd~ntZWo*rGcj20C4%>J&s@bBGIb9yH z#4FsM&IM5I^PZPHvfO#ydGR-kV_wh8wP6mJ#A^wGYI4FK`gwY$E7JLi)nFOwYmFu5 zDkvu=oL)|f7@CQ;o0}0Jmt)-D2z&%4qpNGaNGgBE+nvOF;Kn7n<7^%s(l0v{L)=t< zz64J*_>_qTE8YY8ORg{XYKsYHl#`_8mMt+MuEH7ViUbv&B>yjHi9J5o16T<1y=tp@SiO->jiqREmqbeJU~9_wlolAH;?y}?h<}VcnWv;7p&jgS6Bpka8EF= zS)gb9aa>T*EYpDKAz6=8v^V7iDC^pU=%xhg7zYkab$m<0yV#6WiO!ylOsMTlsq#J% z;+}Jl+h0?}4dAzPZIHnK;ze1|*}l3SXY#xIGp@Za8uU`I2kXX3GYutJ9ErH^gZA>o2>Yg~1!IYR8UtZPT5 z3>v!UEO7a2ic*2xF3#0$*~y$HPI%^aoRM!i(KQuN38l7>*vEce%8EJkm+(R`gUub( zAo9cgEyo z4S==<6~48SsF@mQTtaUp2pX&+@kGl-*W9+8A1n?*m3AmnG`hgKf@&Ez#9FGNYoRgt zhGDZH2pfHWLu)qV^oxd=^5IvG&-udb(&R!zlR@2JhI z+Ua}9U&t0I9v6WX$4aK;u30D3KUJva+4RFT#gS}v+(1qxm+L~@d5Xr?c$cp9257{I zI~MlEh3>PcsR=A@1-r?)n&Um@)zv}z20tw;7wUx$VeG$l_1N{#=)nSGbt={GI|@#a zN+U8ri?ng;x7^x7V?$ATpF)dB;_Ev2i5fw)XKHa+1V1g!mn}eRALdrMM;aOs><12T?Sg#3cW$X;ipEueIWTb`EEIf~ z%2HR~oS{`7Yz(UiCfMR4))#fsyBRw?l;Hrvx-P`wkF<=1ya^MX*$_3dYVh$SdAmg- zQz+c3mv{eoJi7W-Ume{4;gUHy9GLv4>_x|e;j$vQm?P3*DCGy{L&RrkJoSp)W&-qW zp_}H`9-r=)*njEnAo?Z>FHD#+8>*Q1iXK&~R^z#BNq0_0qu|{TqB<#F1dqFrso6a` zaj}0wbo|-N3VkC*RWzv#%z;S)p`np?7g*}*TQaoDg3H3ng9$dc*ljtDbZ#aN|HyEJ zd*UBd;`lncke{Re_b(FWA}QHv=#$;7m!16gV+FpGLn1s8=0}ge;B+kBY2=yRVvr3| zv*C|U=uS>?3~q2U_pmFGe6X&drZlV%viToo-FdndfN5bC6V;@_RD$=4_c_> znmiu36mX-dcYJcg{8+mL$BnA}#zs^cP4}qzj2Tu3jIB8Pjv3W9vc^>E>HF04plNmM zm777d{Y=bViuOS!(6~tlgq70B&$9Y7UZSJtm-?t4^_A)}T}?$H#yBg_;~*q~h45}M zRVe&8NOHW{GB+ujZzt}h{=nhPTk|iIAXYlkeSSI3 z=fzrN#VzF#3`kBh~`2Xbq7 z+4e#YF$s#YL*du%Qy_C!g^1KoOY{f zxY-a6MS_WP3KN-H`&IF`3B<(40UPovKM&&-r(@UMSCMU1ESj)E=c?3um&~x26|#5g zqL#Zw*WdU&B{VC1v+xWws#$LFK3PT)qV1#OCT!3-k<8c|AyevsrKwRdOPC}9vR*Kv zv{aeq9bNO3LXxy9?6-0G+d$-hK*tuibaNr{RiWn<2^@+cH-ZyzUZBEJD_6l);s&} z$s+pOIQpxY^`7-lFuN%L={YNO4=&oX^m?E6`%=JN2MOfPQQ7I#R4%BaluzE4EiiCA zcrV)tvqiTinPBo2QqqJ_OpMT>rUb$BHCLg&iHMF;O$-63;*{#@eAEGtgJ?5LXqs6c|8aOoy-= z@OhkHz^m+~p_#r;!J_$5w#!jeIh(VwreXJ&$V4tW*jgy`aHth_=Gmn(yG)LRxWA}_j04|ni*7s44!UZgyQ=K24s=7bu#i3tQNT_`294iFl zjaLo5gk3>Wb#UF8(|0Gk)yDP{qZ*Z7OGbA;8OT=fff%7udv{Hy8P@X7wTh8LsT8YRUG`#ra(N*FdBIh3DL#s z<3yMVv<7K8G=IJA}Qj5cUlHN8hIk$fcfC7Rt6`@fgkD_T&U<18oOJ zh<`E`Bd?>cQJ6D_*?+n6t+O8rcdZg{XVX_L%hn8E$*hx&wVKOZ{MxK4e+X}ald{%AD|3f zK|~?JZYsGAR5UO2V!r%s1F-zKcq8eF<^_BR4`F(@5VrT==`OLkQk&pS` zGJ@QFw->dLT9?h1O<`XG!IDm9xDL9$v|D8i&3|a?MA#+xiC^QrHAI8k!u{xycnTT& zg6opvcP7#T{+E4X`8NiQ5i7;)-;J)3HGGvAm9ljS z_RYPTR*hLETn$3Gt5ac$=X!_ds^hNL*7Oi=XK&R>X6bEYwMyfY_h&%6_geut7B0$&Ed(vS>(-yqqhptMA^+9jYp4}opvvKL`)8Zu<6lXHZ$Tu_nGm( zZJ+`F_g13;wU~k2rXlFTpdSYLYjGJ$P5?nX!RU^gEtI zI^qD+QtB^r&6HqOU#PM^XG8bMrUIAkws^)Q2Jg(QlO>3xZ=p28%nm zBNqw}Mzp7EsoODz1U3bFXxV9PJ-=}kHc&aAxP9>Q>GoE$ozKkJVr-hi2H@$Di+VSeULmE*u{$`AOt=4Mwha2Q%+iV}eN)A3(@?5W(;#W8k-Lx}zpV7nMdk!tYESf2 zf3lm@S_9b_5j=3{{JqJ=JVbsft->G5IJ#W?Kp>-<=E|C0}>+M2|Y43 zs(kldK*@HN03dW$?Yh9FqjwUbbue}l^yu`Ea^#2i0aaD6+XtM6p{INPIWr4 z3~b+BG^%39kc9PD2BsiC<4^g2CfUFHaa2BpZ6$^kiL+DXO#hq#Yt1$I?yH3j@9lbZ zGG?!$Wbf9>?T+dnpv(!6a&)-EJa;58_LZ`cAj_jj&>eXOLu@QaW-)0A&Eo6e5xwMs zp53Xb`)hLr{)@8(y*J0``GHJknQa@~$vlW8f%{L)oQEFIBXPy0A<+bE1S3W2o}1u}A>k3{ zFPC>`cUsD&xpHz{pWL;~((qVnG(D7`JOyWfXm=mr=Fcg$1y#3atl(KOG=-ycM0TG) zSA3URf5t?4CeZYN#Omg<)RSTZY&Zf9zN-}PTLUsB`Ui_Xn68XdP03wLj)ht{w4psy z)N&RzDhUuj+PC+Ql#Wwa2tWT9SNv0*I_lp#F`8>K+piY4R_@(t*77PEUNxj&L?CI} z{^?!PrRUV0<%8ReN(Vj98PeI*x*0U*PjEKi40UjBMJPOp+d0@Sx-k@5Kcoy?uWSneEDQa5etg(&gqhk7J*J=^tb3YnyrOIM?~!Lt zfjqA*$TQCz%GffhWco|#T4Ce2q1|hARm4*;dOaw8eC}6S>d~E6L!VMXqY-Lx7P*L3 zU+NTzh&rFTpqb3=eyoF<($3DWQgY-gZ3hZb9}=HzM3pEyENYZj(3S}M132q8U75?X|3C3w-{7^_e$b=$w|9^c>@dg?FnVT2WXq+jdj5GnU3^cjUK&2W zEpU)8_BiK1Li2aV;-&(laBs2O26W>}hj)35;|pGVLaDR2&9i{Y)#CGs4y7p;$&xW) zb(If|_%hD^U1|TwK(MGVIABXIXJustA76yFo`nY`|CfpW*egkJl5ORGtc+E6?B#9p z>BRS>#HZkc_{yq7d@QpW*}$>Afu^#0Qocw`FXw1)pYDVq+x4AK-x*UEzT8dZ-|^a_ zt^})bx-J+PlMA@{v!j*KBqrJ6T!5Y45e4)|BL4GTuR-Thfab|GfhC*Ob!DyTF}_i& zn4^ZB3Sz+Yq-wkytBt47sN+Woe7);}gY>iM=m*`>S4>Gu+NM~2b`(1O%xFqkN90gq zvs?1Ntz=^I{tMus9feY(SL-QIDqd`{d-1K_ zC3NGbE~G@AhNtzC;8;g+iM6}}Lj=7Zzaxeun?r8!>{2-lF1h1HQAvrhNTC>(@Hgmpq&Gx4RhG_Ux;Jf4ONb{c$ zFYb~J+ZR?O_HXkDSt5f%ZH=huSeH5JwvtP5NMj`+4rg(IdP@#a$zc+@8uts+f1DFL z7~R*~{|Yc=|F7xv_Y~``+UVH{VDiff(;P}7hOHP^TwRs0Ymb)^xn*jvVk=4UQGybs z9D;ECM;oFr$vIdhau#k>@!pd6QBjE1HhZwh*#e!X)^`!W{-evg42}7F2G`elx)3x) zq=~#uIO@B^&zkpS3t-MFHslV(zY7Gz7rxVcn1C=irTMk@qh?>olD?e;dvkD$PLr?U z$l{cwQ9`I-nZa~zD#JM zD3HfeZd-J-C);UBb7SUX9*QW|oLaaSHKjY5T-sUOqQ$idV0PPdQMXoKJ8B7-eDFC=6=9-0{EY?|Ev~qtxEW<^H><0*x2cvg+~vTdL$L&vq|VXpdTOxXYyj(O{nfWlW5 z#4iVKe$BX0UyEhZ9xWGgFmRMC;a6N@hSRn{TF>DltgMw@V2bNlQ?o8J!yWq`9qd)J zJ&`(!V-c|y$8Z9>aTFID3t<{H-kioPi$%t{{ldX7p)NS&9*-)PFM~%r$~PKZax0I6 z4A@2ukOv)dBWV34#K}-$v|pjj4y6!Ht>+>1|3UC>a3e$hm zcB=oQ5v?Vh^aIB2!0dv z>V1P54nB;8L7v(D%U0^2Wy)XFeh=)0>pyhem)!9j4BSJ>lms)J4fS~|XY$`q?g96| zt?!B6{|uiO(`dDuhQp*@aPnN8wYaw}+)FazX|~afP71l@$BK;_p0+r+1kIl`*cB>T zaI72-hNz(10!l;RHV+T%TZDey9c zXu6hbl%GD-Fb;ZS}@>&*gBe*#I$13|Eaa{@ychwmEUCHo1*wu z&v0x)$3N3t*tsmj?J61vlPXT{OSF=K5l6k251x;H2!+FF5U={M>o}xXK>K%Wgf5{VQSa-t*1fi<#e}#N4CY^Lr+XJx$p3?g}U` zDHut*Y&$WGFxu&XY&Cm59ufcX{w`6{pALd8$Bl*$wQT{BH8FsVK zKgh;+JEiZTSbli=8l%`xyGGYmbvwxnVk_0+ArhmCYU|y|5A(zPNPZ+gx<1N4q#O?I z8Tt>n{hhR$nS0Z^7d54dOkNRow+OJO@C@*u_*1Jsz&~Epeymar_^{4tj&*y%BYOOzBPp&wr z%UU-p0{-{^Rs^J~zw5S1e}Ux-{Rg5KlR_rL@a%zIKb~#?rY*Hl$6=m!vN0ZN>gz!@rNPpz4ps`arJ-=Qg8+jS5hbtq zqUfIG5SNKOk%L@YFQm~b5oIa@m7&3T(r5*MZBmV}%BqB!o{r+Iv+7DLl`F0ZwAoe; zEpkl+*_^suh`kUfZT#1HV?EvN#2LXgN+VLXgrz;l$uf(kl}-nV+{XW#hrF^z2TG&0 z&{xDF6N*zDMx>cOX)7cnh5|KFn5AiHAn8I{n@?14AvSyNb+`~% z`{f+a@zSS#`lHzR{QX}f}b0V@*lzHO5vr$umW@@(_OqV2Sz(I<+29C%%) zeP4Z><+D6^A*5!c3!SfU>;et98y5(pYJf~Ji;1?ZpJZ!f@P3J-Z@T^cAYtVZTY zwUnE3>D=bW;UUpugQO%P9)##`eNX5Vtq3}`!EH+V1v$^h%z$Tuf{>_{Oq;Z6++~KR zue-f$CVs0iM4hCqoP_rxXfA|8`JwvN>BjviiK)mm#ez1glrUGB2ZKu#O2u;M8Z@Gt z<`>`Ce|X&dWQGfmXO_+s=F=&C?tN7~9Fvn`CD;TbO_%mLdPhQ_2@*!fb)4R6L9j>j z?xlkbI--KgW9_BEj0?aGqXH?EPUw(uOVIWMYg8Qpqxb{fu)ASoa*qcpr)x@Ys`3$y zrlbT2hi!$YGYFMzJahc46(_Y<)qR-Gfo%@uC< znjc$|@9G)I-Nk=i`^m|4Mf3wV<4W%!q#_LRH;=7-UBmM>mP=RaZjbs3Qum`D09ijw z;0t-(2#^WuRM>fcwY-m<*T}A?1(HQx_K}hk&~zi`{n6L|-tpkp1poIT$(=hI-nfnV6Pp=WY)%k;G&e)E8}-aQdJ$Ae$O#A%w3OC~n8A@l@1GH0 z(ob@Hp*C@-m>8Qgi`bl?5-@IyrqQAhbR&VJgG9Q>#CVCc(=;!prYTQmfVU=V5EbQk zTRqg8nrO;2pnd!0!&?ot>eKbe3=5{^pe4F#p)5b$z+^IM+AEu&Qe0YCs79{$P{mFcFT5Qp&)R8Y$B^82hcAMnC8ak}w^7G^n(kt|aG|mo z9!ke`9%_w6Rqo9AY7avClPKD$;FTXOx1FrR;pVdX5l1=C0Ez-NEP>QfpH*b`5W4f)I$xnYb4=>id zwM4UJVlVWqF|4Q4twXt{=Jk?&hg{TX1=mbKQb@DXiCPsMglse;fajl&0{%e>a8~4O zIN&mn8KD{p@f5xM8NPw*KIkTNoPY7__b$#CnMy>sW@{?Hemb{`Svw}h3_|EL9Z)W5 zk&0y63JR0pnoSrTkMsPqer;{ibD=p(gvl8d89bC?`=bIDJkvw%|f6M@a2vuyY?^ajV-R?}323*)}Q zNUZ!Y_PK)3*fUF_1?iwm*c|y0C4H1%6I+S?H3J-&AQU)%@7CCMo_h<|5szJ`E)L=w z97tP!gY9SB+skU4!^j9F;T3;_&{dU11g4MXY%f4RrlD%z767tsgX^?H`frc~djBjd z_ie<9&5F?#xmlB3wj=1OB~^@Hr4G{9ps-h-)sDMu9bkP6kbde{_$2n2%+n4FZI+m1 z8a^rp+xL*De+I^kenxKAvbl>-VPa#oiLpGmpt>s~3ZR6;7x`XHFv5yEDiAi~k%43bUucyR?DzW`^U1ORfCvnP@ddnrj2 zi!VmsvzjJHw=s7v?Qx9vdw4at##rH=y&_6+Bam>M;rWs2RYTx34OU3n&QXfi3hXl= zBX$#fRX!jH=udTpRTV~3qG53}aKo5$Nf)gO8i`75m{}{H&9#i>SOTg`4mvs)iWFoQ zAsusBl-!|UC}pS1FA!qf8#(w9dOB9J1AWhUmu+%tkK57h?(Eo3v1!6zykU4T8&*-0 z?U5vr;o8mcNKk68+8~R7%K3uQTFObaVAk9z5NTPe8o3OLf*c)O5DS&oy~PmZ;39z0R2*U)k0202 z0NXd7<|m}p#c^fJ;DQ|OkP)g1Xix@5k;|JuGo>jdcyJkVCmtK){`v;q!xIvCpm|vO zy*+h-qj%J{1{pw3=X=@;%GD&)atmx<5s)~6sAB|o#3+xqm|r4P@-k<}J+`Z(Cg_uW z0G>r*V0GDf@wNQ)6;d7-!=^VnG+mg(}aRA*Dqb^S?%6v~?}*sG|nNW((sZ zh$GLhe*}ULE@Oq;!;pVOrQ!=OtQ8c3Q>HXP@X4W^_(N(=Ap0q%raXYq>WfS_z?iZG z#1sLT1sXv>J_hF$wk%QEWylvT-O)ze^ef^ejEg7?CP}a%v8O8ll$knfnDQYGO%|2g z*?2V8^@c-KvgKDMgIurLZh|=nB{@R99lB}`t3r9>*F{-cC1v2Sh@8|WiNM3C91(=l zKu|W?=ujco>}xn13Y0YJ#7ta^ zKNvlZ-sbmN3X&84;ds-=1R&-<(^rt*Am)ITH!ruGcE$ z>06%6Ri9t%-xW(_G1%<3>1`btl~~HXk?NzyG)1 zR`VczME`~Iagh^|Dta40f}tWBt6+*y6voRC9Ld6UE+eN6^YDZD^?R?(G3T5!F=Wz$ zR-QQClknoybcb8gq|jtJaU3{)F-EKuoUy9lrEvz3YLGDfPChMuzWBfWKWs{&6dVa| z<{rh{(Yw(vM?LD?>M9gYS7x#6SzVQ%A%f>IK^6&YCujQ`AABBo`IFUpAy5JsL~0px z=bUg(3Qeh+V<^dl_#3%sRi@LA*bb#E3d42KGff)< zCK{@Z$E0R83wN`RHKoHk6sg~oPHP!xH@2n<7 zFba3Xl@JRdcb+|v@fplNiQK|YAw74ERV zZxrQ(F0RF;eW0N4tReT#;18@v>w5t7`DbuQj+4wm-1UhomhOS0uMyFWK?U!zQt_5a zo-n@#b!{$SnrT6#h+ZI#tvGWikFeccFzx@&@G}fFsyO6gR0vqeih%8i5Ka3E>8!884@t z#9sAWYnb&e#_&j$MGjap6!ylfe?4K@c+~dv9bGg_ekv5ChUOU;C)RW}Fb+%)hkwI& z*69}Aycx}-&_i3zk-Ci}7m^Om;LkA(8<&-3xP77<2k5YnCj;COq?XDVR)59Eq z#_wdtns=}0z2{ZtQI~AnE6Krw3koR&jDom z%Gmkx!`M-XwNbHHC~b0Y0I zIcaEmgnzg}*1b^|Q($t#k2sI86fVRiUitZ+~122z@PL?`Jn&xa~Il@G9Nj zMVrqnHZdJlESsU9UL(LSRJ@vBzxQ83_^Mnu)>t!%d+Y48^{Etoc@Xj*wFvSg z^Bz!KFYdT1-&zEoEX~Tzua@rNZZMx6os07Gyy5dj0 zk&rhmt&1&&_%v7bOOj|k?yR!bxk(Bz__-B(N|`Px75SHNN=7RbmqkJ8+h!p?D5sZE zq}mS-dugqdA82)%Wt47Qijv{bM@4t&4ts^1Zi71#@rbBGNP7ZP{T@|;9D~b3kQuvh zF#$+IfS&~D0ALuCZ48ZluqJUCm+&NRSfV-DXSskXKv~fc(E!?*x;|5sQzbT znZTaJIypw8&7R?ag6!dzZHmHeb_PEx#TV8z)7!xmh!>0EIn-_h!*o+IjYPYpT`q~T zbs8!fa>^F#gKnq7?bRWfCr#i*PemEbKBi*wERdmZ6s$|96hLbwyA476N^J2nDUq93 zwS$A&U9ENcJ}&8_F1L3jk@h3%GLBQ!lL~voq*A9*1@lE_ng*U14MS-&86Y9mDiM*vIBTn$yM@&%)C#TyTyIVtNb`n4^ ziUtK6X;#iK1m^>A$N4!5q{48t=ytlDl7oKHQKr4SwUZ)eEhb!&^gcmg$0mXWGlaCW zN1MAH>mYUj>S9^8ktG${Zn9s4fO`y2Fa;O3xWKy_aly9I6%G|$LzY{J0B%nNcxbF+ zC=Y|QWr(f<%M@r&)@A&RVd+zyu~ycs;h`D8Fa;u3Z;6BXOHG(YBfwIy1La(Q(VY4b;l}9eYd1S3FrZSX^CXYm6CB}_SKCW@d8V^Lpx49a^6O)?1`*} zJ?*MB>LuMDoC`NPcyy_9+A78-BExM_X8L+8iIBlPIm?bF9Td_6cT{P)V{tv@9Er4} z14BJ!fNK|d-LYjiX#gx_5~49OQz&k0$4i4YbiIYf21C^banCCziO#H@n=ETt*O`#) z2pj3iSmjs=p6ba*wGny6bQFv?&?k8l+qhzx@nxCm9hXcuF%6~eNa%}{GEY{+)127i zVi)<7cO0lCvWjmFZYY(Y0+adXL`fbAJ4R7Yw}&!j(ds~irnaHwMhbg20`NXY4DK2t zP38kPHyh|-c$j1sCwwL{9n zLMRSG#+?FLRJkh;!DYV4?TVO(lMy)=H)A*2mDhFmizm|^wx^<`2~516#^DY`lM*>B z?`4`hjBDdK7>n&RouM$zN_Xc@1!*}ul$zMeDr$PWkWS=~lo|jXKqLBM2?;Bq&|8Ya zx?pp%D^e7OgISfIWlFGU1AC2&h2z^!ct8_`y+!cu-B19S-4wpV*BTFxdWXQ#ro7R! z9iXG0YxEAJ*Bh|5sauiu)Y51SPFrWd(@xPmBt{^yNwIYgvJj1{Ii;IB0-aGBQFPFU zhq&SrUNog^ zcI1Y@?9fG%Qq%2HB*_HHoQ=1|6AUvWJ6On70u2+7>?3QycM0!Qw^uaYPED{;GZ#7q z&|ma4-}_*ixqA0(5nLQ>rvK`o-IQlGus|MYP- zMjnaeuwd9yx1_id2td|by%K=PC?!NPmV=a{xT8D9>1dIMxk94(70_57D3q<&tIJPl zr-YI}*>4@535<0XD3glakYwtdKyQ! zDQB@S#0i~%95uf0T&M3`N!ONi*K%Vv4tjk3Fxl>H-{SBPMGvp>K87wfql-o{szse; zP#ns(g$Ehj8Qk4rkl+?za1uOtg1cL=;BLX)WpMWZ!F_-sxO;F376OEK?x}kB{`;!B z*Q#o%-BtZ#ZD(FlzkR1l3Ko<71k#ZmM{t}qg=hR;`jgse4VBJXwi05pyFO8ghLYDS zV)S!v0;dZk^3(E(7u4NZXRKL&h@zBE;(gOdH1G02iFZEvem9DB95>wxRPw;|#QF=* z+m|V+6?3VjCwgddRVrgQI60AZl%QFjxACf1H>{yo0D~ESg&crDv=$OLp5MbMafeNr znA6#&80Wd$!_I(%ZXC%0HqI!dG6F8~!FcCzr94FMT2Xg5=M9LP&PZ>RM@);NSLQ$XdXDL`1$$#T|p+$LW?ZH zg7F1yP>vJ~4O7jPXT7x)*6hq$l?>AZ) z!WT7KTGKQq`O-IaFWo}q%et%qVnaWL6C{2;|;(y$BF2wA+~JlHb6K>sXQR2666P`9H8?Ck(ib8 zhH#j@nT|-;suk-?JDXl_raRv!Ogz1swD+Fh>V5nJci!mxC+5LiY<>~%C0GLX6#k79CX zqy)dP-I0kh77jBuE=9jSE3YiPeE2-R9i)zQXR%=V#auob=+L5F(i)#1iND2bM`^Dn z5sSe93$;7p9$Zx<%asUFEpz{l-5k48uWOcN1r_EP4RdN%lK|iBn#+w&KvG@H)<)UybhlNTnq-$ZUeB5uKPziqBRS8S5T26nJ zv#_GB!*Pv{Xa%L)*!z%9nwZapPZ>ZGVunq^5@erhb$&+{VuNM9@{leDWR9cG*4=f4 zQ(cbAieU*)X+%EiEW~|FqyX-m%xg>B$#GaSxd=QzX;EFYxaKPr2_Za{!VX$_mD%KW zz-xYvQ^(?lP&p2jQKj?snr+h69PAEAa-jQeR{F7!+)^NY#M>B{6R+;&M;k7Bw$t_2 zu`?vkJgZ_)cD3zJ!VxB8c&HolNVDIiKI@>8X@7o#FP&7z<#N3K3x~vsxTjh3{N=~! zr7rwK+ep2W(;w&z_g$iE3dK?#5nsRqZ-Pq8D5o7AE8sNgdkd`Vm2K(*auL|$?Z#$KjWWr`CIud1s8Dq_^E=oRa3Vh8*4@R+H zH}NqO*!w*Wu^)2+vJ@>8MWJLG^Mixr(IuZnd>8 zzO}J|M6)DW_kP*n7B=eVcf?7N0~(wEY2eO1|^^@ttKZqm9Jrex6^wcl`rTBQ>NF zKfLK^BVSfb?sgB0vdNCjL-9oMMpH@Tr$@1+&&5C+d-zXriQnS`#dWGLYyEpcO;7|w zGRbdltxUidqq_WA611&%rMgVhGx(*@pWvwLby9Ysf@Jz;8D&I<09lzno0c5a^pwF$ z)%02uek6kFWq!U-nzo#|$rA}rDfA+T{SJEf;uK(>f$0VB_CGJ)c~O?hE=<6fepAtf9RJeN)k(mPL<`@OKkZPk zw@#tx#aI9F37!NtFLBB*YsgU|*Zvh>gc;6FrDkEpNj?w?%33kk+ZB;O4vk>h^U>v4 zTheU+FFL%n@0rNIxGD-uGQ$x`Zys8h0X(UDDroN&k`3wJqn(q+bN*;sj}Zk2U{W|a z37KcIB&nc>>*z_{0;PSh!cNF6UHJvmC9bcCvTs_kPP>!l@P8K$$hO#=Gj(p!?GlaLpZf_*3?Mu?Uu`aV zt2+qTQe$k$F_JMOCc!-G5S2Ea)ZIEkE53l}jVolk*=B=lqp z??1`Our?Wx_YSJkX8G0G;=R4BXl)>u3A8gF8d9(poI<$B7(W2_+<8|BMJ)XMcYAHE;I656j*eiZ7sJvhG@8H?C5jmhz- z7=!CMtq^+~FZ}U$a-fz6u@MmiI|E47Fkjf~cmi|kRE zlJ9phJij7ceSS;ICwL-E+Hq9DF-sT3jPNEih04GsVb>;o*daVY_NT@!Z$bGE`%uWBcTbBMJ?3&N`9=sZ}gdq-V1 zRw13doz{**?!60wVk@_DRH8dSCbU7E{%JLN7ibn$&@JCUKD#JCNWW~|kes+!#|}f? zbtt#CPfJn5%`9O!pcb-yYa}IG0Ss))-T+#oS+rC$EJiZFUg@Gld*LYJtCk3k$VtaS_*$k4pj`A9jW(vPGt6bW^A>t@O3d57U?__nX=EJi5=%ra;8`Rpp7pbK zmdO@8yLBZM4k32zH-!JRA{}cv5pz3xE=H*@g#Tv1}$f!hq^-q6@ zqG`3jSUV0y=VXu)KvXTyb1rZx=Sg{LQjcZR|5t zs@AEtAoBFeZ}d3U=1pc)XFW9pR!yru`mv+LE)3lhvce*x;umea2BXbcqO#bUqm!Zq<3Dc!a-%k=pj zOTi_VyBng#fbP*J-k_P!Y0DiVX3woV+@$s}3sttewe;nL6i23&_svl|V1YmWjvY+< z<_4~mgN*hRO*U0-@HxNWz}*1eBE-KWf9+pUdmXoOI~#Qr{wf=NlsBrZmUh@G&Rr$j zI$mMy`79WW_?PfC{&is0wSd&WnZ4GB&QBEmZ~SY;e(kH)>*!ya<)z#vNb~iI$je#Z zY9qsp*h_CTudq19^wiv3Fazc$Z6{#!(Il2P&`yKu>1J}IQp$Ho9Mbl-ARxKE`HOa% z%a`RSw>r#`s?p@Qd_hZn3ueYK%-ypYh5dR0(~I-njgWF=nXg+3G^5U#eukTAAJg-b z0zGLN^ya^OVTpxmvA8d*)N==3*4rB;m&{p9jnT zk%vb0{mFV0zM0|Eu_uccw#)9Qk|htan(GO$ii|!Aq>!zhu~6R9CPcPz%bHV8z(Aj6 zNV)7Zd9=}wDJLh>6ARTn6SUrWP^)JfzD6hi%I-gz=T&zaJCtuTmEGbGLq$dv3s*0X zVe}cE>79Rl6*RG`{gM^N05Viq@moA5^-A>9}%qUuy#UbRjIRzLSPA`F--{UIX;q4F&!Kst>And9Vs zCPlRo|Ad^kPw)z*29c-6*2r&;p}BMRNB+%&}XDx%wO_{<8Wew>*`5~Jw zBP5Gmgj#jJ+cF}pLiHy*e%wDXUB1*;VA;e~&q{I%>C_;(KNoXsdAbDv%F5yOLNJp# z_fvmlqQ7)Mee_fur956EuLe&x{}o+F8C2Fy)`Bc8xy>BIDA;48kCylhR+MXk-a4h_G?i3W;E$`RGw@`CgdWXU)%6 zSU?#8Pe{i-`u>o?%-?Zd3g^(AyL8&0UJhMf9i0^c1)zsziC_3zFVz>Ts64alGnPBQ zrGRXAo}DvMsgUW+s2yuKGvJf!DjrgbsxS$?s*xjgy>?9XIPkzp2lc5pClhN%SZV zg<9ILX(0o_H3?DSoR<5FnUz2jXrzvY!i~%MR~>mFZGPq%d zPJfcq6&Ih6$xNlGt9|>ALJTyIJx-;o?ODPDHaoZvZhxC2tb3&)(^zA50W(qY>VzC=kQG;j?2V za{u%3fH5UH#m1xof&K30B3?g^oAm6-pOb1Z37HF)?VBx9VQ4b8vYOgiq`S-vzZL)$ z#A0_LRB#o6VrwrK@{JB>fP$fmw1R24_m;VVHfikmAp%qI0{XkC_JPpnkK^_9Pi~sc!-Pjh4P2 z+p-5-{MsFRF;;N+!PX|$Alo%=NraK}QtC1w<7TA{h9FUP&}(7MH_jB)p=OocEu z?xSY0ectJEpV0HdDjJ!zrXJfjVKo`=QEW>0LcKk`kFid4ypOwn*fBVKM1 zjp3h^rXqQpe7uT`QxuCx9}H&JF>(6*`SCXpIeaJzxIK_Y;Y}^>bA33NK@*4&B#jsh z3`Ro%B9S1{X+IQ(U2eYO(#bH^u)@u@hhhkM-qLq7BFiyafV9VLjz}~0G#gx9uCK}n z6d4%lndz7qpoOKy>F@Tu9h)q2AorR$#WL8wEu)^FNn2c0Iul3qbjF+ai*UQ{{+Jof zD6)tOXVv0}tU7k_x=c+>yOG_%%6h}HkmsmcEpovq9E^}pj7q7I2?ZZ4zLRoB*({{`;FM^#|4Cix)b zjr*SGn9pJ&nMezroXnYebf<#e`Er9FS~WC6Mr zw1%?5Yq1=qVa__DmMLJl8mI4m$kpKP;^umD_3IiF4Ff$kDkfS*QCVqnY+{^)m7T3x zIt)EoQ%7rQc7ARVzVJgxniS2_NU<#5^P=wID+u<<%G7c%NH#(EFidMY1RRqhFd5s# z=fKzzY_{$OwwsEYad z9v6I@H_mZKe>}SNY|zXscd}U$d z$J&yVi{I7s?A6#2sinV}o1L$fm(!PE2+Vw{^}X)a1B5xb(t|l?k|d_g4HzA+ydQ9l4I1@c(VcKT62{EgndFDb_pr9K}i`tbn)>IR%c9Cv~&yC zEL*hk^bLhuwCOo|MgBODFXGjs%$H_NV$&wi>$mvtZTau9$Lpf59%J9*IS6EN=??Y7 z$3+-pmCGiF7hn?p?lsVijP}I(g6|prVkiWN1pAY2JzBrFsi&rI=~`dwe=wl6@D|1- z8+idL(xT1NZD(oV(*kke>ytofVOVPV4p7VZBjmU|h)bkWgDX{gMD1C|smJVmuiI16 z{o_6{n!eK#^8pgq@P|ohv^WEa4YW>ACy9_*uM}yxShQ50!HWljnde1BG*BvLdV_5H zMD`pn-FYB>FVxT4#d<$1&x>DiyrgN#oZIH8p8LISVaQhBWPf4)TRZK?*_2=hq|0rP z9drN>fodjl5x(?RawAs29b0^UOlk9c-wo%D$n6`OGj{wZES`4;C4S!Tf@m&Df4?*> zlOlYh-|9~2nLcaoaYv>EUGi-R8@ApwB^WjqKN($~fG)UiYfN|$Effq)Qs}RJOy-!o zSHwbCtqtmTJQYDbvUBt-vOf!-ZH_5DMHOf-*8Q@|_XalucR~5?>6jDV#r z1IK99ppy%(!oZ(cl|wV7?7-;A!#9uPr3=H8L8CL5{S?>O8X5*Jii;K0h+_YzG&ov= zWE9!TQZ@g&%oA&OItHN;PITC)Tp6N5!dVc2A@}_>s0w$q9f3oM97MU-9G(K4w7<>^ zGCbE;S8lr+kQZjWBma+SdE~nGvIFt&Q;Igl zw!VWVVQYrZ!2@rHn5!iASz`aQq_3NN>Z4AVqO929Q2=hXb`LC6?h}iP&z&V8>IdO- z#?f!6S&i-QN1kU%{EGmi-uR1~%S#GeIMTpSdfy#dLI_{^!U|Jp_X;4=^5Pk{f9ZeaWm$^XSP!L~KP|GT%X zA^r~$7*kz&mH%|h)jzqD;yAxzVp31n)?FVV%#4tV-ffGN>5=-g4t#2%7DwmfZ|;Zy z#*Loo(|@};!`SSb(S5%tFl;Y7t=R72*_n7y6&rNxI>9n-_)A|SRZyiVSyKLL0GwC) z@a6sUY2tK$=GOp?C#`MePP$@7ntt%?8ZHf!Sm}2tR`zC^Y!@bPIX>*eXto; zJzY~_@OE69;PcSaipTwV+}Zc%8Z!?;eR3IrepgGvXwH4K6= zTU=0)0OD@DlRs44HejF(>@WYju0pwe6i_=Uj*c#RB|NsC0{A3Zw znqAD?E+_KJQ+?$@nG%7>o)~H(iGmPHg@PjsA~T$e#F9mqP$5Go6K8Xsyya)T4d!lT zX{(_llUu5WOq%E$@tT-v*57%YvtHRdG;|1h#3)CQGUtm)OXsp5p4IW)yl9}rZHoYh;=+XD-$r9;E!Z)Y-WG4nx(hM?#OY(S7U3DGY1 zQb_YL(wiIZrRi56yUPe;9AN^9zL>HM=mVKNFfnp+2Ar6gmN-!yl7BKM*4P3S=gzk& zW;2Os_;jAQug=Tdn$h2Vw)hS2dp5PD zo$kja-3>?Q{<|CD$`!k^3XEM3Q8j9v7rs87)UWCp*~?@v9RNYJL43d*F{MD@C-wj7 zwEmxwWSJFmoH#JHBgGEmShBzY18o#srUTXyHq8~y0#`>B75x>>zN-iZz-@&a$3{1x zOa)njxM7QcGGq!46mS9#+&MO>X{Kpo>8`HKmUoS*)pcF#s_$C+y4k$z>&8(|tL`ev zwz{jVC_dybKc2_mlVzHjkSX!tQY_a;%KqfcBBNl5pZCAE>fb9}0ab}gDsG(anVnf+ zzxT;&>RIgFXX2APbmk!BEOd}MNjw1S>{JZnSUEY2z04DN^2E85eKJp;b57=%%rmBP zn3`ItSb5R26LRYLnSHwy;ja)`^h-YbWqn_WQWx7<1W`&UAs^%r@*#^1iU@jH$U-kf z=-XL?IP0@5vQdQS%0d=OolUkg_8|A}w?jM>5~R%Q#7u4C`$Wj(-4}6ovr2K0yU41;7#b$akg6&bxn-BwHv&RO<^JLAtk z6cAEQyCtOzSZMPk&LO0G zPZ&K4F4hj*=SuoX)%+eXzyNt7W(LRvL5dV5QX*FVrW5i1zvIT^?*0^u`s&iTy|7*< z>2hhi=nlUA*XMe=Z&mfM7Ga}MjuVX$D1+8ti8D!f>&w))rdR?V7`of9bxLm7kDhl2 z{DreKe+x{Kwm>@@whRcIn^NUYbB2UVUj5=)Ch1|}@2#FN=w<;W2BwmB``?_FAe@h2*(|9Q&V63&;fkSqdzK3jx`YANYhl`$3iyb#2-<+LA6tD}X1*u1X7Z4O7-5CJod!R0X7gFVztB^!qrXzLE zxpmXI=vFinRd5LTp02Lye*gb|L<5aQ5IGd6 zK!K8mqBfAAC?>7k|2LolFkBZ!$w6KRIcLr|iNFL3)Yu?MSr~E03`%K34BX9h6y*?4 zbM(Ub3XcTy62P&G|-5ZYFWxf12V)>c1x7CNp{LMgtCjm)nHgSk?8Z3qog-J zH8%Rqa38HQrHVhvo+tK`^}l=Zk}M5F>EhQS4u-f=3{`^arafGXPa&k%Nr%lOnTC~x zp>)4rwKk`iDVHwr1a6;PS zLcDlum*PhWC5VWKNRSYMNN@bkSqNY}reZ`|Uk*DDI^#4sZ0(8d2wW3aBSi`MSWzO9 z&EIB?GVD%0s>T8UqF}$<9vKk??_J7_0Cr-b)!l}Ir4TrM*;7v{E&xQVZo8&80Z!x%mdJzz{SuW0LWG}zU$!LT5D+Ua>T7LP zV*^%u=0DB0n-1L%XZS+wZmgeCPOEtU5f0KxYV}DWUjJ|FWfIOK$b1~-iN$0_zcoPK4^z~HjZru>tiXVu?aTKme>l*voqO6>Pro$oYax2LcEKDwSb% z_5sK)(}cf`WhMJek){FwkSDp_f|N8&$|9~S$h8Px1D3HN`#8;5G07 z_^iJ^xA%74okqP@t&~f}?XAs? zf@51|-q3S=eQkARd1-NBer|ShVtj0LBr~X~0}c=S-Db$a_s$xv9HDmZ&N@U~9I_u;`JSs`)rnpJJmWw@q z8jrr>?y~tvpWnk0o;$Wff|lFD0j1PLB9OF}sIB#^4yG%X?nw*=3~u)i!#WWI!MFPe z_CylUSxQ$oh$||9f}#)l&|4L!nQu zYe#^x0hYecvq-?&aiO?6S+Z(3mn#+8mLF6dVk=bpjWM2jht*Z78qE)B>3wYiJ_C|< zL#0em-+scy(O;|ZDrSM$E^-X~OlCoj*Bb z(W*JzJmy5Sw*kkym>5^bR6;rg*#pvz*h6po^>uqm6)&4_F#SKqizGixi;G|js!g%B z0oC|d+vyF^?_>|m4ai6ZZh$;HH?N_2`e+^(qSXEIUJG-6h%{z)75IAY;Ybe zK-3w4uQ&6n4Vf|^SSq>n?o1}v~3ktvbmNo z-6MfKrjvJ-j)vr;ni<14MF{p$-HZtm!{s&(l$Am_VhYa@!0;l+0EDkVPF}Y18*fuQ zSJ_;6u{%V)ot6O8w*`po5s^rtJArgRM=+h&k z9~i|c*r^}Vm0c(KZg#H)gpXl76(ypxHzj)O!98L_l%$s-5wQc(0o zWI`!9I8QFMircWP1(~?(oxu`OY;EO06z4L20Q{yNfL-q=H&YqLB%JCxlbjSsl?M@=pT!)L+ zR{RWy=9LrYqHEE)U7~%*CPBQ?@xA7Z7CcW4jR3JCuHgV33glrWw2HbkFljV*4Dx`x z_C6;#Y&&MF6j)>@(FjP~T=LDnzEnFj-e zO%$%#rcTW)le17DR+sF46eZnfBmq!Znc6e6MF??V>9*XP24orOmHTt*gxv!A(ZrSt zmSx^}KqQa(Y56dMVLK8bFC8_Z0eOvg!$g8TD#UXs z#APRnQspiZVvaPQPF_#S&O@(dTA#Wketbq$>ZRAHu<%JsxGGQWlhCOVPI{{sEzQDbQ(WTM65yoj%j-Llc!F!73a3`C`$DIp7zVLLOlY zNNOTfSFQ!eC9J}8TJXVwS7w>ep{sO6%c|{4R<5OM(!7fO*h1qW&31S+;Hj+f+#z?t ztyS%}e{uf=2`dxZg~YUITQQnrlD^oOcDmhoRkx%p2+aj=s~|GIN~WcbPDARn>FCm6 z40F>0%e18_`2PB;2}u|dW-AlU6bkB+-S0L7DdGxc$P?-;gDvZM7qcZ!98+ZS=y^fv z)DVUHCQT7E?PYW{DL+$;FRfr|R5!Yj`YsRKyP6SLQQ^JOnE1|1I7j7Vg4ifvk*|qw zo%oLKn4feE@*wO9MpN7f2M4=K1wqxk+b565y@#L^k(b?xuhPICHxlL7o%^!7HsIkl z^*xRp<^CfUSCP_0*BeA0x2YC5?crd*y{9MqNH&_jmmpibObb&q=ES9j2YVD$bC$?5 zA(Im19ZoToNWqSUZLr+&`|d-$v}p+v<&y*f+XgiZ%YxwPKNs_Yax$7+?w`dZFsd^< zynpV*4PNlU3*UVAT~yL-YdmiqiX!s?>(YXI1z+OWpz@8R_4#avdz?+Tso#`8cr9P1 z2a0upFVax#7OdzQVW3=iO$A6*Cs5v951niT4U7VYHF}x>KZdY_6P%NDAx^KOWXDKZ zW3Rx(4_2z(XAJcNfun1nd|1}D>m4u!48DEg3Rhgu$0REyUcm^jrV{4EDpq3#qe0u* zR-4MG({?b4L0HrXh)5p-&+L@akzFw0sZ~bZ-$L4GJ9~$PYXn04m14Ui%r^lnjmJWF z7#Ak(6N$Y=a2Xd18?iws&ib^wK{9nda<8NHr*2}E=h&|IN(yLiV;@_N zjhGPBU)eya8a>vmxg`O7y6D&+6~Rlw-7h!ml6n?RY#@m^G>CW(3^ym^t!Z2LH;kMB7Semi6VAtr*dt8Io)t~EN!6>`CxjXKRChg%U91o*2 z7}bFyVbqw_rD7^rANC;OGrcyd>>c#s3H|l(08dx-MSOJ%yzdl*WoI;_jl8tz^u^x3 zkqIfADR3nCm{<}VQvXF5T%>Np_e_#ANe9+Y7W{{0Gl{sxYnYCg%})GWYB7Mr_R+B0 zGHJCon(v7 z2eqDQoL~k$nIt)H2ExT=n&W;;qG06#MIMf>2pGoV{uA8Cw3ms)FgXL#ExvqWFD@D+ zKwZLNH}6zSPI@2N^8pD+Z6pJes>i=6?>X46H(JuVt%1YR9Vku%bjImQK7qVnw8 z=d{qBl@wn!g?ucmIar5Y&A3JpJ2q$ReFBpKUTX%W&(k{EWXE<4H+ge}fuyk^iu zHtOPWN4*D(H&jK)`$h?9e*X}gvk)b8xe6}m-+r@Cs$=D;tjYCRhs249!BV`{X7liO z<1wXKX;-Ad5^GPSc?!lw48~&m5~W4S1iafGry_T@&H-gIRSz?}>Atx-gXWo+y)?Z| z$K9M%4Af>x_bxH2Z1?B%yj1kIZc{^?FX?~;lT|oM%sVGEwOPwA7~>E=?DK=-3{biY zZWs&^JtVB_S@w>l&QRO?CrpFpK_k!p+Y2OP0A_zwT$miEMOFB+VUV5xOS21JvDlcc z+$mrn83AM6J!?aHo_%@ugABo)4~1GwolW^BEl%$5S0*<-fLKP}0lb7jRV0v%3@5v0 zgLEeVBi^Y4tD?SB%QaeD> z?=ezw8r61eQ7+P`NR9CSuT&6m&p-yTHU6Us-iv}YuNzNypa%5DI1!b5R)*fKQ$mi@ zwXS%XN9B8AKkNhOu$@-Q7ORl|qYTvCtBwC-fn(j@yK{E+VyI`kr1pL}Ne5PAG_4R2 zw$>Z$vCIH_WpgHGjNTO!t^n0-HG4H|vrZp`XFI&@vNN-tUuef6cS^DsR|OvzJD%j) zLL$f1BiLO4O~SBM5d<1BGbbtPN-3Zq26szt_$`3P{7VDT=8!8GsU=)(a*13wz=QcE zWm)9X??d*FXcT}BLic0eNuXC)r-%7J9=lC)fRg~~jvFZ8C;MOft zQBC^mKRN_JHS%J@CXj2ZtPE6%Kd=Q>-!*N@i zk|)K__Sk7r-F%Q58T=?*=|>Z)=czFDOA*z`^Ls^l$<=ah_yUYK0RfUUS*Kb+HL77t z5>XLf32?(jhA(xO^t39SuU$ zpID*6vT1bS7YnYM?zPb*OM5&NkghRSWC=;A;ow1^hh8hJRASBMky{f_qMqq$5Rf1{ zy4%=t|GiEF3?L{19v7~mOMddPUsm-Nm$ZL^fR8 zw$E3X(W$JYVP>?gt3bg2Y}AiK8NPeDyB!;8d%_E8D4BJ09ay864J?_S`%aR>?b!Hc zKT;q)$ut#&v6{90iT?coaP7X+7GUV~piCydOxOhEeEa zW{1%4w8K}VkYR0Rx2I;-@Af1cT;{pQ;17Ik%pg8?*o>~XkilwyLIcZ|0?gQ5Nzd4^ zq*Ix%_xhWD0Qu(lowhw1_=>`+7`9;w>}WNsdc+NT9&ZZ&0&-ysC7tTJ7mfgoRtf=O3;?#QFW~$x_d4e!5+a)z!~~92!(3MyZb$GRju! z2X*8qf=`8bzKDYd5E)8oj65N=r3(k$pX}`x4>QW;9)ro_$+~YB;1mVBCWaZqH>{A2#;N2o0q#P`c7&!Nmt#+o036Zuh&1>gW+$||@?R>>ZCtOM@cuigljTyM4w-RKnZ&ci1N zh5%2t)o+%)QoJVN*00Eg?*02WwtQJm?)k9+YPmxGHy|moYfg%mmHs|^jrM3&RJj=-d&lAQi`?oOEMri(rB1>)d@GU?30D1Egv0|P5C zR{{8{3f@0K|7=p8YJ)OMPsJjbj~h`5Df~@CuGnLpw2O+>xBo;@X{Sn|=cQ52?U42> z>U{LmDj7X)F15dxE5B3l@DHUI?)p2wS86V7b%Wgq+=dv4T3O=*H43DB#}Y{6 zQj&{cDKGc}F(f6QET8BYj&0OwU+t)-{(E4K9A$5f$GL_wN5i@SG@}6|d-DAgS^5m%P@Y|2n z!8}f=uMEa8&+4F613qo{S2R66S4L-qJ0Xlx5CM&`y8@|f$O}%Ec@nt!?67qJfFf-~ zZvdY{)=JGf!tQ$VQy<99mZ&8j3#E^2ahKrd^jeTNZaI-8HgH3aX5iF|8`*&R+lGZ; z&)GA->OGsvT>c@BgiF^hFVDgGmWUQ^3gC~}yBvjh!{f0g)8zh^Ss%9_*$DQ8`B@; z**Uhm&#NMjbsxgO;K|2vw7b>idCQY8i% zhqq6d&Xb_Kb1x@xN3F=GQAnwm!npj}jG|cAgvg^!{b)ke&}JT--jatBC)lE1#1!u_ z*@40WBw6yAVyd$q(Nauz6osg|Rww;SVVD9nm%~tH`C;`iXI>={F}%nG;>IkFoiHdh z>2a)z9^pZ(f5k_U*IEe}UksQ2SYZ!7S zc=xfmTh2zwAc(gI)0>s#VDetdg8+?|cScB-Ajol1l#tues~;luSAMBCYA%8!s`(Kv zOvDcvE>T7xv42l|)R^x5Nyi{zzcP_aUD>X0mSsN^`3&eNh@^Z>d| zR*yd$!T~!4SiJyMKwPKKqxG2^&J@9QA&MeK4t7gdMz!L% z)T9l2%r12=F=DQw$0?^^b>Y`?cN#EIsK}qKlp@$Q{^8#2nokSUPlv9OuJDHi!2k6_ z8c`^OzSfE`qR@!q6_5L4CtVGb*Pp(Q{A_KWy;$26>0IKqAsSJ#7HmX~!2ljCy4$_+ z6TH0iv_serRTkR(<->)ql_mp|H9#1qp-wUY@A07ww zwF4!E^jJRg061GLNK}9e|M~(=L1mNrv6v_E+A8r{S+&tdPvm}lE^P2Rrb4}C0liK` z()B57zv}AZliw0t)e?6E_9cibUvEI55y*5yY*6Fs%Hg8d&SqT9_pH~ff#0(G$E4>I&*P0d z1Jgw*sf<3h3QcqlZgY}4UbrUPa+=If{EoeChoD`L?;AE5)*Hryp&S~`HIqEMiOy3D z?vWW7*5rv^bl1tq@BAxoC0}rpU;$-%93}cLS>IBdqm|d^HszMXhItNFM;8B`?_j1E z)1JdEja_JxAG}4>`NZk{YR?Zfl8;g&c1?_|+;09)8~A|;E(QnEMR_F$l2qkdmQLD~ zex239+{lBzju5+q=Q?-k0MK3U->?v)IBDLEcUyk8{12h;wUwyG1F4$U%(4USJ4t$o zvSer~foL&WI3uqxNsZ6Q`|3bcEs3D4VWvfq*;pbsQJZ$-Sz}e(h6FX&M1{BV=3Wy; zFEuw$NH<4jom~FAaRy{~OO4c{&`e2gNfuX^&dkqcWvkmb-MFbrYt|R%H%6-|Hx?9G zj8V>Sq7Q4!wCfCI22E||^hG8EjJ?CVl304=w+KChijS_{)P{b&>YU8^Zh1 z{Y!ahv{O$<^$eEVL0Ks7b)-vT)1+}2Au)BsMYn$1>p|L$zazCFm5X7b61E6S&dtqX z@OwF})}q(xD+*cW1LruK_g`T=#ci~B@3Oj0T_ekbxUe6O{5M0-vKfSdX6-DMBno41 z{GUfepH4pAHp+eeKW30)jR&b6_u`QisQYM^^FPniGS>bbcl!r5X{1a;dUi@CZo_e-+;P5w_D6s|?Vp?&vDX?E+w}$hfsbwRSXj$mr(ic5 zXXAXr1mCW`bnwBRAVm(ByXvSHnmll%NUJb2FC%un4OhHBU8PiTSX_$~Eg8Jh*0q&C zt21SMv;J$d%%DEbYbN( z`6bYuB+j1iyV<1P3wpAS#gD4%K>$-qR;A6oa1`Uwe=cfKY6=%h}bu}|3*Py z6DHC<29UBFoL&9ip)yHM6EQpcle6djglro|e&GY3(zaZ+rNhT;YPZNOZlOJ?-pMmQ zJp1`e#(V~ER0jFQM>a~giWgW*?1z!@ZGMqvc8OlSzQT!e@Fnek*#^Vrp9HD^J3#vg zEy^Es`Nzu* zSS*7CZ5%Y);y2*aXzDM4BU9s+j)Feo7eLEPz2m#`mn1r8ZuIpp(jLQrC2aTxzTaH+ zT^R7wu(CGVjljyKi0xm+PZ?4@99g;H)$Ok=%~8;9rq)g2VM+9zd>En0Ap)kDCqpJr z?f#gU!jp~s9U1v}sEO&?cn4~L_^(PHB0&6Y3*w8`59rJ;H@f^iI!91q*`v*d>A)#?`kaK%Ysw2`M^$2Eu@hF<^;+|sr_;EevrGLmF zjGg;I;Dh+#{2}e6Y@lCvk6=H56o{4$(K<}=Q1UWr?VF(Eiq@P=`EWvH-P*VEWs1o96gnv9 zrI8PM{ZF)D+21^WF0Pjbd8;hsm`@Z){a^QMz|=o5@6HoYE+pf41oNuR3-JHM6S>oO zGU6Ep#JEI>HeQ7?%my8~n?7dE^%M_3^jXL`Ni|fbo`5Sx6l?-3lUxp3EQBPaD3pr< zja>$1&(SuTiT9^y04dP+AcuB55E2id0HfBr<}Y%M0qPtcrJ3Hb-yv3jd4Y2Ye5QWw_;AO-drwlR(+dcmLD zz9e|1Tn*TR1BmdTtp}WySE7+Kk zu03j@$sBnV`vwTJNwN5TzIEUWHUKGtMqTS?njY+3mZbB0m;{6uDmhK|4bYLy4r3v^ zJv&3CHT4(&{@ap|LHFYaE<5iaXCBA`I3sM!98_J@)>E(X*%EV?;JCEiYKn8cw2ell zbdYb$V3l7K?S3^DoXreRIpj~wUhqWHBXgFnx(_3dJlDY!HRvD7CT&TOH2iM%7VxU6 zi0x<18{R8IuK3a~nXtXYcpU-EirPV|Bi7_nTN(S=#AXy&6gd>GJJ&ckxr8Zg3^n`) z*kR%dJYq>*Ag&1_W-b`k9h+Ml-$uJv(5ljnitT+TXe4nl%+b7YpqSWH!trsTgnzpu z_l2XGs%#4bPx*H`3kCV4S3fRfkefTq54?WloJmTkCEJyJ+hTo%|Eqhbvy(9FsgJ7u zK!|^hIlGRTjXD06{Jzu^g_ug_@qW`2rY9f(gn8=#W|3F}=)!rwf=y+1JZ$pfw(oE354Fl1!dX?p1TLO>Bn6g^dKs!!Bmh3z_&=vL|!-L)q{|HT4Ou#1w0z)?jVh& zfJ_y&ZT=puzLgDC-srLwgniJ;Jq6o7>;tp|Zlw@=Elmv}#pM%fjiG9IC$&7bncfgm zV%nk6431f7MyVx9R3@)X9iY~Ym+0(JMB>yMyU-#L|yg%*3h~r>3`-45)m~? zmXVYs6D1{xBq_+QlY>{OZWl(DP6OUuKV9~?b-8dE@aK(w+Y4zvhFZz<;Dl!;g!42f zL(!OtUt=7`d@Fu8&}LF_UlTooi#G|d8eUf9LfYms+e~_cEV(&%Jo~U^dM4B4g9v+> zt~OwUxnE9LLu)Uf*TO7hmDrLvl#(b@6h!TidVcKD)@F&sIdVQPM=lm=r4O}MH4;gV zBE6eLs>zCow_dvZ*FqcX+F@1N{vh_N2>Qs)!>g_Jt&91pLS60muJH+sH{VWJ=3e|T zhBz~4d2MDAuD&=sXL)59F+EmNLhrq~xP-Q-m~Q*F0$RH56D4$8x6-kap2tKIgq5@` zb8~A&%_igta#IKAXc#%s08SUqy2lQOYX^#Rl7^apv5CTBlQWV7Wls4{Oun#t`$?9! znYT7*q2}K;w!z7aCP{b$#dHm_&=kP&OP_Vn+L9e&n3wGHR=;rI}j2~q?;`}e$*o+J+ zH6xQm5l9je%-Y~%U#W&Xzdn_CTG<{SJ*dC&r{-2Z8Oa#guq38bqZ+K#PhXI)87hdV z#D_?!%G|v12rV8be<$LbR8Uu4P;RlRVL86NJB<6BZ}xPPRtz%c6_AV;#$KUr1UKU3G* zJ62gdGCN*lN|00Zdz$PG(5w;R&d1Cdep)|G`1;Om@bm2cpJjNPduu|rkfLyLeQIyi z@3V`Ud;pCR5NPW!xeisQYZ#AzO|W@iq(o0oWX6zl^Kwh|rN$C{uBKdHXfzixfIuM7 z&8PYez{&5h-uEb)yEJC}y*xb*_JFL+Z>lDmzpqjm}9Da1-}h zy@Fghh@E+LTf!Ii+BXvGp1$RLG$YJR72?t1=XiK|Obe@^TGBLNEg;iHG2}wF_Td62 zI^(wPmmpx$d1VKlRNZ9PfKSIx=w~$vHnBELjeV#^yz#|5(f6-TYSK6V*S7_{m|)2z z&c@WdAf@}O;T;iTz`N#btw~5O;S6lj)5xLJA&0{^RB;X2>G+#dkJ^pxq}qaRvhe+E zXZUgai5wRPT)>+@#K60!MUAYi4(*J?fi+*Jn6I}eKisIPO})0-_i&oc_M&*>wfDx^ z#ey7OMdP~}^YlU8L4IT72|Ye~jQ?|sRGC7lQYKMmr}5;fyxp^f@vS^o%omUt8{T3< zrCH`(SjAr#vj-XOmUO4!!tN9KjAi`Mn{>_t4g$EUl^ z)No`?6zKg>erT^xJB_=u_6!<84)_pW=3BQn*@WF>-vl-nUI+qE>+Yx?kxv$R$P z{PHB@>GlFxK2Sbejw^3IYJNQ^zid44df~NVLG$QrCe(E$wdk}c6Pbm!iqNU-ie@0G#@_p8QK8U;mXq z#OsJK+m}?eJKu_{V_I_u3L%LO7*rjd|1v7ydwWTZ3eR7S4v-PF(OsIJx7NNmw^y0H z@zI)U>YbMz@`pfo*vlF%-Jcg`QJTV`;hreub`0E0=351;K6T3Q!>t{AO~hpR17`OgGwaMV7;24amp1k_A+HT7 zAq{IWzSsVWb(@oVeTnPMU7b!c=#Gp~V{9(tVC=yh#&|QL&vJEH83@AqGZMsPuB(2{ z=yM;c(B^~ftBOKVDawly;>|s``g4^5JeT3RdvyZ;ex{GSV~IgmK*^V?X?|>o%SW5D zF}Dn&w{G}sNDgisO7yE4!i3aq!oK&Z!;A<2HLfB``}n{xRNJ%(<;)c~=Q3~U@#7R= zBIh>08CV6+0wbxu1&1h`Lgs={ij@)$3kCLFyF^(PvB2l}d>tgjvToz$R|nKxsY$VO zd_D=Ac{6GPHb3tSk-|a@pZ!&E4~O8P(t}=ywiuXi^>JRehm%31+EvFJ5JB5FsVRk7 z66nF*B~pqaP*KhOJUkF;BOFst70aXlcEV(u9Q)elRTOWzhPZEhB>mA@_i z?320`yOn>`)t?=D?U;K6<*2*|GjHz)IckT=+_>pF}2`hQYWsFCZGc{s(Th(n;`!F}U5rB#{NAoL~bt%xVU520~u zFB{+H-P5DK;R?C|rEYCm)#=-T3iN3Ss$I3J-WFW93M8p-8RSX>J7Ye@pG8(wbv=I8 z@(k$P(p34W=bJElCs`F8Gb;TFodFukZ;k8PY_R#C-7vG-gHYg8$#s z8{E;ai%|!g=OFm(tU9}K%50M!3yE|T3*=&7La(1L9L>t8jb{X&dV1h^^Rio>PzrM{)RCkw_-f-271lB?re0hO889^s^AQ zMU0mNL2J2J!rOD7Bl0m8YIsW6v#zz|rJ~#FU*x}h*FC#Y+8@G<$e@2ybjbcILj1{p zgx>#j_HEz0Pumkt{CT)YoNeVj4qDiqfUb~?zJN(i5s#TWpEEoKj#x4O@-~Pgv%|{QGvb=}#LH~qp5!d`QULwy z!qbj?gqqjQLVldv;NwzmS`cYF`A zLEg?yglAm?aDE;T4Q6HjAkOex+NcCUS-0j1zB@(Mh z@5(9G84y&&Kw~H&m(EyPAZg&O*d$Hf`V2TlTTd$u?CrlwjGQS&$o;z^BW?Vf{JH)f zagqN@L(sW&c;Ml#qipOpNw6`pO4q17bgAg0g^Nj?z&6W>IA&RJN-UlzuEK!ZX#2l! z>iw`xQ#BMG36Gohrt`7)FSdnMi*jUo`FP8Q4tyYb8}!$98Av>G!!Ns!=?PJPReMI& zk8ay_4?I4IW6#j)0*9Vj;J!f{sZu zYs3GalFR7U&xkD^V5spo2I!-y{IuTGG}&lIN2<(Lg3m?|Qasbm4G09frN05i{vxad z=H?X*AR9rAgMLQ#Dt2EN>qnv=heM7V04bavATA)CmhQP~S9}KI9B&DU*GT*hm6%u8 z;ra+~syMnAb0ij=*h@QFnu@Ej27c0U;9hlW+NMyc;0BNmq9{})?wXVei@yjIj%B>u zK9s-bnXv}nVBucvsXBTMP3)ALv1-X|KE7g&(Crs(D1>>`D?K|l4G5G!2INgdPvjOH z-gn%0P$aYJ-oDH^@A7J_!}8*f5=H3`zru(&mrEs*YGFN@X?)UJYaFJLDx~vUt$J|A zRo`!61jneazK+p7e^=XGmo+jPv64Gd*VsLG*U`MY7x99g%sZ@vD>jj;B;Yx^sr|We z8RLv@CoQk)$>kVlO8G9FTGpt+9>vZ6olFNQmKzf}jLR!-fE6??-|r5)c5x$-BfWcQ87H<2H2QuF&SS_o%!&@^@4M>W2a6+>p7t$JbOnB))w|_bp>`s=2-| zepa~UTDBV5?|_N1jF-FIu=zDM&{}*=Lg7va9Kh&-6k5Xso0bs*Ozj%IG6q$ zRvgobz}EL@UKEC+t0}gm7q}pisoSxtti!_Ll3~Vg=1&r`W62}ZY3ab8f>fO@`Uh5N z3!9Nr{DE2i=lW+|3YH^kN!VY#^D?~Q^5=%LYpw4Y*!)iqM_N*Azl&TnegPoCV}bSZ z{BogCTcouJB&yj4IRH68#=lVi_unzn>FultwiURRuQOVbhAMMZ_`*Fbg(q96Gtr2dz*BQrKO9od4+ zN6fT_&PsQq6zDDVcG~V)Xlv+9*1-<}Ms$pDEWKFW;?h7`fqTEV-=1Y|>9!1VtM~50 zcq`*u&a!&pv8Po(T9y(>)I40g?3 znDLYmBFZxdser*km0*Vz<1Tl+N$iml@!Y&oVxtXdYm+!&Lz0CvNV5%s6xfh(0bEck zut93!Rfy6~@jt;_sNi2Mzp{e_m|yKBVFbT<>-@_QCRX_7T|j4ntsOeop|?zQxT3nf z#M%K}VAr})FaOCK*aW-T1}PWVApcT9H_bx<<<(=t*KJ5!(U8&X$I;&La{dM%fY$^7 zX@evQS_E+dn`nbC{NEASgj>X>aMg{FV)*YHxh{OrtR9bC{@YF%Y)od7MX9%#YqX1W z09#uvyb?jXO!wSw`hrBVUB;+P+AY?AR{LVu|J#b(S%3ep*(Dg{aqX~kZ2>^mbs0-! zTB4Vyj70u!`H~;=4Da?2l-mb|j^|nY5`!ZtPXBxU3%0tk4UM$r6>wb+{C2{Str`}`LOdw+tEHjH1t2Zf)&t$6Ok5~NDpM2{_w zef~5djPi0NoTAt5rh}RYN58@mudRF;j!O{nd*TaUiYLsKseQHuo- z7&KgHfD{YLnby96QR2=m$!Hn}jBY=t*R}%^rR0BrJ86e>M!3)?f8 zSIH~L%|gNK_GI%5`(B-0Ossf_7YKao(4M(jewIlk1?&n68arf^*U*8I{no87fE@m3 zCCHzWp#?g~Z&_4lok&tZfSA ztoiiIiLgdxqx=8Xb&jd&)2vuOn*7;O_aRB)faC7LaY*$4J@IjH-&ztxF5w6POQF=~ zJ?cVSB0i^t<#ly~1M0)hBTB29o7#SQ&3BW&Kqs~l$1lWh)yPNQ`d8sWANO(A>;|71 zq5?KVtso~d>2Zw9is~?isM^|?9ck!fZm3w|&77O9f`{i`>DxbT1(%%xNE<@l5o(7y zgv(W3qq|8FdqYcHu0F63LY|VIzWID5{J_Hhq7vYQuL4EC4WHvLv1n9_Gg8*%n>O#d zGIw>>W!rGCFgxgFAlvk_^k6F6NImh7{GGt@*4b!aU}(qXERlbefqx&W(XPYP$J%6L z_(A+ti<6^1&^P(Euy?kxy=$bZxNqiNEfkl7S1;7TbBK)F72U&i-L3DN!p({FBUz~Q z(z$Z4Tn*-2W~}z?A2FUHE%x2lx!(h8`?Ipm_$Nj2l7}*_VuUmY&xLYM+=pTw=>hPHb*2IU|-+>Fu zX{x2J<9{t1VB6kg#1R+QV;;`1*?Fh91j0&LgX64PRu|qy(ykFzuz4+PB#99;#Z>PN zsR?4aySuyd{nt9Sbn`zyySBTw+=PAkzNFYwjnEp6D)FXQ-w>{yf9dkaKi(+WsCLr> zuC+5Np)gXeA#snko*D5lyyNL2v;XsNFa`jN=yQk0JUvW`JtdQp3l;&SoSUF#2tej^ zcwDgHeb?FT-JH%&W~+46t6V5tR$+M^fBo{^>$yrY(nM-;gn;=l+>0uUy_6@P%(u*) z4;@ip4QX-5dIn4L`o=O^+=gYCy%6;nen`^bZ$^rqre|QIV{mfL8L&#hujb@v z7oh(KiZN4D+lVC0_JnIE=O(66uJNg6B88Ymx^ZfGjEyeFSo-|RF{$+=t*qimIyH^y zmrEB~=L$7gaU`48%*BQKaOiu=&{GT5*D?JS_r|WxLd@Lx^RxTWu)1S`P$e6G)U6%W z42j+TYcean{59V@Pal2Y+D|-3Awu(iF}FkXfoU@~YmPyDC`Z`WuD-^gUBsV)f!%;u z&gvK}vbqDsWyQw8D^5i{?fuzP*LV7LAHUn$G5m*3_}y~E0K-7_aZ3yu(lT77=FCLv zCB}KFFvDPKLp~~dx_t1BBk7fITr_DzdC{OGt{;QE5VR`yEa16tg5MJp3<<<4IPoQ1 z2*;5>h4UNgave(CF2b}BAOMeoeu}abYgPJCJ7SE@F|Eav+?Re!!?KK zcEZA2(?XtquJ&Es7w{<48y$7`m(x{UQ#X97AGOa*5zq7s5h~6MS-d&pMIf5acsu_~ z@H{(&lspC?mxnzFOJ*N4#O!7EdHJuGSB221HhG!sP2MKN=(uP>g%g&tGbyq86+{Yrq7FVCI<*qWLJ-4gBpg>{?%(SAvK$ly1bFU zBRPLZa^)=z!iDo(=03R@O5Xvv_4o5(=&PL0Q0d zrjAxL-g=R*oJsezgd?i&C17>>&DELx*mUlD%r(MpBh?uGgJJ}Gt6SqOuGWUHXMA@6 zfjbJ$IO3K$z!6`XaM4)%nwDmBLtj+#f&&3*y~7KlXdl#i^yB(i?Ef?uDmM+EU=pY# zCe4j6USRp#{3_LL_qdEW)!NxiEhSN@ z0`)jZ{mSA9I=jnJgHAMaN+hNVyye?Mb?)Ltbp9k3nrNdPE!9aFAkTzzi$-MUH=XSF z0#@ye)o#5eBC&f$W!T5B%VYP9>Aoe)lm^3QVROPv-{i}U3Rt@SDqtyxn=J|%D9%Vi zm?OH)jjR1>wTZQ<12qj12($U)1809Xh2`vl%3Q2;L!N_?x(VS|zk!NYW^>E#*I(SM zGu*AA&p-89n$};_xYEjcz-qQ`Ebq?s{P@7d->rf5VKjb#>znii^L@_Y4cYnQBHdq& zriaR?+cK)&msFKpS2xi1G|AT0kBX;ck9uX5hs*Xg*-Jl|$7yt{!$t;Qw_5Y-vtm(Q zLg$lmC;3sUWt4hTz69`^_o;Av??$fpic^0)zGPQ$qq<O$T zl)`&XbD>J}_A+H|hCi{^BPhQ>> z&YFhrE^1??g?$Lll^M#1aTXiA`)`UdRy+(z8;+*=IkdRPhjzt=(pNJ*Er@r|J-O26 zX~-^BRw}afp1Kw-|MVgOUGCK-HdBd2>ew~^M0P0 zylt6~1ajA6plSxi$Mv80tjr~>Q}qQU>Z0|&`0y4?^gXzQo13BYn--}N36H3;rtqnr zD0ti|ej2$x3hBX*O-V?Pjlm#enmBe`?uvGFet|JMzXYwiQlNHH2VP_@iYhv-tCbff zek6qd42|bA5~zIU%n>I6=I1~Dz5E3lFQg|>gv_o(PU0vk@zr%JP7j2UND;ESta(?a zta-HpMnar`Ic3FH>D67Qbf)ce#xOzTFDQZF*n70HwK%NGDr7Uh2PyhjA#Iq{fwHov zc3Eh{adf5Av~4(^>B;g)O4PGe+C1Zc-f5uktUGg6o71{#0C<{5=vm0r~ThaLP5`QG zgVq{}=hfRY>K)Xp{hib7|GzxtwD(8{nMymo9dfM^5xm5w_(1Gq3&50gcsb>z{&y@5 z9kToV#qg^c6xt*CG$8>p(lto#t1fuz);=Jo`u}_QDTsh-D-4%LulJ0wSzSj0NmAy~ z%7bF}eNYeR#pe9d(l4+m9uWS)FX_Q9-Y{T3MUFanUkv5*Ku`c@`kds7;0JyXPV#$@ z=?`mO1v%RxzGchf9ucR9uDSI{U&NK7VlWT$waoe4lgL$?jc#l5{SX=SK^?`-%@kST zr~pIxm7@iMDI4GMP`=6T&!{>k#{VG5b4-eTchpNgpyrs%*D5kaT9@36sAetxx1FW^ zmS&IP(gPH5a7#HT@oDFIn^#p0u4bveTQhKt(;Q9g2?jI_etB>K%_udr z+tZ(>r`K>VQ0+j_+l>^v8&))JPkZFG(M;zp?I@4QJGs`GcaHIkKKh*XG92Do&?l{` z>BXsSX`0=LcbUBGp%0OMj&6BMt6c}{4yDc7uKD~l%50cSl`t&tG_Ye^530<8LmZ13 zMdU&9!Bqdrk?Gf*GdrKbL)vUnBl1{1c;{*ktZeM&+q?uE-^h0HY8t28XphDY1_(zF zEAPP6luCy*t08Hbk|HmE*uS_CJd}^AG8tNWy~^6X6LiTovlag9?=U~^uKVb?pXyP8 zt*N>o?i~}|k%2@n1os>NAD(?#IZ=h;M$DPMoRd@ZA^l!$Z*1@-=4_+JBYV?AT?An2 zul?&%yf^RliIer-{H65nm*#QMk-XCV@QpRQl<)UgNHZ^9aSUzr(UuoU(5>RXC7xkG zS}HCz6_EOKEq^oI^*qoY*r+l5(*J8aNpQk7Fyq7}kMK)l-v~SV8<|c~C%w}=53til zk(wl{Nk{_w6&PvCUmc=u^$03}Q>FPHWLjdUF$-$U@Cf38da}vr?0a=iHy7SC>b7+XKz=nkS%KXyDY7c@mb`PY~{Y z@id>P3X@oyUd)dqZ2H9+-PkKuKdfy}&upwgf55?zM1BSxT2*1ltCC%RfHCIW`G46< zBdYcWh|9rSKLW)ALZJlLE)Qak-){oHkZkofY_j!M6Nj*E5q&8WCpv2?20EMD_z;>i zjxo7Om|U2sDwf27x_3$ziFZzqNDM^^fm!ov=nCNvSNHPZ$ zcU*!*EGs8wK*b#p0w$+=P|I^bZ!3fSnT;i6FyR6ix=k>)+eirF;ZFprbyJ`f^snjp zIUSN?(AIHe29>}!&1-_pjcZ=rwORhV2%8YxdeG?L$lPduxf1#PGksrGM42Jz=0Mz_ zf-ubvIfhe;9xAgn-;it1+5!82Q-)`jdcQ!G@F%|)%!!Nq?{e>WIXXpYTJw4V%=HBx z$84usp6l?wFSRPaw`0549fJX7bt6KCfzsKrXBpl#;B8v2RJ+9SUBW)yW+fCiaAA z=>dP<3^C#KZ{&anxBl?j=OJg%8&bA-XTT;J_%8j*&{2H-NtTD^av%_U<;_ZAXF=O` zVjDH}_Ed%=Bvz*X=Ar*MO)-THqt&U^bqxiXP7yo`bYuHTGbvZmK2MWo)NOkAMzt8q zBCs~I?OsQV$yb=AayNFoK?y()%N98*=%uqJkzqMtVptYS9=<~ow)8?YmFOK~r`n?{PSv*B zn)2Eaq3ya(gbC&1!+=(4H@s5ap2+gMSLfvTz3_=xAc8{q@9&~P+e4zikrOOLr{)n|7N`uHUFMvlYH4edwC?FQ}?v2w! zmP5Nw0Asfl=(m{?9sZ+4a9^fxW#a+cvuJo_X{3GdZeLw>G7<0y8#z5_;=iq#;O54z zjvt_UFm35g^`u2tFwQsW#DLO@P}8?L4?-$QPaoLq3(n<;x5ty-R{ZDNiZ6v3funh6 ztA&g9IU$zr=b45B2I-7z!1YeQ7VG!Nrx$;I$^9Ww0SCXq6UFQ_ibQK2jK8_s6D}Wp za^s|$AR{4VU%Wv2#wT%~GL_9|98zm~aVNm!Hk4~kDuE@ETd=M5;+`FOKQ=F; zc|!l8jyUsPBN2&|yM5?PK7R6f<$w5~?%G+!6Bz$wwq;3wUYZj(>m4e05gpj19j{V%*>9o0YI=Sh2>2b_L#=AOvb?dkLcGE?h8f_aXy?|Mklue$6vYt(xscz7`y#`)(!?K6_&om8Fj?$g`u{YO=V{E(yB) z5}KX!2E_Pb>3rZfT;nU;awBv3)2#dwp`!$VCSKaMPb4W9Cwh74 z3;{#)S6N7py*{CWu}9|%9RRO_*V5fMx+#ut-wsi#bs5dl<~Uwh@{F%)4yfL&xW{1B za8PX*(upF&$gk?z+rVhL?g@ygOl*zv;dpRyWvQ2pdgeL7)oH=iE?kM=;Dc2u^FdrMiI4re@9i&L#bJnRhYL*?v%Dj zR5{fMM9eaf{9D3_n%@v{z~hdg+}WEe&tz#?kfzZkpJ4Wmj)Q%P$0}=b1@Kns z>OM=UP(5L7DXP3CvVp%g*biB33@sKK&x!NAVp6g2mL*f%%q`s#*`Un|eUPB;5uS2nYUKWkkL*6YT(sp5B6{`ti>dcle&^3*d9gAbnJSw^lq(N z34(_L9iXZo1$npIz=bTC z%Nz~qsNeZR9EgopS}Z|hZy>|Xk$ zzF>@R^V%bfng&_&d{&&De2ok-O6(X+QNX@nsnwY0?Cvfh)Vu#L8r@+f{5g%RV*!A# z#48uK+{BpRFjS*?td8#)HC zNB*crA_OWJCNgdaysW}JpQ(E@duHW}lcnf{>f!~T+~46B@qhyVoXs~WuD-Aj1f)=B z=Yqa-XfU&2>=>HdY0QhF+UV(2SYW(wVWld}faXMfyzlEK6uRefgGu3K?EOO&PY|B>5X<$?P>?PtJd>>GR<2iUyVb!=8z~UP!@$$1HHmx3 zUzeU>{EY;YuMk|R~~-Bi>%b? z=`OA?!G%T84h?{(xcsxdw6&30F>p(FJfyWf$}IKFxN3~Rtvyn{xK zE?OvWktMq;_-+g6@>~X;r6h+hm^(I&6BZ&$CwR(rU+0Zh9U*9Q{;rHE*6o#=>+QNXwXS0WKIL1T zg#LJiNfUDUQAq!<9-GZ-VOErUQU4!x;f0az=d%Cr{1h?OM=EDE@^pQ7=9AZp<^F3t ze~2HhX1phQvYy(}KJ1$$0Dk-hJ@y(FR(e>TS*$O^wYa1%H)N)5fb#Bdxudp5jMVat zx897&z;2LO^&+}^&ajuP?+PDivzGJ$(ogI-eAw4~xk1!g{lqHR5TuGJjh@H{`C zB^p}B2`Qt0No}Y?1Pb#Y%g^cXFF4GGjd11sBrD0?y!rvR`swj?L$31duT_Nhq_LOu zbzN|@t93?>YMh{~KcJ&NRg8c-eWaxNxx+hUI%lI+W82U|zm8}-yGZ47&G7f!19soj zWl;>t(-nb*a*}))8Oj>uh=|^L9^h^9NR>5pVH=H=T@GuH)snE%YMr)O=Lw2|@^yNu zZtYOkqdi@Z3(Co8&(z(5atOk+bNx78!pv4Road#eEGY6=8S>e@S;`7oJAJT)c3zD3 zYGTx!Dk!79K@*M8#Go8gYSBbDG*N??lB^4n{r9S8qn|ms#}bopscVrY(bk}=V))O%FS?r0&&JOymBhG%i4QrPgJG2 z)6vk`QR@tG+d_R_SwnNHgCgS$;dM~#wuWYZ3-$H7Glb}pvB+w#^iUu!88)XawI4g7 zjk30vtFBahkz?)}KuA+xR{@BVhzBafjzEgvJ)lVWZp zk^a%eV%HuH5G(V5oV4~B@s#yc54_DM5ERS5;y==?%?>Uj|+%Q%tc){mSz4@^wELCyRwwN{8Xtzs}{fin-*Lq`3;_y#n_tKYJvfa;CX-E!6(+lo18qUO*9 zWYo_#K8M+iD9N;Di(OK%W&m88bjW#BnuY1fm zn}o?5O02A3wEP&1 zl(g{~eQMDN8D~v+TxcwCix;fv=S9g|Sdv`Tj!#h)$Kn`&xN`h(e52P$CCB}PO`p7e z@OC#uU$E4)t{^q0=b15(FQ?L+1*ldRA z?o6n{SoB~eW`$^uw%`s-V*vwpVJS$aCe$+PWPIu!&^Ob<0bL?BlfjwE=LwIJBT%*8 zP{|OrUhO8jQll9>gJidmH~|NKLT|)pgf?m+&<;FTYI+sEdP2I7s5zU_g0+}gMFJBS zwz{oJA9OjG28`eY*;+V`uKS`58ktt)8-Z09?O|4=E6bxL)RS53+8cs$2yHPV-;o-; zM7^@k7qnh_yPEoG49%11Xzhe5o&+0Fj70hc87rR;*SHHCtiG4|+-#^AC^qfq^5k>= z^Y@hdd4LCSmdQD)^2@$ve6XfROsBC^_St7Z;5Rheu0GdtW9U`!`dRwMWPw64{y4tq zi#nJ}IgXgnc{I6Qgv+g@C%y{)XHF0?Xsfp|%ey(+8t;ES^xZn++d|iWivKstdMVEN zPU6h}K9jp1S48a-!FFR9MVbP#yd*UjqtOCgr{qY1+ar4no};HGf0rDuXYpzdv+g^5vECY2G4M`M z!ZuW6uIg!5EKQNCoMH0@vTp~|^0rk6mW12-Mn|+hWz%Dx)-t6jlFHd7CEEQsxM>CA zdaV_3ZZ@wtOWuzT=h*`M_x($Cq>b$us9NZ!#0H*Eu zL)nijtI+FxF3rsQiC`@*NZBPCFct-ANvM#s}jt9~d2sJk0m z{2?-1(s)7kx-M8Sf-^yB^TaC-y9qQTmmN#$kc*r0v4_~T8ZXG+gfJKg(P(xFo(HQ} zpWaXelpf**nT=SD?v+-z7LoX^|Vj`4aCh8=XY>pJAq*}O0q<*-A>>#47PPwgkG2W+b!U=5u$Y_Bjp z@a{z)7K5=cRUZ!e@b|y}@DEqaHae41v(l`VvoWh})%UB_U0xJC7Qn@i>M7YgV0lQB7q}X?Z@=m*dbNL~p)bbo;;mtaQTN2MJ|BQ#PGJzS5&iR~_(4udipmE5}?-6#|{N0 z!cZ}eT<0Z6=Q6VZt8n=uGT}4-OFCy{`_Vsm?53=S^w&+hal^oALBV{N0$l?0v2@DfAg1kzp^s?hB7+( zpO{n(3cz_f0^o?e^A?01yMI6d6?jrFkCthi(uO=B?)2crD}63mO;+vWrx!S-u3N2Q zD969TjWCZ%z*@5;0`c#NK}KBMY!3$zuvkW6+tNXSbg0(+H<?pMey!D*70HH3^G? ztw{M>d0x=j0ue z24{r6illR9B_j&1tCYfku{S>kLLVvLeG!JA;0Om{PpRNd`Qh;6b`$cP$fa`@YklXt zy*~tMUK0X=zW;$wpkD#p$q9XrB)2ZuE~@2j9L^H65`7jiLLeBiWf2~eaGNI_eH(Vg zQbKB%2$RT5v@ccTlg{!xNlg?fwaWyhq0ppk;|l=sp$~ymh9j)!1!j{;GR<Yx|oOnZm2@l;<%u6JKpwz&Rl#--OVtq5F{0^iz7h@j`Lcf3`b=n`G z2&xUea4sburS(sE-k0DW zd(6jy=q#`0p4-uXZ zjIL{As*;l@pt3I^zJyY7o%23kWN+7D>&QLgV(OK|1+Vn7Uiw!yEfT&_5+xEa+hinvah0eh zHj7H<`v#ND@raoB%+UaNAH?CJ#0OfhCkAZ9PXv)C*9SvLxqGrD^|IpduP1P7cRW^w zPK)t}!<@x_@t?T$8_r>&_Q?7E6TCtuLi$l^3Azqd!ppoRV;DlR!-k(7Q>bf-K=tMk zQ9(Th21a(9MKE;3+MVw^bJ+CQ>8k=Td1JCifNyi(I%5z?Gq7-&vn+)?NwCu+@_?LK zT?Gg6@Vg=Bk;%L_m`*E;+MWHX8A#)I0|s3`S6q>Pjq<(m?|=W{L#*Tr%38oKv#AO5 zb|59XWF;4}csnkQmhiv<-%;UYDj;EO%t^g^5t%bSiI%0+?aIbyzqXkF#fR;~TI;?) zPVevh_$F5FES<9l zSz^t?s`{F!F``E?1b`LLp@`X;0?KXxo~U&zUy;OhYNfz{J6N}iY~v7iBU4X^M0eIWY4**d?MMaDn6mi`CxyKsVb7jOKs4@62}{rw73(25k3tANV!zPzP19<` z3>f<&s26m=Z~?0^Gx88i3%Aja``&SAZJCE?gZAMBB^5LBTt*6xZ$VWxwQxD_lEwH@ zgX)2A`Yi;2UN@-we(uIoj(uLe0B^3{^TRphe!j8|PD2b6ES9VtlE(I1XE9}YMhVD# z-J&wk0@rRbaifP$MtVZcn?A}xoM=Dv;00s?6^Ox#Z`~%(m>rC3l^dh1@g5)DXdwhwO05GW)C*Zh`lWhY;NNf9LW_-DD_N(A7ElT`oDP$8XhI!t*gTWI z#aIM>(=}DyZIcz)vusEWWy-2WZrABgk)n)eNJ0p=oUK#1e8aknA zgzY-2l*5RU+wFn{*sg=zDaFnX*lN{DdZd{ZbUf_MfXZ>hX?rn4fS5T(>5YIKh?1U@ zuGQWJlCDb^GdQLNbMuly+ihCwd?mtS;p^7(3CBXxqi(l>Z(*O&~~0 z87ix?GEX2}`5+;7jcR%-`MOg>Hpxvx%2%mM&zVlGN&uWp@ElnQt2yd_P# z2cRj&PGM(=%DI-q?seR|{||m(5oDQ)h32@?djqkzA*z0U}YU z5hEh$c91MlSg#C}w^$XyS+gf65cA+U6_Ujqg^1z2i>?QvR)ikmzI11q^f-3D?AQmhNV79Qu-LjQ%Iwy zXz9eOej+5a8mAe|?N*-qntqYr_xvFkF_s!(Blf#}`~dFfaSHpkl2zD2i06Z9W_hx| z(lFj*C=zf2Lz>_$aqDZl>v*kh9K6#MHd=(`0AYAc-F=5?AJy+dlupv-5jMwk%-(*# zTmpPZo<1v*XU*Gpu$+0#Ve-!Sq`zICcm>xP)z1h9BAS=xJG0-DP*d3^;#S^CmozE+ zWdyo%##y>~&~M%jwOu#O4UcvC(c8Md3GkOc*%k8q_8DWxhy%ovIc{cS^8$DKjW_O% z6H9>EQ$Y3OCo2{v6KaW_t%HL<9fw!$SvU&5k|xUwdEr|()%oM_r%F=uR$_E2jC~g_ zhI)^O$atKDJI;Xd>LS``eftTYwdPH>@VTW9ysnH0S(uch!wB~ks#En_d1;@)v;1jv zqlRW+49quBhIPj!^cNz>)Us-AGPS(F#??< ze7vuCm8&WE@_0=4wi>FiWQQ}8t4W;K$=4vFI%Ue3O=w2QSqJHzt^kI|Ea>>qetMwf z|9j(HyHDgZ9<~pZ-nSZb6CW%7!Eu5|$LDAg(q<2o){{3Qf-tf#A4=zJ7GkeRkS&Uo z8W~WP1nG|HG}OwnkY(k}QH+0zXl&aa*J8*pS0eJ8fClZSfQ944Vge{zARz|IJQb+c zKqd2+ShbyG#>9_?z{#T2Sa6|Tj?CkvSk7uFt0K2c6USTlV4QqJruE57K9(#Y=dI^q zcs?-sk{AF8<^3wC25$aOB z;Ql^^_U1Efpw6fC@`4GVo&w&VFR*z7)sa=;)N;l^_G5`*cAdIHH}Y0~B=6-b`O-+( zaEt0+!-Y~73uKylHxwz3hX@$$k8Qb3g0lOpK&&~?8yYlHk34!QS&PBYRaM~jzWOF^ znD*x#={tP_;aEm4e`jz`rzrhF3I9qg^&zTGe^ah4FLKjAt`i3$bx9ZGvLWP9PWiAs3Inbm4(V(JmUlTy6y3b;vW7YHk_l-?QuWG&9 z6LL!~;)V=UP0DnlfSW(#;z7mSckFdY%Eii zju`bpKtwF$U{5@20rjcd=YG*F!U$)b3g*nN~S5?)la8!gdbh4`hI_P z_3lUek2+udVL*TKJ)H0E-k+8~IP1;<2KZy!g~#GQ@CeFQY+(?&s!4j+xt@vS$++5e zT+huUJ8`ac*ApcHF8hb}QB?&qpp-sn4+0p%BV-Yd3&0E5KI#EDrk9|anzgP-d@fC) zQR*x;_ez-qb)K&&reyNK^SZ=;WRzO(6EO0G8vN7TIY{To=!B=twgUw>BO@;gF84s5 zRA&1oIH`_KYtp5pF0P(h=X|39`fs=bV)9`nQQnioq}4htwG54QKI02SJ_L9_NC!lv z)0Y;ng>b%x{8Hp6-aGeCx$1*Df1T%nesIMr|Wa70s|3+wpEdI4RH zJRFUEDkCg#M<57~k7ugI08oh*(e=1rYMRjcXr`3bR)&{>Dy==2v@z3R8rx3Nn{b1w z-i|Wq_I-&(!~kc3^;*TGPx6IaZn+}N%U0?Ufi^4HD?CPdXH;8<0%lrt$*XvR7IQo@ z6d$f)pKb)`tB{CojEn$h8(OS!g|U%K>~zx=_{kH52Qx*+yD*uj&v@mXZWhCd(y0ubXoQAD687lK9NeM;I|?~C9v$B_BC<(*D`9b+^VEj;$qH$r7E+t$R? z9frb7179qm;zdJbxlm-Xey;m?n#rLtVX{O*buQZFrORKuqKS=_O6{} z%TT#j^b2=hmbT+p=X9QDPnkoiuG+{bg^`KYsw6GgP{6?XEEZsnh5SAQmpmbBfE{lRWjr48e}5_owxI{WGu@TbAT7@^#aw_B9JVfSu&&PjMZ^WIf|gh zxxaBtqC1^Cq4~OoaY*C?rysK8z6=!&n4fbZ6a!uLeFbpYwwIS%R7aJcsCAp34lHTw zRSRlFJrlM>79g=rR;Fov-$j@u8rG)Wv}|Bqka>~CA<+}bx2uHDWW~@-lVl$B{fHWx ze1Zt)j^vANvI~xficm00BRdZE!p(s04`f+ps%MjnPR`(0am|fiJTA&|KCQth#tXt@ za*NH93D-{M5QJ3HMBLsE(w_ge-*Hq!2JSdq!)!7WfE*n?sw)XVQx>kOe3$W zWr6#meN*AAG9O~U{7OHnCJO0ORTV%B+WOn-*W$4~!ie?MP$}t{?!nn~fFEYs#y_jW; zkDQZ`E!ZQ4la*rKS6b?megFsWBNSzp7(Fq-v3*jO@W_R5#vL~>mjH*6E|U;rt$qXt z)K^@7=-N0=IKM&b7bSV>jU9CM#)Ocjr?S!TK?fdm@up0P#v< zFzI8fMXik1Mr$mDlx9k3h>XWVV`m0p%$D1jJVvZ%La~GMe83lG!8bHitM2ZBvv4jwgA2K-1s>;scON!_yZ~Z!qMlf&|Y|lPbR}OTqn5LMAivaePeJYz!qgVv2EM7t%+^hPA0Y|w(W^+ z+qP|e@#ekS+E@FxyDu8mb*uZ_b2Bq&iAs`YUobx~@5`zi=NzFjq50uWxq`)W|S&q+D2o)EJSo0y`~dZ2lM9y(Kx1OZ$e%AY!v`Kr{?N;VqH@GH(r?)cfYd*NZE1{5rZ2^ z#!Ql8DIQA|y3;OC>`pk_;xI~4kkawIGGghp9S>#3;OY=nxsIyQ6b#d;W+l0qcpYNy z^OfmOQIanv(x0uY~3Ce6VToKNpvt88^ z!vqUs;xoPsZjw}d$Yx`+VvqF>105pJR9Qx(02R;3bSEOzOQ#LlVO#846}8*WC&l|m zjh3l|A{EJHcWkMwj*=yB!iMP(l48UueM^GD$gsy>V*eb%NvWeBc01Q&Ft&>_7<;(s z9R-B_J2XKk&{kl!pE3g{IyoYfox?Ayn^g7)|5zpnr}t8_0dmOq>=H@H;t&}eL%iWI zm7~?C#qc`y3jGZ{)FYqib)zD|QIxJ+P#1_%_y!j(7%0xPRByvMm`DX2tv#oKrkW1t zOWYSQcm=Tj(4@F7@T_y#qJHWp=A8x|aMA1aRHcL4Hfb6MTSbnK{%gxGDU zeevtHrWx&`r+wv!2q>i()$+lJ6UvWkbN$7OhYi)M8-w)}07@Igvm=+ra$9Ld8sT8y zB3%S@+n=nm3ajFLkJo#sU6yL{sW%td2PKi1DafQ-EtTiMa<`!S%n;ys zsG{i*Z2jt(2q>L0hv>8Myid1i$bm1v;DdzWT8jBVnd_hj!_fF4Pf|j-`4*_&EtL{@i%*OmtI!vcd<9>mMQ-XIk#?UvbXZF-|E=8PP$#qjeMx)kba6{BpiK;j+`D$dpMLxiIS_x^*%H zRE`}y8lF!mMurI=>`qI4Mr2Ps#zE<}cPB;Y>K0>oGG8+7OD-S5e`ceFnB851eCz}^ zIeRjKqzna7iP4~9V;vqh^Pr#MhlpWrg+eP5>}iew$hBhjx)oP}b+7Vv#tB#3Y!|UTZu&16va{8@As zN!GCh0m1@h*Uj}Z8L-9zNxfgg?cq~NcG-<^U{#7iEQO5C*|yHv*_qf!wTbWnsE&|r z^1M8t_KG;=0e5eUqnpwas&LPLm(Uo8GW!O58Ge%q_ktr0Gw`XjO29jfOd`BSBPY*|cdBuWCL)9c#t~ zX8R-5nvWO4ZaT6-=#l_*u0S?YG1AbpaN^H9Uwcof%NcN+quXCg%h6;o_F)bNBTaU} z4TcEvm9O>=x)KYmfRYkh2HQt9n_sujFcIZUtPD9dd)^lF**_)f3@Y-{(@dZCiqA2o zF`{aO-Q{o1Ha>tqS}u0NY+DW&R_(O4A3U=T4O#tqPd_P7oB`E^mmm74;@U#SupK}# ziv+*33KG@>4mLB&o8FJ=g@OEfG#0a?v80b_FV~#2P10{H_&vW_%)kHa%z7;Bi!Oe* z-Q?;UQ`ll>s9&6ND5GepXW?(#mCKAI5T$%Xp_~i7__VLxE}CWb4w!<8Ij79wdUzvm zh^nhrwpK3I7pnxE2=Hp3IM?~cEX-&d#&Kbs&10AJvRA7XSHjfYwW}kie}aC$NifS2 zC^-5(o{Yr>II3in1W0ObtdF6-wx-QS>xDFtxjas$QG|MoN?Kry#kTc(BPqipuZ<0E zG(Yi-jBj<1Df80#o{?H7l1Dc-JQH3fBx!|{TmXC&pB?^OUh|_fnqDx5i>hJj=|W;Z z?FDc7^zT~@!!MKQgJHf6Qz0mE8^!-cUNSWkGIFqml}w_P(WHTVkS<>Zt-Gof`t<

33OR1_N*!%ylDDa|3D1;gP8brBkv%FrMeyX$5% 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�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 literal 0 HcmV?d00001 diff --git a/book/theme/fonts/open-sans-v17-all-charsets-italic.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..398b68a0853fbf6368758deb1da49d347e3e7d89 GIT binary patch literal 41076 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

  • ~`;p}3;==ZtNy# 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 literal 0 HcmV?d00001 diff --git a/book/theme/fonts/open-sans-v17-all-charsets-regular.woff2 b/book/theme/fonts/open-sans-v17-all-charsets-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..8383e94c65478622baf43553262e0e31b8725e2b GIT binary patch literal 43236 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⪚aqC6F-jh=?`}zBG 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/, + contains: [ + { + className: 'literal', + begin: '\\[(\\|\\|)?\\]|\\(\\)', + relevance: 0 + }, + hljs.COMMENT( + '\\(\\*', + '\\*\\)', + { contains: [ 'self' ] } + ), + // hljs.inherit( + // hljs.COMMENT(), + // { + // match: [ + // /(^|\s)/, + // /\/\/.*$/ + // ], + // scope: { + // 2: 'comment' + // } + // } + // ), + { /* type variable */ + className: 'symbol', + begin: '\'[A-Za-z_](?!\')[\\w\']*' + /* the grammar is ambiguous on how 'a'b should be interpreted but not the compiler */ + }, + { /* module or constructor */ + className: 'type', + begin: '\\b[A-Z][\\w\']*', + relevance: 0 + }, + { /* don't color identifiers, but safely catch all identifiers with ' */ + begin: '[a-z_]\\w*\'[\\w\']*', + relevance: 0 + }, + hljs.inherit(hljs.APOS_STRING_MODE, { + className: 'string', + relevance: 0 + }), + hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }), + { + className: 'number', + begin: + '\\b(0[xX][a-fA-F0-9_]+[Lln]?|' + + '0[oO][0-7_]+[Lln]?|' + + '0[bB][01_]+[Lln]?|' + + '[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)', + relevance: 0 + }, + { begin: /->/ // relevance booster + } + ] + }; + } + + return fstar; + +})(); + hljs.registerLanguage('fstar', hljsGrammar); + })(); + +// hljs.initHighlightingOnLoad(); + diff --git a/book/theme/highlight.css b/book/theme/highlight.css new file mode 100644 index 000000000..ba57b82b2 --- /dev/null +++ b/book/theme/highlight.css @@ -0,0 +1,82 @@ +/* + * An increased contrast highlighting scheme loosely based on the + * "Base16 Atelier Dune Light" theme by Bram de Haan + * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) + * Original Base16 color scheme by Chris Kempson + * (https://github.com/chriskempson/base16) + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #575757; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d70025; +} + +/* Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b21e00; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #008200; +} + +/* Blue */ +.hljs-title, +.hljs-section { + color: #0030f2; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #9d00ec; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f6f7f6; + color: #000; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #22863a; + background-color: #f0fff4; +} + +.hljs-deletion { + color: #b31d28; + background-color: #ffeef0; +} diff --git a/book/theme/highlight.css.old b/book/theme/highlight.css.old new file mode 100644 index 000000000..ba57b82b2 --- /dev/null +++ b/book/theme/highlight.css.old @@ -0,0 +1,82 @@ +/* + * An increased contrast highlighting scheme loosely based on the + * "Base16 Atelier Dune Light" theme by Bram de Haan + * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) + * Original Base16 color scheme by Chris Kempson + * (https://github.com/chriskempson/base16) + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #575757; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d70025; +} + +/* Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b21e00; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #008200; +} + +/* Blue */ +.hljs-title, +.hljs-section { + color: #0030f2; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #9d00ec; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f6f7f6; + color: #000; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #22863a; + background-color: #f0fff4; +} + +.hljs-deletion { + color: #b31d28; + background-color: #ffeef0; +} diff --git a/book/theme/highlight.js b/book/theme/highlight.js new file mode 100644 index 000000000..3256c00ed --- /dev/null +++ b/book/theme/highlight.js @@ -0,0 +1,53 @@ +/* + Highlight.js 10.1.1 (93fd0d73) + License: BSD-3-Clause + Copyright (c) 2006-2020, Ivan Sagalaev +*/ +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
    ":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); +hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}()); +hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}()); +hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}()); +hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}()); +hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}()); +hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}()); +hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}()); +hljs.registerLanguage("css",function(){"use strict";return function(e){var n={begin:/(?:[A-Z\_\.\-]+|--[a-zA-Z0-9_-]+)\s*:/,returnBegin:!0,end:";",endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":",excludeEnd:!0,starts:{endsWithParent:!0,excludeEnd:!0,contains:[{begin:/[\w-]+\(/,returnBegin:!0,contains:[{className:"built_in",begin:/[\w-]+/},{begin:/\(/,end:/\)/,contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{className:"number",begin:"#[0-9A-Fa-f]+"},{className:"meta",begin:"!important"}]}}]};return{name:"CSS",case_insensitive:!0,illegal:/[=\/|'\$]/,contains:[e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/},{className:"selector-class",begin:/\.[A-Za-z0-9_-]+/},{className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",illegal:/:/,returnBegin:!0,contains:[{className:"keyword",begin:/@\-?\w[\w]*(\-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:"and or not only",contains:[{begin:/[a-z-]+:/,className:"attribute"},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},{begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,n]}]}}}()); +hljs.registerLanguage("diff",function(){"use strict";return function(e){return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,variants:[{begin:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/={3,}/,end:/$/},{begin:/^\-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{begin:/^\*{15}$/}]},{className:"addition",begin:"^\\+",end:"$"},{className:"deletion",begin:"^\\-",end:"$"},{className:"addition",begin:"^\\!",end:"$"}]}}}()); +hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:"e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}()); +hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}()); +hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}()); +hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}()); +hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}()); +hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}()); +hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}()); +hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}()); +hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}()); +hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}()); +hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}()); +hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}()); +hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}()); +hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}()); +hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}()); +hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}()); +hljs.registerLanguage("python",function(){"use strict";return function(e){var n={keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10",built_in:"Ellipsis NotImplemented",literal:"False None True"},a={className:"meta",begin:/^(>>>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}()); +hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}()); +hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}()); +hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}()); +hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}()); +hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}()); +hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}()); +hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}()); +hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}()); +hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}()); +hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}()); +hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}()); +hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}()); +hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}()); +hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}()); +hljs.registerLanguage("nim",function(){"use strict";return function(e){return{name:"Nim",aliases:["nim"],keywords:{keyword:"addr and as asm bind block break case cast const continue converter discard distinct div do elif else end enum except export finally for from func generic if import in include interface is isnot iterator let macro method mixin mod nil not notin object of or out proc ptr raise ref return shl shr static template try tuple type using var when while with without xor yield",literal:"shared guarded stdin stdout stderr result true false",built_in:"int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 bool char string cstring pointer expr stmt void auto any range array openarray varargs seq set clong culong cchar cschar cshort cint csize clonglong cfloat cdouble clongdouble cuchar cushort cuint culonglong cstringarray semistatic"},contains:[{className:"meta",begin:/{\./,end:/\.}/,relevance:10},{className:"string",begin:/[a-zA-Z]\w*"/,end:/"/,contains:[{begin:/""/}]},{className:"string",begin:/([a-zA-Z]\w*)?"""/,end:/"""/},e.QUOTE_STRING_MODE,{className:"type",begin:/\b[A-Z]\w+\b/,relevance:0},{className:"number",relevance:0,variants:[{begin:/\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/},{begin:/\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/},{begin:/\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/},{begin:/\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/}]},e.HASH_COMMENT_MODE]}}}()); +hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}()); +hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}()); +hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}()); \ No newline at end of file diff --git a/book/theme/index.hbs b/book/theme/index.hbs new file mode 100644 index 000000000..080b78516 --- /dev/null +++ b/book/theme/index.hbs @@ -0,0 +1,346 @@ + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + + {{> head}} + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + +
    + + diff --git a/book/theme/lz-string.js b/book/theme/lz-string.js new file mode 100644 index 000000000..534b61ff6 --- /dev/null +++ b/book/theme/lz-string.js @@ -0,0 +1 @@ +var LZString=function(){var r=String.fromCharCode,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",e={};function t(r,o){if(!e[r]){e[r]={};for(var n=0;n>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null==o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;e>=1}else{for(t=1,e=0;e>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e>=1;0==--l&&(l=Math.pow(2,h),h++),s[p]=f++,c=String(a)}if(""!==c){if(Object.prototype.hasOwnProperty.call(u,c)){if(c.charCodeAt(0)<256){for(e=0;e>=1}else{for(t=1,e=0;e>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e>=1;0==--l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;e>=1;for(;;){if(m<<=1,v==o-1){d.push(n(m));break}v++}return d.join("")},decompress:function(r){return null==r?"":""==r?null:i._decompress(r.length,32768,function(o){return r.charCodeAt(o)})},_decompress:function(o,n,e){var t,i,s,u,a,p,c,l=[],f=4,h=4,d=3,m="",v=[],g={val:e(0),position:n,index:1};for(t=0;t<3;t+=1)l[t]=t;for(s=0,a=Math.pow(2,2),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 2:return""}for(l[3]=c,i=c,v.push(c);;){if(g.index>o)return"";for(s=0,a=Math.pow(2,d),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(c=s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 2:return v.join("")}if(0==f&&(f=Math.pow(2,d),d++),l[c])m=l[c];else{if(c!==h)return null;m=i+i.charAt(0)}v.push(m),l[h++]=i+m.charAt(0),i=m,0==--f&&(f=Math.pow(2,d),d++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString}); From b9045c1a9b91754a8e095e397679573687c5424b Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 17:26:09 +0100 Subject: [PATCH 191/253] refactor(book) --- book/src/SUMMARY.md | 8 ++++++-- book/src/examples/coq/intro.md | 1 + book/src/examples/fstar/intro.md | 1 + book/src/examples/intro.md | 12 ++++++++++++ book/src/examples/readme.md | 0 book/src/examples/rust-by-examples/intro.md | 1 + book/src/faq/into.md | 2 -- book/src/faq/intro.md | 3 +++ 8 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 book/src/examples/coq/intro.md create mode 100644 book/src/examples/fstar/intro.md create mode 100644 book/src/examples/intro.md delete mode 100644 book/src/examples/readme.md create mode 100644 book/src/examples/rust-by-examples/intro.md create mode 100644 book/src/faq/intro.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 7da2c743f..e5f094882 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -1,17 +1,21 @@ # Summary - [Introduction](./readme.md) -- [Examples]() - [Quick start](quick_start/intro.md) - [Tutorial](tutorial/readme.md) - [Panic freedom](tutorial/panic-freedom.md) - [Properties on functions](tutorial/properties.md) - [Data invariants](tutorial/data-invariants.md) +- [Examples](examples/intro.md) + - [Rust By Example](examples/rust-by-examples/intro.md) + - [Using the F* backend](examples/fstar/intro.md) + - [Using the Coq backend](examples/coq/intro.md) + - [Using the ProVerif backend](examples/coq/intro.md) - [Proofs]() - [F*]() - [Coq]() - [`libcore`]() -- [Troubleshooting/FAQ](faq/into.md) +- [Troubleshooting/FAQ](faq/intro.md) - [Command line usage]() - [The include flag: which items should be extracted, and how?](faq/include-flags.md) - [Contributing]() diff --git a/book/src/examples/coq/intro.md b/book/src/examples/coq/intro.md new file mode 100644 index 000000000..84914c08f --- /dev/null +++ b/book/src/examples/coq/intro.md @@ -0,0 +1 @@ +# Using the ProVerif backend diff --git a/book/src/examples/fstar/intro.md b/book/src/examples/fstar/intro.md new file mode 100644 index 000000000..9b80bca00 --- /dev/null +++ b/book/src/examples/fstar/intro.md @@ -0,0 +1 @@ +# Using the F* backend diff --git a/book/src/examples/intro.md b/book/src/examples/intro.md new file mode 100644 index 000000000..269e5f19f --- /dev/null +++ b/book/src/examples/intro.md @@ -0,0 +1,12 @@ +# Examples + +This chapter contains various examples that demonstrates how hax can +be used to prove properties about programs. Each example is +self-contained. hax being a tool that can extract Rust to various +backends, this section provides examples for each backends.. + +The first subsection takes some examples from [Rust by +Example](https://doc.rust-lang.org/rust-by-example/), and shows how to +prove properties on them. + +The other sections present backend-specific examples. diff --git a/book/src/examples/readme.md b/book/src/examples/readme.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/book/src/examples/rust-by-examples/intro.md b/book/src/examples/rust-by-examples/intro.md new file mode 100644 index 000000000..d8d487984 --- /dev/null +++ b/book/src/examples/rust-by-examples/intro.md @@ -0,0 +1 @@ +# Rust By Example diff --git a/book/src/faq/into.md b/book/src/faq/into.md index cefa77ebd..856d84b65 100644 --- a/book/src/faq/into.md +++ b/book/src/faq/into.md @@ -1,3 +1 @@ # Troubleshooting/FAQ - -This chapter captures a list of common questions or issues and how to resolve them. If you happen to run into an issue that is not documented here, please consider submitting a pull request! diff --git a/book/src/faq/intro.md b/book/src/faq/intro.md new file mode 100644 index 000000000..cefa77ebd --- /dev/null +++ b/book/src/faq/intro.md @@ -0,0 +1,3 @@ +# Troubleshooting/FAQ + +This chapter captures a list of common questions or issues and how to resolve them. If you happen to run into an issue that is not documented here, please consider submitting a pull request! From af4b220d86f9904a079de6bc55547a3cb2f28277 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 17:58:03 +0100 Subject: [PATCH 192/253] fix typo --- book/src/examples/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/examples/intro.md b/book/src/examples/intro.md index 269e5f19f..0ff72fdfa 100644 --- a/book/src/examples/intro.md +++ b/book/src/examples/intro.md @@ -3,7 +3,7 @@ This chapter contains various examples that demonstrates how hax can be used to prove properties about programs. Each example is self-contained. hax being a tool that can extract Rust to various -backends, this section provides examples for each backends.. +backends, this section provides examples for each backend. The first subsection takes some examples from [Rust by Example](https://doc.rust-lang.org/rust-by-example/), and shows how to From ac5f43d644d06c71807ace2aae1c08d78a889cc7 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 08:57:36 +0100 Subject: [PATCH 193/253] feat(just/nix): add `just book` to serve the book --- flake.nix | 1 + justfile | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/flake.nix b/flake.nix index dbc5dcde2..a57e309fb 100644 --- a/flake.nix +++ b/flake.nix @@ -177,6 +177,7 @@ pkgs.pkg-config pkgs.rust-analyzer pkgs.toml2json + pkgs.mdbook rustfmt rustc diff --git a/justfile b/justfile index 2414dd5f0..0edcc0754 100644 --- a/justfile +++ b/justfile @@ -59,6 +59,10 @@ _test: test-review: (_ensure_command_in_path "cargo-insta" "Insta (https://insta.rs)") cargo insta review +# Serve the book +book: (_ensure_command_in_path "mdbook" "mdBook (https://rust-lang.github.io/mdBook/)") + cd book && mdbook serve + # Check the coherency between issues labeled `marked-unimplemented` on GitHub and issues mentionned in the engine in the `Unimplemented {issue_id: ...}` errors. @check-issues: just _ensure_command_in_path jq "jq (https://jqlang.github.io/jq/)" From d75213ac1a0cf1ac2853970426cf123f439cac57 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Thu, 24 Oct 2024 16:44:17 +0200 Subject: [PATCH 194/253] Generic printer for coq Remove comments Move interface to another PR Do not fix version issues in this PR Do not fix version issues in this PR --- engine/backends/coq/coq/coq_backend.ml | 2886 +++++++++++++---- engine/lib/generic_printer/generic_printer.ml | 178 +- .../generic_printer_template.ml | 3 - .../generate_from_ast/codegen_printer.ml | 1 + .../snapshots/toolchain__assert into-coq.snap | 30 +- .../toolchain__enum-repr into-coq.snap | 64 +- .../snapshots/toolchain__guards into-coq.snap | 154 +- .../toolchain__include-flag into-coq.snap | 66 +- .../toolchain__let-else into-coq.snap | 36 +- .../toolchain__literals into-coq.snap | 169 +- .../toolchain__pattern-or into-coq.snap | 75 +- .../toolchain__reordering into-coq.snap | 46 +- .../snapshots/toolchain__slices into-coq.snap | 23 +- 13 files changed, 2798 insertions(+), 933 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index dfb33fff4..23142a5fa 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -12,6 +12,14 @@ include include On.Monadic_binding include On.Macro include On.Construct_base + (* include On.Trait_item_default *) + + (* include On.Loop *) + (* include On.For_loop *) + (* include On.While_loop *) + (* include On.For_index_loop *) + (* include On.State_passing_loop *) + (* include On.Fold_like_loop *) end) (struct let backend = Diagnostics.Backend.Coq @@ -34,18 +42,18 @@ module SubtypeToInputLanguage and type monadic_action = Features.Off.monadic_action and type arbitrary_lhs = Features.Off.arbitrary_lhs and type nontrivial_lhs = Features.Off.nontrivial_lhs - and type loop = Features.Off.loop and type block = Features.Off.block - and type for_loop = Features.Off.for_loop - and type while_loop = Features.Off.while_loop - and type for_index_loop = Features.Off.for_index_loop and type quote = Features.Off.quote - and type state_passing_loop = Features.Off.state_passing_loop - and type fold_like_loop = Features.Off.fold_like_loop and type dyn = Features.Off.dyn and type match_guard = Features.Off.match_guard and type trait_item_default = Features.Off.trait_item_default - and type unsafe = Features.Off.unsafe) = + and type unsafe = Features.Off.unsafe + and type loop = Features.Off.loop + and type for_loop = Features.Off.for_loop + and type while_loop = Features.Off.while_loop + and type for_index_loop = Features.Off.for_index_loop + and type state_passing_loop = Features.Off.state_passing_loop + and type fold_like_loop = Features.Off.fold_like_loop) = struct module FB = InputLanguage @@ -59,6 +67,14 @@ struct include Features.SUBTYPE.On.Construct_base include Features.SUBTYPE.On.Slice include Features.SUBTYPE.On.Macro + (* include Features.SUBTYPE.On.Trait_item_default *) + + (* include Features.SUBTYPE.On.Loop *) + (* include Features.SUBTYPE.On.For_loop *) + (* include Features.SUBTYPE.On.While_loop *) + (* include Features.SUBTYPE.On.For_index_loop *) + (* include Features.SUBTYPE.On.State_passing_loop *) + (* include Features.SUBTYPE.On.Fold_like_loop *) end) let metadata = Phase_utils.Metadata.make (Reject (NotInBackendLang backend)) @@ -88,598 +104,2221 @@ module Context = struct type t = { current_namespace : string * string list } end -let primitive_to_string (id : primitive_ident) : string = - match id with - | Deref -> "(TODO: Deref)" (* failwith "Deref" *) - | Cast -> "cast" (* failwith "Cast" *) - | LogicalOp op -> ( match op with And -> "andb" | Or -> "orb") +let hardcoded_coq_headers = + "(* File automatically generated by Hacspec *)\n\ + From Coq Require Import ZArith.\n\ + Require Import List.\n\ + Import List.ListNotations.\n\ + Open Scope Z_scope.\n\ + Open Scope bool_scope.\n\ + Require Import Ascii.\n\ + Require Import String.\n\ + Require Import Coq.Floats.Floats.\n\ + From RecordUpdate Require Import RecordSet.\n\ + Import RecordSetNotations.\n" -module Make (Ctx : sig - val ctx : Context.t -end) = +module Make (Default : sig + val default : string -> string +end) +(Attrs : Attrs.WITH_ITEMS) = struct - open Ctx - - let pconcrete_ident (id : concrete_ident) : string = - let id = U.Concrete_ident_view.to_view id in - let crate, path = ctx.current_namespace in - if String.(crate = id.crate) && [%eq: string list] id.path path then - id.definition - else - (* id.crate ^ "_" ^ *) - (* List.fold_left ~init:"" ~f:(fun x y -> x ^ "_" ^ y) *) - id.definition - - let pglobal_ident (id : global_ident) : string = - match id with - | `Projector (`Concrete cid) | `Concrete cid -> pconcrete_ident cid - | `Primitive p_id -> primitive_to_string p_id - | `TupleType _i -> "TODO (global ident) tuple type" - | `TupleCons _i -> "TODO (global ident) tuple cons" - | `Projector (`TupleField _) | `TupleField _ -> - "TODO (global ident) tuple field" - | _ -> . - - module TODOs_debug = struct - let __TODO_pat__ _ s = C.AST.Ident (s ^ " todo(pat)") - let __TODO_ty__ _ s : C.AST.ty = C.AST.NameTy (s ^ " todo(ty)") - let __TODO_item__ _ s = C.AST.Unimplemented (s ^ " todo(item)") - let __TODO_term__ _ s = C.AST.Const (C.AST.Const_string (s ^ " todo(term)")) - end + module Base = Generic_printer.Make (InputLanguage) + open PPrint - module TODOs = struct - let __TODO_ty__ span s : C.AST.ty = - Error.unimplemented ~details:("[ty] node " ^ s) span + let default_string_for s = "TODO: please implement the method `" ^ s ^ "`" + let default_document_for = default_string_for >> string - let __TODO_pat__ span s = - Error.unimplemented ~details:("[pat] node " ^ s) span + let is_document_empty doc : bool = + (* Replace the following with: [PPrint.is_empty], however this currently does not work, bug? *) + let buf = Buffer.create 0 in + PPrint.ToBuffer.pretty 1.0 80 buf doc; + String.equal "" (Buffer.contents buf) - let __TODO_term__ span s = - Error.unimplemented ~details:("[expr] node " ^ s) span + module CoqNotation = struct + let definition_struct keyword n name generics params typ body = + keyword ^^ space ^^ name ^^ generics + ^^ concat_map (fun x -> space ^^ x) params + ^^ space ^^ colon ^^ space ^^ typ ^^ space ^^ string ":=" + ^^ nest n (break 1 ^^ body) + ^^ dot - let __TODO_item__ _span s = C.AST.Unimplemented (s ^ " todo(item)") + let proof_struct keyword name generics params statement = + keyword ^^ space ^^ name ^^ generics + ^^ concat_map (fun x -> space ^^ x) params + ^^ space ^^ colon + ^^ nest 2 (break 1 ^^ statement ^^ dot) + ^^ break 1 ^^ string "Proof" ^^ dot ^^ space ^^ string "Admitted" ^^ dot + + let definition = definition_struct (string "Definition") 2 + let fixpoint = definition_struct (string "Fixpoint") 2 + let inductive = definition_struct (string "Inductive") 0 + let record = definition_struct (string "Record") 2 + let instance = definition_struct (string "Instance") 2 + let class_ = definition_struct (string "Class") 2 + let lemma = proof_struct (string "Lemma") end - open TODOs - - let pint_kind (k : int_kind) : C.AST.int_type = - { - size = - (match k.size with - | S8 -> U8 - | S16 -> U16 - | S32 -> U32 - | S64 -> U64 - | S128 -> U128 - | SSize -> USize); - signed = (match k.signedness with Signed -> true | _ -> false); - } - - let pliteral span (e : literal) = - match e with - | String s -> C.AST.Const_string s - | Char c -> C.AST.Const_char (Char.to_int c) - | Int { value; kind; _ } -> C.AST.Const_int (value, pint_kind kind) - | Float _ -> Error.unimplemented ~details:"pliteral: Float" span - | Bool b -> C.AST.Const_bool b - - let rec pty span (t : ty) : C.AST.ty = - match t with - | TBool -> C.AST.Bool - | TChar -> __TODO_ty__ span "char" - | TInt k -> C.AST.Int (pint_kind k) - | TStr -> __TODO_ty__ span "str" - | TApp { ident = `TupleType 0; args = [] } -> C.AST.Unit - | TApp { ident = `TupleType 1; args = [ GType ty ] } -> pty span ty - | TApp { ident = `TupleType n; args } when n >= 2 -> - C.AST.Product (args_ty span args) - | TApp { ident; args } -> - C.AST.AppTy - (C.AST.NameTy (pglobal_ident ident ^ "_t"), args_ty span args) - | TArrow (inputs, output) -> - List.fold_right ~init:(pty span output) - ~f:(fun x y -> C.AST.Arrow (x, y)) - (List.map ~f:(pty span) inputs) - | TFloat _ -> __TODO_ty__ span "pty: Float" - | TArray { typ; _ } -> - C.AST.ArrayTy (pty span typ, "TODO: Int.to_string length") - | TSlice { ty; _ } -> C.AST.SliceTy (pty span ty) - | TParam i -> C.AST.NameTy i.name - | TAssociatedType _ -> C.AST.WildTy - | TOpaque _ -> __TODO_ty__ span "pty: TAssociatedType/TOpaque" - | _ -> . - - and args_ty span (args : generic_value list) : C.AST.ty list = - (* List.map ~f:pty *) - match args with - | arg :: xs -> - (match arg with - | GLifetime _ -> __TODO_ty__ span "lifetime" - | GType x -> pty span x - | GConst _ -> __TODO_ty__ span "const") - :: args_ty span xs - | [] -> [] - - let rec ppat (p : pat) : C.AST.pat = - match p.p with - | PWild -> C.AST.WildPat - | PAscription { typ; pat; _ } -> - C.AST.AscriptionPat (ppat pat, pty p.span typ) - | PBinding - { - mut = Immutable; - mode = _; - subpat = None; - var; - typ = _ (* we skip type annot here *); - } -> - C.AST.Ident var.name - | POr { subpats } -> C.AST.DisjunctivePat (List.map ~f:ppat subpats) - | PArray _ -> __TODO_pat__ p.span "Parray?" - | PConstruct { constructor = `TupleCons 0; fields = []; _ } -> C.AST.UnitPat - | PConstruct { constructor = `TupleCons 1; fields = [ _ ]; _ } -> - __TODO_pat__ p.span "tuple 1" - | PConstruct { constructor = `TupleCons _n; fields; _ } -> - C.AST.TuplePat (List.map ~f:(fun { pat; _ } -> ppat pat) fields) - | PConstruct { constructor; fields; is_record = true; _ } -> - C.AST.RecordPat (pglobal_ident constructor, pfield_pats fields) - | PConstruct { constructor; fields; is_record = false; _ } -> - C.AST.ConstructorPat - (pglobal_ident constructor, List.map ~f:(fun p -> ppat p.pat) fields) - | PConstant { lit } -> C.AST.Lit (pliteral p.span lit) - | _ -> . - - and pfield_pats (args : field_pat list) : (string * C.AST.pat) list = - match args with - | { field; pat } :: xs -> (pglobal_ident field, ppat pat) :: pfield_pats xs - | _ -> [] - - (* TODO: I guess this should be named `notations` rather than `operators`, for the Coq backend, right? *) - let operators = - let c = Global_ident.of_name Value in - [ - (c Rust_primitives__hax__array_of_list, (3, [ ""; ".["; "]<-"; "" ])); - (c Core__ops__index__Index__index, (2, [ ""; ".["; "]" ])); - (c Core__ops__bit__BitXor__bitxor, (2, [ ""; ".^"; "" ])); - (c Core__ops__bit__BitAnd__bitand, (2, [ ""; ".&"; "" ])); - (c Core__ops__bit__BitOr__bitor, (2, [ ""; ".|"; "" ])); - (c Core__ops__arith__Add__add, (2, [ ""; ".+"; "" ])); - (c Core__ops__arith__Sub__sub, (2, [ ""; ".-"; "" ])); - (c Core__ops__arith__Mul__mul, (2, [ ""; ".*"; "" ])); - (c Core__ops__arith__Div__div, (2, [ ""; "./"; "" ])); - (c Core__cmp__PartialEq__eq, (2, [ ""; "=.?"; "" ])); - (c Core__cmp__PartialOrd__lt, (2, [ ""; "<.?"; "" ])); - (c Core__cmp__PartialOrd__le, (2, [ ""; "<=.?"; "" ])); - (c Core__cmp__PartialOrd__ge, (2, [ ""; ">=.?"; "" ])); - (c Core__cmp__PartialOrd__gt, (2, [ ""; ">.?"; "" ])); - (c Core__cmp__PartialEq__ne, (2, [ ""; "<>"; "" ])); - (c Core__ops__arith__Rem__rem, (2, [ ""; ".%"; "" ])); - (c Core__ops__bit__Shl__shl, (2, [ ""; " shift_left "; "" ])); - (c Core__ops__bit__Shr__shr, (2, [ ""; " shift_right "; "" ])); - (* TODO: those two are not notations/operators at all, right? *) - (* (c "secret_integers::rotate_left", (2, [ "rol "; " "; "" ])); *) - (* (c "hacspec::lib::foldi", (4, [ "foldi "; " "; " "; " "; "" ])); *) - - (* (c "secret_integers::u8", (0, ["U8"])); *) - (* (c "secret_integers::u16", (0, ["U16"])); *) - (* (c "secret_integers::u32", (0, ["U32"])); *) - (* (c "secret_integers::u64", (0, ["U64"])); *) - (* (c "secret_integers::u128", (0, ["U128"])); *) - ] - |> Map.of_alist_exn (module Global_ident) - - let rec pexpr (e : expr) = - try pexpr_unwrapped e - with Diagnostics.SpanFreeError.Exn _ -> - TODOs_debug.__TODO_term__ e.span "failure" - - and pexpr_unwrapped (e : expr) : C.AST.term = - let span = e.span in - match e.e with - | Literal l -> C.AST.Const (pliteral e.span l) - | LocalVar local_ident -> C.AST.NameTerm local_ident.name - | GlobalVar (`TupleCons 0) - | Construct { constructor = `TupleCons 0; fields = []; _ } -> - C.AST.UnitTerm - | GlobalVar global_ident -> C.AST.Var (pglobal_ident global_ident) - | App - { - f = { e = GlobalVar (`Projector (`TupleField _)); _ }; - args = [ _ ]; - _; - } -> - __TODO_term__ span "app global vcar projector tuple" - | App { f = { e = GlobalVar x; _ }; args; _ } when Map.mem operators x -> - let arity, op = Map.find_exn operators x in - if List.length args <> arity then - Error.assertion_failure span "expr: function application: bad arity"; - let args = List.map ~f:(fun x -> C.AST.Value (pexpr x, true, 0)) args in - C.AST.AppFormat (op, args) - (* | App { f = { e = GlobalVar x }; args } -> *) - (* __TODO_term__ span "GLOBAL APP?" *) - | App { f; args; _ } -> - let base = pexpr f in - let args = List.map ~f:pexpr args in - C.AST.App (base, args) - | If { cond; then_; else_ } -> - C.AST.If - ( pexpr cond, - pexpr then_, - Option.value_map else_ ~default:(C.AST.Literal "()") ~f:pexpr ) - | Array l -> C.AST.Array (List.map ~f:pexpr l) - | Let { lhs; rhs; body; monadic } -> - C.AST.Let - { - pattern = ppat lhs; - mut = - (match lhs.p with - | PBinding { mut = Mutable _; _ } -> true - | _ -> false); - value = pexpr rhs; - body = pexpr body; - value_typ = pty span lhs.typ; - monad_typ = - Option.map - ~f:(fun (m, _) -> - match m with - | MException typ -> C.AST.Exception (pty span typ) - | MResult typ -> C.AST.Result (pty span typ) - | MOption -> C.AST.Option) - monadic; - } - | Match { scrutinee; arms } -> - C.AST.Match - ( pexpr scrutinee, - List.map - ~f:(fun { arm = { arm_pat; body; _ }; _ } -> - (ppat arm_pat, pexpr body)) - arms ) - | Ascription _ -> __TODO_term__ span "asciption" - | Construct { constructor = `TupleCons 1; fields = [ (_, e) ]; _ } -> - pexpr e - | Construct { constructor = `TupleCons _n; fields; _ } -> - C.AST.Tuple (List.map ~f:(snd >> pexpr) fields) - | Construct { is_record = true; constructor; fields; _ } -> - (* TODO: handle base *) - C.AST.RecordConstructor - ( pglobal_ident constructor, - List.map ~f:(fun (f, e) -> (pglobal_ident f, pexpr e)) fields ) - | Construct { is_record = false; constructor; fields = [ (_f, e) ]; _ } -> - C.AST.App (C.AST.Var (pglobal_ident constructor), [ pexpr e ]) - | Construct { constructor; _ } -> - (* __TODO_term__ span "constructor" *) - C.AST.Var - (pglobal_ident constructor - ^ C.ty_to_string_without_paren (pty span e.typ)) - | Closure { params; body; _ } -> - C.AST.Lambda (List.map ~f:ppat params, pexpr body) - | MacroInvokation { macro; _ } -> - Error.raise - @@ { - kind = UnsupportedMacro { id = [%show: global_ident] macro }; - span = e.span; - } - | _ -> . - - let pgeneric_param_as_argument span : generic_param -> C.AST.argument = - function - | { ident; kind = GPType; _ } -> - C.AST.Explicit (C.AST.Ident ident.name, C.AST.WildTy) - | _ -> Error.unimplemented ~details:"Coq: TODO: generic_params" span - - let rec pitem (e : item) : C.AST.decl list = - try pitem_unwrapped e - with Diagnostics.SpanFreeError.Exn _ -> - [ C.AST.Unimplemented "item error backend" ] - - and pitem_unwrapped (e : item) : C.AST.decl list = - let span = e.span in - match e.v with - | Fn { name; body; params; _ } -> - [ - C.AST.Definition - ( pconcrete_ident name, - List.map - ~f:(fun { pat; typ; _ } -> - C.AST.Explicit (ppat pat, pty span typ)) - params, - pexpr body, - pty span body.typ ); - ] - | TyAlias { name; ty; _ } -> - [ - C.AST.Notation - ( "'" ^ pconcrete_ident name ^ "_t" ^ "'", - C.AST.Type (pty span ty), - None ); - ] - (* record *) - | Type { name; generics; variants = [ v ]; is_struct = true } -> - [ - (* TODO: generics *) - C.AST.Record - ( U.Concrete_ident_view.to_definition_name name, - List.map ~f:(pgeneric_param_as_argument span) generics.params, - List.map - ~f:(fun (x, y) -> C.AST.Named (x, y)) - (p_record_record span v.arguments) ); - ] - (* enum *) - | Type { name; generics; variants; _ } -> - [ - C.AST.Inductive - ( U.Concrete_ident_view.to_definition_name name, - List.map ~f:(pgeneric_param_as_argument span) generics.params, - p_inductive span variants name ); - ] - (* TODO: this is never matched, now *) - (* | Type { name; generics; variants } -> *) - (* [ *) - (* C.AST.Notation *) - (* ( U.Concrete_ident_view.to_definition_name name, *) - (* C.AST.Product (List.map ~f:snd (p_record span variants name)) ); *) - (* C.AST.Definition *) - (* ( U.Concrete_ident_view.to_definition_name name, *) - (* [], *) - (* C.AST.Var "id", *) - (* C.AST.Arrow *) - (* ( C.AST.Name (U.Concrete_ident_view.to_definition_name name), *) - (* C.AST.Name (U.Concrete_ident_view.to_definition_name name) ) ); *) - (* ] *) - | IMacroInvokation { macro; argument; _ } -> ( - let unsupported () = - let id = [%show: concrete_ident] macro in - Error.raise { kind = UnsupportedMacro { id }; span = e.span } + type ('get_span_data, 'a) object_type = + ('get_span_data, 'a) Base.Gen.object_type + + class printer = + (* let associated_expr = let open m in associated_expr in *) + object (self) + inherit Base.base + + method private primitive_to_string (id : primitive_ident) : document = + match id with + | Deref -> default_document_for "(TODO: Deref)" (* failwith "Deref" *) + | Cast -> string "cast" (* failwith "Cast" *) + | LogicalOp op -> ( + match op with And -> string "andb" | Or -> string "orb") + + (* BEGIN GENERATED *) + method arm ~arm ~span:_ = arm#p + + method arm' ~super:_ ~arm_pat ~body ~guard:_ = + arm_pat#p ^^ space ^^ string "=>" ^^ nest 2 (break 1 ^^ body#p) + + method attrs x1 = default_document_for "attrs" + + method binding_mode_ByRef _x1 _x2 = + default_document_for "binding_mode_ByRef" + + method binding_mode_ByValue = default_document_for "binding_mode_ByValue" + method borrow_kind_Mut _x1 = default_document_for "borrow_kind_Mut" + method borrow_kind_Shared = default_document_for "borrow_kind_Shared" + method borrow_kind_Unique = default_document_for "borrow_kind_Unique" + method common_array x1 = brackets (separate (semi ^^ space) x1) + + method dyn_trait_goal ~trait:_ ~non_self_args:_ = + default_document_for "dyn_trait_goal" + + method error_expr x1 = parens (string x1 ^^ string "(* ERROR_EXPR *)") + method error_item x1 = parens (string x1 ^^ string "(* ERROR_ITEM *)") + method error_pat x1 = parens (string x1 ^^ string "(* ERROR_PAT *)") + + method expr ~e ~span:_ ~typ = + e#p (* parens (e#p ^^ space ^^ colon ^^ space ^^ typ#p) *) + + method expr'_AddressOf ~super:_ ~mut:_ ~e:_ ~witness = + match witness with _ -> . + + method expr'_App_application ~super:_ ~f ~args ~generics:_ = + f#p ^^ concat_map (fun x -> space ^^ parens x#p) args + + method expr'_App_constant ~super:_ ~constant ~generics:_ = constant#p + (* default_document_for "expr'_App_constant" *) + + method expr'_App_field_projection ~super:_ ~field ~e = + (* e#p *) + field#p ^^ space ^^ e#p + (* TODO: Do nothing if is zero *) + + method expr'_App_tuple_projection ~super:_ ~size:_ ~nth:_ ~e:_ = + default_document_for "expr'_App_tuple_projection" + + method expr'_Ascription ~super:_ ~e ~typ = + e#p ^^ space ^^ colon ^^ space ^^ typ#p + + method expr'_Assign ~super:_ ~lhs:_ ~e:_ ~witness = + match witness with _ -> . + + method expr'_Block ~super:_ ~e:_ ~safety_mode:_ ~witness = + match witness with _ -> . + + method expr'_Borrow ~super:_ ~kind:_ ~e:_ ~witness = + match witness with _ -> . + + method expr'_Break ~super:_ ~e:_ ~acc:_ ~label:_ ~witness = + match witness with _ -> . + + method expr'_Closure ~super:_ ~params ~body ~captures:_ = + !^"fun" + ^^ concat_map (fun x -> space ^^ x#p) params + ^^ space ^^ !^"=>" ^^ space + ^^ nest 2 (break 1 ^^ body#p) + + method expr'_Construct_inductive ~super:_ ~constructor ~is_record + ~is_struct ~fields ~base = + if is_struct then + if is_record then + (* Struct *) + Option.value + ~default: + (string "Build_t_" ^^ constructor#p + ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields + ) + (Option.map + ~f:(fun b -> + b#p + ^^ concat_map + (fun (ident, exp) -> + space ^^ string "<|" ^^ space ^^ ident#p ^^ space + ^^ !^":=" ^^ space ^^ parens exp#p ^^ space + ^^ string "|>") + fields + ^^ space) + base) + else + (* Tuple struct *) + string "Build_" ^^ constructor#p + ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields + else + (* Indutive type *) + constructor#p + ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields + + method expr'_Construct_tuple ~super:_ ~components = + if List.length components == 0 then !^"tt" + else parens (separate_map comma (fun x -> x#p) components) + + method expr'_Continue ~super:_ ~acc:_ ~label:_ ~witness = + match witness with _ -> . + + method expr'_EffectAction ~super:_ ~action:_ ~argument:_ = + default_document_for "expr'_EffectAction" + + method expr'_GlobalVar_concrete ~super:_ x2 = x2#p + method expr'_GlobalVar_primitive ~super:_ x2 = self#primitive_to_string x2 + + method expr'_If ~super:_ ~cond ~then_ ~else_ = + string "if" + ^^ nest 2 (break 1 ^^ cond#p) + ^^ break 1 ^^ string "then" + ^^ nest 2 (break 1 ^^ then_#p) + ^^ break 1 ^^ string "else" + ^^ nest 2 + (break 1 ^^ match else_ with Some x -> x#p | None -> string "tt") + + method expr'_Let ~super:_ ~monadic:_ ~lhs ~rhs ~body = + string "let" ^^ space ^^ lhs#p ^^ space ^^ string ":=" ^^ space ^^ rhs#p + ^^ space ^^ string "in" ^^ break 1 ^^ body#p + + method expr'_Literal ~super:_ x2 = x2#p + method expr'_LocalVar ~super:_ x2 = x2#p + + method expr'_Loop ~super:_ ~body ~kind ~state ~control_flow ~label:_ + ~witness:_ = + kind#p ^^ space + ^^ brackets + (Option.value ~default:(string "is_none") + (Option.map ~f:(fun x -> x#p) control_flow)) + ^^ Option.value ~default:(string "default") + (Option.map ~f:(fun x -> x#p) state) + ^^ space ^^ string "of" ^^ space + ^^ parens (nest 2 (break 1 ^^ body#p)) + + method expr'_MacroInvokation ~super:_ ~macro:_ ~args:_ ~witness:_ = + default_document_for "expr'_MacroInvokation" + + method expr'_Match ~super:_ ~scrutinee ~arms = + string "match" ^^ space ^^ scrutinee#p ^^ space ^^ string "with" + ^^ break 1 + ^^ concat_map (fun x -> string "|" ^^ space ^^ x#p ^^ break 1) arms + ^^ string "end" + + method expr'_QuestionMark ~super:_ ~e:_ ~return_typ:_ ~witness = + match witness with _ -> . + + method expr'_Quote ~super:_ _x2 = default_document_for "expr'_Quote" + method expr'_Return ~super:_ ~e:_ ~witness = match witness with _ -> . + + method cf_kind_BreakOrReturn = + default_document_for "cf_kind_BreakOrReturn" + + method cf_kind_BreakOnly = default_document_for "cf_kind_BreakOnly" + method field_pat ~field ~pat = pat#p + (* brackets( string ([%show: global_ident] field) ^^ space ^^ pat#p ) ^^ string "(\* TODO *\)" *) + + method generic_constraint_GCLifetime _x1 _x2 = + default_document_for "generic_constraint_GCLifetime" + + method generic_constraint_GCProjection x1 = string "`" ^^ braces x1#p + method generic_constraint_GCType x1 = string "`" ^^ braces x1#p + + method generic_param ~ident ~span:_ ~attrs:_ ~kind = + string "`" ^^ braces (ident#p ^^ space ^^ colon ^^ space ^^ kind#p) + + method generic_param_kind_GPConst ~typ = typ#p + + method generic_param_kind_GPLifetime ~witness = + match witness with _ -> . + + method generic_param_kind_GPType = string "Type" + method generic_value_GConst x1 = x1#p + + method generic_value_GLifetime ~lt:_ ~witness = + match witness with _ -> . + + method generic_value_GType x1 = parens x1#p + + method generics ~params ~constraints = + let params_document = concat_map (fun x -> space ^^ x#p) params in + let constraints_document = + concat_map (fun x -> space ^^ x#p) constraints + in + params_document ^^ constraints_document + + method guard ~guard:_ ~span:_ = default_document_for "guard" + + method guard'_IfLet ~super:_ ~lhs:_ ~rhs:_ ~witness = + match witness with _ -> . + + method impl_expr ~kind:_ ~goal = goal#p + + method impl_expr_kind_Builtin _x1 = + default_document_for "impl_expr_kind_Builtin" + + method impl_expr_kind_Concrete _x1 = + default_document_for "impl_expr_kind_Concrete" + + method impl_expr_kind_Dyn = default_document_for "impl_expr_kind_Dyn" + + method impl_expr_kind_ImplApp ~impl:_ ~args:_ = + default_document_for "impl_expr_kind_ImplApp" + + method impl_expr_kind_LocalBound ~id:_ = + default_document_for "impl_expr_kind_LocalBound" + + method impl_expr_kind_Parent ~impl:_ ~ident:_ = + default_document_for "impl_expr_kind_Parent" + + method impl_expr_kind_Projection ~impl:_ ~item:_ ~ident:_ = + default_document_for "impl_expr_kind_Projection" + + method impl_expr_kind_Self = default_document_for "impl_expr_kind_Self" + method impl_ident ~goal ~name:_ = goal#p + (* string name ^^ space ^^ colon ^^ space ^^ goal#p *) + (* TODO: include names and do something about numbered names of instance *) + + method impl_item ~ii_span:_ ~ii_generics:_ ~ii_v ~ii_ident ~ii_attrs:_ = + ii_ident#p (* ^^ ii_generics#p *) ^^ space + ^^ string ":=" ^^ space ^^ ii_v#p ^^ semi + + method impl_item'_IIFn ~body ~params = + if List.length params == 0 then body#p + else + string "fun" ^^ space + ^^ concat_map (fun x -> x#p ^^ space) params + ^^ string "=>" + ^^ nest 2 (break 1 ^^ body#p) + + method impl_item'_IIType ~typ ~parent_bounds:_ = typ#p + + method item ~v ~span:_ ~ident:_ ~attrs:_ = + if is_document_empty v#p then empty else v#p ^^ break 1 + + method item'_Alias ~super:_ ~name ~item = + string "Notation" ^^ space ^^ string "\"'" ^^ name#p ^^ string "'\"" + ^^ space ^^ string ":=" ^^ space ^^ parens item#p ^^ dot + + method item'_Fn ~super ~name ~generics ~body ~params ~safety:_ = + (* TODO: Why is type not available here ? *) + let is_rec = + Set.mem + (U.Reducers.collect_concrete_idents#visit_expr () body#v) + name#v + in + let typ = + self#_do_not_override_lazy_of_ty AstPos_item'_Fn_body body#v.typ + in + + let get_expr_of kind f : document = + Attrs.associated_expr kind super.attrs + |> Option.map ~f:(self#entrypoint_expr >> f) + |> Option.value ~default:empty + in + let requires = + get_expr_of Requires (fun x -> + x ^^ space ^^ string "=" ^^ space ^^ string "true") + in + let ensures = + get_expr_of Ensures (fun x -> + x ^^ space ^^ string "=" ^^ space ^^ string "true") + in + + let is_lemma = Attrs.lemma super.attrs in + if is_lemma then + CoqNotation.lemma name#p generics#p + (List.map ~f:(fun x -> x#p) params) + (requires ^^ space ^^ !^"->" ^^ break 1 ^^ ensures) + else if is_rec then + CoqNotation.fixpoint name#p generics#p + (List.map ~f:(fun x -> x#p) params + @ + if is_document_empty requires then [] + else [ string "`" ^^ braces requires ]) + typ#p body#p (* ^^ TODO: ensures? *) + else + CoqNotation.definition name#p generics#p + (List.map ~f:(fun x -> x#p) params + @ + if is_document_empty requires then [] + else [ string "`" ^^ braces requires ]) + typ#p body#p (* ^^ TODO: ensures? *) + + method item'_HaxError ~super:_ _x2 = default_document_for "item'_HaxError" + + method item'_IMacroInvokation ~super:_ ~macro:_ ~argument:_ ~span:_ + ~witness:_ = + default_document_for "item'_IMacroInvokation" + + method item'_Impl ~super ~generics ~self_ty ~of_trait ~items + ~parent_bounds:_ ~safety:_ = + let name, args = of_trait#v in + CoqNotation.instance + (name#p ^^ string "_" ^^ string (Int.to_string ([%hash: item] super))) + generics#p [] + (name#p ^^ concat_map (fun x -> space ^^ parens x#p) args) + (braces + (nest 2 + (concat_map (fun x -> break 1 ^^ name#p ^^ !^"_" ^^ x#p) items) + ^^ break 1)) + + method item'_NotImplementedYet = string "(* NotImplementedYet *)" + + method item'_Quote ~super:_ ~quote:_ ~origin:_ = + default_document_for "item'_Quote" + + method item'_Trait ~super:_ ~name ~generics ~items ~safety:_ = + let _, params, constraints = generics#v in + CoqNotation.class_ name#p generics#p [] !^"Type" + (braces + (nest 2 (concat_map (fun x -> break 1 ^^ x#p) items) ^^ break 1)) + ^^ break 1 ^^ !^"Arguments" ^^ space ^^ name#p ^^ colon + ^^ !^"clear implicits" ^^ dot ^^ break 1 ^^ !^"Arguments" ^^ space + ^^ name#p + ^^ concat_map (fun _ -> space ^^ !^"(_)") params + ^^ concat_map (fun _ -> space ^^ !^"{_}") constraints + ^^ dot + + method item'_TyAlias ~super:_ ~name ~generics:_ ~ty = + string "Notation" ^^ space ^^ string "\"'" ^^ name#p ^^ string "'\"" + ^^ space ^^ string ":=" ^^ space ^^ ty#p ^^ dot + + method item'_Type_struct ~super:_ ~name ~generics ~tuple_struct:_ + ~arguments = + CoqNotation.record name#p generics#p [] (string "Type") + (braces + (nest 2 + (concat_map + (fun (ident, typ, attr) -> + break 1 ^^ ident#p ^^ space ^^ colon ^^ space ^^ typ#p + ^^ semi) + arguments) + ^^ break 1)) + ^^ break 1 ^^ !^"Arguments" ^^ space ^^ name#p ^^ colon + ^^ !^"clear implicits" ^^ dot ^^ break 1 ^^ !^"Arguments" ^^ space + ^^ name#p + ^^ concat_map (fun _ -> space ^^ !^"(_)") generics#v.params + ^^ concat_map (fun _ -> space ^^ !^"{_}") generics#v.constraints + ^^ dot ^^ break 1 ^^ !^"Arguments" ^^ space ^^ !^"Build_" ^^ name#p + ^^ concat_map (fun _ -> space ^^ !^"{_}") generics#v.params + ^^ concat_map (fun _ -> space ^^ !^"{_}") generics#v.constraints + ^^ dot ^^ break 1 ^^ !^"#[export]" ^^ space + ^^ CoqNotation.instance + (string "settable" ^^ string "_" ^^ name#p) + generics#p [] + (!^"Settable" ^^ space ^^ !^"_") + (string "settable!" ^^ space + ^^ parens (!^"@" ^^ !^"Build_" ^^ name#p ^^ generics#p) + ^^ space ^^ string "<" + ^^ separate_map (semi ^^ space) + (fun (ident, typ, attr) -> ident#p) + arguments + ^^ string ">") + + method item'_Type_enum ~super:_ ~name ~generics ~variants = + CoqNotation.inductive name#p generics#p [] (string "Type") + (separate_map (break 1) + (fun x -> string "|" ^^ space ^^ x#p) + variants) + ^^ break 1 ^^ !^"Arguments" ^^ space ^^ name#p ^^ colon + ^^ !^"clear implicits" ^^ dot ^^ break 1 ^^ !^"Arguments" ^^ space + ^^ name#p + ^^ concat_map (fun _ -> space ^^ !^"(_)") generics#v.params + ^^ concat_map (fun _ -> space ^^ !^"{_}") generics#v.constraints + ^^ dot + + method item'_Use ~super:_ ~path ~is_external ~rename:_ = + if List.length path == 0 || is_external then empty + else + let crate = + String.capitalize + (Option.value ~default:"(TODO CRATE)" + (Option.map ~f:fst current_namespace)) + in + let concat_capitalize l = + String.concat ~sep:"_" (List.map ~f:String.capitalize l) + in + let concat_capitalize_include l = + concat_capitalize (List.drop_last_exn l) + ^ " (t_" ^ List.last_exn l ^ ")" + in + let path_string = + match path with + | "crate" :: xs -> concat_capitalize_include (crate :: xs) + | "super" :: xs -> + concat_capitalize + (crate + :: List.drop_last_exn + (Option.value ~default:[] + (Option.map ~f:snd current_namespace)) + @ xs) + | [ a ] -> a + | xs -> concat_capitalize_include xs + in + if String.is_empty path_string then empty + else + string "From" ^^ space ^^ string crate ^^ space + ^^ string "Require Import" ^^ space ^^ string path_string ^^ dot + ^^ break 1 ^^ string "Export" ^^ space ^^ string path_string ^^ dot + + method lhs_LhsArbitraryExpr ~e:_ ~witness = match witness with _ -> . + + method lhs_LhsArrayAccessor ~e:_ ~typ:_ ~index:_ ~witness = + match witness with _ -> . + + method lhs_LhsFieldAccessor_field ~e:_ ~typ:_ ~field:_ ~witness = + match witness with _ -> . + + method lhs_LhsFieldAccessor_tuple ~e:_ ~typ:_ ~nth:_ ~size:_ ~witness = + match witness with _ -> . + + method lhs_LhsLocalVar ~var:_ ~typ:_ = + default_document_for "lhs_LhsLocalVar" + + method literal_Bool x1 = string (if x1 then "true" else "false") + + method literal_Char x1 = + string "\"" ^^ string (Char.escaped x1) ^^ string "\"" ^^ string "%char" + + method literal_Float ~value ~negative:_ ~kind:_ = + string value ^^ string "%float" + + method literal_Int ~value ~negative:_ ~kind:_ = + (* let outer, inner = *) + (* match kind.size with *) + (* | S8 -> ("u8", "U8") *) + (* | S16 -> ("u16", "U16") *) + (* | S32 -> ("u32", "U32") *) + (* | S64 -> ("u64", "U64") *) + (* | S128 -> ("u128", "U128") *) + (* | SSize -> ("usize", "U64") *) + (* (\* Dependens on architecture.. *\) *) + (* in *) + (* string ("Build_t_" ^ outer) *) + (* ^^ space *) + (* ^^ parens *) + (* (string ("Build_t_" ^ inner) *) + (* ^^ space ^^ string value ^^ string "%N") *) + string value + + method literal_String x1 = string "\"" ^^ string x1 ^^ string "\"%string" + + method loop_kind_ForIndexLoop ~start:_ ~end_:_ ~var:_ ~var_typ:_ ~witness + = + default_document_for "loop_kind_ForIndexLoop" + + method loop_kind_ForLoop ~pat ~it ~witness = + braces it#p ^^ space ^^ string "inP?" ^^ space ^^ brackets pat#p + + method loop_kind_UnconditionalLoop = + default_document_for "loop_kind_UnconditionalLoop" + + method loop_kind_WhileLoop ~condition:_ ~witness:_ = + default_document_for "loop_kind_WhileLoop" + + method loop_state ~init ~bpat ~witness:_ = + parens (init#p ^^ space ^^ !^"state" ^^ space ^^ bpat#p) + + method modul _x1 = default_document_for "modul" + + method param ~pat ~typ ~typ_span:_ ~attrs:_ = + parens (pat#p ^^ space ^^ colon ^^ space ^^ typ#p) + + method pat ~p ~span:_ ~typ:_ = p#p + + method pat'_PAscription ~super:_ ~typ ~typ_span:_ ~pat = + pat#p ^^ space ^^ colon ^^ space ^^ typ#p (* Ignore asscription pat? *) + + method pat'_PBinding ~super:_ ~mut:_ ~mode:_ ~var ~typ:_ ~subpat:_ = + var#p (* ^^ space ^^ colon ^^ space ^^ typ#p *) + + method pat'_PConstant ~super:_ ~lit = lit#p + + method pat'_PConstruct_inductive ~super:_ ~constructor ~is_record:_ + ~is_struct ~fields = + (if is_struct then string "Build_t_" else empty) + ^^ constructor#p + ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields + + method pat'_PConstruct_tuple ~super:_ ~components = + (* TODO: Only add `'` if you are a top-level pattern *) + string "'" ^^ parens (separate_map comma (fun x -> x#p) components) + + method pat'_PDeref ~super:_ ~subpat:_ ~witness:_ = + default_document_for "pat'_PDeref" + + (* method pat'_POr ~super ~subpats = *) + (* parens( subpats ) *) + + method pat'_PWild = string "_" + method printer_name = "Coq printer" + + method projection_predicate ~impl:_ ~assoc_item ~typ = + string "_" (* TODO: name of impl#p *) ^^ dot + ^^ parens assoc_item#p ^^ space ^^ string "=" ^^ space ^^ typ#p + + method safety_kind_Safe = default_document_for "safety_kind_Safe" + method safety_kind_Unsafe _x1 = default_document_for "safety_kind_Unsafe" + + method supported_monads_MException _x1 = + default_document_for "supported_monads_MException" + + method supported_monads_MOption = + default_document_for "supported_monads_MOption" + + method supported_monads_MResult _x1 = + default_document_for "supported_monads_MResult" + + method trait_goal ~trait ~args = + trait#p ^^ concat_map (fun x -> space ^^ x#p) args + + method trait_item ~ti_span:_ ~ti_generics ~ti_v ~ti_ident ~ti_attrs:_ = + let _, params, constraints = ti_generics#v in + let generic_params = concat_map (fun x -> space ^^ x#p) params in + let filter_constraints = function + | GCProjection { impl = { goal = { trait; _ }; _ }; _ } -> true + | GCType + { + goal = { trait; args = [ GType (TAssociatedType { item; _ }) ] }; + _; + } -> + Concrete_ident.(item == ti_ident#v) + | _ -> true + in + let generic_constraints_other = + concat_map + (fun x -> space ^^ self#entrypoint_generic_constraint x) + (List.filter ~f:filter_constraints + (List.map ~f:(fun x -> x#v) constraints)) + in + let generic_constraints_self = + concat_map + (fun x -> + break 1 ^^ string "_" ^^ space ^^ string "::" ^^ space + ^^ self#entrypoint_generic_constraint x + ^^ semi) + (List.filter + ~f:(fun x -> not (filter_constraints x)) + (List.map ~f:(fun x -> x#v) constraints)) in - match U.Concrete_ident_view.to_view macro with - | { crate = "hacspec_lib"; path = _; definition = name } -> ( - match name with - | "public_nat_mod" -> - let open Hacspeclib_macro_parser in - let o : PublicNatMod.t = - PublicNatMod.parse argument |> Result.ok_or_failwith - in - [ - C.AST.Notation - ( "'" ^ o.type_name ^ "_t" ^ "'", - C.AST.Type - (C.AST.NatMod - ( o.type_of_canvas, - o.bit_size_of_field, - o.modulo_value )), - None ); - C.AST.Definition - ( o.type_name, - [], - C.AST.Var "id", - C.AST.Arrow - ( C.AST.NameTy (o.type_name ^ "_t"), - C.AST.NameTy (o.type_name ^ "_t") ) ); - ] - | "bytes" -> - let open Hacspeclib_macro_parser in - let o : Bytes.t = - Bytes.parse argument |> Result.ok_or_failwith - in - [ - C.AST.Notation - ( "'" ^ o.bytes_name ^ "_t" ^ "'", - C.AST.Type - (C.AST.ArrayTy - ( C.AST.Int { size = C.AST.U8; signed = false }, - (* int_of_string *) o.size )), - None ); - C.AST.Definition - ( o.bytes_name, - [], - C.AST.Var "id", - C.AST.Arrow - ( C.AST.NameTy (o.bytes_name ^ "_t"), - C.AST.NameTy (o.bytes_name ^ "_t") ) ); - ] - | "unsigned_public_integer" -> - let open Hacspeclib_macro_parser in - let o = - UnsignedPublicInteger.parse argument |> Result.ok_or_failwith - in - [ - C.AST.Notation - ( "'" ^ o.integer_name ^ "_t" ^ "'", - C.AST.Type - (C.AST.ArrayTy - ( C.AST.Int { size = C.AST.U8; signed = false }, - Int.to_string ((o.bits + 7) / 8) )), - None ); - C.AST.Definition - ( o.integer_name, - [], - C.AST.Var "id", - C.AST.Arrow - ( C.AST.NameTy (o.integer_name ^ "_t"), - C.AST.NameTy (o.integer_name ^ "_t") ) ); - ] - | "public_bytes" -> - let open Hacspeclib_macro_parser in - let o : Bytes.t = - Bytes.parse argument |> Result.ok_or_failwith - in - let typ = - C.AST.ArrayTy - ( C.AST.Int { size = C.AST.U8; signed = false }, - (* int_of_string *) o.size ) - in - [ - C.AST.Notation - ("'" ^ o.bytes_name ^ "_t" ^ "'", C.AST.Type typ, None); - C.AST.Definition - ( o.bytes_name, - [], - C.AST.Var "id", - C.AST.Arrow - ( C.AST.NameTy (o.bytes_name ^ "_t"), - C.AST.NameTy (o.bytes_name ^ "_t") ) ); - ] - | "array" -> - let open Hacspeclib_macro_parser in - let o : Array.t = - Array.parse argument |> Result.ok_or_failwith - in - let typ = - match o.typ with - (* Some *) - | "U128" -> C.AST.U128 - (* Some *) - | "U64" -> C.AST.U64 - (* Some *) - | "U32" -> C.AST.U32 - (* Some *) - | "U16" -> C.AST.U16 - (* Some *) - | "U8" -> C.AST.U8 - | _usize -> C.AST.U32 (* TODO: usize? *) - in - [ - C.AST.Notation - ( "'" ^ o.array_name ^ "_t" ^ "'", - C.AST.Type - (C.AST.ArrayTy - ( C.AST.Int { size = typ; signed = false }, - (* int_of_string *) o.size )), - None ); - C.AST.Definition - ( o.array_name, - [], - C.AST.Var "id", - C.AST.Arrow - ( C.AST.NameTy (o.array_name ^ "_t"), - C.AST.NameTy (o.array_name ^ "_t") ) ); - ] - | _ -> unsupported ()) - | _ -> unsupported ()) - | Use { path; is_external; rename } -> - if is_external then [] else [ C.AST.Require (None, path, rename) ] - | HaxError s -> [ __TODO_item__ span s ] - | NotImplementedYet -> [ __TODO_item__ span "Not implemented yet?" ] - | Alias _ -> [ __TODO_item__ span "Not implemented yet? alias" ] - | Trait { name; generics; items } -> - [ - C.AST.Class - ( U.Concrete_ident_view.to_definition_name name, - List.map - ~f:(pgeneric_param_as_argument span) - (match List.rev generics.params with - | _ :: xs -> List.rev xs - | _ -> []), - List.map - ~f:(fun x -> - C.AST.Named - ( U.Concrete_ident_view.to_definition_name x.ti_ident, - match x.ti_v with - | TIFn fn_ty -> pty span fn_ty - | TIDefault _ -> . - | _ -> __TODO_ty__ span "field_ty" )) - items ); - ] - | Impl { generics; self_ty; of_trait = name, gen_vals; items } -> - [ - C.AST.Instance - ( pconcrete_ident name, - List.map ~f:(pgeneric_param_as_argument span) generics.params, - pty span self_ty, - args_ty span gen_vals, - List.map - ~f:(fun x -> - match x.ii_v with - | IIFn { body; params } -> - ( U.Concrete_ident_view.to_definition_name x.ii_ident, - List.map - ~f:(fun { pat; typ; _ } -> - C.AST.Explicit (ppat pat, pty span typ)) - params, - pexpr body, - pty span body.typ ) - | _ -> - ( "todo_name", - [], - __TODO_term__ span "body", - __TODO_ty__ span "typ" )) - items ); - ] - - and p_inductive span variants _parrent_name : C.AST.inductive_case list = - List.map variants ~f:(fun { name; arguments; is_record; _ } -> + ti_ident#p ^^ generic_params ^^ generic_constraints_other ^^ space + ^^ (match ti_v#v with TIDefault _ -> string ":=" | _ -> colon) + ^^ space ^^ ti_v#p ^^ semi ^^ generic_constraints_self + + method trait_item'_TIDefault ~params ~body ~witness:_ = + (if List.is_empty params then empty + else + string "fun" ^^ space + ^^ separate_map space (fun x -> x#p) params + ^^ space ^^ string "=>") + ^^ nest 2 (break 1 ^^ body#p) + (* default_document_for "trait_item'_TIDefault" *) + + method trait_item'_TIFn x1 = x1#p + method trait_item'_TIType x1 = string "Type" + (* TODO, type should implement x1 traits *) + (* concat_map (fun x -> x#p) x1 *) + + method ty_TApp_application ~typ ~generics = + typ#p ^^ concat_map (fun x -> space ^^ parens x#p) generics + + method ty_TApp_tuple ~types = + if List.length types == 0 then string "unit" + else parens (separate_map star (fun x -> self#entrypoint_ty x) types) + + method ty_TArray ~typ ~length = + string "t_Array" ^^ space ^^ parens typ#p ^^ space ^^ parens length#p + + method ty_TArrow x1 x2 = + concat_map (fun x -> x#p ^^ space ^^ string "->" ^^ space) x1 ^^ x2#p + + method ty_TAssociatedType ~impl:_ ~item = item#p + method ty_TBool = string "bool" + method ty_TChar = string "ascii" + method ty_TDyn ~witness:_ ~goals:_ = default_document_for "ty_TDyn" + method ty_TFloat _x1 = string "float" + + method ty_TInt x1 = + string "t_" + ^^ + match x1 with + | { size; signedness } -> ( + (match signedness with + | Unsigned -> string "u" + | Signed -> string "i") + ^^ + match size with + | S8 -> string "8" + | S16 -> string "16" + | S32 -> string "32" + | S64 -> string "64" + | S128 -> string "128" + | SSize -> string "size") + + method ty_TOpaque x1 = x1#p + method ty_TParam x1 = x1#p + method ty_TRawPointer ~witness:_ = default_document_for "ty_TRawPointer" + + method ty_TRef ~witness:_ ~region:_ ~typ:_ ~mut:_ = + default_document_for "ty_TRef" + + method ty_TSlice ~witness:_ ~ty = !^"t_Slice" ^^ space ^^ ty#p + method ty_TStr = string "string" + + method item'_Enum_Variant ~name ~arguments ~is_record ~attrs:_ = if is_record then - C.AST.InductiveCase - ( U.Concrete_ident_view.to_definition_name name, - C.AST.RecordTy - (pconcrete_ident name, p_record_record span arguments) ) + concat_map + (fun (ident, typ, attr) -> + ident#p ^^ space ^^ colon ^^ space ^^ typ#p) + arguments + ^^ semi + else if List.length arguments == 0 then name#p else - let name = U.Concrete_ident_view.to_definition_name name in - match arguments with - | [] -> C.AST.BaseCase name - | [ (_arg_name, arg_ty, _arg_attrs) ] -> - C.AST.InductiveCase (name, pty span arg_ty) - | _ -> - C.AST.InductiveCase - (name, C.AST.Product (List.map ~f:(snd3 >> pty span) arguments))) - (* match variants with _ -> [] *) - (* TODO: I don't get this pattern maching below. Variant with more than one payloads are rejected implicitely? *) - (* | { name; arguments = [ (arg_name, arg_ty) ] } :: xs -> *) - (* if (index_of_field >> Option.is_some) arg_name then *) - (* C.AST.InductiveCase (U.Concrete_ident_view.to_definition_name name, pty span arg_ty) *) - (* :: p_inductive span xs parrent_name *) - (* else *) - (* C.AST.InductiveCase (U.Concrete_ident_view.to_definition_name arg_name, pty span arg_ty) *) - (* :: p_inductive span xs parrent_name *) - (* | { name; arguments = [] } :: xs -> *) - (* C.AST.BaseCase (U.Concrete_ident_view.to_definition_name name) *) - (* :: p_inductive span xs parrent_name *) - (* | { name; arguments } :: xs -> *) - (* C.AST.InductiveCase *) - (* ( U.Concrete_ident_view.to_definition_name name, *) - (* C.AST.RecordTy (pglobal_ident name, p_record_record span arguments) *) - (* ) *) - (* :: p_inductive span xs parrent_name *) - (* | _ -> [] *) - - and p_record_record span arguments : (string * C.AST.ty) list = - List.map - ~f:(function - | arg_name, arg_ty, _arg_attrs -> - (U.Concrete_ident_view.to_definition_name arg_name, pty span arg_ty)) - arguments + name#p ^^ space ^^ colon ^^ space + ^^ separate_map + (space ^^ string "->" ^^ space) + (fun (ident, typ, attr) -> + typ#p + (* parens (ident#p ^^ space ^^ colon ^^ space ^^ typ#p) *)) + arguments + ^^ space ^^ string "->" ^^ space ^^ string "_" + (* END GENERATED *) + + method module_path_separator = "." + + method concrete_ident ~local:_ id : document = + string + (match id.definition with + | "not" -> "negb" + | "eq" -> "t_PartialEq_f_eq" + | "lt" -> "t_PartialOrd_f_lt" + | "gt" -> "t_PartialOrd_f_gt" + | "le" -> "t_PartialOrd_f_le" + | "ge" -> "t_PartialOrd_f_ge" + | "rem" -> "t_Rem_f_rem" + | "add" -> "t_Add_f_add" + | "mul" -> "t_Mul_f_mul" + | "div" -> "t_Div_f_div" + | x -> x) + (* string (String.concat ~sep:"_" (id.crate :: (id.path @ [ id.definition ]))) *) + (* string (String.concat ~sep:"_" (id.definition :: Option.to_list (List.last id.path) )) *) + + (* val mutable current_namespace : (string * string list) option = None *) + end end +class type printer_type = + object + val concrete_ident_view : (module Hax_engine.Concrete_ident.VIEW_API) + val mutable current_namespace : (string * string list) option + + method _do_not_override_expr'_App : + super:expr -> + f:expr Generic_printer.LazyDoc.lazy_doc -> + args:expr Generic_printer.LazyDoc.lazy_doc list -> + generic_args:generic_value Generic_printer.LazyDoc.lazy_doc list -> + bounds_impls:impl_expr Generic_printer.LazyDoc.lazy_doc list -> + trait: + (impl_expr Generic_printer.LazyDoc.lazy_doc + * generic_value Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc + option -> + PPrint.document + + method _do_not_override_expr'_Construct : + super:expr -> + constructor:global_ident -> + is_record:bool -> + is_struct:bool -> + fields: + (global_ident * expr Generic_printer.LazyDoc.lazy_doc) + Generic_printer.LazyDoc.lazy_doc + list -> + base: + (expr Generic_printer.LazyDoc.lazy_doc * InputLanguage.construct_base) + Generic_printer.LazyDoc.lazy_doc + option -> + PPrint.document + + method _do_not_override_expr'_GlobalVar : + super:expr -> global_ident -> PPrint.document + + method _do_not_override_item'_Type : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + variants:variant Generic_printer.LazyDoc.lazy_doc list -> + is_struct:bool -> + PPrint.document + + method _do_not_override_lazy_of_arm : + Generated_generic_printer_base.ast_position -> + arm -> + arm Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_arm' : + super:arm -> + Generated_generic_printer_base.ast_position -> + arm' -> + arm' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_attrs : + Generated_generic_printer_base.ast_position -> + attrs -> + attrs Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_binding_mode : + Generated_generic_printer_base.ast_position -> + binding_mode -> + binding_mode Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_borrow_kind : + Generated_generic_printer_base.ast_position -> + borrow_kind -> + borrow_kind Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_cf_kind : + Generated_generic_printer_base.ast_position -> + cf_kind -> + cf_kind Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_concrete_ident : + Generated_generic_printer_base.ast_position -> + concrete_ident -> + concrete_ident Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_global_ident : + Generated_generic_printer_base.ast_position -> + global_ident -> + global_ident Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_dyn_trait_goal : + Generated_generic_printer_base.ast_position -> + dyn_trait_goal -> + dyn_trait_goal Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_expr : + Generated_generic_printer_base.ast_position -> + expr -> + expr Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_expr' : + super:expr -> + Generated_generic_printer_base.ast_position -> + expr' -> + expr' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_field_pat : + Generated_generic_printer_base.ast_position -> + field_pat -> + field_pat Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_generic_constraint : + Generated_generic_printer_base.ast_position -> + generic_constraint -> + generic_constraint Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_generic_param : + Generated_generic_printer_base.ast_position -> + generic_param -> + generic_param Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_generic_param_kind : + Generated_generic_printer_base.ast_position -> + generic_param_kind -> + generic_param_kind Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_generic_value : + Generated_generic_printer_base.ast_position -> + generic_value -> + generic_value Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_generics : + Generated_generic_printer_base.ast_position -> + generics -> + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_guard : + Generated_generic_printer_base.ast_position -> + guard -> + guard Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_guard' : + super:guard -> + Generated_generic_printer_base.ast_position -> + guard' -> + guard' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_impl_expr : + Generated_generic_printer_base.ast_position -> + impl_expr -> + impl_expr Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_impl_expr_kind : + Generated_generic_printer_base.ast_position -> + impl_expr_kind -> + impl_expr_kind Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_impl_ident : + Generated_generic_printer_base.ast_position -> + impl_ident -> + impl_ident Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_impl_item : + Generated_generic_printer_base.ast_position -> + impl_item -> + impl_item Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_impl_item' : + Generated_generic_printer_base.ast_position -> + impl_item' -> + impl_item' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_item : + Generated_generic_printer_base.ast_position -> + item -> + item Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_item' : + super:item -> + Generated_generic_printer_base.ast_position -> + item' -> + item' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_lhs : + Generated_generic_printer_base.ast_position -> + lhs -> + lhs Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_literal : + Generated_generic_printer_base.ast_position -> + literal -> + literal Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_local_ident : + Generated_generic_printer_base.ast_position -> + local_ident -> + local_ident Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_loop_kind : + Generated_generic_printer_base.ast_position -> + loop_kind -> + loop_kind Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_loop_state : + Generated_generic_printer_base.ast_position -> + loop_state -> + loop_state Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_modul : + Generated_generic_printer_base.ast_position -> + item list -> + item list Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_param : + Generated_generic_printer_base.ast_position -> + param -> + param Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_pat : + Generated_generic_printer_base.ast_position -> + pat -> + pat Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_pat' : + super:pat -> + Generated_generic_printer_base.ast_position -> + pat' -> + pat' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_projection_predicate : + Generated_generic_printer_base.ast_position -> + projection_predicate -> + projection_predicate Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_quote : + Generated_generic_printer_base.ast_position -> + quote -> + quote Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_safety_kind : + Generated_generic_printer_base.ast_position -> + safety_kind -> + safety_kind Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_supported_monads : + Generated_generic_printer_base.ast_position -> + supported_monads -> + supported_monads Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_trait_goal : + Generated_generic_printer_base.ast_position -> + trait_goal -> + trait_goal Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_trait_item : + Generated_generic_printer_base.ast_position -> + trait_item -> + trait_item Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_trait_item' : + Generated_generic_printer_base.ast_position -> + trait_item' -> + trait_item' Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_ty : + Generated_generic_printer_base.ast_position -> + ty -> + ty Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lazy_of_variant : + Generated_generic_printer_base.ast_position -> + variant -> + variant Generic_printer.LazyDoc.lazy_doc + + method _do_not_override_lhs_LhsFieldAccessor : + e:lhs Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + field:global_ident -> + witness:InputLanguage.nontrivial_lhs -> + PPrint.document + + method _do_not_override_pat'_PConstruct : + super:pat -> + constructor:global_ident -> + is_record:bool -> + is_struct:bool -> + fields:field_pat Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method _do_not_override_ty_TApp : + ident:global_ident -> + args:generic_value Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method _do_not_override_variant : + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + arguments: + (concrete_ident Generic_printer.LazyDoc.lazy_doc + * ty Generic_printer.LazyDoc.lazy_doc + * attrs Generic_printer.LazyDoc.lazy_doc) + list -> + is_record:bool -> + attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method arm : + arm:arm' Generic_printer.LazyDoc.lazy_doc -> span:span -> PPrint.document + + method arm' : + super:arm -> + arm_pat:pat Generic_printer.LazyDoc.lazy_doc -> + body:expr Generic_printer.LazyDoc.lazy_doc -> + guard:guard Generic_printer.LazyDoc.lazy_doc option -> + PPrint.document + + method assertion_failure : string -> 'any + method attrs : attr list -> PPrint.document + + method binding_mode_ByRef : + borrow_kind Generic_printer.LazyDoc.lazy_doc -> + InputLanguage.reference -> + PPrint.document + + method binding_mode_ByValue : PPrint.document + method borrow_kind_Mut : InputLanguage.mutable_reference -> PPrint.document + method borrow_kind_Shared : PPrint.document + method borrow_kind_Unique : PPrint.document + + method catch_exn : + (string -> PPrint.document) -> + (unit -> PPrint.document) -> + PPrint.document + + method private catch_exn' : + (Diagnostics.Context.t -> Diagnostics.kind -> PPrint.document) -> + (unit -> PPrint.document) -> + PPrint.document + + method cf_kind_BreakOnly : PPrint.document + method cf_kind_BreakOrReturn : PPrint.document + method common_array : PPrint.document list -> PPrint.document + method concrete_ident : local:bool -> Concrete_ident.view -> PPrint.document + method current_span : span + + method dyn_trait_goal : + trait:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + non_self_args:generic_value Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method entrypoint_arm : arm -> PPrint.document + method entrypoint_attrs : attrs -> PPrint.document + method entrypoint_binding_mode : binding_mode -> PPrint.document + method entrypoint_borrow_kind : borrow_kind -> PPrint.document + method entrypoint_cf_kind : cf_kind -> PPrint.document + method entrypoint_dyn_trait_goal : dyn_trait_goal -> PPrint.document + method entrypoint_expr : expr -> PPrint.document + method entrypoint_field_pat : field_pat -> PPrint.document + method entrypoint_generic_constraint : generic_constraint -> PPrint.document + method entrypoint_generic_param : generic_param -> PPrint.document + method entrypoint_generic_param_kind : generic_param_kind -> PPrint.document + method entrypoint_generic_value : generic_value -> PPrint.document + method entrypoint_generics : generics -> PPrint.document + method entrypoint_guard : guard -> PPrint.document + method entrypoint_impl_expr : impl_expr -> PPrint.document + method entrypoint_impl_expr_kind : impl_expr_kind -> PPrint.document + method entrypoint_impl_ident : impl_ident -> PPrint.document + method entrypoint_impl_item : impl_item -> PPrint.document + method entrypoint_impl_item' : impl_item' -> PPrint.document + method entrypoint_item : item -> PPrint.document + method entrypoint_lhs : lhs -> PPrint.document + method entrypoint_literal : literal -> PPrint.document + method entrypoint_loop_kind : loop_kind -> PPrint.document + method entrypoint_loop_state : loop_state -> PPrint.document + method entrypoint_modul : item list -> PPrint.document + method entrypoint_param : param -> PPrint.document + method entrypoint_pat : pat -> PPrint.document + + method entrypoint_projection_predicate : + projection_predicate -> PPrint.document + + method entrypoint_safety_kind : safety_kind -> PPrint.document + method entrypoint_supported_monads : supported_monads -> PPrint.document + method entrypoint_trait_goal : trait_goal -> PPrint.document + method entrypoint_trait_item : trait_item -> PPrint.document + method entrypoint_trait_item' : trait_item' -> PPrint.document + method entrypoint_ty : ty -> PPrint.document + method entrypoint_variant : variant -> PPrint.document + method error_expr : string -> PPrint.document + method error_item : string -> PPrint.document + method error_pat : string -> PPrint.document + + method expr : + e:expr' Generic_printer.LazyDoc.lazy_doc -> + span:span -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_AddressOf : + super:expr -> + mut:InputLanguage.mutable_pointer mutability -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.raw_pointer -> + PPrint.document + + method expr'_App_application : + super:expr -> + f:expr Generic_printer.LazyDoc.lazy_doc -> + args:expr Generic_printer.LazyDoc.lazy_doc list -> + generics:generic_value Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method expr'_App_constant : + super:expr -> + constant:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics:generic_value Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method expr'_App_field_projection : + super:expr -> + field:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_App_tuple_projection : + super:expr -> + size:int -> + nth:int -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_Array : + super:expr -> + expr Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method expr'_Ascription : + super:expr -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_Assign : + super:expr -> + lhs:lhs Generic_printer.LazyDoc.lazy_doc -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.mutable_variable -> + PPrint.document + + method expr'_Block : + super:expr -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + safety_mode:safety_kind Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.block -> + PPrint.document + + method expr'_Borrow : + super:expr -> + kind:borrow_kind Generic_printer.LazyDoc.lazy_doc -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.reference -> + PPrint.document + + method expr'_Break : + super:expr -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + acc: + (expr Generic_printer.LazyDoc.lazy_doc + * InputLanguage.state_passing_loop) + Generic_printer.LazyDoc.lazy_doc + option -> + label:string option -> + witness:InputLanguage.break * InputLanguage.loop -> + PPrint.document + + method expr'_Closure : + super:expr -> + params:pat Generic_printer.LazyDoc.lazy_doc list -> + body:expr Generic_printer.LazyDoc.lazy_doc -> + captures:expr Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method expr'_Construct_inductive : + super:expr -> + constructor:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + is_record:bool -> + is_struct:bool -> + fields: + (concrete_ident Generic_printer.LazyDoc.lazy_doc + * expr Generic_printer.LazyDoc.lazy_doc) + list -> + base: + (expr Generic_printer.LazyDoc.lazy_doc * InputLanguage.construct_base) + Generic_printer.LazyDoc.lazy_doc + option -> + PPrint.document + + method expr'_Construct_tuple : + super:expr -> + components:expr Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method expr'_Continue : + super:expr -> + acc: + (expr Generic_printer.LazyDoc.lazy_doc + * InputLanguage.state_passing_loop) + Generic_printer.LazyDoc.lazy_doc + option -> + label:string option -> + witness:InputLanguage.continue * InputLanguage.loop -> + PPrint.document + + method expr'_EffectAction : + super:expr -> + action:InputLanguage.monadic_action -> + argument:expr Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_GlobalVar_concrete : + super:expr -> + concrete_ident Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_GlobalVar_primitive : + super:expr -> primitive_ident -> PPrint.document + + method expr'_If : + super:expr -> + cond:expr Generic_printer.LazyDoc.lazy_doc -> + then_:expr Generic_printer.LazyDoc.lazy_doc -> + else_:expr Generic_printer.LazyDoc.lazy_doc option -> + PPrint.document + + method expr'_Let : + super:expr -> + monadic: + (supported_monads Generic_printer.LazyDoc.lazy_doc + * InputLanguage.monadic_binding) + Generic_printer.LazyDoc.lazy_doc + option -> + lhs:pat Generic_printer.LazyDoc.lazy_doc -> + rhs:expr Generic_printer.LazyDoc.lazy_doc -> + body:expr Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_Literal : + super:expr -> literal Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method expr'_LocalVar : + super:expr -> + local_ident Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method expr'_Loop : + super:expr -> + body:expr Generic_printer.LazyDoc.lazy_doc -> + kind:loop_kind Generic_printer.LazyDoc.lazy_doc -> + state:loop_state Generic_printer.LazyDoc.lazy_doc option -> + control_flow: + (cf_kind Generic_printer.LazyDoc.lazy_doc + * InputLanguage.fold_like_loop) + Generic_printer.LazyDoc.lazy_doc + option -> + label:string option -> + witness:InputLanguage.loop -> + PPrint.document + + method expr'_MacroInvokation : + super:expr -> + macro:global_ident -> + args:string -> + witness:InputLanguage.macro -> + PPrint.document + + method expr'_Match : + super:expr -> + scrutinee:expr Generic_printer.LazyDoc.lazy_doc -> + arms:arm Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method expr'_QuestionMark : + super:expr -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + return_typ:ty Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.question_mark -> + PPrint.document + + method expr'_Quote : + super:expr -> quote Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method expr'_Return : + super:expr -> + e:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.early_exit -> + PPrint.document + + method field_pat : + field:global_ident -> + pat:pat Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method generic_constraint_GCLifetime : + string -> InputLanguage.lifetime -> PPrint.document + + method generic_constraint_GCProjection : + projection_predicate Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method generic_constraint_GCType : + impl_ident Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method generic_param : + ident:local_ident Generic_printer.LazyDoc.lazy_doc -> + span:span -> + attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + kind:generic_param_kind Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method generic_param_kind_GPConst : + typ:ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method generic_param_kind_GPLifetime : + witness:InputLanguage.lifetime -> PPrint.document + + method generic_param_kind_GPType : PPrint.document + + method generic_value_GConst : + expr Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method generic_value_GLifetime : + lt:string -> witness:InputLanguage.lifetime -> PPrint.document + + method generic_value_GType : + ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method generics : + params:generic_param Generic_printer.LazyDoc.lazy_doc list -> + constraints:generic_constraint Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method guard : + guard:guard' Generic_printer.LazyDoc.lazy_doc -> + span:span -> + PPrint.document + + method guard'_IfLet : + super:guard -> + lhs:pat Generic_printer.LazyDoc.lazy_doc -> + rhs:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.match_guard -> + PPrint.document + + method impl_expr : + kind:impl_expr_kind Generic_printer.LazyDoc.lazy_doc -> + goal:trait_goal Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method impl_expr_kind_Builtin : + trait_goal Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method impl_expr_kind_Concrete : + trait_goal Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method impl_expr_kind_Dyn : PPrint.document + + method impl_expr_kind_ImplApp : + impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> + args:impl_expr Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method impl_expr_kind_LocalBound : id:string -> PPrint.document + + method impl_expr_kind_Parent : + impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> + ident:impl_ident Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method impl_expr_kind_Projection : + impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> + item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + ident:impl_ident Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method impl_expr_kind_Self : PPrint.document + + method impl_ident : + goal:trait_goal Generic_printer.LazyDoc.lazy_doc -> + name:string -> + PPrint.document + + method impl_item : + ii_span:span -> + ii_generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + ii_v:impl_item' Generic_printer.LazyDoc.lazy_doc -> + ii_ident:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + ii_attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method impl_item'_IIFn : + body:expr Generic_printer.LazyDoc.lazy_doc -> + params:param Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method impl_item'_IIType : + typ:ty Generic_printer.LazyDoc.lazy_doc -> + parent_bounds: + (impl_expr Generic_printer.LazyDoc.lazy_doc + * impl_ident Generic_printer.LazyDoc.lazy_doc) + list -> + PPrint.document + + method item : + v:item' Generic_printer.LazyDoc.lazy_doc -> + span:span -> + ident:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_Alias : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_Enum_Variant : + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + arguments: + (concrete_ident Generic_printer.LazyDoc.lazy_doc + * ty Generic_printer.LazyDoc.lazy_doc + * attrs Generic_printer.LazyDoc.lazy_doc) + list -> + is_record:bool -> + attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_Fn : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + body:expr Generic_printer.LazyDoc.lazy_doc -> + params:param Generic_printer.LazyDoc.lazy_doc list -> + safety:safety_kind Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_HaxError : super:item -> string -> PPrint.document + + method item'_IMacroInvokation : + super:item -> + macro:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + argument:string -> + span:span -> + witness:InputLanguage.macro -> + PPrint.document + + method item'_Impl : + super:item -> + generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + self_ty:ty Generic_printer.LazyDoc.lazy_doc -> + of_trait: + (concrete_ident Generic_printer.LazyDoc.lazy_doc + * generic_value Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + items:impl_item Generic_printer.LazyDoc.lazy_doc list -> + parent_bounds: + (impl_expr Generic_printer.LazyDoc.lazy_doc + * impl_ident Generic_printer.LazyDoc.lazy_doc) + list -> + safety:safety_kind Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_NotImplementedYet : PPrint.document + + method item'_Quote : + super:item -> + quote:quote Generic_printer.LazyDoc.lazy_doc -> + origin:item_quote_origin -> + PPrint.document + + method item'_Trait : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + items:trait_item Generic_printer.LazyDoc.lazy_doc list -> + safety:safety_kind Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_TyAlias : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + ty:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method item'_Type_enum : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics:generics Generic_printer.LazyDoc.lazy_doc -> + variants:variant Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method item'_Type_struct : + super:item -> + name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics:generics Generic_printer.LazyDoc.lazy_doc -> + tuple_struct:bool -> + arguments: + (concrete_ident Generic_printer.LazyDoc.lazy_doc + * ty Generic_printer.LazyDoc.lazy_doc + * attr list Generic_printer.LazyDoc.lazy_doc) + list -> + PPrint.document + + method item'_Use : + super:item -> + path:string list -> + is_external:bool -> + rename:string option -> + PPrint.document + + method lhs_LhsArbitraryExpr : + e:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.arbitrary_lhs -> + PPrint.document + + method lhs_LhsArrayAccessor : + e:lhs Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + index:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.nontrivial_lhs -> + PPrint.document + + method lhs_LhsFieldAccessor_field : + e:lhs Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + field:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.nontrivial_lhs -> + PPrint.document + + method lhs_LhsFieldAccessor_tuple : + e:lhs Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + nth:int -> + size:int -> + witness:InputLanguage.nontrivial_lhs -> + PPrint.document + + method lhs_LhsLocalVar : + var:local_ident -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method literal_Bool : bool -> PPrint.document + method literal_Char : Prelude.char -> PPrint.document + + method literal_Float : + value:string -> negative:bool -> kind:float_kind -> PPrint.document + + method literal_Int : + value:string -> negative:bool -> kind:int_kind -> PPrint.document + + method literal_String : string -> PPrint.document + method local_ident : local_ident -> PPrint.document + + method loop_kind_ForIndexLoop : + start:expr Generic_printer.LazyDoc.lazy_doc -> + end_:expr Generic_printer.LazyDoc.lazy_doc -> + var:local_ident Generic_printer.LazyDoc.lazy_doc -> + var_typ:ty Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.for_index_loop -> + PPrint.document + + method loop_kind_ForLoop : + pat:pat Generic_printer.LazyDoc.lazy_doc -> + it:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.for_loop -> + PPrint.document + + method loop_kind_UnconditionalLoop : PPrint.document + + method loop_kind_WhileLoop : + condition:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.while_loop -> + PPrint.document + + method loop_state : + init:expr Generic_printer.LazyDoc.lazy_doc -> + bpat:pat Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.state_passing_loop -> + PPrint.document + + method modul : item Generic_printer.LazyDoc.lazy_doc list -> PPrint.document + method module_path_separator : string + + method param : + pat:pat Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + typ_span:span option -> + attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method pat : + p:pat' Generic_printer.LazyDoc.lazy_doc -> + span:span -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method pat'_PArray : + super:pat -> + args:pat Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method pat'_PAscription : + super:pat -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + typ_span:span -> + pat:pat Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method pat'_PBinding : + super:pat -> + mut:InputLanguage.mutable_variable mutability -> + mode:binding_mode Generic_printer.LazyDoc.lazy_doc -> + var:local_ident Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + subpat: + (pat Generic_printer.LazyDoc.lazy_doc * InputLanguage.as_pattern) + Generic_printer.LazyDoc.lazy_doc + option -> + PPrint.document + + method pat'_PConstant : + super:pat -> + lit:literal Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method pat'_PConstruct_inductive : + super:pat -> + constructor:global_ident Generic_printer.LazyDoc.lazy_doc -> + is_record:bool -> + is_struct:bool -> + fields: + (global_ident Generic_printer.LazyDoc.lazy_doc + * pat Generic_printer.LazyDoc.lazy_doc) + list -> + PPrint.document + + method pat'_PConstruct_tuple : + super:pat -> + components:pat Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method pat'_PDeref : + super:pat -> + subpat:pat Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.reference -> + PPrint.document + + method pat'_POr : + super:pat -> + subpats:pat Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method pat'_PWild : PPrint.document + + method print_arm : + Generated_generic_printer_base.ast_position -> arm -> PPrint.document + + method print_attrs : + Generated_generic_printer_base.ast_position -> attrs -> PPrint.document + + method print_binding_mode : + Generated_generic_printer_base.ast_position -> + binding_mode -> + PPrint.document + + method print_borrow_kind : + Generated_generic_printer_base.ast_position -> + borrow_kind -> + PPrint.document + + method print_cf_kind : + Generated_generic_printer_base.ast_position -> cf_kind -> PPrint.document + + method print_dyn_trait_goal : + Generated_generic_printer_base.ast_position -> + dyn_trait_goal -> + PPrint.document + + method print_expr : + Generated_generic_printer_base.ast_position -> expr -> PPrint.document + + method print_field_pat : + Generated_generic_printer_base.ast_position -> + field_pat -> + PPrint.document + + method print_generic_constraint : + Generated_generic_printer_base.ast_position -> + generic_constraint -> + PPrint.document + + method print_generic_param : + Generated_generic_printer_base.ast_position -> + generic_param -> + PPrint.document + + method print_generic_param_kind : + Generated_generic_printer_base.ast_position -> + generic_param_kind -> + PPrint.document + + method print_generic_value : + Generated_generic_printer_base.ast_position -> + generic_value -> + PPrint.document + + method print_generics : + Generated_generic_printer_base.ast_position -> generics -> PPrint.document + + method print_guard : + Generated_generic_printer_base.ast_position -> guard -> PPrint.document + + method print_impl_expr : + Generated_generic_printer_base.ast_position -> + impl_expr -> + PPrint.document + + method print_impl_expr_kind : + Generated_generic_printer_base.ast_position -> + impl_expr_kind -> + PPrint.document + + method print_impl_ident : + Generated_generic_printer_base.ast_position -> + impl_ident -> + PPrint.document + + method print_impl_item : + Generated_generic_printer_base.ast_position -> + impl_item -> + PPrint.document + + method print_impl_item' : + Generated_generic_printer_base.ast_position -> + impl_item' -> + PPrint.document + + method print_item : + Generated_generic_printer_base.ast_position -> item -> PPrint.document + + method print_lhs : + Generated_generic_printer_base.ast_position -> lhs -> PPrint.document + + method print_literal : + Generated_generic_printer_base.ast_position -> literal -> PPrint.document + + method print_loop_kind : + Generated_generic_printer_base.ast_position -> + loop_kind -> + PPrint.document + + method print_loop_state : + Generated_generic_printer_base.ast_position -> + loop_state -> + PPrint.document + + method print_modul : + Generated_generic_printer_base.ast_position -> + item list -> + PPrint.document + + method print_param : + Generated_generic_printer_base.ast_position -> param -> PPrint.document + + method print_pat : + Generated_generic_printer_base.ast_position -> pat -> PPrint.document + + method print_projection_predicate : + Generated_generic_printer_base.ast_position -> + projection_predicate -> + PPrint.document + + method print_safety_kind : + Generated_generic_printer_base.ast_position -> + safety_kind -> + PPrint.document + + method print_supported_monads : + Generated_generic_printer_base.ast_position -> + supported_monads -> + PPrint.document + + method print_trait_goal : + Generated_generic_printer_base.ast_position -> + trait_goal -> + PPrint.document + + method print_trait_item : + Generated_generic_printer_base.ast_position -> + trait_item -> + PPrint.document + + method print_trait_item' : + Generated_generic_printer_base.ast_position -> + trait_item' -> + PPrint.document + + method print_ty : + Generated_generic_printer_base.ast_position -> ty -> PPrint.document + + method print_variant : + Generated_generic_printer_base.ast_position -> variant -> PPrint.document + + method printer_name : string + + method projection_predicate : + impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> + assoc_item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method quote : quote -> PPrint.document + method safety_kind_Safe : PPrint.document + method safety_kind_Unsafe : InputLanguage.unsafe -> PPrint.document + method span_data : Generic_printer.Annotation.t list + + method supported_monads_MException : + ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method supported_monads_MOption : PPrint.document + + method supported_monads_MResult : + ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method trait_goal : + trait:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + args:generic_value Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method trait_item : + ti_span:span -> + ti_generics: + (generics Generic_printer.LazyDoc.lazy_doc + * generic_param Generic_printer.LazyDoc.lazy_doc list + * generic_constraint Generic_printer.LazyDoc.lazy_doc list) + Generic_printer.LazyDoc.lazy_doc -> + ti_v:trait_item' Generic_printer.LazyDoc.lazy_doc -> + ti_ident:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + ti_attrs:attrs Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method trait_item'_TIDefault : + params:param Generic_printer.LazyDoc.lazy_doc list -> + body:expr Generic_printer.LazyDoc.lazy_doc -> + witness:InputLanguage.trait_item_default -> + PPrint.document + + method trait_item'_TIFn : + ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method trait_item'_TIType : + impl_ident Generic_printer.LazyDoc.lazy_doc list -> PPrint.document + + method ty_TApp_application : + typ:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + generics:generic_value Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method ty_TApp_tuple : types:ty list -> PPrint.document + + method ty_TArray : + typ:ty Generic_printer.LazyDoc.lazy_doc -> + length:expr Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method ty_TArrow : + ty Generic_printer.LazyDoc.lazy_doc list -> + ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method ty_TAssociatedType : + impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> + item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method ty_TBool : PPrint.document + method ty_TChar : PPrint.document + + method ty_TDyn : + witness:InputLanguage.dyn -> + goals:dyn_trait_goal Generic_printer.LazyDoc.lazy_doc list -> + PPrint.document + + method ty_TFloat : float_kind -> PPrint.document + method ty_TInt : int_kind -> PPrint.document + + method ty_TOpaque : + concrete_ident Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method ty_TParam : + local_ident Generic_printer.LazyDoc.lazy_doc -> PPrint.document + + method ty_TRawPointer : witness:InputLanguage.raw_pointer -> PPrint.document + + method ty_TRef : + witness:InputLanguage.reference -> + region:string -> + typ:ty Generic_printer.LazyDoc.lazy_doc -> + mut:InputLanguage.mutable_reference mutability -> + PPrint.document + + method ty_TSlice : + witness:InputLanguage.slice -> + ty:ty Generic_printer.LazyDoc.lazy_doc -> + PPrint.document + + method ty_TStr : PPrint.document + method unreachable : unit -> 'any + method with_span : span:span -> (unit -> PPrint.document) -> PPrint.document + + method wrap_arm : + Generated_generic_printer_base.ast_position -> + arm -> + PPrint.document -> + PPrint.document + + method wrap_arm' : + Generated_generic_printer_base.ast_position -> + arm' -> + PPrint.document -> + PPrint.document + + method wrap_attrs : + Generated_generic_printer_base.ast_position -> + attrs -> + PPrint.document -> + PPrint.document + + method wrap_binding_mode : + Generated_generic_printer_base.ast_position -> + binding_mode -> + PPrint.document -> + PPrint.document + + method wrap_borrow_kind : + Generated_generic_printer_base.ast_position -> + borrow_kind -> + PPrint.document -> + PPrint.document + + method wrap_cf_kind : + Generated_generic_printer_base.ast_position -> + cf_kind -> + PPrint.document -> + PPrint.document + + method wrap_dyn_trait_goal : + Generated_generic_printer_base.ast_position -> + dyn_trait_goal -> + PPrint.document -> + PPrint.document + + method wrap_expr : + Generated_generic_printer_base.ast_position -> + expr -> + PPrint.document -> + PPrint.document + + method wrap_expr' : + Generated_generic_printer_base.ast_position -> + expr' -> + PPrint.document -> + PPrint.document + + method wrap_field_pat : + Generated_generic_printer_base.ast_position -> + field_pat -> + PPrint.document -> + PPrint.document + + method wrap_generic_constraint : + Generated_generic_printer_base.ast_position -> + generic_constraint -> + PPrint.document -> + PPrint.document + + method wrap_generic_param : + Generated_generic_printer_base.ast_position -> + generic_param -> + PPrint.document -> + PPrint.document + + method wrap_generic_param_kind : + Generated_generic_printer_base.ast_position -> + generic_param_kind -> + PPrint.document -> + PPrint.document + + method wrap_generic_value : + Generated_generic_printer_base.ast_position -> + generic_value -> + PPrint.document -> + PPrint.document + + method wrap_generics : + Generated_generic_printer_base.ast_position -> + generics -> + PPrint.document -> + PPrint.document + + method wrap_guard : + Generated_generic_printer_base.ast_position -> + guard -> + PPrint.document -> + PPrint.document + + method wrap_guard' : + Generated_generic_printer_base.ast_position -> + guard' -> + PPrint.document -> + PPrint.document + + method wrap_impl_expr : + Generated_generic_printer_base.ast_position -> + impl_expr -> + PPrint.document -> + PPrint.document + + method wrap_impl_expr_kind : + Generated_generic_printer_base.ast_position -> + impl_expr_kind -> + PPrint.document -> + PPrint.document + + method wrap_impl_ident : + Generated_generic_printer_base.ast_position -> + impl_ident -> + PPrint.document -> + PPrint.document + + method wrap_impl_item : + Generated_generic_printer_base.ast_position -> + impl_item -> + PPrint.document -> + PPrint.document + + method wrap_impl_item' : + Generated_generic_printer_base.ast_position -> + impl_item' -> + PPrint.document -> + PPrint.document + + method wrap_item : + Generated_generic_printer_base.ast_position -> + item -> + PPrint.document -> + PPrint.document + + method wrap_item' : + Generated_generic_printer_base.ast_position -> + item' -> + PPrint.document -> + PPrint.document + + method wrap_lhs : + Generated_generic_printer_base.ast_position -> + lhs -> + PPrint.document -> + PPrint.document + + method wrap_literal : + Generated_generic_printer_base.ast_position -> + literal -> + PPrint.document -> + PPrint.document + + method wrap_loop_kind : + Generated_generic_printer_base.ast_position -> + loop_kind -> + PPrint.document -> + PPrint.document + + method wrap_loop_state : + Generated_generic_printer_base.ast_position -> + loop_state -> + PPrint.document -> + PPrint.document + + method wrap_modul : + Generated_generic_printer_base.ast_position -> + item list -> + PPrint.document -> + PPrint.document + + method wrap_param : + Generated_generic_printer_base.ast_position -> + param -> + PPrint.document -> + PPrint.document + + method wrap_pat : + Generated_generic_printer_base.ast_position -> + pat -> + PPrint.document -> + PPrint.document + + method wrap_pat' : + Generated_generic_printer_base.ast_position -> + pat' -> + PPrint.document -> + PPrint.document + + method wrap_projection_predicate : + Generated_generic_printer_base.ast_position -> + projection_predicate -> + PPrint.document -> + PPrint.document + + method wrap_safety_kind : + Generated_generic_printer_base.ast_position -> + safety_kind -> + PPrint.document -> + PPrint.document + + method wrap_supported_monads : + Generated_generic_printer_base.ast_position -> + supported_monads -> + PPrint.document -> + PPrint.document + + method wrap_trait_goal : + Generated_generic_printer_base.ast_position -> + trait_goal -> + PPrint.document -> + PPrint.document + + method wrap_trait_item : + Generated_generic_printer_base.ast_position -> + trait_item -> + PPrint.document -> + PPrint.document + + method wrap_trait_item' : + Generated_generic_printer_base.ast_position -> + trait_item' -> + PPrint.document -> + PPrint.document + + method wrap_ty : + Generated_generic_printer_base.ast_position -> + ty -> + PPrint.document -> + PPrint.document + + method wrap_variant : + Generated_generic_printer_base.ast_position -> + variant -> + PPrint.document -> + PPrint.document + end + module type S = sig - val pitem : item -> C.AST.decl list + class printer : printer_type end -let make ctx = - (module Make (struct - let ctx = ctx - end) : S) +let make (module M : Attrs.WITH_ITEMS) = + (module Make + (struct + let default x = x + end) + (M) : S) -let string_of_item (item : item) : string = - let (module Print) = - make { current_namespace = U.Concrete_ident_view.to_namespace item.ident } - in - List.map ~f:C.decl_to_string @@ Print.pitem item |> String.concat ~sep:"\n" +module ASTGen = Ast_utils.ASTGenerator (InputLanguage) -let string_of_items : AST.item list -> string = - List.map ~f:string_of_item >> List.map ~f:String.strip - >> List.filter ~f:(String.is_empty >> not) - >> String.concat ~sep:"\n\n" +let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = + let (module Printer) = make m in + let my_printer = new Printer.printer in -let hardcoded_coq_headers = - "(* File automatically generated by Hacspec *)\n\ - From Hacspec Require Import Hacspec_Lib MachineIntegers.\n\ - From Coq Require Import ZArith.\n\ - Import List.ListNotations.\n\ - Open Scope Z_scope.\n\ - Open Scope bool_scope.\n" - -let translate _ (_bo : BackendOptions.t) ~(bundles : AST.item list list) - (items : AST.item list) : Types.file list = U.group_items_by_namespace items |> Map.to_alist |> List.map ~f:(fun (ns, items) -> @@ -694,9 +2333,94 @@ let translate _ (_bo : BackendOptions.t) ~(bundles : AST.item list list) { path = mod_name ^ ".v"; contents = - hardcoded_coq_headers ^ "\n" ^ string_of_items items ^ "\n"; + hardcoded_coq_headers ^ "\n" + ^ String.concat ~sep:"\n" + (List.map + ~f:(fun item -> + let buf = Buffer.create 0 in + PPrint.ToBuffer.pretty 1.0 80 buf + (my_printer#entrypoint_item item); + Buffer.contents buf) + items); sourcemap = None; }) +(* @ ( *) +(* (\* let (my_literals, my_tys, my_pats, my_exprs, my_items) : literal list * ty list * pat list * expr list * item list = ASTGen.generate_full_ast () in *\) *) +(* let my_literals : literal list = ASTGen.generate_flat_literals () in *) +(* let literal_str = *) +(* String.concat ~sep:"\n" *) +(* (List.map *) +(* ~f:(fun literal -> *) +(* let buf = Buffer.create 0 in *) +(* PPrint.ToBuffer.pretty 1.0 80 buf *) +(* (my_printer#entrypoint_literal literal); *) +(* "Check" ^ " " ^ Buffer.contents buf ^ ".") *) +(* (my_literals)) *) +(* in *) + +(* let my_tys : ty list = ASTGen.generate_flat_tys () (\* 1 *\) in *) +(* let ty_str = *) +(* String.concat ~sep:"\n" *) +(* (List.map *) +(* ~f:(fun ty -> *) +(* let buf = Buffer.create 0 in *) +(* PPrint.ToBuffer.pretty 1.0 80 buf *) +(* (my_printer#entrypoint_ty ty); *) +(* "Check" ^ " " ^ Buffer.contents buf ^ ".") *) +(* (my_tys)) *) +(* in *) + +(* let my_pats : pat list = ASTGen.generate_flat_pats (\* 1 *\) () in *) +(* let pat_str = *) +(* String.concat ~sep:"\n" *) +(* (List.map *) +(* ~f:(fun pat -> *) +(* let buf = Buffer.create 0 in *) +(* PPrint.ToBuffer.pretty 1.0 80 buf *) +(* (my_printer#entrypoint_pat pat); *) +(* "Check match _ with | " ^ " " ^ Buffer.contents buf ^ " => _ | _ => _ end.") *) +(* (my_pats)) *) +(* in *) + +(* let my_exprs : expr list = ASTGen.generate_flat_exprs (\* 1 *\) () in *) +(* let expr_str = *) +(* String.concat ~sep:"\n" *) +(* (List.map *) +(* ~f:(fun expr -> *) +(* let buf = Buffer.create 0 in *) +(* PPrint.ToBuffer.pretty 1.0 80 buf *) +(* (my_printer#entrypoint_expr expr); *) +(* "Check" ^ " " ^ Buffer.contents buf ^ ".") *) +(* (my_exprs)) *) +(* in *) + +(* let my_items : item list = ASTGen.generate_flat_items (\* 1 *\) () in *) +(* let item_str = *) +(* String.concat ~sep:"\n" *) +(* (List.map *) +(* ~f:(fun item -> *) +(* let buf = Buffer.create 0 in *) +(* PPrint.ToBuffer.pretty 1.0 80 buf *) +(* (my_printer#entrypoint_item item); *) +(* Buffer.contents buf) *) +(* (my_items)) *) +(* in *) + +(* [ *) +(* Types. *) +(* { *) +(* path = "full_ast.v"; *) +(* contents = *) +(* hardcoded_coq_headers ^ "\n" *) +(* ^ literal_str ^ "\n\n" *) +(* ^ ty_str ^ "\n\n" *) +(* ^ pat_str ^ "\n\n" *) +(* ^ expr_str ^ "\n\n" *) +(* ^ item_str; *) +(* sourcemap = None; *) +(* } *) +(* ] *) +(* ) *) open Phase_utils diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 838a32596..dba323a00 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -281,10 +281,10 @@ module Make (F : Features.T) = struct method virtual pat'_PConstruct_inductive : super:pat -> - constructor:concrete_ident lazy_doc -> + constructor:global_ident lazy_doc -> is_record:bool -> is_struct:bool -> - fields:(concrete_ident lazy_doc * pat lazy_doc) list -> + fields:(global_ident lazy_doc * pat lazy_doc) list -> document method virtual pat'_PConstruct_tuple @@ -435,37 +435,45 @@ module Make (F : Features.T) = struct self#expr'_App_field_projection ~super ~field ~e) | _ -> self#assertion_failure "Primitive app of arity 0" - method _do_not_override_expr'_Construct ~super ~constructor ~is_record + method _do_not_override_expr'_Construct ~super:_ ~constructor ~is_record ~is_struct ~fields ~base = - match constructor with - | `Concrete constructor -> - let constructor = - self#_do_not_override_lazy_of_concrete_ident - AstPos_expr'_Construct_constructor constructor - in - let fields = - List.map - ~f:(fun field -> - let name, expr = field#v in - let name = - match name with - | `Concrete name -> name - | _ -> - self#assertion_failure - "expr'.Construct: field: non-`Concrete" - in - ( self#_do_not_override_lazy_of_concrete_ident - AstPos_expr'_Construct_fields name, - expr )) - fields - in - self#expr'_Construct_inductive ~super ~constructor ~is_record - ~is_struct ~fields ~base - | `TupleCons _ -> - let components = List.map ~f:(fun field -> snd field#v) fields in - self#expr'_Construct_tuple ~super ~components - | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> - self#assertion_failure "Construct unexpected constructors" + let fields_or_empty add_space = + if List.is_empty fields then empty + else + add_space + ^^ parens + (separate_map (comma ^^ space) (fun x -> (snd x#v)#p) fields) + in + match (constructor, fields, base) with + | `TupleCons 0, [], _ -> string "tt" + | `TupleCons 1, [ e ], _ -> + let _, e' = e#v in + string "(* tuple_cons 1 *)" ^^ e'#p + | `TupleCons _, _, None -> fields_or_empty empty + | _, _, _ -> + if is_record && is_struct then + match base with + | Some x -> + string "Build_" ^^ x#p ^^ fields_or_empty space + | None -> + string "Build_t_" + ^^ (self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base + .AstPos_pat'_PConstruct_constructor constructor) + #p ^^ fields_or_empty space + else if not is_record then + if is_struct then + string "Build_t_" + ^^ (self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base + .AstPos_pat'_PConstruct_constructor constructor) + #p ^^ fields_or_empty space + else + (self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base + .AstPos_pat'_PConstruct_constructor constructor) + #p ^^ fields_or_empty space + else string "(* TODO: Record? *)" method _do_not_override_expr'_GlobalVar ~super global_ident = match global_ident with @@ -477,6 +485,7 @@ module Make (F : Features.T) = struct self#expr'_GlobalVar_concrete ~super concrete | `Primitive primitive -> self#expr'_GlobalVar_primitive ~super primitive + | `TupleCons 0 -> string "tt" | _ -> self#assertion_failure @@ "GlobalVar: expected a concrete or primitive global ident, got:" @@ -484,44 +493,41 @@ module Make (F : Features.T) = struct method _do_not_override_pat'_PConstruct ~super ~constructor ~is_record ~is_struct ~fields = - match constructor with - | `Concrete constructor -> - let constructor = - self#_do_not_override_lazy_of_concrete_ident - AstPos_pat'_PConstruct_constructor constructor - in - let fields = - List.map - ~f:(fun field -> - let { field; pat } = field#v in - let field = - match field with - | `Concrete field -> field - | _ -> - self#assertion_failure - "expr'.Construct: field: non-`Concrete" - in - let pat = - self#_do_not_override_lazy_of_pat AstPos_field_pat__pat pat - in - ( self#_do_not_override_lazy_of_concrete_ident - AstPos_pat'_PConstruct_fields field, - pat )) - fields - in - self#pat'_PConstruct_inductive ~super ~constructor ~is_record - ~is_struct ~fields - | `TupleCons _ -> - let components = - List.map - ~f:(fun field -> - self#_do_not_override_lazy_of_pat AstPos_field_pat__pat - field#v.pat) - fields - in - self#pat'_PConstruct_tuple ~super ~components - | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> - self#assertion_failure "Construct unexpected constructors" + match (constructor, fields) with + | `TupleCons 0, [] -> string "'tt (* const unit *)" (* Unit pat *) + | `TupleCons 1, [ p ] -> p#p + | `TupleCons _n, _ -> + parens (separate_map (comma ^^ space) (fun x -> x#p) fields) + | _, _ -> + if is_record then + (self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base + .AstPos_pat'_PConstruct_constructor constructor) + #p ^^ space + ^^ parens (separate_map (comma ^^ space) (fun x -> x#p) fields) + else + self#pat'_PConstruct_inductive ~super + ~constructor: + (self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base + .AstPos_pat'_PConstruct_constructor constructor) + ~is_record ~is_struct + ~fields: + (List.map + ~f:(fun field -> + let { field; pat } = field#v in + let pat = + self#_do_not_override_lazy_of_pat + Generated_generic_printer_base + .AstPos_pat'_PConstruct_fields pat + in + let field = + self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base + .AstPos_pat'_PConstruct_fields field + in + (field, pat)) + fields) method _do_not_override_ty_TApp ~ident ~args = match ident with @@ -546,6 +552,7 @@ module Make (F : Features.T) = struct method _do_not_override_item'_Type ~super ~name ~generics ~variants ~is_struct = + let generics, _, _ = generics#v in if is_struct then match variants with | [ variant ] -> @@ -594,6 +601,37 @@ module Make (F : Features.T) = struct self#concrete_ident ~local id) ast_position id + method _do_not_override_lazy_of_global_ident ast_position + (id : global_ident) : global_ident lazy_doc = + lazy_doc + (fun (id : global_ident) -> + match id with + | `Concrete cid -> + (self#_do_not_override_lazy_of_concrete_ident ast_position cid) + #p + | `Primitive _prim_id -> string "(*TODO*) prim_id" + | `TupleType 0 -> string "unit" + (* | `TupleCons n when n <= 1 -> *) + (* Error.assertion_failure span *) + (* ("Got a [TupleCons " ^ string_of_int n ^ "]") *) + (* | `TupleType n when n <= 14 -> *) + (* F.lid [ "FStar"; "Pervasives"; "tuple" ^ string_of_int n ] *) + (* | `TupleCons n when n <= 14 -> *) + (* F.lid [ "FStar"; "Pervasives"; "Mktuple" ^ string_of_int n ] *) + (* | `TupleType n | `TupleCons n -> *) + (* let reason = "F* doesn't support tuple of size greater than 14" in *) + (* Error.raise *) + (* { *) + (* kind = UnsupportedTupleSize { tuple_size = Int64.of_int n; reason }; *) + (* span; *) + (* } *) + (* | `TupleField _ | `Projector _ -> *) + (* Error.assertion_failure span *) + (* ("pglobal_ident: expected to be handled somewhere else: " *) + (* ^ show_global_ident id) *) + | _ -> string "(* TODO *) error global ident type?") + ast_position id + method _do_not_override_lazy_of_quote ast_position (value : quote) : quote lazy_doc = lazy_doc (fun (value : quote) -> self#quote value) ast_position value diff --git a/engine/lib/generic_printer/generic_printer_template.ml b/engine/lib/generic_printer/generic_printer_template.ml index 02386dcf3..9105966aa 100644 --- a/engine/lib/generic_printer/generic_printer_template.ml +++ b/engine/lib/generic_printer/generic_printer_template.ml @@ -233,9 +233,6 @@ struct method item'_TyAlias ~super:_ ~name:_ ~generics:_ ~ty:_ = default_document_for "item'_TyAlias" - method item'_Type ~super:_ ~name:_ ~generics:_ ~variants:_ ~is_struct:_ = - default_document_for "item'_Type" - method item'_Type_enum ~super:_ ~name:_ ~generics:_ ~variants:_ = default_document_for "item'_Type_enum" diff --git a/engine/utils/generate_from_ast/codegen_printer.ml b/engine/utils/generate_from_ast/codegen_printer.ml index 58b3368ed..a1a932b3c 100644 --- a/engine/utils/generate_from_ast/codegen_printer.ml +++ b/engine/utils/generate_from_ast/codegen_printer.ml @@ -27,6 +27,7 @@ let is_hidden_method = "pat'_PConstruct"; "expr'_GlobalVar"; "variant"; + "item'_Type"; ] in List.mem ~equal:[%eq: string] list diff --git a/test-harness/src/snapshots/toolchain__assert into-coq.snap b/test-harness/src/snapshots/toolchain__assert into-coq.snap index fd9ff5e71..c198bf926 100644 --- a/test-harness/src/snapshots/toolchain__assert into-coq.snap +++ b/test-harness/src/snapshots/toolchain__assert into-coq.snap @@ -28,24 +28,30 @@ diagnostics = [] [stdout.files] "Assert.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. -(*Not implemented yet? todo(item)*) + +(* NotImplementedYet *) Definition asserts (_ : unit) : unit := - let _ := assert true : unit in - let _ := assert ((@repr WORDSIZE32 1)=.?(@repr WORDSIZE32 1)) : unit in - let _ := match ((@repr WORDSIZE32 2),(@repr WORDSIZE32 2)) with - | '(left_val,right_val) => - assert (left_val=.?right_val) - end : unit in - let _ := match ((@repr WORDSIZE32 1),(@repr WORDSIZE32 2)) with - | '(left_val,right_val) => - assert (not (left_val=.?right_val)) - end : unit in + let _ := assert (true) in + let _ := assert (t_PartialEq_f_eq (1) (1)) in + let _ := match (2, 2) with + | (left_val, right_val) => + assert (t_PartialEq_f_eq (left_val) (right_val)) + end in + let _ := match (1, 2) with + | (left_val, right_val) => + assert (negb (t_PartialEq_f_eq (left_val) (right_val))) + end in tt. ''' diff --git a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap index 22894e237..4f5cf2c7b 100644 --- a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap +++ b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap @@ -29,48 +29,56 @@ diagnostics = [] [stdout.files] "Enum_repr.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. -Definition discriminant_EnumWithRepr_ExplicitDiscr1 : int16 := - (@repr WORDSIZE16 1). -Definition discriminant_EnumWithRepr_ExplicitDiscr2 : int16 := - (@repr WORDSIZE16 5). +Definition discriminant_t_EnumWithRepr_ExplicitDiscr1 : t_u16 := + 1. + +Definition discriminant_t_EnumWithRepr_ExplicitDiscr2 : t_u16 := + 5. Inductive t_EnumWithRepr : Type := -| EnumWithRepr_ExplicitDiscr1 : t_EnumWithRepr -| EnumWithRepr_ExplicitDiscr2 : t_EnumWithRepr -| EnumWithRepr_ImplicitDiscrEmptyTuple : t_EnumWithRepr -| EnumWithRepr_ImplicitDiscrEmptyStruct : t_EnumWithRepr. +| t_EnumWithRepr_ExplicitDiscr1 +| t_EnumWithRepr_ExplicitDiscr2 +| t_EnumWithRepr_ImplicitDiscrEmptyTuple +| t_EnumWithRepr_ImplicitDiscrEmptyStruct. +Arguments t_EnumWithRepr:clear implicits. +Arguments t_EnumWithRepr. -Definition t_EnumWithRepr_cast_to_repr (x : t_EnumWithRepr_t) : int16 := +Definition t_EnumWithRepr_cast_to_repr (x : t_EnumWithRepr) : t_u16 := match x with - | EnumWithRepr_ExplicitDiscr1 => - discriminant_EnumWithRepr_ExplicitDiscr1 - | EnumWithRepr_ExplicitDiscr2 => - discriminant_EnumWithRepr_ExplicitDiscr2 - | EnumWithRepr_ImplicitDiscrEmptyTuple => - discriminant_EnumWithRepr_ExplicitDiscr2.+(@repr WORDSIZE16 1) - | EnumWithRepr_ImplicitDiscrEmptyStruct => - discriminant_EnumWithRepr_ExplicitDiscr2.+(@repr WORDSIZE16 2) + | t_EnumWithRepr_ExplicitDiscr1 => + discriminant_t_EnumWithRepr_ExplicitDiscr1 + | t_EnumWithRepr_ExplicitDiscr2 => + discriminant_t_EnumWithRepr_ExplicitDiscr2 + | t_EnumWithRepr_ImplicitDiscrEmptyTuple => + t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (1) + | t_EnumWithRepr_ImplicitDiscrEmptyStruct => + t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (2) end. -(*Not implemented yet? todo(item)*) +(* NotImplementedYet *) -Definition f (_ : unit) : int32 := - let _x := cast (discriminant_EnumWithRepr_ExplicitDiscr2.+(@repr WORDSIZE16 0)) : int16 in - (cast (t_EnumWithRepr_cast_to_repr EnumWithRepr_ImplicitDiscrEmptyTuplet_EnumWithRepr_t)).+(cast (t_EnumWithRepr_cast_to_repr EnumWithRepr_ImplicitDiscrEmptyStructt_EnumWithRepr_t)). +Definition f (_ : unit) : t_u32 := + let v__x := cast (t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (0)) in + t_Add_f_add (cast (t_EnumWithRepr_cast_to_repr (t_EnumWithRepr_ImplicitDiscrEmptyTuple))) (cast (t_EnumWithRepr_cast_to_repr (t_EnumWithRepr_ImplicitDiscrEmptyStruct))). -Definition ff__CONST : int16 := - cast (discriminant_EnumWithRepr_ExplicitDiscr1.+(@repr WORDSIZE16 0)). +Definition ff__CONST : t_u16 := + cast (t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr1) (0)). -Definition get_casted_repr (x : t_EnumWithRepr_t) : int64 := - cast (t_EnumWithRepr_cast_to_repr x). +Definition get_casted_repr (x : t_EnumWithRepr) : t_u64 := + cast (t_EnumWithRepr_cast_to_repr (x)). -Definition get_repr (x : t_EnumWithRepr_t) : int16 := - t_EnumWithRepr_cast_to_repr x. +Definition get_repr (x : t_EnumWithRepr) : t_u16 := + t_EnumWithRepr_cast_to_repr (x). ''' diff --git a/test-harness/src/snapshots/toolchain__guards into-coq.snap b/test-harness/src/snapshots/toolchain__guards into-coq.snap index 858c6b949..ca5f0a562 100644 --- a/test-harness/src/snapshots/toolchain__guards into-coq.snap +++ b/test-harness/src/snapshots/toolchain__guards into-coq.snap @@ -28,126 +28,132 @@ diagnostics = [] [stdout.files] "Guards.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. -(*Not implemented yet? todo(item)*) -Definition equivalent (x : t_Option_t (t_Result_t int32 int32)) : int32 := +(* NotImplementedYet *) + +Definition equivalent (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with - | Option_None => - (@repr WORDSIZE32 0) + | t_Option_None => + 0 | _ => match match x with - | Option_Some v => - match v with - | Result_Ok y => - Option_Some y - | _ => - Option_Nonet_Option_t int32 - end + | t_Option_Some (v) => + match v with + | t_Result_Ok (y) => + t_Option_Some (y) | _ => - Option_Nonet_Option_t int32 - end with - | Option_Some y => + t_Option_None + end + | _ => + t_Option_None + end with + | t_Option_Some (y) => y - | Option_None => + | t_Option_None => match x with - | Option_Some Result_Err y => + | t_Option_Some (t_Result_Err (y)) => y | _ => - (@repr WORDSIZE32 1) + 1 end end end. -Definition if_guard (x : t_Option_t int32) : int32 := +Definition if_guard (x : t_Option ((t_i32))) : t_i32 := match match x with - | Option_Some v => - match v>.?(@repr WORDSIZE32 0) with - | true => - Option_Some v - | _ => - Option_Nonet_Option_t int32 - end + | t_Option_Some (v) => + match t_PartialOrd_f_gt (v) (0) with + | true => + t_Option_Some (v) | _ => - Option_Nonet_Option_t int32 - end with - | Option_Some x => + t_Option_None + end + | _ => + t_Option_None + end with + | t_Option_Some (x) => x - | Option_None => - (@repr WORDSIZE32 0) + | t_Option_None => + 0 end. -Definition if_let_guard (x : t_Option_t (t_Result_t int32 int32)) : int32 := +Definition if_let_guard (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with - | Option_None => - (@repr WORDSIZE32 0) + | t_Option_None => + 0 | _ => match match x with - | Option_Some v => - match v with - | Result_Ok y => - Option_Some y - | _ => - Option_Nonet_Option_t int32 - end + | t_Option_Some (v) => + match v with + | t_Result_Ok (y) => + t_Option_Some (y) | _ => - Option_Nonet_Option_t int32 - end with - | Option_Some x => + t_Option_None + end + | _ => + t_Option_None + end with + | t_Option_Some (x) => x - | Option_None => + | t_Option_None => match x with - | Option_Some Result_Err y => + | t_Option_Some (t_Result_Err (y)) => y | _ => - (@repr WORDSIZE32 1) + 1 end end end. -Definition multiple_guards (x : t_Option_t (t_Result_t int32 int32)) : int32 := +Definition multiple_guards (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with - | Option_None => - (@repr WORDSIZE32 0) + | t_Option_None => + 0 | _ => match match x with - | Option_Some Result_Ok v => - match Option_Some (v.+(@repr WORDSIZE32 1)) with - | Option_Some (@repr WORDSIZE32 1) => - Option_Some (@repr WORDSIZE32 0) - | _ => - Option_Nonet_Option_t int32 - end + | t_Option_Some (t_Result_Ok (v)) => + match t_Option_Some (t_Add_f_add (v) (1)) with + | t_Option_Some (1) => + t_Option_Some (0) | _ => - Option_Nonet_Option_t int32 - end with - | Option_Some x => + t_Option_None + end + | _ => + t_Option_None + end with + | t_Option_Some (x) => x - | Option_None => + | t_Option_None => match match x with - | Option_Some v => - match v with - | Result_Ok y => - Option_Some y - | _ => - Option_Nonet_Option_t int32 - end + | t_Option_Some (v) => + match v with + | t_Result_Ok (y) => + t_Option_Some (y) | _ => - Option_Nonet_Option_t int32 - end with - | Option_Some x => + t_Option_None + end + | _ => + t_Option_None + end with + | t_Option_Some (x) => x - | Option_None => + | t_Option_None => match x with - | Option_Some Result_Err y => + | t_Option_Some (t_Result_Err (y)) => y | _ => - (@repr WORDSIZE32 1) + 1 end end end diff --git a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap index 71c7a484a..18e23b99b 100644 --- a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap +++ b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap @@ -28,22 +28,38 @@ diagnostics = [] [stdout.files] "Include_flag.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. - -Record t_Foo : Type := { -}. - -Class t_Trait (Self : Type) := { -}. - -#[global] Instance t_Foo_t_t_Trait : t_Trait t_Foo_t := { -}. - -(*Not implemented yet? todo(item)*) +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. + + +Record t_Foo : Type := + { + }. +Arguments t_Foo:clear implicits. +Arguments t_Foo. +Arguments Build_t_Foo. +#[export] Instance settable_t_Foo : Settable _ := + settable! (@Build_t_Foo) <>. + +Class t_Trait `{v_Self : Type} : Type := + { + }. +Arguments t_Trait:clear implicits. +Arguments t_Trait (_). + +Instance t_Trait_187936720 : t_Trait ((t_Foo)) := + { + }. + +(* NotImplementedYet *) Definition main_a_a (_ : unit) : unit := tt. @@ -54,10 +70,10 @@ Definition main_a_b (_ : unit) : unit := Definition main_a_c (_ : unit) : unit := tt. -Definition main_a (x : T) : unit := - let _ := main_a_a tt : unit in - let _ := main_a_b tt : unit in - let _ := main_a_c tt : unit in +Definition main_a `{v_T : Type} `{t_Sized (v_T)} `{t_Trait (v_T)} (x : v_T) : unit := + let _ := main_a_a (tt) in + let _ := main_a_b (tt) in + let _ := main_a_c (tt) in tt. Definition main_b_a (_ : unit) : unit := @@ -70,9 +86,9 @@ Definition main_b_c (_ : unit) : unit := tt. Definition main_b (_ : unit) : unit := - let _ := main_b_a tt : unit in - let _ := main_b_b tt : unit in - let _ := main_b_c tt : unit in + let _ := main_b_a (tt) in + let _ := main_b_b (tt) in + let _ := main_b_c (tt) in tt. Definition main_c_a (_ : unit) : unit := @@ -85,14 +101,14 @@ Definition main_c_c (_ : unit) : unit := tt. Definition main_c (_ : unit) : unit := - let _ := main_c_a tt : unit in - let _ := main_c_b tt : unit in - let _ := main_c_c tt : unit in + let _ := main_c_a (tt) in + let _ := main_c_b (tt) in + let _ := main_c_c (tt) in tt. Definition main (_ : unit) : unit := - let _ := main_a Foot_Foo_t : unit in - let _ := main_b tt : unit in - let _ := main_c tt : unit in + let _ := main_a (Build_t_Foo) in + let _ := main_b (tt) in + let _ := main_c (tt) in tt. ''' diff --git a/test-harness/src/snapshots/toolchain__let-else into-coq.snap b/test-harness/src/snapshots/toolchain__let-else into-coq.snap index 85110e910..64d5f5c52 100644 --- a/test-harness/src/snapshots/toolchain__let-else into-coq.snap +++ b/test-harness/src/snapshots/toolchain__let-else into-coq.snap @@ -28,28 +28,34 @@ diagnostics = [] [stdout.files] "Let_else.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. -(*Not implemented yet? todo(item)*) -Definition let_else (opt : t_Option_t int32) : bool := - run match opt with - | Option_Some x => - ControlFlow_Continue true +(* NotImplementedYet *) + +Definition let_else (opt : t_Option ((t_u32))) : bool := + run (match opt with + | t_Option_Some (x) => + t_ControlFlow_Continue (true) | _ => - ControlFlow_Break false - end. + t_ControlFlow_Break (false) + end). -Definition let_else_different_type (opt : t_Option_t int32) : bool := +Definition let_else_different_type (opt : t_Option ((t_u32))) : bool := run (let hoist1 := match opt with - | Option_Some x => - ControlFlow_Continue (Option_Some (x.+(@repr WORDSIZE32 1))) - | _ => - ControlFlow_Break false - end : t_Option_t int32 in - ControlFlow_Continue (let_else hoist1)). + | t_Option_Some (x) => + t_ControlFlow_Continue (t_Option_Some (t_Add_f_add (x) (1))) + | _ => + t_ControlFlow_Break (false) + end in + t_ControlFlow_Continue (let_else (hoist1))). ''' diff --git a/test-harness/src/snapshots/toolchain__literals into-coq.snap b/test-harness/src/snapshots/toolchain__literals into-coq.snap index 223829d28..ad3302afe 100644 --- a/test-harness/src/snapshots/toolchain__literals into-coq.snap +++ b/test-harness/src/snapshots/toolchain__literals into-coq.snap @@ -21,7 +21,23 @@ info: backend_options: ~ --- exit = 0 -stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' +stderr = ''' +warning: unused variable: `attr` + --> /home/au538501/Documents/git/hax/hax-lib-macros/src/lib.rs:387:18 + | +387 | pub fn interface(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { + | ^^^^ help: if this is intentional, prefix it with an underscore: `_attr` + | + = note: `#[warn(unused_variables)]` on by default + +warning: unused variable: `block` + --> /home/au538501/Documents/git/hax/hax-lib-macros/src/lib.rs:395:9 + | +395 | block, + | ^^^^^ help: try ignoring the field: `block: _` + +warning: `hax-lib-macros` (lib) generated 2 warnings + Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs''' [stdout] diagnostics = [] @@ -29,100 +45,109 @@ diagnostics = [] [stdout.files] "Literals.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. + -Require Import Hax_lib_Int. -Export Hax_lib_Int. +From Literals Require Import Hax_lib (t_int). +Export Hax_lib (t_int). -Record t_Foo : Type := { - f_field : int8; -}. +Record t_Foo : Type := + { + t_Foo_f_field : t_u8; + }. +Arguments t_Foo:clear implicits. +Arguments t_Foo. +Arguments Build_t_Foo. +#[export] Instance settable_t_Foo : Settable _ := + settable! (@Build_t_Foo) . -(*Not implemented yet? todo(item)*) +(* NotImplementedYet *) -Definition v_CONSTANT : t_Foo_t := - Build_Foo (f_field := (@repr WORDSIZE8 3)). +Definition v_CONSTANT : t_Foo := + Build_t_Foo (3). -Definition casts (x8 : int8) (x16 : int16) (x32 : int32) (x64 : int64) (xs : uint_size) : unit := - let (_ : int64) := ((((cast x8).+(cast x16)).+(cast x32)).+x64).+(cast xs) : int64 in - let (_ : int32) := ((((cast x8).+(cast x16)).+x32).+(cast x64)).+(cast xs) : int32 in - let (_ : int16) := ((((cast x8).+x16).+(cast x32)).+(cast x64)).+(cast xs) : int16 in - let (_ : int8) := (((x8.+(cast x16)).+(cast x32)).+(cast x64)).+(cast xs) : int8 in - let (_ : int64) := ((((cast x8).+(cast x16)).+(cast x32)).+(cast x64)).+(cast xs) : int64 in - let (_ : int32) := ((((cast x8).+(cast x16)).+(cast x32)).+(cast x64)).+(cast xs) : int32 in - let (_ : int16) := ((((cast x8).+(cast x16)).+(cast x32)).+(cast x64)).+(cast xs) : int16 in - let (_ : int8) := ((((cast x8).+(cast x16)).+(cast x32)).+(cast x64)).+(cast xs) : int8 in +Definition casts (x8 : t_u8) (x16 : t_u16) (x32 : t_u32) (x64 : t_u64) (xs : t_usize) : unit := + let _ : t_u64 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (x64)) (cast (xs)) in + let _ : t_u32 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (x32)) (cast (x64))) (cast (xs)) in + let _ : t_u16 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (x16)) (cast (x32))) (cast (x64))) (cast (xs)) in + let _ : t_u8 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (x8) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in + let _ : t_i64 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in + let _ : t_i32 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in + let _ : t_i16 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in + let _ : t_i8 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in tt. Definition fn_pointer_cast (_ : unit) : unit := - let (f : int32 -> int32) := fun x => - x : int32 -> int32 in + let f : t_u32 -> t_u32 := fun x => + x in tt. -Definition math_integers (x : t_Int_t) : int8 := - let (_ : t_Int_t) := f_lift (@repr WORDSIZE32 3) : t_Int_t in - let _ := (impl__Int___unsafe_from_str -340282366920938463463374607431768211455000)>.?(impl__Int___unsafe_from_str 340282366920938463463374607431768211455000) : bool in - let _ := x<.?x : bool in - let _ := x>=.?x : bool in - let _ := x<=.?x : bool in - let _ := x<>x : bool in - let _ := x=.?x : bool in - let _ := x.+x : t_Int_t in - let _ := x.-x : t_Int_t in - let _ := x.*x : t_Int_t in - let _ := x./x : t_Int_t in - let (_ : int16) := impl__Int__to_i16 x : int16 in - let (_ : int32) := impl__Int__to_i32 x : int32 in - let (_ : int64) := impl__Int__to_i64 x : int64 in - let (_ : int128) := impl__Int__to_i128 x : int128 in - let (_ : uint_size) := impl__Int__to_isize x : uint_size in - let (_ : int16) := impl__Int__to_u16 x : int16 in - let (_ : int32) := impl__Int__to_u32 x : int32 in - let (_ : int64) := impl__Int__to_u64 x : int64 in - let (_ : int128) := impl__Int__to_u128 x : int128 in - let (_ : uint_size) := impl__Int__to_usize x : uint_size in - impl__Int__to_u8 (x.+(x.*x)). +Definition math_integers (x : t_Int) `{andb (t_PartialOrd_f_gt (x) (impl__Int___unsafe_from_str ("0"%string))) (t_PartialOrd_f_lt (x) (impl__Int___unsafe_from_str ("16"%string))) = true} : t_u8 := + let _ : t_Int := t_Abstraction_f_lift (3) in + let _ := t_PartialOrd_f_gt (impl__Int___unsafe_from_str ("-340282366920938463463374607431768211455000"%string)) (impl__Int___unsafe_from_str ("340282366920938463463374607431768211455000"%string)) in + let _ := t_PartialOrd_f_lt (x) (x) in + let _ := t_PartialOrd_f_ge (x) (x) in + let _ := t_PartialOrd_f_le (x) (x) in + let _ := t_PartialEq_f_ne (x) (x) in + let _ := t_PartialEq_f_eq (x) (x) in + let _ := t_Add_f_add (x) (x) in + let _ := t_Sub_f_sub (x) (x) in + let _ := t_Mul_f_mul (x) (x) in + let _ := t_Div_f_div (x) (x) in + let _ : t_i16 := impl__Int__to_i16 (x) in + let _ : t_i32 := impl__Int__to_i32 (x) in + let _ : t_i64 := impl__Int__to_i64 (x) in + let _ : t_i128 := impl__Int__to_i128 (x) in + let _ : t_isize := impl__Int__to_isize (x) in + let _ : t_u16 := impl__Int__to_u16 (x) in + let _ : t_u32 := impl__Int__to_u32 (x) in + let _ : t_u64 := impl__Int__to_u64 (x) in + let _ : t_u128 := impl__Int__to_u128 (x) in + let _ : t_usize := impl__Int__to_usize (x) in + impl__Int__to_u8 (t_Add_f_add (x) (t_Mul_f_mul (x) (x))). Definition numeric (_ : unit) : unit := - let (_ : uint_size) := (@repr WORDSIZE32 123) : uint_size in - let (_ : uint_size) := (@repr WORDSIZE32 42) : uint_size in - let (_ : uint_size) := (@repr WORDSIZE32 42) : uint_size in - let (_ : int32) := (@repr WORDSIZE32 42) : int32 in - let (_ : int128) := (@repr WORDSIZE128 22222222222222222222) : int128 in + let _ : t_usize := 123 in + let _ : t_isize := 42 in + let _ : t_isize := 42 in + let _ : t_i32 := 42 in + let _ : t_u128 := 22222222222222222222 in tt. Definition patterns (_ : unit) : unit := - let _ := match (@repr WORDSIZE8 1) with - | (@repr WORDSIZE8 2) => - tt - | _ => - tt - end : unit in - let _ := match (hello,((@repr WORDSIZE32 123),array_from_list [a; - b])) with - | '(hello,((@repr WORDSIZE32 123),_todo)) => - tt - | _ => - tt - end : unit in - let _ := match Build_Foo (f_field := (@repr WORDSIZE8 4)) with - | {| - f_field := (@repr WORDSIZE8 3) - |} => - tt - | _ => - tt - end : unit in + let _ := match 1 with + | 2 => + tt + | _ => + tt + end in + let _ := match ("hello"%string, (123, ["a"%string; "b"%string])) with + | ("hello"%string, (123, v__todo)) => + tt + | _ => + tt + end in + let _ := match Build_t_Foo (4) with + | Foo (3) => + tt + | _ => + tt + end in tt. Definition panic_with_msg (_ : unit) : unit := - never_to_any (panic_fmt (impl_2__new_const (array_from_list [with msg]))). + never_to_any (panic_fmt (impl_2__new_const (["with msg"%string]))). Definition empty_array (_ : unit) : unit := - let (_ : seq int8) := unsize !TODO empty array! : seq int8 in + let _ : t_Slice t_u8 := unsize ([]) in tt. ''' diff --git a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap index a7897333d..318b43ef9 100644 --- a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap +++ b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap @@ -29,63 +29,82 @@ diagnostics = [] [stdout.files] "Pattern_or.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. + Inductive t_E : Type := -| E_A : t_E -| E_B : t_E. +| t_E_A +| t_E_B. +Arguments t_E:clear implicits. +Arguments t_E. -Definition t_E_cast_to_repr (x : t_E_t) : uint_size := +Definition t_E_cast_to_repr (x : t_E) : t_isize := match x with - | E_A => - (@repr WORDSIZE32 0) - | E_B => - (@repr WORDSIZE32 1) + | t_E_A => + 0 + | t_E_B => + 1 end. -(*Not implemented yet? todo(item)*) +(* NotImplementedYet *) -Definition bar (x : t_E_t) : unit := +Definition bar (x : t_E) : unit := match x with - | E_A | E_B => + | t_E_A + | t_E_B => tt end. -Definition deep (x : int32 × t_Option_t int32) : int32 := +Definition deep (x : (t_i32*t_Option ((t_i32)))) : t_i32 := match x with - | '((@repr WORDSIZE32 1) | (@repr WORDSIZE32 2),Option_Some (@repr WORDSIZE32 3) | (@repr WORDSIZE32 4)) => - (@repr WORDSIZE32 0) - | '(x,_) => + | (1 + | 2, t_Option_Some (3 + | 4)) => + 0 + | (x, _) => x end. -Definition deep_capture (x : t_Result_t (int32 × int32) (int32 × int32)) : int32 := +Definition deep_capture (x : t_Result (((t_i32*t_i32))) (((t_i32*t_i32)))) : t_i32 := match x with - | Result_Ok ((@repr WORDSIZE32 1) | (@repr WORDSIZE32 2),x) | Result_Err ((@repr WORDSIZE32 3) | (@repr WORDSIZE32 4),x) => + | t_Result_Ok ((1 + | 2, x)) + | t_Result_Err ((3 + | 4, x)) => x - | Result_Ok (x,_) | Result_Err (x,_) => + | t_Result_Ok ((x, _)) + | t_Result_Err ((x, _)) => x end. -Definition equivalent (x : int32 × t_Option_t int32) : int32 := +Definition equivalent (x : (t_i32*t_Option ((t_i32)))) : t_i32 := match x with - | '((@repr WORDSIZE32 1),Option_Some (@repr WORDSIZE32 3)) | '((@repr WORDSIZE32 1),Option_Some (@repr WORDSIZE32 4)) | '((@repr WORDSIZE32 2),Option_Some (@repr WORDSIZE32 3)) | '((@repr WORDSIZE32 2),Option_Some (@repr WORDSIZE32 4)) => - (@repr WORDSIZE32 0) - | '(x,_) => + | (1, t_Option_Some (3)) + | (1, t_Option_Some (4)) + | (2, t_Option_Some (3)) + | (2, t_Option_Some (4)) => + 0 + | (x, _) => x end. -Definition nested (x : t_Option_t int32) : int32 := +Definition nested (x : t_Option ((t_i32))) : t_i32 := match x with - | Option_Some (@repr WORDSIZE32 1) | (@repr WORDSIZE32 2) => - (@repr WORDSIZE32 1) - | Option_Some x => + | t_Option_Some (1 + | 2) => + 1 + | t_Option_Some (x) => x - | Option_None => - (@repr WORDSIZE32 0) + | t_Option_None => + 0 end. ''' diff --git a/test-harness/src/snapshots/toolchain__reordering into-coq.snap b/test-harness/src/snapshots/toolchain__reordering into-coq.snap index 17c28800f..97ed08290 100644 --- a/test-harness/src/snapshots/toolchain__reordering into-coq.snap +++ b/test-harness/src/snapshots/toolchain__reordering into-coq.snap @@ -28,35 +28,49 @@ diagnostics = [] [stdout.files] "Reordering.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. + Inductive t_Foo : Type := -| Foo_A : t_Foo -| Foo_B : t_Foo. +| t_Foo_A +| t_Foo_B. +Arguments t_Foo:clear implicits. +Arguments t_Foo. -Record t_Bar : Type := { - 0 : t_Foo_t; -}. +Record t_Bar : Type := + { + t_Bar_0 : t_Foo; + }. +Arguments t_Bar:clear implicits. +Arguments t_Bar. +Arguments Build_t_Bar. +#[export] Instance settable_t_Bar : Settable _ := + settable! (@Build_t_Bar) . -Definition t_Foo_cast_to_repr (x : t_Foo_t) : uint_size := +Definition t_Foo_cast_to_repr (x : t_Foo) : t_isize := match x with - | Foo_A => - (@repr WORDSIZE32 0) - | Foo_B => - (@repr WORDSIZE32 1) + | t_Foo_A => + 0 + | t_Foo_B => + 1 end. -(*Not implemented yet? todo(item)*) +(* NotImplementedYet *) -Definition f (_ : int32) : t_Foo_t := - Foo_At_Foo_t. +Definition f (_ : t_u32) : t_Foo := + t_Foo_A. -Definition g (_ : unit) : t_Bar_t := - Bar (f (@repr WORDSIZE32 32)). +Definition g (_ : unit) : t_Bar := + Build_t_Bar (f (32)). Definition no_dependency_1_ (_ : unit) : unit := tt. diff --git a/test-harness/src/snapshots/toolchain__slices into-coq.snap b/test-harness/src/snapshots/toolchain__slices into-coq.snap index af66d22c6..784821f9c 100644 --- a/test-harness/src/snapshots/toolchain__slices into-coq.snap +++ b/test-harness/src/snapshots/toolchain__slices into-coq.snap @@ -29,24 +29,29 @@ diagnostics = [] [stdout.files] "Slices.v" = ''' (* File automatically generated by Hacspec *) -From Hacspec Require Import Hacspec_Lib MachineIntegers. From Coq Require Import ZArith. +Require Import List. Import List.ListNotations. Open Scope Z_scope. Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. -(*Not implemented yet? todo(item)*) -Definition v_VERSION : seq int8 := - unsize (array_from_list [(@repr WORDSIZE8 118); - (@repr WORDSIZE8 49)]). +(* NotImplementedYet *) -Definition do_something (_ : seq int8) : unit := +Definition v_VERSION : t_Slice t_u8 := + unsize ([118; 49]). + +Definition do_something (_ : t_Slice t_u8) : unit := tt. -Definition r#unsized (_ : nseq (seq int8) TODO: Int.to_string length) : unit := +Definition r#unsized (_ : t_Array (t_Slice t_u8) (1)) : unit := tt. -Definition sized (x : nseq (nseq int8 TODO: Int.to_string length) TODO: Int.to_string length) : unit := - r#unsized (array_from_list [unsize (x.[(@repr WORDSIZE32 0)])]). +Definition sized (x : t_Array (t_Array (t_u8) (4)) (1)) : unit := + r#unsized ([unsize (index (x) (0))]). ''' From 3b26843ba13456fc7cfcad016c45714e834a40cf Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Tue, 29 Oct 2024 12:24:06 +0100 Subject: [PATCH 195/253] fmt --- engine/lib/generic_printer/generic_printer.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index dba323a00..439a90b11 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -453,8 +453,7 @@ module Make (F : Features.T) = struct | _, _, _ -> if is_record && is_struct then match base with - | Some x -> - string "Build_" ^^ x#p ^^ fields_or_empty space + | Some x -> string "Build_" ^^ x#p ^^ fields_or_empty space | None -> string "Build_t_" ^^ (self#_do_not_override_lazy_of_global_ident From 21f97f0885461ad175bbbf8ff81b2900190fb51c Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Tue, 29 Oct 2024 13:07:14 +0100 Subject: [PATCH 196/253] Remove AST gen used for testing --- engine/backends/coq/coq/coq_backend.ml | 79 -------------------------- 1 file changed, 79 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 23142a5fa..2d03600ff 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -2313,8 +2313,6 @@ let make (module M : Attrs.WITH_ITEMS) = end) (M) : S) -module ASTGen = Ast_utils.ASTGenerator (InputLanguage) - let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = let (module Printer) = make m in let my_printer = new Printer.printer in @@ -2344,83 +2342,6 @@ let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = items); sourcemap = None; }) -(* @ ( *) -(* (\* let (my_literals, my_tys, my_pats, my_exprs, my_items) : literal list * ty list * pat list * expr list * item list = ASTGen.generate_full_ast () in *\) *) -(* let my_literals : literal list = ASTGen.generate_flat_literals () in *) -(* let literal_str = *) -(* String.concat ~sep:"\n" *) -(* (List.map *) -(* ~f:(fun literal -> *) -(* let buf = Buffer.create 0 in *) -(* PPrint.ToBuffer.pretty 1.0 80 buf *) -(* (my_printer#entrypoint_literal literal); *) -(* "Check" ^ " " ^ Buffer.contents buf ^ ".") *) -(* (my_literals)) *) -(* in *) - -(* let my_tys : ty list = ASTGen.generate_flat_tys () (\* 1 *\) in *) -(* let ty_str = *) -(* String.concat ~sep:"\n" *) -(* (List.map *) -(* ~f:(fun ty -> *) -(* let buf = Buffer.create 0 in *) -(* PPrint.ToBuffer.pretty 1.0 80 buf *) -(* (my_printer#entrypoint_ty ty); *) -(* "Check" ^ " " ^ Buffer.contents buf ^ ".") *) -(* (my_tys)) *) -(* in *) - -(* let my_pats : pat list = ASTGen.generate_flat_pats (\* 1 *\) () in *) -(* let pat_str = *) -(* String.concat ~sep:"\n" *) -(* (List.map *) -(* ~f:(fun pat -> *) -(* let buf = Buffer.create 0 in *) -(* PPrint.ToBuffer.pretty 1.0 80 buf *) -(* (my_printer#entrypoint_pat pat); *) -(* "Check match _ with | " ^ " " ^ Buffer.contents buf ^ " => _ | _ => _ end.") *) -(* (my_pats)) *) -(* in *) - -(* let my_exprs : expr list = ASTGen.generate_flat_exprs (\* 1 *\) () in *) -(* let expr_str = *) -(* String.concat ~sep:"\n" *) -(* (List.map *) -(* ~f:(fun expr -> *) -(* let buf = Buffer.create 0 in *) -(* PPrint.ToBuffer.pretty 1.0 80 buf *) -(* (my_printer#entrypoint_expr expr); *) -(* "Check" ^ " " ^ Buffer.contents buf ^ ".") *) -(* (my_exprs)) *) -(* in *) - -(* let my_items : item list = ASTGen.generate_flat_items (\* 1 *\) () in *) -(* let item_str = *) -(* String.concat ~sep:"\n" *) -(* (List.map *) -(* ~f:(fun item -> *) -(* let buf = Buffer.create 0 in *) -(* PPrint.ToBuffer.pretty 1.0 80 buf *) -(* (my_printer#entrypoint_item item); *) -(* Buffer.contents buf) *) -(* (my_items)) *) -(* in *) - -(* [ *) -(* Types. *) -(* { *) -(* path = "full_ast.v"; *) -(* contents = *) -(* hardcoded_coq_headers ^ "\n" *) -(* ^ literal_str ^ "\n\n" *) -(* ^ ty_str ^ "\n\n" *) -(* ^ pat_str ^ "\n\n" *) -(* ^ expr_str ^ "\n\n" *) -(* ^ item_str; *) -(* sourcemap = None; *) -(* } *) -(* ] *) -(* ) *) open Phase_utils From e2721192b79a6e4386d9225ac86014155f6a48ca Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 14:02:55 +0100 Subject: [PATCH 197/253] fix(engine/generic-printer): `get_span_data` is actually named `span_data` --- engine/lib/generic_printer/generic_printer.ml | 4 ++-- .../utils/generate_from_ast/codegen_printer.ml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 439a90b11..d74a04509 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -134,7 +134,7 @@ module Make (F : Features.T) = struct open Ast.Make (F) module Gen = Generated_generic_printer_base.Make (F) - type printer = (unit -> Annotation.t list, PPrint.document) Gen.object_type + type printer = (Annotation.t list, PPrint.document) Gen.object_type type finalized_printer = (unit, string * Annotation.t list) Gen.object_type let finalize (new_printer : unit -> printer) : finalized_printer = @@ -143,7 +143,7 @@ module Make (F : Features.T) = struct let doc = apply printer in let buf = Buffer.create 0 in PPrint.ToBuffer.pretty 1.0 80 buf doc; - (Buffer.contents buf, printer#get_span_data ())) + (Buffer.contents buf, printer#span_data)) class virtual base = object (self) diff --git a/engine/utils/generate_from_ast/codegen_printer.ml b/engine/utils/generate_from_ast/codegen_printer.ml index a1a932b3c..3e764c892 100644 --- a/engine/utils/generate_from_ast/codegen_printer.ml +++ b/engine/utils/generate_from_ast/codegen_printer.ml @@ -383,23 +383,23 @@ module Make (F : Features.T) = struct %s end - type ('get_span_data, 'a) object_type = < - get_span_data : 'get_span_data; + type ('span_data, 'a) object_type = < + span_data : 'span_data; %s > - let map (type get_span_data) (type a) (type b) - (f: ((get_span_data, a) object_type -> a) -> b) + let map (type span_data) (type a) (type b) + (f: ((span_data, a) object_type -> a) -> b) : (unit, b) object_type = object - method get_span_data: unit = () + method span_data: unit = () %s end - let map_get_span_data (type a) (type b) (type t) + let map_span_data (type a) (type b) (type t) (obj: (a, t) object_type) - (get_span_data: b) + (span_data: b) : (b, t) object_type = object - method get_span_data: b = get_span_data + method span_data: b = span_data %s end end From 6ede00ffe5749d83b69bcd31dac8b8efc6d68b84 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Tue, 29 Oct 2024 14:03:28 +0100 Subject: [PATCH 198/253] fix(engine/coq-gen-printer): use `finalize` to expose the printer --- engine/backends/coq/coq/coq_backend.ml | 1519 +----------------------- 1 file changed, 16 insertions(+), 1503 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 2d03600ff..8190957a4 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -117,12 +117,12 @@ let hardcoded_coq_headers = From RecordUpdate Require Import RecordSet.\n\ Import RecordSetNotations.\n" +module BasePrinter = Generic_printer.Make (InputLanguage) module Make (Default : sig val default : string -> string end) (Attrs : Attrs.WITH_ITEMS) = struct - module Base = Generic_printer.Make (InputLanguage) open PPrint let default_string_for s = "TODO: please implement the method `" ^ s ^ "`" @@ -159,12 +159,12 @@ struct end type ('get_span_data, 'a) object_type = - ('get_span_data, 'a) Base.Gen.object_type + ('get_span_data, 'a) BasePrinter.Gen.object_type class printer = (* let associated_expr = let open m in associated_expr in *) object (self) - inherit Base.base + inherit BasePrinter.base method private primitive_to_string (id : primitive_ident) : document = match id with @@ -818,1505 +818,25 @@ struct (* val mutable current_namespace : (string * string list) option = None *) end -end -class type printer_type = - object - val concrete_ident_view : (module Hax_engine.Concrete_ident.VIEW_API) - val mutable current_namespace : (string * string list) option - - method _do_not_override_expr'_App : - super:expr -> - f:expr Generic_printer.LazyDoc.lazy_doc -> - args:expr Generic_printer.LazyDoc.lazy_doc list -> - generic_args:generic_value Generic_printer.LazyDoc.lazy_doc list -> - bounds_impls:impl_expr Generic_printer.LazyDoc.lazy_doc list -> - trait: - (impl_expr Generic_printer.LazyDoc.lazy_doc - * generic_value Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc - option -> - PPrint.document - - method _do_not_override_expr'_Construct : - super:expr -> - constructor:global_ident -> - is_record:bool -> - is_struct:bool -> - fields: - (global_ident * expr Generic_printer.LazyDoc.lazy_doc) - Generic_printer.LazyDoc.lazy_doc - list -> - base: - (expr Generic_printer.LazyDoc.lazy_doc * InputLanguage.construct_base) - Generic_printer.LazyDoc.lazy_doc - option -> - PPrint.document - - method _do_not_override_expr'_GlobalVar : - super:expr -> global_ident -> PPrint.document - - method _do_not_override_item'_Type : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - variants:variant Generic_printer.LazyDoc.lazy_doc list -> - is_struct:bool -> - PPrint.document - - method _do_not_override_lazy_of_arm : - Generated_generic_printer_base.ast_position -> - arm -> - arm Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_arm' : - super:arm -> - Generated_generic_printer_base.ast_position -> - arm' -> - arm' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_attrs : - Generated_generic_printer_base.ast_position -> - attrs -> - attrs Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_binding_mode : - Generated_generic_printer_base.ast_position -> - binding_mode -> - binding_mode Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_borrow_kind : - Generated_generic_printer_base.ast_position -> - borrow_kind -> - borrow_kind Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_cf_kind : - Generated_generic_printer_base.ast_position -> - cf_kind -> - cf_kind Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_concrete_ident : - Generated_generic_printer_base.ast_position -> - concrete_ident -> - concrete_ident Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_global_ident : - Generated_generic_printer_base.ast_position -> - global_ident -> - global_ident Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_dyn_trait_goal : - Generated_generic_printer_base.ast_position -> - dyn_trait_goal -> - dyn_trait_goal Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_expr : - Generated_generic_printer_base.ast_position -> - expr -> - expr Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_expr' : - super:expr -> - Generated_generic_printer_base.ast_position -> - expr' -> - expr' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_field_pat : - Generated_generic_printer_base.ast_position -> - field_pat -> - field_pat Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_generic_constraint : - Generated_generic_printer_base.ast_position -> - generic_constraint -> - generic_constraint Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_generic_param : - Generated_generic_printer_base.ast_position -> - generic_param -> - generic_param Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_generic_param_kind : - Generated_generic_printer_base.ast_position -> - generic_param_kind -> - generic_param_kind Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_generic_value : - Generated_generic_printer_base.ast_position -> - generic_value -> - generic_value Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_generics : - Generated_generic_printer_base.ast_position -> - generics -> - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_guard : - Generated_generic_printer_base.ast_position -> - guard -> - guard Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_guard' : - super:guard -> - Generated_generic_printer_base.ast_position -> - guard' -> - guard' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_impl_expr : - Generated_generic_printer_base.ast_position -> - impl_expr -> - impl_expr Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_impl_expr_kind : - Generated_generic_printer_base.ast_position -> - impl_expr_kind -> - impl_expr_kind Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_impl_ident : - Generated_generic_printer_base.ast_position -> - impl_ident -> - impl_ident Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_impl_item : - Generated_generic_printer_base.ast_position -> - impl_item -> - impl_item Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_impl_item' : - Generated_generic_printer_base.ast_position -> - impl_item' -> - impl_item' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_item : - Generated_generic_printer_base.ast_position -> - item -> - item Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_item' : - super:item -> - Generated_generic_printer_base.ast_position -> - item' -> - item' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_lhs : - Generated_generic_printer_base.ast_position -> - lhs -> - lhs Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_literal : - Generated_generic_printer_base.ast_position -> - literal -> - literal Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_local_ident : - Generated_generic_printer_base.ast_position -> - local_ident -> - local_ident Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_loop_kind : - Generated_generic_printer_base.ast_position -> - loop_kind -> - loop_kind Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_loop_state : - Generated_generic_printer_base.ast_position -> - loop_state -> - loop_state Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_modul : - Generated_generic_printer_base.ast_position -> - item list -> - item list Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_param : - Generated_generic_printer_base.ast_position -> - param -> - param Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_pat : - Generated_generic_printer_base.ast_position -> - pat -> - pat Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_pat' : - super:pat -> - Generated_generic_printer_base.ast_position -> - pat' -> - pat' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_projection_predicate : - Generated_generic_printer_base.ast_position -> - projection_predicate -> - projection_predicate Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_quote : - Generated_generic_printer_base.ast_position -> - quote -> - quote Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_safety_kind : - Generated_generic_printer_base.ast_position -> - safety_kind -> - safety_kind Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_supported_monads : - Generated_generic_printer_base.ast_position -> - supported_monads -> - supported_monads Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_trait_goal : - Generated_generic_printer_base.ast_position -> - trait_goal -> - trait_goal Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_trait_item : - Generated_generic_printer_base.ast_position -> - trait_item -> - trait_item Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_trait_item' : - Generated_generic_printer_base.ast_position -> - trait_item' -> - trait_item' Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_ty : - Generated_generic_printer_base.ast_position -> - ty -> - ty Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lazy_of_variant : - Generated_generic_printer_base.ast_position -> - variant -> - variant Generic_printer.LazyDoc.lazy_doc - - method _do_not_override_lhs_LhsFieldAccessor : - e:lhs Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - field:global_ident -> - witness:InputLanguage.nontrivial_lhs -> - PPrint.document - - method _do_not_override_pat'_PConstruct : - super:pat -> - constructor:global_ident -> - is_record:bool -> - is_struct:bool -> - fields:field_pat Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method _do_not_override_ty_TApp : - ident:global_ident -> - args:generic_value Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method _do_not_override_variant : - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - arguments: - (concrete_ident Generic_printer.LazyDoc.lazy_doc - * ty Generic_printer.LazyDoc.lazy_doc - * attrs Generic_printer.LazyDoc.lazy_doc) - list -> - is_record:bool -> - attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method arm : - arm:arm' Generic_printer.LazyDoc.lazy_doc -> span:span -> PPrint.document - - method arm' : - super:arm -> - arm_pat:pat Generic_printer.LazyDoc.lazy_doc -> - body:expr Generic_printer.LazyDoc.lazy_doc -> - guard:guard Generic_printer.LazyDoc.lazy_doc option -> - PPrint.document - - method assertion_failure : string -> 'any - method attrs : attr list -> PPrint.document - - method binding_mode_ByRef : - borrow_kind Generic_printer.LazyDoc.lazy_doc -> - InputLanguage.reference -> - PPrint.document - - method binding_mode_ByValue : PPrint.document - method borrow_kind_Mut : InputLanguage.mutable_reference -> PPrint.document - method borrow_kind_Shared : PPrint.document - method borrow_kind_Unique : PPrint.document - - method catch_exn : - (string -> PPrint.document) -> - (unit -> PPrint.document) -> - PPrint.document - - method private catch_exn' : - (Diagnostics.Context.t -> Diagnostics.kind -> PPrint.document) -> - (unit -> PPrint.document) -> - PPrint.document - - method cf_kind_BreakOnly : PPrint.document - method cf_kind_BreakOrReturn : PPrint.document - method common_array : PPrint.document list -> PPrint.document - method concrete_ident : local:bool -> Concrete_ident.view -> PPrint.document - method current_span : span - - method dyn_trait_goal : - trait:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - non_self_args:generic_value Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method entrypoint_arm : arm -> PPrint.document - method entrypoint_attrs : attrs -> PPrint.document - method entrypoint_binding_mode : binding_mode -> PPrint.document - method entrypoint_borrow_kind : borrow_kind -> PPrint.document - method entrypoint_cf_kind : cf_kind -> PPrint.document - method entrypoint_dyn_trait_goal : dyn_trait_goal -> PPrint.document - method entrypoint_expr : expr -> PPrint.document - method entrypoint_field_pat : field_pat -> PPrint.document - method entrypoint_generic_constraint : generic_constraint -> PPrint.document - method entrypoint_generic_param : generic_param -> PPrint.document - method entrypoint_generic_param_kind : generic_param_kind -> PPrint.document - method entrypoint_generic_value : generic_value -> PPrint.document - method entrypoint_generics : generics -> PPrint.document - method entrypoint_guard : guard -> PPrint.document - method entrypoint_impl_expr : impl_expr -> PPrint.document - method entrypoint_impl_expr_kind : impl_expr_kind -> PPrint.document - method entrypoint_impl_ident : impl_ident -> PPrint.document - method entrypoint_impl_item : impl_item -> PPrint.document - method entrypoint_impl_item' : impl_item' -> PPrint.document - method entrypoint_item : item -> PPrint.document - method entrypoint_lhs : lhs -> PPrint.document - method entrypoint_literal : literal -> PPrint.document - method entrypoint_loop_kind : loop_kind -> PPrint.document - method entrypoint_loop_state : loop_state -> PPrint.document - method entrypoint_modul : item list -> PPrint.document - method entrypoint_param : param -> PPrint.document - method entrypoint_pat : pat -> PPrint.document - - method entrypoint_projection_predicate : - projection_predicate -> PPrint.document - - method entrypoint_safety_kind : safety_kind -> PPrint.document - method entrypoint_supported_monads : supported_monads -> PPrint.document - method entrypoint_trait_goal : trait_goal -> PPrint.document - method entrypoint_trait_item : trait_item -> PPrint.document - method entrypoint_trait_item' : trait_item' -> PPrint.document - method entrypoint_ty : ty -> PPrint.document - method entrypoint_variant : variant -> PPrint.document - method error_expr : string -> PPrint.document - method error_item : string -> PPrint.document - method error_pat : string -> PPrint.document - - method expr : - e:expr' Generic_printer.LazyDoc.lazy_doc -> - span:span -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_AddressOf : - super:expr -> - mut:InputLanguage.mutable_pointer mutability -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.raw_pointer -> - PPrint.document - - method expr'_App_application : - super:expr -> - f:expr Generic_printer.LazyDoc.lazy_doc -> - args:expr Generic_printer.LazyDoc.lazy_doc list -> - generics:generic_value Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method expr'_App_constant : - super:expr -> - constant:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics:generic_value Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method expr'_App_field_projection : - super:expr -> - field:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_App_tuple_projection : - super:expr -> - size:int -> - nth:int -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_Array : - super:expr -> - expr Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method expr'_Ascription : - super:expr -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_Assign : - super:expr -> - lhs:lhs Generic_printer.LazyDoc.lazy_doc -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.mutable_variable -> - PPrint.document - - method expr'_Block : - super:expr -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - safety_mode:safety_kind Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.block -> - PPrint.document - - method expr'_Borrow : - super:expr -> - kind:borrow_kind Generic_printer.LazyDoc.lazy_doc -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.reference -> - PPrint.document - - method expr'_Break : - super:expr -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - acc: - (expr Generic_printer.LazyDoc.lazy_doc - * InputLanguage.state_passing_loop) - Generic_printer.LazyDoc.lazy_doc - option -> - label:string option -> - witness:InputLanguage.break * InputLanguage.loop -> - PPrint.document - - method expr'_Closure : - super:expr -> - params:pat Generic_printer.LazyDoc.lazy_doc list -> - body:expr Generic_printer.LazyDoc.lazy_doc -> - captures:expr Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method expr'_Construct_inductive : - super:expr -> - constructor:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - is_record:bool -> - is_struct:bool -> - fields: - (concrete_ident Generic_printer.LazyDoc.lazy_doc - * expr Generic_printer.LazyDoc.lazy_doc) - list -> - base: - (expr Generic_printer.LazyDoc.lazy_doc * InputLanguage.construct_base) - Generic_printer.LazyDoc.lazy_doc - option -> - PPrint.document - - method expr'_Construct_tuple : - super:expr -> - components:expr Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method expr'_Continue : - super:expr -> - acc: - (expr Generic_printer.LazyDoc.lazy_doc - * InputLanguage.state_passing_loop) - Generic_printer.LazyDoc.lazy_doc - option -> - label:string option -> - witness:InputLanguage.continue * InputLanguage.loop -> - PPrint.document - - method expr'_EffectAction : - super:expr -> - action:InputLanguage.monadic_action -> - argument:expr Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_GlobalVar_concrete : - super:expr -> - concrete_ident Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_GlobalVar_primitive : - super:expr -> primitive_ident -> PPrint.document - - method expr'_If : - super:expr -> - cond:expr Generic_printer.LazyDoc.lazy_doc -> - then_:expr Generic_printer.LazyDoc.lazy_doc -> - else_:expr Generic_printer.LazyDoc.lazy_doc option -> - PPrint.document - - method expr'_Let : - super:expr -> - monadic: - (supported_monads Generic_printer.LazyDoc.lazy_doc - * InputLanguage.monadic_binding) - Generic_printer.LazyDoc.lazy_doc - option -> - lhs:pat Generic_printer.LazyDoc.lazy_doc -> - rhs:expr Generic_printer.LazyDoc.lazy_doc -> - body:expr Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_Literal : - super:expr -> literal Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method expr'_LocalVar : - super:expr -> - local_ident Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method expr'_Loop : - super:expr -> - body:expr Generic_printer.LazyDoc.lazy_doc -> - kind:loop_kind Generic_printer.LazyDoc.lazy_doc -> - state:loop_state Generic_printer.LazyDoc.lazy_doc option -> - control_flow: - (cf_kind Generic_printer.LazyDoc.lazy_doc - * InputLanguage.fold_like_loop) - Generic_printer.LazyDoc.lazy_doc - option -> - label:string option -> - witness:InputLanguage.loop -> - PPrint.document - - method expr'_MacroInvokation : - super:expr -> - macro:global_ident -> - args:string -> - witness:InputLanguage.macro -> - PPrint.document - - method expr'_Match : - super:expr -> - scrutinee:expr Generic_printer.LazyDoc.lazy_doc -> - arms:arm Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method expr'_QuestionMark : - super:expr -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - return_typ:ty Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.question_mark -> - PPrint.document - - method expr'_Quote : - super:expr -> quote Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method expr'_Return : - super:expr -> - e:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.early_exit -> - PPrint.document - - method field_pat : - field:global_ident -> - pat:pat Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method generic_constraint_GCLifetime : - string -> InputLanguage.lifetime -> PPrint.document - - method generic_constraint_GCProjection : - projection_predicate Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method generic_constraint_GCType : - impl_ident Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method generic_param : - ident:local_ident Generic_printer.LazyDoc.lazy_doc -> - span:span -> - attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - kind:generic_param_kind Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method generic_param_kind_GPConst : - typ:ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method generic_param_kind_GPLifetime : - witness:InputLanguage.lifetime -> PPrint.document - - method generic_param_kind_GPType : PPrint.document - - method generic_value_GConst : - expr Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method generic_value_GLifetime : - lt:string -> witness:InputLanguage.lifetime -> PPrint.document - - method generic_value_GType : - ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method generics : - params:generic_param Generic_printer.LazyDoc.lazy_doc list -> - constraints:generic_constraint Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method guard : - guard:guard' Generic_printer.LazyDoc.lazy_doc -> - span:span -> - PPrint.document - - method guard'_IfLet : - super:guard -> - lhs:pat Generic_printer.LazyDoc.lazy_doc -> - rhs:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.match_guard -> - PPrint.document - - method impl_expr : - kind:impl_expr_kind Generic_printer.LazyDoc.lazy_doc -> - goal:trait_goal Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method impl_expr_kind_Builtin : - trait_goal Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method impl_expr_kind_Concrete : - trait_goal Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method impl_expr_kind_Dyn : PPrint.document - - method impl_expr_kind_ImplApp : - impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> - args:impl_expr Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method impl_expr_kind_LocalBound : id:string -> PPrint.document - - method impl_expr_kind_Parent : - impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> - ident:impl_ident Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method impl_expr_kind_Projection : - impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> - item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - ident:impl_ident Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method impl_expr_kind_Self : PPrint.document - - method impl_ident : - goal:trait_goal Generic_printer.LazyDoc.lazy_doc -> - name:string -> - PPrint.document - - method impl_item : - ii_span:span -> - ii_generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - ii_v:impl_item' Generic_printer.LazyDoc.lazy_doc -> - ii_ident:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - ii_attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method impl_item'_IIFn : - body:expr Generic_printer.LazyDoc.lazy_doc -> - params:param Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method impl_item'_IIType : - typ:ty Generic_printer.LazyDoc.lazy_doc -> - parent_bounds: - (impl_expr Generic_printer.LazyDoc.lazy_doc - * impl_ident Generic_printer.LazyDoc.lazy_doc) - list -> - PPrint.document - - method item : - v:item' Generic_printer.LazyDoc.lazy_doc -> - span:span -> - ident:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_Alias : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_Enum_Variant : - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - arguments: - (concrete_ident Generic_printer.LazyDoc.lazy_doc - * ty Generic_printer.LazyDoc.lazy_doc - * attrs Generic_printer.LazyDoc.lazy_doc) - list -> - is_record:bool -> - attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_Fn : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - body:expr Generic_printer.LazyDoc.lazy_doc -> - params:param Generic_printer.LazyDoc.lazy_doc list -> - safety:safety_kind Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_HaxError : super:item -> string -> PPrint.document - - method item'_IMacroInvokation : - super:item -> - macro:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - argument:string -> - span:span -> - witness:InputLanguage.macro -> - PPrint.document - - method item'_Impl : - super:item -> - generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - self_ty:ty Generic_printer.LazyDoc.lazy_doc -> - of_trait: - (concrete_ident Generic_printer.LazyDoc.lazy_doc - * generic_value Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - items:impl_item Generic_printer.LazyDoc.lazy_doc list -> - parent_bounds: - (impl_expr Generic_printer.LazyDoc.lazy_doc - * impl_ident Generic_printer.LazyDoc.lazy_doc) - list -> - safety:safety_kind Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_NotImplementedYet : PPrint.document - - method item'_Quote : - super:item -> - quote:quote Generic_printer.LazyDoc.lazy_doc -> - origin:item_quote_origin -> - PPrint.document - - method item'_Trait : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - items:trait_item Generic_printer.LazyDoc.lazy_doc list -> - safety:safety_kind Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_TyAlias : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - ty:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method item'_Type_enum : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics:generics Generic_printer.LazyDoc.lazy_doc -> - variants:variant Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method item'_Type_struct : - super:item -> - name:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics:generics Generic_printer.LazyDoc.lazy_doc -> - tuple_struct:bool -> - arguments: - (concrete_ident Generic_printer.LazyDoc.lazy_doc - * ty Generic_printer.LazyDoc.lazy_doc - * attr list Generic_printer.LazyDoc.lazy_doc) - list -> - PPrint.document - - method item'_Use : - super:item -> - path:string list -> - is_external:bool -> - rename:string option -> - PPrint.document - - method lhs_LhsArbitraryExpr : - e:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.arbitrary_lhs -> - PPrint.document - - method lhs_LhsArrayAccessor : - e:lhs Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - index:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.nontrivial_lhs -> - PPrint.document - - method lhs_LhsFieldAccessor_field : - e:lhs Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - field:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.nontrivial_lhs -> - PPrint.document - - method lhs_LhsFieldAccessor_tuple : - e:lhs Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - nth:int -> - size:int -> - witness:InputLanguage.nontrivial_lhs -> - PPrint.document - - method lhs_LhsLocalVar : - var:local_ident -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method literal_Bool : bool -> PPrint.document - method literal_Char : Prelude.char -> PPrint.document - - method literal_Float : - value:string -> negative:bool -> kind:float_kind -> PPrint.document - - method literal_Int : - value:string -> negative:bool -> kind:int_kind -> PPrint.document - - method literal_String : string -> PPrint.document - method local_ident : local_ident -> PPrint.document - - method loop_kind_ForIndexLoop : - start:expr Generic_printer.LazyDoc.lazy_doc -> - end_:expr Generic_printer.LazyDoc.lazy_doc -> - var:local_ident Generic_printer.LazyDoc.lazy_doc -> - var_typ:ty Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.for_index_loop -> - PPrint.document - - method loop_kind_ForLoop : - pat:pat Generic_printer.LazyDoc.lazy_doc -> - it:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.for_loop -> - PPrint.document - - method loop_kind_UnconditionalLoop : PPrint.document - - method loop_kind_WhileLoop : - condition:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.while_loop -> - PPrint.document - - method loop_state : - init:expr Generic_printer.LazyDoc.lazy_doc -> - bpat:pat Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.state_passing_loop -> - PPrint.document - - method modul : item Generic_printer.LazyDoc.lazy_doc list -> PPrint.document - method module_path_separator : string - - method param : - pat:pat Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - typ_span:span option -> - attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method pat : - p:pat' Generic_printer.LazyDoc.lazy_doc -> - span:span -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method pat'_PArray : - super:pat -> - args:pat Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method pat'_PAscription : - super:pat -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - typ_span:span -> - pat:pat Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method pat'_PBinding : - super:pat -> - mut:InputLanguage.mutable_variable mutability -> - mode:binding_mode Generic_printer.LazyDoc.lazy_doc -> - var:local_ident Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - subpat: - (pat Generic_printer.LazyDoc.lazy_doc * InputLanguage.as_pattern) - Generic_printer.LazyDoc.lazy_doc - option -> - PPrint.document - - method pat'_PConstant : - super:pat -> - lit:literal Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method pat'_PConstruct_inductive : - super:pat -> - constructor:global_ident Generic_printer.LazyDoc.lazy_doc -> - is_record:bool -> - is_struct:bool -> - fields: - (global_ident Generic_printer.LazyDoc.lazy_doc - * pat Generic_printer.LazyDoc.lazy_doc) - list -> - PPrint.document - - method pat'_PConstruct_tuple : - super:pat -> - components:pat Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method pat'_PDeref : - super:pat -> - subpat:pat Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.reference -> - PPrint.document - - method pat'_POr : - super:pat -> - subpats:pat Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method pat'_PWild : PPrint.document - - method print_arm : - Generated_generic_printer_base.ast_position -> arm -> PPrint.document - - method print_attrs : - Generated_generic_printer_base.ast_position -> attrs -> PPrint.document - - method print_binding_mode : - Generated_generic_printer_base.ast_position -> - binding_mode -> - PPrint.document - - method print_borrow_kind : - Generated_generic_printer_base.ast_position -> - borrow_kind -> - PPrint.document - - method print_cf_kind : - Generated_generic_printer_base.ast_position -> cf_kind -> PPrint.document - - method print_dyn_trait_goal : - Generated_generic_printer_base.ast_position -> - dyn_trait_goal -> - PPrint.document - - method print_expr : - Generated_generic_printer_base.ast_position -> expr -> PPrint.document - - method print_field_pat : - Generated_generic_printer_base.ast_position -> - field_pat -> - PPrint.document - - method print_generic_constraint : - Generated_generic_printer_base.ast_position -> - generic_constraint -> - PPrint.document - - method print_generic_param : - Generated_generic_printer_base.ast_position -> - generic_param -> - PPrint.document - - method print_generic_param_kind : - Generated_generic_printer_base.ast_position -> - generic_param_kind -> - PPrint.document - - method print_generic_value : - Generated_generic_printer_base.ast_position -> - generic_value -> - PPrint.document - - method print_generics : - Generated_generic_printer_base.ast_position -> generics -> PPrint.document - - method print_guard : - Generated_generic_printer_base.ast_position -> guard -> PPrint.document - - method print_impl_expr : - Generated_generic_printer_base.ast_position -> - impl_expr -> - PPrint.document - - method print_impl_expr_kind : - Generated_generic_printer_base.ast_position -> - impl_expr_kind -> - PPrint.document - - method print_impl_ident : - Generated_generic_printer_base.ast_position -> - impl_ident -> - PPrint.document - - method print_impl_item : - Generated_generic_printer_base.ast_position -> - impl_item -> - PPrint.document - - method print_impl_item' : - Generated_generic_printer_base.ast_position -> - impl_item' -> - PPrint.document - - method print_item : - Generated_generic_printer_base.ast_position -> item -> PPrint.document - - method print_lhs : - Generated_generic_printer_base.ast_position -> lhs -> PPrint.document - - method print_literal : - Generated_generic_printer_base.ast_position -> literal -> PPrint.document - - method print_loop_kind : - Generated_generic_printer_base.ast_position -> - loop_kind -> - PPrint.document - - method print_loop_state : - Generated_generic_printer_base.ast_position -> - loop_state -> - PPrint.document - - method print_modul : - Generated_generic_printer_base.ast_position -> - item list -> - PPrint.document - - method print_param : - Generated_generic_printer_base.ast_position -> param -> PPrint.document - - method print_pat : - Generated_generic_printer_base.ast_position -> pat -> PPrint.document - - method print_projection_predicate : - Generated_generic_printer_base.ast_position -> - projection_predicate -> - PPrint.document - - method print_safety_kind : - Generated_generic_printer_base.ast_position -> - safety_kind -> - PPrint.document - - method print_supported_monads : - Generated_generic_printer_base.ast_position -> - supported_monads -> - PPrint.document - - method print_trait_goal : - Generated_generic_printer_base.ast_position -> - trait_goal -> - PPrint.document - - method print_trait_item : - Generated_generic_printer_base.ast_position -> - trait_item -> - PPrint.document - - method print_trait_item' : - Generated_generic_printer_base.ast_position -> - trait_item' -> - PPrint.document - - method print_ty : - Generated_generic_printer_base.ast_position -> ty -> PPrint.document - - method print_variant : - Generated_generic_printer_base.ast_position -> variant -> PPrint.document - - method printer_name : string - - method projection_predicate : - impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> - assoc_item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method quote : quote -> PPrint.document - method safety_kind_Safe : PPrint.document - method safety_kind_Unsafe : InputLanguage.unsafe -> PPrint.document - method span_data : Generic_printer.Annotation.t list - - method supported_monads_MException : - ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method supported_monads_MOption : PPrint.document - - method supported_monads_MResult : - ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method trait_goal : - trait:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - args:generic_value Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method trait_item : - ti_span:span -> - ti_generics: - (generics Generic_printer.LazyDoc.lazy_doc - * generic_param Generic_printer.LazyDoc.lazy_doc list - * generic_constraint Generic_printer.LazyDoc.lazy_doc list) - Generic_printer.LazyDoc.lazy_doc -> - ti_v:trait_item' Generic_printer.LazyDoc.lazy_doc -> - ti_ident:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - ti_attrs:attrs Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method trait_item'_TIDefault : - params:param Generic_printer.LazyDoc.lazy_doc list -> - body:expr Generic_printer.LazyDoc.lazy_doc -> - witness:InputLanguage.trait_item_default -> - PPrint.document - - method trait_item'_TIFn : - ty Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method trait_item'_TIType : - impl_ident Generic_printer.LazyDoc.lazy_doc list -> PPrint.document - - method ty_TApp_application : - typ:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - generics:generic_value Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method ty_TApp_tuple : types:ty list -> PPrint.document - - method ty_TArray : - typ:ty Generic_printer.LazyDoc.lazy_doc -> - length:expr Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method ty_TArrow : - ty Generic_printer.LazyDoc.lazy_doc list -> - ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method ty_TAssociatedType : - impl:impl_expr Generic_printer.LazyDoc.lazy_doc -> - item:concrete_ident Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method ty_TBool : PPrint.document - method ty_TChar : PPrint.document - - method ty_TDyn : - witness:InputLanguage.dyn -> - goals:dyn_trait_goal Generic_printer.LazyDoc.lazy_doc list -> - PPrint.document - - method ty_TFloat : float_kind -> PPrint.document - method ty_TInt : int_kind -> PPrint.document - - method ty_TOpaque : - concrete_ident Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method ty_TParam : - local_ident Generic_printer.LazyDoc.lazy_doc -> PPrint.document - - method ty_TRawPointer : witness:InputLanguage.raw_pointer -> PPrint.document - - method ty_TRef : - witness:InputLanguage.reference -> - region:string -> - typ:ty Generic_printer.LazyDoc.lazy_doc -> - mut:InputLanguage.mutable_reference mutability -> - PPrint.document - - method ty_TSlice : - witness:InputLanguage.slice -> - ty:ty Generic_printer.LazyDoc.lazy_doc -> - PPrint.document - - method ty_TStr : PPrint.document - method unreachable : unit -> 'any - method with_span : span:span -> (unit -> PPrint.document) -> PPrint.document - - method wrap_arm : - Generated_generic_printer_base.ast_position -> - arm -> - PPrint.document -> - PPrint.document - - method wrap_arm' : - Generated_generic_printer_base.ast_position -> - arm' -> - PPrint.document -> - PPrint.document - - method wrap_attrs : - Generated_generic_printer_base.ast_position -> - attrs -> - PPrint.document -> - PPrint.document - - method wrap_binding_mode : - Generated_generic_printer_base.ast_position -> - binding_mode -> - PPrint.document -> - PPrint.document - - method wrap_borrow_kind : - Generated_generic_printer_base.ast_position -> - borrow_kind -> - PPrint.document -> - PPrint.document - - method wrap_cf_kind : - Generated_generic_printer_base.ast_position -> - cf_kind -> - PPrint.document -> - PPrint.document - - method wrap_dyn_trait_goal : - Generated_generic_printer_base.ast_position -> - dyn_trait_goal -> - PPrint.document -> - PPrint.document - - method wrap_expr : - Generated_generic_printer_base.ast_position -> - expr -> - PPrint.document -> - PPrint.document - - method wrap_expr' : - Generated_generic_printer_base.ast_position -> - expr' -> - PPrint.document -> - PPrint.document - - method wrap_field_pat : - Generated_generic_printer_base.ast_position -> - field_pat -> - PPrint.document -> - PPrint.document - - method wrap_generic_constraint : - Generated_generic_printer_base.ast_position -> - generic_constraint -> - PPrint.document -> - PPrint.document - - method wrap_generic_param : - Generated_generic_printer_base.ast_position -> - generic_param -> - PPrint.document -> - PPrint.document - - method wrap_generic_param_kind : - Generated_generic_printer_base.ast_position -> - generic_param_kind -> - PPrint.document -> - PPrint.document - - method wrap_generic_value : - Generated_generic_printer_base.ast_position -> - generic_value -> - PPrint.document -> - PPrint.document - - method wrap_generics : - Generated_generic_printer_base.ast_position -> - generics -> - PPrint.document -> - PPrint.document - - method wrap_guard : - Generated_generic_printer_base.ast_position -> - guard -> - PPrint.document -> - PPrint.document - - method wrap_guard' : - Generated_generic_printer_base.ast_position -> - guard' -> - PPrint.document -> - PPrint.document - - method wrap_impl_expr : - Generated_generic_printer_base.ast_position -> - impl_expr -> - PPrint.document -> - PPrint.document - - method wrap_impl_expr_kind : - Generated_generic_printer_base.ast_position -> - impl_expr_kind -> - PPrint.document -> - PPrint.document - - method wrap_impl_ident : - Generated_generic_printer_base.ast_position -> - impl_ident -> - PPrint.document -> - PPrint.document - - method wrap_impl_item : - Generated_generic_printer_base.ast_position -> - impl_item -> - PPrint.document -> - PPrint.document - - method wrap_impl_item' : - Generated_generic_printer_base.ast_position -> - impl_item' -> - PPrint.document -> - PPrint.document - - method wrap_item : - Generated_generic_printer_base.ast_position -> - item -> - PPrint.document -> - PPrint.document - - method wrap_item' : - Generated_generic_printer_base.ast_position -> - item' -> - PPrint.document -> - PPrint.document - - method wrap_lhs : - Generated_generic_printer_base.ast_position -> - lhs -> - PPrint.document -> - PPrint.document - - method wrap_literal : - Generated_generic_printer_base.ast_position -> - literal -> - PPrint.document -> - PPrint.document - - method wrap_loop_kind : - Generated_generic_printer_base.ast_position -> - loop_kind -> - PPrint.document -> - PPrint.document - - method wrap_loop_state : - Generated_generic_printer_base.ast_position -> - loop_state -> - PPrint.document -> - PPrint.document - - method wrap_modul : - Generated_generic_printer_base.ast_position -> - item list -> - PPrint.document -> - PPrint.document - - method wrap_param : - Generated_generic_printer_base.ast_position -> - param -> - PPrint.document -> - PPrint.document - - method wrap_pat : - Generated_generic_printer_base.ast_position -> - pat -> - PPrint.document -> - PPrint.document - - method wrap_pat' : - Generated_generic_printer_base.ast_position -> - pat' -> - PPrint.document -> - PPrint.document - - method wrap_projection_predicate : - Generated_generic_printer_base.ast_position -> - projection_predicate -> - PPrint.document -> - PPrint.document - - method wrap_safety_kind : - Generated_generic_printer_base.ast_position -> - safety_kind -> - PPrint.document -> - PPrint.document - - method wrap_supported_monads : - Generated_generic_printer_base.ast_position -> - supported_monads -> - PPrint.document -> - PPrint.document - - method wrap_trait_goal : - Generated_generic_printer_base.ast_position -> - trait_goal -> - PPrint.document -> - PPrint.document - - method wrap_trait_item : - Generated_generic_printer_base.ast_position -> - trait_item -> - PPrint.document -> - PPrint.document - - method wrap_trait_item' : - Generated_generic_printer_base.ast_position -> - trait_item' -> - PPrint.document -> - PPrint.document - - method wrap_ty : - Generated_generic_printer_base.ast_position -> - ty -> - PPrint.document -> - PPrint.document - - method wrap_variant : - Generated_generic_printer_base.ast_position -> - variant -> - PPrint.document -> - PPrint.document - end + let new_printer: BasePrinter.finalized_printer = + BasePrinter.finalize (fun () -> (new printer :> BasePrinter.printer)) +end module type S = sig - class printer : printer_type + val new_printer: BasePrinter.finalized_printer end let make (module M : Attrs.WITH_ITEMS) = - (module Make - (struct - let default x = x - end) - (M) : S) + let open (Make + (struct + let default x = x + end) + (M) : S) in + new_printer let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = - let (module Printer) = make m in - let my_printer = new Printer.printer in - + let my_printer = make m in U.group_items_by_namespace items |> Map.to_alist |> List.map ~f:(fun (ns, items) -> @@ -2326,20 +846,13 @@ let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = ~f:(map_first_letter String.uppercase) (fst ns :: snd ns)) in - + let (contents, _annotations) = my_printer#entrypoint_modul items in Types. { path = mod_name ^ ".v"; contents = hardcoded_coq_headers ^ "\n" - ^ String.concat ~sep:"\n" - (List.map - ~f:(fun item -> - let buf = Buffer.create 0 in - PPrint.ToBuffer.pretty 1.0 80 buf - (my_printer#entrypoint_item item); - Buffer.contents buf) - items); + ^ contents; sourcemap = None; }) From fae8afc8663ebb6d101b51977c0471434231c26d Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Tue, 29 Oct 2024 17:42:36 +0100 Subject: [PATCH 199/253] Fixed issues in backend, restore generic printer --- engine/backends/coq/coq/coq_backend.ml | 171 ++++++++++-------- engine/lib/generic_printer/generic_printer.ml | 165 +++++++---------- 2 files changed, 157 insertions(+), 179 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 8190957a4..2c07c4b3d 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -12,14 +12,6 @@ include include On.Monadic_binding include On.Macro include On.Construct_base - (* include On.Trait_item_default *) - - (* include On.Loop *) - (* include On.For_loop *) - (* include On.While_loop *) - (* include On.For_index_loop *) - (* include On.State_passing_loop *) - (* include On.Fold_like_loop *) end) (struct let backend = Diagnostics.Backend.Coq @@ -67,14 +59,6 @@ struct include Features.SUBTYPE.On.Construct_base include Features.SUBTYPE.On.Slice include Features.SUBTYPE.On.Macro - (* include Features.SUBTYPE.On.Trait_item_default *) - - (* include Features.SUBTYPE.On.Loop *) - (* include Features.SUBTYPE.On.For_loop *) - (* include Features.SUBTYPE.On.While_loop *) - (* include Features.SUBTYPE.On.For_index_loop *) - (* include Features.SUBTYPE.On.State_passing_loop *) - (* include Features.SUBTYPE.On.Fold_like_loop *) end) let metadata = Phase_utils.Metadata.make (Reject (NotInBackendLang backend)) @@ -87,23 +71,6 @@ module CoqNamePolicy = Concrete_ident.DefaultNamePolicy module U = Ast_utils.MakeWithNamePolicy (InputLanguage) (CoqNamePolicy) open AST -module CoqLibrary : Library = struct - module Notation = struct - let int_repr (x : string) (i : string) : string = - "(@repr" ^ " " ^ "WORDSIZE" ^ x ^ " " ^ i ^ ")" - - let type_str : string = "Type" - let bool_str : string = "bool" - let unit_str : string = "unit" - end -end - -module C = Coq (CoqLibrary) - -module Context = struct - type t = { current_namespace : string * string list } -end - let hardcoded_coq_headers = "(* File automatically generated by Hacspec *)\n\ From Coq Require Import ZArith.\n\ @@ -128,12 +95,6 @@ struct let default_string_for s = "TODO: please implement the method `" ^ s ^ "`" let default_document_for = default_string_for >> string - let is_document_empty doc : bool = - (* Replace the following with: [PPrint.is_empty], however this currently does not work, bug? *) - let buf = Buffer.create 0 in - PPrint.ToBuffer.pretty 1.0 80 buf doc; - String.equal "" (Buffer.contents buf) - module CoqNotation = struct let definition_struct keyword n name generics params typ body = keyword ^^ space ^^ name ^^ generics @@ -240,33 +201,81 @@ struct method expr'_Construct_inductive ~super:_ ~constructor ~is_record ~is_struct ~fields ~base = - if is_struct then - if is_record then - (* Struct *) - Option.value - ~default: - (string "Build_t_" ^^ constructor#p - ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields - ) - (Option.map - ~f:(fun b -> - b#p - ^^ concat_map - (fun (ident, exp) -> - space ^^ string "<|" ^^ space ^^ ident#p ^^ space - ^^ !^":=" ^^ space ^^ parens exp#p ^^ space - ^^ string "|>") - fields - ^^ space) - base) + let fields_or_empty add_space = + if List.is_empty fields then empty else - (* Tuple struct *) - string "Build_" ^^ constructor#p - ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields - else - (* Indutive type *) - constructor#p - ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields + add_space + ^^ parens + (separate_map (comma ^^ space) (fun x -> (snd x)#p) fields) + in + if is_record && is_struct then + match base with + | Some x -> string "Build_" ^^ x#p ^^ fields_or_empty space + | None -> + string "Build_t_" ^^ constructor#p ^^ fields_or_empty space + else if not is_record then + if is_struct then + string "Build_t_" ^^ constructor#p ^^ fields_or_empty space + else + constructor#p ^^ fields_or_empty space + else string "(* TODO: Record? *)" + (* let fields_or_empty add_space = *) + (* if List.is_empty fields then empty *) + (* else *) + (* add_space *) + (* ^^ parens *) + (* (separate_map (comma ^^ space) (fun x -> (snd x#v)#p) fields) *) + (* in *) + (* if is_record && is_struct then *) + (* match base with *) + (* | Some x -> string "Build_" ^^ x#p ^^ fields_or_empty space *) + (* | None -> *) + (* string "Build_t_" *) + (* ^^ (self#_do_not_override_lazy_of_global_ident *) + (* Generated_generic_printer_base *) + (* .AstPos_pat'_PConstruct_constructor constructor) *) + (* #p ^^ fields_or_empty space *) + (* else if not is_record then *) + (* if is_struct then *) + (* string "Build_t_" *) + (* ^^ (self#_do_not_override_lazy_of_global_ident *) + (* Generated_generic_printer_base *) + (* .AstPos_pat'_PConstruct_constructor constructor) *) + (* #p ^^ fields_or_empty space *) + (* else *) + (* (self#_do_not_override_lazy_of_global_ident *) + (* Generated_generic_printer_base *) + (* .AstPos_pat'_PConstruct_constructor constructor) *) + (* #p ^^ fields_or_empty space *) + (* else string "(\* TODO: Record? *\)" *) + + (* if is_struct then *) + (* if is_record then *) + (* (\* Struct *\) *) + (* Option.value *) + (* ~default: *) + (* (string "Build_t_" ^^ constructor#p *) + (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) + (* ) *) + (* (Option.map *) + (* ~f:(fun b -> *) + (* b#p *) + (* ^^ concat_map *) + (* (fun (ident, exp) -> *) + (* space ^^ string "<|" ^^ space ^^ ident#p ^^ space *) + (* ^^ !^":=" ^^ space ^^ parens exp#p ^^ space *) + (* ^^ string "|>") *) + (* fields *) + (* ^^ space) *) + (* base) *) + (* else *) + (* (\* Tuple struct *\) *) + (* string "Build_" ^^ constructor#p *) + (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) + (* else *) + (* (\* Indutive type *\) *) + (* constructor#p *) + (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) method expr'_Construct_tuple ~super:_ ~components = if List.length components == 0 then !^"tt" @@ -406,7 +415,8 @@ struct method impl_item'_IIType ~typ ~parent_bounds:_ = typ#p method item ~v ~span:_ ~ident:_ ~attrs:_ = - if is_document_empty v#p then empty else v#p ^^ break 1 + v#p + (* if is_document_empty v#p then empty else v#p ^^ break 1 *) method item'_Alias ~super:_ ~name ~item = string "Notation" ^^ space ^^ string "\"'" ^^ name#p ^^ string "'\"" @@ -423,10 +433,9 @@ struct self#_do_not_override_lazy_of_ty AstPos_item'_Fn_body body#v.typ in - let get_expr_of kind f : document = + let get_expr_of kind f : document option = Attrs.associated_expr kind super.attrs |> Option.map ~f:(self#entrypoint_expr >> f) - |> Option.value ~default:empty in let requires = get_expr_of Requires (fun x -> @@ -441,20 +450,18 @@ struct if is_lemma then CoqNotation.lemma name#p generics#p (List.map ~f:(fun x -> x#p) params) - (requires ^^ space ^^ !^"->" ^^ break 1 ^^ ensures) + (Option.value ~default:empty (requires) ^^ space ^^ !^"->" ^^ break 1 ^^ Option.value ~default:empty ensures) else if is_rec then CoqNotation.fixpoint name#p generics#p (List.map ~f:(fun x -> x#p) params - @ - if is_document_empty requires then [] - else [ string "`" ^^ braces requires ]) + @ + Option.value ~default:[] (Option.map ~f:(fun x -> [string "`" ^^ braces x]) requires)) typ#p body#p (* ^^ TODO: ensures? *) else CoqNotation.definition name#p generics#p (List.map ~f:(fun x -> x#p) params @ - if is_document_empty requires then [] - else [ string "`" ^^ braces requires ]) + Option.value ~default:[] (Option.map ~f:(fun x -> [string "`" ^^ braces x]) requires)) typ#p body#p (* ^^ TODO: ensures? *) method item'_HaxError ~super:_ _x2 = default_document_for "item'_HaxError" @@ -632,7 +639,7 @@ struct method loop_state ~init ~bpat ~witness:_ = parens (init#p ^^ space ^^ !^"state" ^^ space ^^ bpat#p) - method modul _x1 = default_document_for "modul" + method modul x1 = separate_map (break 1) (fun x -> x#p) x1 (* default_document_for "modul" *) method param ~pat ~typ ~typ_span:_ ~attrs:_ = parens (pat#p ^^ space ^^ colon ^^ space ^^ typ#p) @@ -647,15 +654,19 @@ struct method pat'_PConstant ~super:_ ~lit = lit#p - method pat'_PConstruct_inductive ~super:_ ~constructor ~is_record:_ + method pat'_PConstruct_inductive ~super:_ ~constructor ~is_record ~is_struct ~fields = - (if is_struct then string "Build_t_" else empty) - ^^ constructor#p - ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields + if is_record + then + constructor#p ^^ space ^^ parens (separate_map (comma ^^ space) (fun field_pat -> (snd field_pat)#p) fields) + else + (if is_struct then string "Build_t_" else empty) + ^^ constructor#p + ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields method pat'_PConstruct_tuple ~super:_ ~components = (* TODO: Only add `'` if you are a top-level pattern *) - string "'" ^^ parens (separate_map comma (fun x -> x#p) components) + (* string "'" ^^ *) parens (separate_map comma (fun x -> x#p) components) method pat'_PDeref ~super:_ ~subpat:_ ~witness:_ = default_document_for "pat'_PDeref" diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index d74a04509..561b820da 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -260,7 +260,7 @@ module Make (F : Features.T) = struct constructor:concrete_ident lazy_doc -> is_record:bool -> is_struct:bool -> - fields:(concrete_ident lazy_doc * expr lazy_doc) list -> + fields:(global_ident lazy_doc * expr lazy_doc) list -> base:(expr lazy_doc * F.construct_base) lazy_doc option -> document (** [expr'_Construct_inductive ~super ~is_record ~is_struct @@ -281,7 +281,7 @@ module Make (F : Features.T) = struct method virtual pat'_PConstruct_inductive : super:pat -> - constructor:global_ident lazy_doc -> + constructor:concrete_ident lazy_doc -> is_record:bool -> is_struct:bool -> fields:(global_ident lazy_doc * pat lazy_doc) list -> @@ -435,44 +435,30 @@ module Make (F : Features.T) = struct self#expr'_App_field_projection ~super ~field ~e) | _ -> self#assertion_failure "Primitive app of arity 0" - method _do_not_override_expr'_Construct ~super:_ ~constructor ~is_record + method _do_not_override_expr'_Construct ~super ~constructor ~is_record ~is_struct ~fields ~base = - let fields_or_empty add_space = - if List.is_empty fields then empty - else - add_space - ^^ parens - (separate_map (comma ^^ space) (fun x -> (snd x#v)#p) fields) - in - match (constructor, fields, base) with - | `TupleCons 0, [], _ -> string "tt" - | `TupleCons 1, [ e ], _ -> - let _, e' = e#v in - string "(* tuple_cons 1 *)" ^^ e'#p - | `TupleCons _, _, None -> fields_or_empty empty - | _, _, _ -> - if is_record && is_struct then - match base with - | Some x -> string "Build_" ^^ x#p ^^ fields_or_empty space - | None -> - string "Build_t_" - ^^ (self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base - .AstPos_pat'_PConstruct_constructor constructor) - #p ^^ fields_or_empty space - else if not is_record then - if is_struct then - string "Build_t_" - ^^ (self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base - .AstPos_pat'_PConstruct_constructor constructor) - #p ^^ fields_or_empty space - else - (self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base - .AstPos_pat'_PConstruct_constructor constructor) - #p ^^ fields_or_empty space - else string "(* TODO: Record? *)" + match constructor with + | `Concrete constructor -> + let constructor = + self#_do_not_override_lazy_of_concrete_ident + AstPos_expr'_Construct_constructor constructor + in + let fields = + List.map + ~f:(fun field -> + let name, expr = field#v in + ( self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base.AstPos_pat'_PConstruct_constructor name, + expr )) + fields + in + self#expr'_Construct_inductive ~super ~constructor ~is_record + ~is_struct ~fields ~base + | `TupleCons _ -> + let components = List.map ~f:(fun field -> snd field#v) fields in + self#expr'_Construct_tuple ~super ~components + | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> + self#assertion_failure "Construct unexpected constructors" method _do_not_override_expr'_GlobalVar ~super global_ident = match global_ident with @@ -484,7 +470,7 @@ module Make (F : Features.T) = struct self#expr'_GlobalVar_concrete ~super concrete | `Primitive primitive -> self#expr'_GlobalVar_primitive ~super primitive - | `TupleCons 0 -> string "tt" + | `TupleCons 0 -> self#_do_not_override_expr'_Construct ~super ~constructor:global_ident ~is_record:false ~is_struct:false ~fields:[] ~base:None | _ -> self#assertion_failure @@ "GlobalVar: expected a concrete or primitive global ident, got:" @@ -492,41 +478,42 @@ module Make (F : Features.T) = struct method _do_not_override_pat'_PConstruct ~super ~constructor ~is_record ~is_struct ~fields = - match (constructor, fields) with - | `TupleCons 0, [] -> string "'tt (* const unit *)" (* Unit pat *) - | `TupleCons 1, [ p ] -> p#p - | `TupleCons _n, _ -> - parens (separate_map (comma ^^ space) (fun x -> x#p) fields) - | _, _ -> - if is_record then - (self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base - .AstPos_pat'_PConstruct_constructor constructor) - #p ^^ space - ^^ parens (separate_map (comma ^^ space) (fun x -> x#p) fields) - else - self#pat'_PConstruct_inductive ~super - ~constructor: - (self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base - .AstPos_pat'_PConstruct_constructor constructor) - ~is_record ~is_struct - ~fields: - (List.map - ~f:(fun field -> - let { field; pat } = field#v in - let pat = - self#_do_not_override_lazy_of_pat - Generated_generic_printer_base - .AstPos_pat'_PConstruct_fields pat - in - let field = - self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base - .AstPos_pat'_PConstruct_fields field - in - (field, pat)) - fields) + match constructor with + | `Concrete constructor -> + let constructor = + self#_do_not_override_lazy_of_concrete_ident + AstPos_pat'_PConstruct_constructor constructor + in + let fields = + List.map + ~f:(fun field -> + let { field; pat } = field#v in + let field = + self#_do_not_override_lazy_of_global_ident + Generated_generic_printer_base.AstPos_pat'_PConstruct_fields + field + in + let pat = + self#_do_not_override_lazy_of_pat + Generated_generic_printer_base.AstPos_pat'_PConstruct_fields + pat + in + (field, pat)) + fields + in + self#pat'_PConstruct_inductive ~super ~constructor ~is_record + ~is_struct ~fields + | `TupleCons _ -> + let components = + List.map + ~f:(fun field -> + self#_do_not_override_lazy_of_pat AstPos_field_pat__pat + field#v.pat) + fields + in + self#pat'_PConstruct_tuple ~super ~components + | `Primitive _ | `TupleType _ | `TupleField _ | `Projector _ -> + self#assertion_failure "Construct unexpected constructors" method _do_not_override_ty_TApp ~ident ~args = match ident with @@ -605,30 +592,10 @@ module Make (F : Features.T) = struct lazy_doc (fun (id : global_ident) -> match id with - | `Concrete cid -> - (self#_do_not_override_lazy_of_concrete_ident ast_position cid) - #p - | `Primitive _prim_id -> string "(*TODO*) prim_id" - | `TupleType 0 -> string "unit" - (* | `TupleCons n when n <= 1 -> *) - (* Error.assertion_failure span *) - (* ("Got a [TupleCons " ^ string_of_int n ^ "]") *) - (* | `TupleType n when n <= 14 -> *) - (* F.lid [ "FStar"; "Pervasives"; "tuple" ^ string_of_int n ] *) - (* | `TupleCons n when n <= 14 -> *) - (* F.lid [ "FStar"; "Pervasives"; "Mktuple" ^ string_of_int n ] *) - (* | `TupleType n | `TupleCons n -> *) - (* let reason = "F* doesn't support tuple of size greater than 14" in *) - (* Error.raise *) - (* { *) - (* kind = UnsupportedTupleSize { tuple_size = Int64.of_int n; reason }; *) - (* span; *) - (* } *) - (* | `TupleField _ | `Projector _ -> *) - (* Error.assertion_failure span *) - (* ("pglobal_ident: expected to be handled somewhere else: " *) - (* ^ show_global_ident id) *) - | _ -> string "(* TODO *) error global ident type?") + | `Concrete cid -> (self#_do_not_override_lazy_of_concrete_ident ast_position cid)#p + (* | `Primitive _prim_id -> string "(\*TODO*\) prim_id" *) + (* | `TupleType 0 -> string "unit" *) + | _ -> self#assertion_failure "[global_ident]") ast_position id method _do_not_override_lazy_of_quote ast_position (value : quote) From 87b962c8b23304d4cd685c1217f00c2527b0832b Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Tue, 29 Oct 2024 17:43:30 +0100 Subject: [PATCH 200/253] Insta review --- .../snapshots/toolchain__assert into-coq.snap | 12 +++---- .../toolchain__enum-repr into-coq.snap | 11 +----- .../snapshots/toolchain__guards into-coq.snap | 7 +--- .../toolchain__include-flag into-coq.snap | 19 +--------- .../toolchain__let-else into-coq.snap | 5 +-- .../toolchain__literals into-coq.snap | 35 +++---------------- .../toolchain__pattern-or into-coq.snap | 32 +++++++---------- .../toolchain__reordering into-coq.snap | 10 +----- .../snapshots/toolchain__slices into-coq.snap | 7 +--- 9 files changed, 27 insertions(+), 111 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__assert into-coq.snap b/test-harness/src/snapshots/toolchain__assert into-coq.snap index c198bf926..9f6ecd8fa 100644 --- a/test-harness/src/snapshots/toolchain__assert into-coq.snap +++ b/test-harness/src/snapshots/toolchain__assert into-coq.snap @@ -41,17 +41,15 @@ Import RecordSetNotations. (* NotImplementedYet *) - Definition asserts (_ : unit) : unit := let _ := assert (true) in let _ := assert (t_PartialEq_f_eq (1) (1)) in - let _ := match (2, 2) with - | (left_val, right_val) => + let _ := match (2,2) with + | (left_val,right_val) => assert (t_PartialEq_f_eq (left_val) (right_val)) end in - let _ := match (1, 2) with - | (left_val, right_val) => + let _ := match (1,2) with + | (left_val,right_val) => assert (negb (t_PartialEq_f_eq (left_val) (right_val))) end in - tt. -''' + tt.''' diff --git a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap index 4f5cf2c7b..e01bebf01 100644 --- a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap +++ b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap @@ -43,10 +43,8 @@ Import RecordSetNotations. Definition discriminant_t_EnumWithRepr_ExplicitDiscr1 : t_u16 := 1. - Definition discriminant_t_EnumWithRepr_ExplicitDiscr2 : t_u16 := 5. - Inductive t_EnumWithRepr : Type := | t_EnumWithRepr_ExplicitDiscr1 | t_EnumWithRepr_ExplicitDiscr2 @@ -54,7 +52,6 @@ Inductive t_EnumWithRepr : Type := | t_EnumWithRepr_ImplicitDiscrEmptyStruct. Arguments t_EnumWithRepr:clear implicits. Arguments t_EnumWithRepr. - Definition t_EnumWithRepr_cast_to_repr (x : t_EnumWithRepr) : t_u16 := match x with | t_EnumWithRepr_ExplicitDiscr1 => @@ -66,19 +63,13 @@ Definition t_EnumWithRepr_cast_to_repr (x : t_EnumWithRepr) : t_u16 := | t_EnumWithRepr_ImplicitDiscrEmptyStruct => t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (2) end. - (* NotImplementedYet *) - Definition f (_ : unit) : t_u32 := let v__x := cast (t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (0)) in t_Add_f_add (cast (t_EnumWithRepr_cast_to_repr (t_EnumWithRepr_ImplicitDiscrEmptyTuple))) (cast (t_EnumWithRepr_cast_to_repr (t_EnumWithRepr_ImplicitDiscrEmptyStruct))). - Definition ff__CONST : t_u16 := cast (t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr1) (0)). - Definition get_casted_repr (x : t_EnumWithRepr) : t_u64 := cast (t_EnumWithRepr_cast_to_repr (x)). - Definition get_repr (x : t_EnumWithRepr) : t_u16 := - t_EnumWithRepr_cast_to_repr (x). -''' + t_EnumWithRepr_cast_to_repr (x).''' diff --git a/test-harness/src/snapshots/toolchain__guards into-coq.snap b/test-harness/src/snapshots/toolchain__guards into-coq.snap index ca5f0a562..387dbbcf9 100644 --- a/test-harness/src/snapshots/toolchain__guards into-coq.snap +++ b/test-harness/src/snapshots/toolchain__guards into-coq.snap @@ -41,7 +41,6 @@ Import RecordSetNotations. (* NotImplementedYet *) - Definition equivalent (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with | t_Option_None => @@ -69,7 +68,6 @@ Definition equivalent (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := end end end. - Definition if_guard (x : t_Option ((t_i32))) : t_i32 := match match x with | t_Option_Some (v) => @@ -87,7 +85,6 @@ Definition if_guard (x : t_Option ((t_i32))) : t_i32 := | t_Option_None => 0 end. - Definition if_let_guard (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with | t_Option_None => @@ -115,7 +112,6 @@ Definition if_let_guard (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 end end end. - Definition multiple_guards (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with | t_Option_None => @@ -157,5 +153,4 @@ Definition multiple_guards (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i end end end - end. -''' + end.''' diff --git a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap index 18e23b99b..9122c374c 100644 --- a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap +++ b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap @@ -48,67 +48,50 @@ Arguments t_Foo. Arguments Build_t_Foo. #[export] Instance settable_t_Foo : Settable _ := settable! (@Build_t_Foo) <>. - Class t_Trait `{v_Self : Type} : Type := { }. Arguments t_Trait:clear implicits. Arguments t_Trait (_). - Instance t_Trait_187936720 : t_Trait ((t_Foo)) := { }. - (* NotImplementedYet *) - Definition main_a_a (_ : unit) : unit := tt. - Definition main_a_b (_ : unit) : unit := tt. - Definition main_a_c (_ : unit) : unit := tt. - Definition main_a `{v_T : Type} `{t_Sized (v_T)} `{t_Trait (v_T)} (x : v_T) : unit := let _ := main_a_a (tt) in let _ := main_a_b (tt) in let _ := main_a_c (tt) in tt. - Definition main_b_a (_ : unit) : unit := tt. - Definition main_b_b (_ : unit) : unit := tt. - Definition main_b_c (_ : unit) : unit := tt. - Definition main_b (_ : unit) : unit := let _ := main_b_a (tt) in let _ := main_b_b (tt) in let _ := main_b_c (tt) in tt. - Definition main_c_a (_ : unit) : unit := tt. - Definition main_c_b (_ : unit) : unit := tt. - Definition main_c_c (_ : unit) : unit := tt. - Definition main_c (_ : unit) : unit := let _ := main_c_a (tt) in let _ := main_c_b (tt) in let _ := main_c_c (tt) in tt. - Definition main (_ : unit) : unit := let _ := main_a (Build_t_Foo) in let _ := main_b (tt) in let _ := main_c (tt) in - tt. -''' + tt.''' diff --git a/test-harness/src/snapshots/toolchain__let-else into-coq.snap b/test-harness/src/snapshots/toolchain__let-else into-coq.snap index 64d5f5c52..a705d6542 100644 --- a/test-harness/src/snapshots/toolchain__let-else into-coq.snap +++ b/test-harness/src/snapshots/toolchain__let-else into-coq.snap @@ -41,7 +41,6 @@ Import RecordSetNotations. (* NotImplementedYet *) - Definition let_else (opt : t_Option ((t_u32))) : bool := run (match opt with | t_Option_Some (x) => @@ -49,7 +48,6 @@ Definition let_else (opt : t_Option ((t_u32))) : bool := | _ => t_ControlFlow_Break (false) end). - Definition let_else_different_type (opt : t_Option ((t_u32))) : bool := run (let hoist1 := match opt with | t_Option_Some (x) => @@ -57,5 +55,4 @@ Definition let_else_different_type (opt : t_Option ((t_u32))) : bool := | _ => t_ControlFlow_Break (false) end in - t_ControlFlow_Continue (let_else (hoist1))). -''' + t_ControlFlow_Continue (let_else (hoist1))).''' diff --git a/test-harness/src/snapshots/toolchain__literals into-coq.snap b/test-harness/src/snapshots/toolchain__literals into-coq.snap index ad3302afe..e2203f3fb 100644 --- a/test-harness/src/snapshots/toolchain__literals into-coq.snap +++ b/test-harness/src/snapshots/toolchain__literals into-coq.snap @@ -21,23 +21,7 @@ info: backend_options: ~ --- exit = 0 -stderr = ''' -warning: unused variable: `attr` - --> /home/au538501/Documents/git/hax/hax-lib-macros/src/lib.rs:387:18 - | -387 | pub fn interface(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream { - | ^^^^ help: if this is intentional, prefix it with an underscore: `_attr` - | - = note: `#[warn(unused_variables)]` on by default - -warning: unused variable: `block` - --> /home/au538501/Documents/git/hax/hax-lib-macros/src/lib.rs:395:9 - | -395 | block, - | ^^^^^ help: try ignoring the field: `block: _` - -warning: `hax-lib-macros` (lib) generated 2 warnings - Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs''' +stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' [stdout] diagnostics = [] @@ -59,7 +43,6 @@ Import RecordSetNotations. From Literals Require Import Hax_lib (t_int). Export Hax_lib (t_int). - Record t_Foo : Type := { t_Foo_f_field : t_u8; @@ -69,12 +52,9 @@ Arguments t_Foo. Arguments Build_t_Foo. #[export] Instance settable_t_Foo : Settable _ := settable! (@Build_t_Foo) . - (* NotImplementedYet *) - Definition v_CONSTANT : t_Foo := Build_t_Foo (3). - Definition casts (x8 : t_u8) (x16 : t_u16) (x32 : t_u32) (x64 : t_u64) (xs : t_usize) : unit := let _ : t_u64 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (x64)) (cast (xs)) in let _ : t_u32 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (x32)) (cast (x64))) (cast (xs)) in @@ -85,12 +65,10 @@ Definition casts (x8 : t_u8) (x16 : t_u16) (x32 : t_u32) (x64 : t_u64) (xs : t_u let _ : t_i16 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in let _ : t_i8 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in tt. - Definition fn_pointer_cast (_ : unit) : unit := let f : t_u32 -> t_u32 := fun x => x in tt. - Definition math_integers (x : t_Int) `{andb (t_PartialOrd_f_gt (x) (impl__Int___unsafe_from_str ("0"%string))) (t_PartialOrd_f_lt (x) (impl__Int___unsafe_from_str ("16"%string))) = true} : t_u8 := let _ : t_Int := t_Abstraction_f_lift (3) in let _ := t_PartialOrd_f_gt (impl__Int___unsafe_from_str ("-340282366920938463463374607431768211455000"%string)) (impl__Int___unsafe_from_str ("340282366920938463463374607431768211455000"%string)) in @@ -114,7 +92,6 @@ Definition math_integers (x : t_Int) `{andb (t_PartialOrd_f_gt (x) (impl__Int___ let _ : t_u128 := impl__Int__to_u128 (x) in let _ : t_usize := impl__Int__to_usize (x) in impl__Int__to_u8 (t_Add_f_add (x) (t_Mul_f_mul (x) (x))). - Definition numeric (_ : unit) : unit := let _ : t_usize := 123 in let _ : t_isize := 42 in @@ -122,7 +99,6 @@ Definition numeric (_ : unit) : unit := let _ : t_i32 := 42 in let _ : t_u128 := 22222222222222222222 in tt. - Definition patterns (_ : unit) : unit := let _ := match 1 with | 2 => @@ -130,8 +106,8 @@ Definition patterns (_ : unit) : unit := | _ => tt end in - let _ := match ("hello"%string, (123, ["a"%string; "b"%string])) with - | ("hello"%string, (123, v__todo)) => + let _ := match ("hello"%string,(123,["a"%string; "b"%string])) with + | ("hello"%string,(123,v__todo)) => tt | _ => tt @@ -143,11 +119,8 @@ Definition patterns (_ : unit) : unit := tt end in tt. - Definition panic_with_msg (_ : unit) : unit := never_to_any (panic_fmt (impl_2__new_const (["with msg"%string]))). - Definition empty_array (_ : unit) : unit := let _ : t_Slice t_u8 := unsize ([]) in - tt. -''' + tt.''' diff --git a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap index 318b43ef9..6f121c290 100644 --- a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap +++ b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap @@ -46,7 +46,6 @@ Inductive t_E : Type := | t_E_B. Arguments t_E:clear implicits. Arguments t_E. - Definition t_E_cast_to_repr (x : t_E) : t_isize := match x with | t_E_A => @@ -54,49 +53,43 @@ Definition t_E_cast_to_repr (x : t_E) : t_isize := | t_E_B => 1 end. - (* NotImplementedYet *) - Definition bar (x : t_E) : unit := match x with | t_E_A | t_E_B => tt end. - Definition deep (x : (t_i32*t_Option ((t_i32)))) : t_i32 := match x with | (1 - | 2, t_Option_Some (3 + | 2,t_Option_Some (3 | 4)) => 0 - | (x, _) => + | (x,_) => x end. - Definition deep_capture (x : t_Result (((t_i32*t_i32))) (((t_i32*t_i32)))) : t_i32 := match x with | t_Result_Ok ((1 - | 2, x)) + | 2,x)) | t_Result_Err ((3 - | 4, x)) => + | 4,x)) => x - | t_Result_Ok ((x, _)) - | t_Result_Err ((x, _)) => + | t_Result_Ok ((x,_)) + | t_Result_Err ((x,_)) => x end. - Definition equivalent (x : (t_i32*t_Option ((t_i32)))) : t_i32 := match x with - | (1, t_Option_Some (3)) - | (1, t_Option_Some (4)) - | (2, t_Option_Some (3)) - | (2, t_Option_Some (4)) => + | (1,t_Option_Some (3)) + | (1,t_Option_Some (4)) + | (2,t_Option_Some (3)) + | (2,t_Option_Some (4)) => 0 - | (x, _) => + | (x,_) => x end. - Definition nested (x : t_Option ((t_i32))) : t_i32 := match x with | t_Option_Some (1 @@ -106,5 +99,4 @@ Definition nested (x : t_Option ((t_i32))) : t_i32 := x | t_Option_None => 0 - end. -''' + end.''' diff --git a/test-harness/src/snapshots/toolchain__reordering into-coq.snap b/test-harness/src/snapshots/toolchain__reordering into-coq.snap index 97ed08290..ddbd8546e 100644 --- a/test-harness/src/snapshots/toolchain__reordering into-coq.snap +++ b/test-harness/src/snapshots/toolchain__reordering into-coq.snap @@ -45,7 +45,6 @@ Inductive t_Foo : Type := | t_Foo_B. Arguments t_Foo:clear implicits. Arguments t_Foo. - Record t_Bar : Type := { t_Bar_0 : t_Foo; @@ -55,7 +54,6 @@ Arguments t_Bar. Arguments Build_t_Bar. #[export] Instance settable_t_Bar : Settable _ := settable! (@Build_t_Bar) . - Definition t_Foo_cast_to_repr (x : t_Foo) : t_isize := match x with | t_Foo_A => @@ -63,18 +61,12 @@ Definition t_Foo_cast_to_repr (x : t_Foo) : t_isize := | t_Foo_B => 1 end. - (* NotImplementedYet *) - Definition f (_ : t_u32) : t_Foo := t_Foo_A. - Definition g (_ : unit) : t_Bar := Build_t_Bar (f (32)). - Definition no_dependency_1_ (_ : unit) : unit := tt. - Definition no_dependency_2_ (_ : unit) : unit := - tt. -''' + tt.''' diff --git a/test-harness/src/snapshots/toolchain__slices into-coq.snap b/test-harness/src/snapshots/toolchain__slices into-coq.snap index 784821f9c..2846fe70d 100644 --- a/test-harness/src/snapshots/toolchain__slices into-coq.snap +++ b/test-harness/src/snapshots/toolchain__slices into-coq.snap @@ -42,16 +42,11 @@ Import RecordSetNotations. (* NotImplementedYet *) - Definition v_VERSION : t_Slice t_u8 := unsize ([118; 49]). - Definition do_something (_ : t_Slice t_u8) : unit := tt. - Definition r#unsized (_ : t_Array (t_Slice t_u8) (1)) : unit := tt. - Definition sized (x : t_Array (t_Array (t_u8) (4)) (1)) : unit := - r#unsized ([unsize (index (x) (0))]). -''' + r#unsized ([unsize (index (x) (0))]).''' From 15120cec1a51743981ff778e9cac775f5ac045cb Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Tue, 29 Oct 2024 17:44:32 +0100 Subject: [PATCH 201/253] fmt --- engine/backends/coq/coq/coq_backend.ml | 120 +++++++++--------- engine/lib/generic_printer/generic_printer.ml | 20 ++- 2 files changed, 76 insertions(+), 64 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 2c07c4b3d..79670a21a 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -85,6 +85,7 @@ let hardcoded_coq_headers = Import RecordSetNotations.\n" module BasePrinter = Generic_printer.Make (InputLanguage) + module Make (Default : sig val default : string -> string end) @@ -206,18 +207,16 @@ struct else add_space ^^ parens - (separate_map (comma ^^ space) (fun x -> (snd x)#p) fields) + (separate_map (comma ^^ space) (fun x -> (snd x)#p) fields) in if is_record && is_struct then match base with | Some x -> string "Build_" ^^ x#p ^^ fields_or_empty space - | None -> - string "Build_t_" ^^ constructor#p ^^ fields_or_empty space + | None -> string "Build_t_" ^^ constructor#p ^^ fields_or_empty space else if not is_record then if is_struct then string "Build_t_" ^^ constructor#p ^^ fields_or_empty space - else - constructor#p ^^ fields_or_empty space + else constructor#p ^^ fields_or_empty space else string "(* TODO: Record? *)" (* let fields_or_empty add_space = *) (* if List.is_empty fields then empty *) @@ -249,33 +248,33 @@ struct (* #p ^^ fields_or_empty space *) (* else string "(\* TODO: Record? *\)" *) - (* if is_struct then *) - (* if is_record then *) - (* (\* Struct *\) *) - (* Option.value *) - (* ~default: *) - (* (string "Build_t_" ^^ constructor#p *) - (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) - (* ) *) - (* (Option.map *) - (* ~f:(fun b -> *) - (* b#p *) - (* ^^ concat_map *) - (* (fun (ident, exp) -> *) - (* space ^^ string "<|" ^^ space ^^ ident#p ^^ space *) - (* ^^ !^":=" ^^ space ^^ parens exp#p ^^ space *) - (* ^^ string "|>") *) - (* fields *) - (* ^^ space) *) - (* base) *) - (* else *) - (* (\* Tuple struct *\) *) - (* string "Build_" ^^ constructor#p *) - (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) - (* else *) - (* (\* Indutive type *\) *) - (* constructor#p *) - (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) + (* if is_struct then *) + (* if is_record then *) + (* (\* Struct *\) *) + (* Option.value *) + (* ~default: *) + (* (string "Build_t_" ^^ constructor#p *) + (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) + (* ) *) + (* (Option.map *) + (* ~f:(fun b -> *) + (* b#p *) + (* ^^ concat_map *) + (* (fun (ident, exp) -> *) + (* space ^^ string "<|" ^^ space ^^ ident#p ^^ space *) + (* ^^ !^":=" ^^ space ^^ parens exp#p ^^ space *) + (* ^^ string "|>") *) + (* fields *) + (* ^^ space) *) + (* base) *) + (* else *) + (* (\* Tuple struct *\) *) + (* string "Build_" ^^ constructor#p *) + (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) + (* else *) + (* (\* Indutive type *\) *) + (* constructor#p *) + (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) method expr'_Construct_tuple ~super:_ ~components = if List.length components == 0 then !^"tt" @@ -413,10 +412,8 @@ struct ^^ nest 2 (break 1 ^^ body#p) method impl_item'_IIType ~typ ~parent_bounds:_ = typ#p - - method item ~v ~span:_ ~ident:_ ~attrs:_ = - v#p - (* if is_document_empty v#p then empty else v#p ^^ break 1 *) + method item ~v ~span:_ ~ident:_ ~attrs:_ = v#p + (* if is_document_empty v#p then empty else v#p ^^ break 1 *) method item'_Alias ~super:_ ~name ~item = string "Notation" ^^ space ^^ string "\"'" ^^ name#p ^^ string "'\"" @@ -450,18 +447,20 @@ struct if is_lemma then CoqNotation.lemma name#p generics#p (List.map ~f:(fun x -> x#p) params) - (Option.value ~default:empty (requires) ^^ space ^^ !^"->" ^^ break 1 ^^ Option.value ~default:empty ensures) + (Option.value ~default:empty requires + ^^ space ^^ !^"->" ^^ break 1 + ^^ Option.value ~default:empty ensures) else if is_rec then CoqNotation.fixpoint name#p generics#p (List.map ~f:(fun x -> x#p) params - @ - Option.value ~default:[] (Option.map ~f:(fun x -> [string "`" ^^ braces x]) requires)) + @ Option.value ~default:[] + (Option.map ~f:(fun x -> [ string "`" ^^ braces x ]) requires)) typ#p body#p (* ^^ TODO: ensures? *) else CoqNotation.definition name#p generics#p (List.map ~f:(fun x -> x#p) params - @ - Option.value ~default:[] (Option.map ~f:(fun x -> [string "`" ^^ braces x]) requires)) + @ Option.value ~default:[] + (Option.map ~f:(fun x -> [ string "`" ^^ braces x ]) requires)) typ#p body#p (* ^^ TODO: ensures? *) method item'_HaxError ~super:_ _x2 = default_document_for "item'_HaxError" @@ -639,7 +638,10 @@ struct method loop_state ~init ~bpat ~witness:_ = parens (init#p ^^ space ^^ !^"state" ^^ space ^^ bpat#p) - method modul x1 = separate_map (break 1) (fun x -> x#p) x1 (* default_document_for "modul" *) + method modul x1 = + separate_map (break 1) + (fun x -> x#p) + x1 (* default_document_for "modul" *) method param ~pat ~typ ~typ_span:_ ~attrs:_ = parens (pat#p ^^ space ^^ colon ^^ space ^^ typ#p) @@ -656,9 +658,12 @@ struct method pat'_PConstruct_inductive ~super:_ ~constructor ~is_record ~is_struct ~fields = - if is_record - then - constructor#p ^^ space ^^ parens (separate_map (comma ^^ space) (fun field_pat -> (snd field_pat)#p) fields) + if is_record then + constructor#p ^^ space + ^^ parens + (separate_map (comma ^^ space) + (fun field_pat -> (snd field_pat)#p) + fields) else (if is_struct then string "Build_t_" else empty) ^^ constructor#p @@ -666,7 +671,8 @@ struct method pat'_PConstruct_tuple ~super:_ ~components = (* TODO: Only add `'` if you are a top-level pattern *) - (* string "'" ^^ *) parens (separate_map comma (fun x -> x#p) components) + (* string "'" ^^ *) + parens (separate_map comma (fun x -> x#p) components) method pat'_PDeref ~super:_ ~subpat:_ ~witness:_ = default_document_for "pat'_PDeref" @@ -830,20 +836,22 @@ struct (* val mutable current_namespace : (string * string list) option = None *) end - let new_printer: BasePrinter.finalized_printer = + let new_printer : BasePrinter.finalized_printer = BasePrinter.finalize (fun () -> (new printer :> BasePrinter.printer)) end module type S = sig - val new_printer: BasePrinter.finalized_printer + val new_printer : BasePrinter.finalized_printer end let make (module M : Attrs.WITH_ITEMS) = - let open (Make - (struct - let default x = x - end) - (M) : S) in + let open ( + Make + (struct + let default x = x + end) + (M) : + S) in new_printer let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = @@ -857,13 +865,11 @@ let translate m _ ~bundles:_ (items : AST.item list) : Types.file list = ~f:(map_first_letter String.uppercase) (fst ns :: snd ns)) in - let (contents, _annotations) = my_printer#entrypoint_modul items in + let contents, _annotations = my_printer#entrypoint_modul items in Types. { path = mod_name ^ ".v"; - contents = - hardcoded_coq_headers ^ "\n" - ^ contents; + contents = hardcoded_coq_headers ^ "\n" ^ contents; sourcemap = None; }) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 561b820da..c2b1cd6d9 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -448,7 +448,8 @@ module Make (F : Features.T) = struct ~f:(fun field -> let name, expr = field#v in ( self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base.AstPos_pat'_PConstruct_constructor name, + Generated_generic_printer_base + .AstPos_pat'_PConstruct_constructor name, expr )) fields in @@ -470,7 +471,10 @@ module Make (F : Features.T) = struct self#expr'_GlobalVar_concrete ~super concrete | `Primitive primitive -> self#expr'_GlobalVar_primitive ~super primitive - | `TupleCons 0 -> self#_do_not_override_expr'_Construct ~super ~constructor:global_ident ~is_record:false ~is_struct:false ~fields:[] ~base:None + | `TupleCons 0 -> + self#_do_not_override_expr'_Construct ~super + ~constructor:global_ident ~is_record:false ~is_struct:false + ~fields:[] ~base:None | _ -> self#assertion_failure @@ "GlobalVar: expected a concrete or primitive global ident, got:" @@ -490,13 +494,13 @@ module Make (F : Features.T) = struct let { field; pat } = field#v in let field = self#_do_not_override_lazy_of_global_ident - Generated_generic_printer_base.AstPos_pat'_PConstruct_fields - field + Generated_generic_printer_base + .AstPos_pat'_PConstruct_fields field in let pat = self#_do_not_override_lazy_of_pat - Generated_generic_printer_base.AstPos_pat'_PConstruct_fields - pat + Generated_generic_printer_base + .AstPos_pat'_PConstruct_fields pat in (field, pat)) fields @@ -592,7 +596,9 @@ module Make (F : Features.T) = struct lazy_doc (fun (id : global_ident) -> match id with - | `Concrete cid -> (self#_do_not_override_lazy_of_concrete_ident ast_position cid)#p + | `Concrete cid -> + (self#_do_not_override_lazy_of_concrete_ident ast_position cid) + #p (* | `Primitive _prim_id -> string "(\*TODO*\) prim_id" *) (* | `TupleType 0 -> string "unit" *) | _ -> self#assertion_failure "[global_ident]") From e440d9f7b5493aea7390861e38e53a2dd06a4cf1 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Tue, 29 Oct 2024 18:13:11 +0100 Subject: [PATCH 202/253] Remove comments --- engine/lib/generic_printer/generic_printer.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index c2b1cd6d9..ea304aaf0 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -599,8 +599,6 @@ module Make (F : Features.T) = struct | `Concrete cid -> (self#_do_not_override_lazy_of_concrete_ident ast_position cid) #p - (* | `Primitive _prim_id -> string "(\*TODO*\) prim_id" *) - (* | `TupleType 0 -> string "unit" *) | _ -> self#assertion_failure "[global_ident]") ast_position id From bfd62a661ac7ed25b9c952dee9f0d2278fb951c4 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Wed, 30 Oct 2024 10:22:06 +0100 Subject: [PATCH 203/253] Update engine/lib/generic_printer/generic_printer.ml Co-authored-by: Lucas Franceschino cleanup Minor fix --- engine/backends/coq/coq/coq_backend.ml | 127 +++--------------- engine/lib/generic_printer/generic_printer.ml | 2 +- 2 files changed, 18 insertions(+), 111 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index 79670a21a..e49162d24 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -124,18 +124,16 @@ struct ('get_span_data, 'a) BasePrinter.Gen.object_type class printer = - (* let associated_expr = let open m in associated_expr in *) object (self) inherit BasePrinter.base method private primitive_to_string (id : primitive_ident) : document = match id with - | Deref -> default_document_for "(TODO: Deref)" (* failwith "Deref" *) - | Cast -> string "cast" (* failwith "Cast" *) + | Deref -> default_document_for "(TODO: Deref)" + | Cast -> string "cast" | LogicalOp op -> ( match op with And -> string "andb" | Or -> string "orb") - (* BEGIN GENERATED *) method arm ~arm ~span:_ = arm#p method arm' ~super:_ ~arm_pat ~body ~guard:_ = @@ -160,7 +158,7 @@ struct method error_pat x1 = parens (string x1 ^^ string "(* ERROR_PAT *)") method expr ~e ~span:_ ~typ = - e#p (* parens (e#p ^^ space ^^ colon ^^ space ^^ typ#p) *) + e#p method expr'_AddressOf ~super:_ ~mut:_ ~e:_ ~witness = match witness with _ -> . @@ -168,13 +166,11 @@ struct method expr'_App_application ~super:_ ~f ~args ~generics:_ = f#p ^^ concat_map (fun x -> space ^^ parens x#p) args - method expr'_App_constant ~super:_ ~constant ~generics:_ = constant#p - (* default_document_for "expr'_App_constant" *) + method expr'_App_constant ~super:_ ~constant ~generics:_ = + constant#p method expr'_App_field_projection ~super:_ ~field ~e = - (* e#p *) field#p ^^ space ^^ e#p - (* TODO: Do nothing if is zero *) method expr'_App_tuple_projection ~super:_ ~size:_ ~nth:_ ~e:_ = default_document_for "expr'_App_tuple_projection" @@ -217,64 +213,7 @@ struct if is_struct then string "Build_t_" ^^ constructor#p ^^ fields_or_empty space else constructor#p ^^ fields_or_empty space - else string "(* TODO: Record? *)" - (* let fields_or_empty add_space = *) - (* if List.is_empty fields then empty *) - (* else *) - (* add_space *) - (* ^^ parens *) - (* (separate_map (comma ^^ space) (fun x -> (snd x#v)#p) fields) *) - (* in *) - (* if is_record && is_struct then *) - (* match base with *) - (* | Some x -> string "Build_" ^^ x#p ^^ fields_or_empty space *) - (* | None -> *) - (* string "Build_t_" *) - (* ^^ (self#_do_not_override_lazy_of_global_ident *) - (* Generated_generic_printer_base *) - (* .AstPos_pat'_PConstruct_constructor constructor) *) - (* #p ^^ fields_or_empty space *) - (* else if not is_record then *) - (* if is_struct then *) - (* string "Build_t_" *) - (* ^^ (self#_do_not_override_lazy_of_global_ident *) - (* Generated_generic_printer_base *) - (* .AstPos_pat'_PConstruct_constructor constructor) *) - (* #p ^^ fields_or_empty space *) - (* else *) - (* (self#_do_not_override_lazy_of_global_ident *) - (* Generated_generic_printer_base *) - (* .AstPos_pat'_PConstruct_constructor constructor) *) - (* #p ^^ fields_or_empty space *) - (* else string "(\* TODO: Record? *\)" *) - - (* if is_struct then *) - (* if is_record then *) - (* (\* Struct *\) *) - (* Option.value *) - (* ~default: *) - (* (string "Build_t_" ^^ constructor#p *) - (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) - (* ) *) - (* (Option.map *) - (* ~f:(fun b -> *) - (* b#p *) - (* ^^ concat_map *) - (* (fun (ident, exp) -> *) - (* space ^^ string "<|" ^^ space ^^ ident#p ^^ space *) - (* ^^ !^":=" ^^ space ^^ parens exp#p ^^ space *) - (* ^^ string "|>") *) - (* fields *) - (* ^^ space) *) - (* base) *) - (* else *) - (* (\* Tuple struct *\) *) - (* string "Build_" ^^ constructor#p *) - (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) - (* else *) - (* (\* Indutive type *\) *) - (* constructor#p *) - (* ^^ concat_map (fun (ident, exp) -> space ^^ parens exp#p) fields *) + else default_document_for "expr'_Construct_inductive [is_record=true, is_struct = false] todo record" method expr'_Construct_tuple ~super:_ ~components = if List.length components == 0 then !^"tt" @@ -336,7 +275,6 @@ struct method cf_kind_BreakOnly = default_document_for "cf_kind_BreakOnly" method field_pat ~field ~pat = pat#p - (* brackets( string ([%show: global_ident] field) ^^ space ^^ pat#p ) ^^ string "(\* TODO *\)" *) method generic_constraint_GCLifetime _x1 _x2 = default_document_for "generic_constraint_GCLifetime" @@ -396,11 +334,9 @@ struct method impl_expr_kind_Self = default_document_for "impl_expr_kind_Self" method impl_ident ~goal ~name:_ = goal#p - (* string name ^^ space ^^ colon ^^ space ^^ goal#p *) - (* TODO: include names and do something about numbered names of instance *) method impl_item ~ii_span:_ ~ii_generics:_ ~ii_v ~ii_ident ~ii_attrs:_ = - ii_ident#p (* ^^ ii_generics#p *) ^^ space + ii_ident#p ^^ space ^^ string ":=" ^^ space ^^ ii_v#p ^^ semi method impl_item'_IIFn ~body ~params = @@ -412,8 +348,7 @@ struct ^^ nest 2 (break 1 ^^ body#p) method impl_item'_IIType ~typ ~parent_bounds:_ = typ#p - method item ~v ~span:_ ~ident:_ ~attrs:_ = v#p - (* if is_document_empty v#p then empty else v#p ^^ break 1 *) + method item ~v ~span:_ ~ident:_ ~attrs:_ = v#p ^^ break 1 method item'_Alias ~super:_ ~name ~item = string "Notation" ^^ space ^^ string "\"'" ^^ name#p ^^ string "'\"" @@ -599,26 +534,11 @@ struct method literal_Char x1 = string "\"" ^^ string (Char.escaped x1) ^^ string "\"" ^^ string "%char" - method literal_Float ~value ~negative:_ ~kind:_ = - string value ^^ string "%float" - - method literal_Int ~value ~negative:_ ~kind:_ = - (* let outer, inner = *) - (* match kind.size with *) - (* | S8 -> ("u8", "U8") *) - (* | S16 -> ("u16", "U16") *) - (* | S32 -> ("u32", "U32") *) - (* | S64 -> ("u64", "U64") *) - (* | S128 -> ("u128", "U128") *) - (* | SSize -> ("usize", "U64") *) - (* (\* Dependens on architecture.. *\) *) - (* in *) - (* string ("Build_t_" ^ outer) *) - (* ^^ space *) - (* ^^ parens *) - (* (string ("Build_t_" ^ inner) *) - (* ^^ space ^^ string value ^^ string "%N") *) - string value + method literal_Float ~value ~negative ~kind:_ = + (if negative then !^"-" else empty) ^^ string value ^^ string "%float" + + method literal_Int ~value ~negative ~kind:_ = + (if negative then !^"-" else empty) ^^ string value method literal_String x1 = string "\"" ^^ string x1 ^^ string "\"%string" @@ -641,7 +561,7 @@ struct method modul x1 = separate_map (break 1) (fun x -> x#p) - x1 (* default_document_for "modul" *) + x1 method param ~pat ~typ ~typ_span:_ ~attrs:_ = parens (pat#p ^^ space ^^ colon ^^ space ^^ typ#p) @@ -649,10 +569,10 @@ struct method pat ~p ~span:_ ~typ:_ = p#p method pat'_PAscription ~super:_ ~typ ~typ_span:_ ~pat = - pat#p ^^ space ^^ colon ^^ space ^^ typ#p (* Ignore asscription pat? *) + pat#p ^^ space ^^ colon ^^ space ^^ typ#p method pat'_PBinding ~super:_ ~mut:_ ~mode:_ ~var ~typ:_ ~subpat:_ = - var#p (* ^^ space ^^ colon ^^ space ^^ typ#p *) + var#p method pat'_PConstant ~super:_ ~lit = lit#p @@ -677,9 +597,6 @@ struct method pat'_PDeref ~super:_ ~subpat:_ ~witness:_ = default_document_for "pat'_PDeref" - (* method pat'_POr ~super ~subpats = *) - (* parens( subpats ) *) - method pat'_PWild = string "_" method printer_name = "Coq printer" @@ -742,12 +659,9 @@ struct ^^ separate_map space (fun x -> x#p) params ^^ space ^^ string "=>") ^^ nest 2 (break 1 ^^ body#p) - (* default_document_for "trait_item'_TIDefault" *) method trait_item'_TIFn x1 = x1#p method trait_item'_TIType x1 = string "Type" - (* TODO, type should implement x1 traits *) - (* concat_map (fun x -> x#p) x1 *) method ty_TApp_application ~typ ~generics = typ#p ^^ concat_map (fun x -> space ^^ parens x#p) generics @@ -807,12 +721,9 @@ struct name#p ^^ space ^^ colon ^^ space ^^ separate_map (space ^^ string "->" ^^ space) - (fun (ident, typ, attr) -> - typ#p - (* parens (ident#p ^^ space ^^ colon ^^ space ^^ typ#p) *)) + (fun (ident, typ, attr) -> typ#p) arguments ^^ space ^^ string "->" ^^ space ^^ string "_" - (* END GENERATED *) method module_path_separator = "." @@ -830,10 +741,6 @@ struct | "mul" -> "t_Mul_f_mul" | "div" -> "t_Div_f_div" | x -> x) - (* string (String.concat ~sep:"_" (id.crate :: (id.path @ [ id.definition ]))) *) - (* string (String.concat ~sep:"_" (id.definition :: Option.to_list (List.last id.path) )) *) - - (* val mutable current_namespace : (string * string list) option = None *) end let new_printer : BasePrinter.finalized_printer = diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index ea304aaf0..155ca3d1b 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -599,7 +599,7 @@ module Make (F : Features.T) = struct | `Concrete cid -> (self#_do_not_override_lazy_of_concrete_ident ast_position cid) #p - | _ -> self#assertion_failure "[global_ident]") + | _ -> self#assertion_failure ("_do_not_override_lazy_of_global_ident: expected [`Concrete _] got [" ^ [%show: global_ident] id ^ "]")) ast_position id method _do_not_override_lazy_of_quote ast_position (value : quote) From dfc162a9f4c370742c7ed6bd22b56a1d3b8ec567 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Wed, 30 Oct 2024 10:58:16 +0100 Subject: [PATCH 204/253] fmt --- engine/backends/coq/coq/coq_backend.ml | 24 +++++++------------ engine/lib/generic_printer/generic_printer.ml | 7 +++++- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index e49162d24..a87d08a6e 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -156,9 +156,7 @@ struct method error_expr x1 = parens (string x1 ^^ string "(* ERROR_EXPR *)") method error_item x1 = parens (string x1 ^^ string "(* ERROR_ITEM *)") method error_pat x1 = parens (string x1 ^^ string "(* ERROR_PAT *)") - - method expr ~e ~span:_ ~typ = - e#p + method expr ~e ~span:_ ~typ = e#p method expr'_AddressOf ~super:_ ~mut:_ ~e:_ ~witness = match witness with _ -> . @@ -166,8 +164,7 @@ struct method expr'_App_application ~super:_ ~f ~args ~generics:_ = f#p ^^ concat_map (fun x -> space ^^ parens x#p) args - method expr'_App_constant ~super:_ ~constant ~generics:_ = - constant#p + method expr'_App_constant ~super:_ ~constant ~generics:_ = constant#p method expr'_App_field_projection ~super:_ ~field ~e = field#p ^^ space ^^ e#p @@ -213,7 +210,10 @@ struct if is_struct then string "Build_t_" ^^ constructor#p ^^ fields_or_empty space else constructor#p ^^ fields_or_empty space - else default_document_for "expr'_Construct_inductive [is_record=true, is_struct = false] todo record" + else + default_document_for + "expr'_Construct_inductive [is_record=true, is_struct = false] \ + todo record" method expr'_Construct_tuple ~super:_ ~components = if List.length components == 0 then !^"tt" @@ -336,8 +336,7 @@ struct method impl_ident ~goal ~name:_ = goal#p method impl_item ~ii_span:_ ~ii_generics:_ ~ii_v ~ii_ident ~ii_attrs:_ = - ii_ident#p ^^ space - ^^ string ":=" ^^ space ^^ ii_v#p ^^ semi + ii_ident#p ^^ space ^^ string ":=" ^^ space ^^ ii_v#p ^^ semi method impl_item'_IIFn ~body ~params = if List.length params == 0 then body#p @@ -558,10 +557,7 @@ struct method loop_state ~init ~bpat ~witness:_ = parens (init#p ^^ space ^^ !^"state" ^^ space ^^ bpat#p) - method modul x1 = - separate_map (break 1) - (fun x -> x#p) - x1 + method modul x1 = separate_map (break 1) (fun x -> x#p) x1 method param ~pat ~typ ~typ_span:_ ~attrs:_ = parens (pat#p ^^ space ^^ colon ^^ space ^^ typ#p) @@ -571,9 +567,7 @@ struct method pat'_PAscription ~super:_ ~typ ~typ_span:_ ~pat = pat#p ^^ space ^^ colon ^^ space ^^ typ#p - method pat'_PBinding ~super:_ ~mut:_ ~mode:_ ~var ~typ:_ ~subpat:_ = - var#p - + method pat'_PBinding ~super:_ ~mut:_ ~mode:_ ~var ~typ:_ ~subpat:_ = var#p method pat'_PConstant ~super:_ ~lit = lit#p method pat'_PConstruct_inductive ~super:_ ~constructor ~is_record diff --git a/engine/lib/generic_printer/generic_printer.ml b/engine/lib/generic_printer/generic_printer.ml index 155ca3d1b..181aef257 100644 --- a/engine/lib/generic_printer/generic_printer.ml +++ b/engine/lib/generic_printer/generic_printer.ml @@ -599,7 +599,12 @@ module Make (F : Features.T) = struct | `Concrete cid -> (self#_do_not_override_lazy_of_concrete_ident ast_position cid) #p - | _ -> self#assertion_failure ("_do_not_override_lazy_of_global_ident: expected [`Concrete _] got [" ^ [%show: global_ident] id ^ "]")) + | _ -> + self#assertion_failure + ("_do_not_override_lazy_of_global_ident: expected [`Concrete \ + _] got [" + ^ [%show: global_ident] id + ^ "]")) ast_position id method _do_not_override_lazy_of_quote ast_position (value : quote) From 1abd1241cb39867cd1ebf663e6b3d93578a74e3d Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Wed, 30 Oct 2024 11:29:40 +0100 Subject: [PATCH 205/253] Snapshots --- .../snapshots/toolchain__assert into-coq.snap | 5 +- .../toolchain__enum-repr into-coq.snap | 46 ++++++---- .../snapshots/toolchain__guards into-coq.snap | 90 ++++++++++--------- .../toolchain__include-flag into-coq.snap | 20 ++++- .../toolchain__let-else into-coq.snap | 18 ++-- .../toolchain__literals into-coq.snap | 48 ++++++---- .../toolchain__pattern-or into-coq.snap | 47 ++++++---- .../toolchain__reordering into-coq.snap | 25 ++++-- .../snapshots/toolchain__slices into-coq.snap | 8 +- 9 files changed, 192 insertions(+), 115 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__assert into-coq.snap b/test-harness/src/snapshots/toolchain__assert into-coq.snap index 9f6ecd8fa..a000cc9f9 100644 --- a/test-harness/src/snapshots/toolchain__assert into-coq.snap +++ b/test-harness/src/snapshots/toolchain__assert into-coq.snap @@ -40,7 +40,9 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + (* NotImplementedYet *) + Definition asserts (_ : unit) : unit := let _ := assert (true) in let _ := assert (t_PartialEq_f_eq (1) (1)) in @@ -52,4 +54,5 @@ Definition asserts (_ : unit) : unit := | (left_val,right_val) => assert (negb (t_PartialEq_f_eq (left_val) (right_val))) end in - tt.''' + tt. +''' diff --git a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap index e01bebf01..bfe3bcc0a 100644 --- a/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap +++ b/test-harness/src/snapshots/toolchain__enum-repr into-coq.snap @@ -41,35 +41,45 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. -Definition discriminant_t_EnumWithRepr_ExplicitDiscr1 : t_u16 := + +Definition discriminant_EnumWithRepr_ExplicitDiscr1 : t_u16 := 1. -Definition discriminant_t_EnumWithRepr_ExplicitDiscr2 : t_u16 := + +Definition discriminant_EnumWithRepr_ExplicitDiscr2 : t_u16 := 5. + Inductive t_EnumWithRepr : Type := -| t_EnumWithRepr_ExplicitDiscr1 -| t_EnumWithRepr_ExplicitDiscr2 -| t_EnumWithRepr_ImplicitDiscrEmptyTuple -| t_EnumWithRepr_ImplicitDiscrEmptyStruct. +| EnumWithRepr_ExplicitDiscr1 +| EnumWithRepr_ExplicitDiscr2 +| EnumWithRepr_ImplicitDiscrEmptyTuple +| EnumWithRepr_ImplicitDiscrEmptyStruct. Arguments t_EnumWithRepr:clear implicits. Arguments t_EnumWithRepr. + Definition t_EnumWithRepr_cast_to_repr (x : t_EnumWithRepr) : t_u16 := match x with - | t_EnumWithRepr_ExplicitDiscr1 => - discriminant_t_EnumWithRepr_ExplicitDiscr1 - | t_EnumWithRepr_ExplicitDiscr2 => - discriminant_t_EnumWithRepr_ExplicitDiscr2 - | t_EnumWithRepr_ImplicitDiscrEmptyTuple => - t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (1) - | t_EnumWithRepr_ImplicitDiscrEmptyStruct => - t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (2) + | EnumWithRepr_ExplicitDiscr1 => + discriminant_EnumWithRepr_ExplicitDiscr1 + | EnumWithRepr_ExplicitDiscr2 => + discriminant_EnumWithRepr_ExplicitDiscr2 + | EnumWithRepr_ImplicitDiscrEmptyTuple => + t_Add_f_add (discriminant_EnumWithRepr_ExplicitDiscr2) (1) + | EnumWithRepr_ImplicitDiscrEmptyStruct => + t_Add_f_add (discriminant_EnumWithRepr_ExplicitDiscr2) (2) end. + (* NotImplementedYet *) + Definition f (_ : unit) : t_u32 := - let v__x := cast (t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr2) (0)) in - t_Add_f_add (cast (t_EnumWithRepr_cast_to_repr (t_EnumWithRepr_ImplicitDiscrEmptyTuple))) (cast (t_EnumWithRepr_cast_to_repr (t_EnumWithRepr_ImplicitDiscrEmptyStruct))). + let v__x := cast (t_Add_f_add (discriminant_EnumWithRepr_ExplicitDiscr2) (0)) in + t_Add_f_add (cast (t_EnumWithRepr_cast_to_repr (EnumWithRepr_ImplicitDiscrEmptyTuple))) (cast (t_EnumWithRepr_cast_to_repr (EnumWithRepr_ImplicitDiscrEmptyStruct))). + Definition ff__CONST : t_u16 := - cast (t_Add_f_add (discriminant_t_EnumWithRepr_ExplicitDiscr1) (0)). + cast (t_Add_f_add (discriminant_EnumWithRepr_ExplicitDiscr1) (0)). + Definition get_casted_repr (x : t_EnumWithRepr) : t_u64 := cast (t_EnumWithRepr_cast_to_repr (x)). + Definition get_repr (x : t_EnumWithRepr) : t_u16 := - t_EnumWithRepr_cast_to_repr (x).''' + t_EnumWithRepr_cast_to_repr (x). +''' diff --git a/test-harness/src/snapshots/toolchain__guards into-coq.snap b/test-harness/src/snapshots/toolchain__guards into-coq.snap index 387dbbcf9..abd2a3274 100644 --- a/test-harness/src/snapshots/toolchain__guards into-coq.snap +++ b/test-harness/src/snapshots/toolchain__guards into-coq.snap @@ -40,117 +40,123 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + (* NotImplementedYet *) + Definition equivalent (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with - | t_Option_None => + | Option_None => 0 | _ => match match x with - | t_Option_Some (v) => + | Option_Some (v) => match v with - | t_Result_Ok (y) => - t_Option_Some (y) + | Result_Ok (y) => + Option_Some (y) | _ => - t_Option_None + Option_None end | _ => - t_Option_None + Option_None end with - | t_Option_Some (y) => + | Option_Some (y) => y - | t_Option_None => + | Option_None => match x with - | t_Option_Some (t_Result_Err (y)) => + | Option_Some (Result_Err (y)) => y | _ => 1 end end end. + Definition if_guard (x : t_Option ((t_i32))) : t_i32 := match match x with - | t_Option_Some (v) => + | Option_Some (v) => match t_PartialOrd_f_gt (v) (0) with | true => - t_Option_Some (v) + Option_Some (v) | _ => - t_Option_None + Option_None end | _ => - t_Option_None + Option_None end with - | t_Option_Some (x) => + | Option_Some (x) => x - | t_Option_None => + | Option_None => 0 end. + Definition if_let_guard (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with - | t_Option_None => + | Option_None => 0 | _ => match match x with - | t_Option_Some (v) => + | Option_Some (v) => match v with - | t_Result_Ok (y) => - t_Option_Some (y) + | Result_Ok (y) => + Option_Some (y) | _ => - t_Option_None + Option_None end | _ => - t_Option_None + Option_None end with - | t_Option_Some (x) => + | Option_Some (x) => x - | t_Option_None => + | Option_None => match x with - | t_Option_Some (t_Result_Err (y)) => + | Option_Some (Result_Err (y)) => y | _ => 1 end end end. + Definition multiple_guards (x : t_Option ((t_Result ((t_i32)) ((t_i32))))) : t_i32 := match x with - | t_Option_None => + | Option_None => 0 | _ => match match x with - | t_Option_Some (t_Result_Ok (v)) => - match t_Option_Some (t_Add_f_add (v) (1)) with - | t_Option_Some (1) => - t_Option_Some (0) + | Option_Some (Result_Ok (v)) => + match Option_Some (t_Add_f_add (v) (1)) with + | Option_Some (1) => + Option_Some (0) | _ => - t_Option_None + Option_None end | _ => - t_Option_None + Option_None end with - | t_Option_Some (x) => + | Option_Some (x) => x - | t_Option_None => + | Option_None => match match x with - | t_Option_Some (v) => + | Option_Some (v) => match v with - | t_Result_Ok (y) => - t_Option_Some (y) + | Result_Ok (y) => + Option_Some (y) | _ => - t_Option_None + Option_None end | _ => - t_Option_None + Option_None end with - | t_Option_Some (x) => + | Option_Some (x) => x - | t_Option_None => + | Option_None => match x with - | t_Option_Some (t_Result_Err (y)) => + | Option_Some (Result_Err (y)) => y | _ => 1 end end end - end.''' + end. +''' diff --git a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap index 9122c374c..7cc86205b 100644 --- a/test-harness/src/snapshots/toolchain__include-flag into-coq.snap +++ b/test-harness/src/snapshots/toolchain__include-flag into-coq.snap @@ -40,6 +40,7 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + Record t_Foo : Type := { }. @@ -48,50 +49,67 @@ Arguments t_Foo. Arguments Build_t_Foo. #[export] Instance settable_t_Foo : Settable _ := settable! (@Build_t_Foo) <>. + Class t_Trait `{v_Self : Type} : Type := { }. Arguments t_Trait:clear implicits. Arguments t_Trait (_). + Instance t_Trait_187936720 : t_Trait ((t_Foo)) := { }. + (* NotImplementedYet *) + Definition main_a_a (_ : unit) : unit := tt. + Definition main_a_b (_ : unit) : unit := tt. + Definition main_a_c (_ : unit) : unit := tt. + Definition main_a `{v_T : Type} `{t_Sized (v_T)} `{t_Trait (v_T)} (x : v_T) : unit := let _ := main_a_a (tt) in let _ := main_a_b (tt) in let _ := main_a_c (tt) in tt. + Definition main_b_a (_ : unit) : unit := tt. + Definition main_b_b (_ : unit) : unit := tt. + Definition main_b_c (_ : unit) : unit := tt. + Definition main_b (_ : unit) : unit := let _ := main_b_a (tt) in let _ := main_b_b (tt) in let _ := main_b_c (tt) in tt. + Definition main_c_a (_ : unit) : unit := tt. + Definition main_c_b (_ : unit) : unit := tt. + Definition main_c_c (_ : unit) : unit := tt. + Definition main_c (_ : unit) : unit := let _ := main_c_a (tt) in let _ := main_c_b (tt) in let _ := main_c_c (tt) in tt. + Definition main (_ : unit) : unit := let _ := main_a (Build_t_Foo) in let _ := main_b (tt) in let _ := main_c (tt) in - tt.''' + tt. +''' diff --git a/test-harness/src/snapshots/toolchain__let-else into-coq.snap b/test-harness/src/snapshots/toolchain__let-else into-coq.snap index a705d6542..330c601b3 100644 --- a/test-harness/src/snapshots/toolchain__let-else into-coq.snap +++ b/test-harness/src/snapshots/toolchain__let-else into-coq.snap @@ -40,19 +40,23 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + (* NotImplementedYet *) + Definition let_else (opt : t_Option ((t_u32))) : bool := run (match opt with - | t_Option_Some (x) => - t_ControlFlow_Continue (true) + | Option_Some (x) => + ControlFlow_Continue (true) | _ => - t_ControlFlow_Break (false) + ControlFlow_Break (false) end). + Definition let_else_different_type (opt : t_Option ((t_u32))) : bool := run (let hoist1 := match opt with - | t_Option_Some (x) => - t_ControlFlow_Continue (t_Option_Some (t_Add_f_add (x) (1))) + | Option_Some (x) => + ControlFlow_Continue (Option_Some (t_Add_f_add (x) (1))) | _ => - t_ControlFlow_Break (false) + ControlFlow_Break (false) end in - t_ControlFlow_Continue (let_else (hoist1))).''' + ControlFlow_Continue (let_else (hoist1))). +''' diff --git a/test-harness/src/snapshots/toolchain__literals into-coq.snap b/test-harness/src/snapshots/toolchain__literals into-coq.snap index e2203f3fb..77d4150c3 100644 --- a/test-harness/src/snapshots/toolchain__literals into-coq.snap +++ b/test-harness/src/snapshots/toolchain__literals into-coq.snap @@ -41,20 +41,25 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + From Literals Require Import Hax_lib (t_int). Export Hax_lib (t_int). + Record t_Foo : Type := { - t_Foo_f_field : t_u8; + f_field : t_u8; }. Arguments t_Foo:clear implicits. Arguments t_Foo. Arguments Build_t_Foo. #[export] Instance settable_t_Foo : Settable _ := - settable! (@Build_t_Foo) . + settable! (@Build_t_Foo) . + (* NotImplementedYet *) + Definition v_CONSTANT : t_Foo := Build_t_Foo (3). + Definition casts (x8 : t_u8) (x16 : t_u16) (x32 : t_u32) (x64 : t_u64) (xs : t_usize) : unit := let _ : t_u64 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (x64)) (cast (xs)) in let _ : t_u32 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (x32)) (cast (x64))) (cast (xs)) in @@ -65,22 +70,24 @@ Definition casts (x8 : t_u8) (x16 : t_u16) (x32 : t_u32) (x64 : t_u64) (xs : t_u let _ : t_i16 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in let _ : t_i8 := t_Add_f_add (t_Add_f_add (t_Add_f_add (t_Add_f_add (cast (x8)) (cast (x16))) (cast (x32))) (cast (x64))) (cast (xs)) in tt. + Definition fn_pointer_cast (_ : unit) : unit := let f : t_u32 -> t_u32 := fun x => x in tt. -Definition math_integers (x : t_Int) `{andb (t_PartialOrd_f_gt (x) (impl__Int___unsafe_from_str ("0"%string))) (t_PartialOrd_f_lt (x) (impl__Int___unsafe_from_str ("16"%string))) = true} : t_u8 := - let _ : t_Int := t_Abstraction_f_lift (3) in - let _ := t_PartialOrd_f_gt (impl__Int___unsafe_from_str ("-340282366920938463463374607431768211455000"%string)) (impl__Int___unsafe_from_str ("340282366920938463463374607431768211455000"%string)) in - let _ := t_PartialOrd_f_lt (x) (x) in - let _ := t_PartialOrd_f_ge (x) (x) in - let _ := t_PartialOrd_f_le (x) (x) in - let _ := t_PartialEq_f_ne (x) (x) in - let _ := t_PartialEq_f_eq (x) (x) in - let _ := t_Add_f_add (x) (x) in - let _ := t_Sub_f_sub (x) (x) in - let _ := t_Mul_f_mul (x) (x) in - let _ := t_Div_f_div (x) (x) in + +Definition math_integers (x : t_Int) `{andb (f_gt (x) (impl__Int___unsafe_from_str ("0"%string))) (f_lt (x) (impl__Int___unsafe_from_str ("16"%string))) = true} : t_u8 := + let _ : t_Int := f_lift (3) in + let _ := f_gt (impl__Int___unsafe_from_str ("-340282366920938463463374607431768211455000"%string)) (impl__Int___unsafe_from_str ("340282366920938463463374607431768211455000"%string)) in + let _ := f_lt (x) (x) in + let _ := f_ge (x) (x) in + let _ := f_le (x) (x) in + let _ := f_ne (x) (x) in + let _ := f_eq (x) (x) in + let _ := f_add (x) (x) in + let _ := f_sub (x) (x) in + let _ := f_mul (x) (x) in + let _ := f_div (x) (x) in let _ : t_i16 := impl__Int__to_i16 (x) in let _ : t_i32 := impl__Int__to_i32 (x) in let _ : t_i64 := impl__Int__to_i64 (x) in @@ -91,14 +98,16 @@ Definition math_integers (x : t_Int) `{andb (t_PartialOrd_f_gt (x) (impl__Int___ let _ : t_u64 := impl__Int__to_u64 (x) in let _ : t_u128 := impl__Int__to_u128 (x) in let _ : t_usize := impl__Int__to_usize (x) in - impl__Int__to_u8 (t_Add_f_add (x) (t_Mul_f_mul (x) (x))). + impl__Int__to_u8 (f_add (x) (f_mul (x) (x))). + Definition numeric (_ : unit) : unit := let _ : t_usize := 123 in + let _ : t_isize := -42 in let _ : t_isize := 42 in - let _ : t_isize := 42 in - let _ : t_i32 := 42 in + let _ : t_i32 := -42 in let _ : t_u128 := 22222222222222222222 in tt. + Definition patterns (_ : unit) : unit := let _ := match 1 with | 2 => @@ -119,8 +128,11 @@ Definition patterns (_ : unit) : unit := tt end in tt. + Definition panic_with_msg (_ : unit) : unit := never_to_any (panic_fmt (impl_2__new_const (["with msg"%string]))). + Definition empty_array (_ : unit) : unit := let _ : t_Slice t_u8 := unsize ([]) in - tt.''' + tt. +''' diff --git a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap index 6f121c290..f4b3cbfe0 100644 --- a/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap +++ b/test-harness/src/snapshots/toolchain__pattern-or into-coq.snap @@ -41,62 +41,71 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + Inductive t_E : Type := -| t_E_A -| t_E_B. +| E_A +| E_B. Arguments t_E:clear implicits. Arguments t_E. + Definition t_E_cast_to_repr (x : t_E) : t_isize := match x with - | t_E_A => + | E_A => 0 - | t_E_B => + | E_B => 1 end. + (* NotImplementedYet *) + Definition bar (x : t_E) : unit := match x with - | t_E_A - | t_E_B => + | E_A + | E_B => tt end. + Definition deep (x : (t_i32*t_Option ((t_i32)))) : t_i32 := match x with | (1 - | 2,t_Option_Some (3 + | 2,Option_Some (3 | 4)) => 0 | (x,_) => x end. + Definition deep_capture (x : t_Result (((t_i32*t_i32))) (((t_i32*t_i32)))) : t_i32 := match x with - | t_Result_Ok ((1 + | Result_Ok ((1 | 2,x)) - | t_Result_Err ((3 + | Result_Err ((3 | 4,x)) => x - | t_Result_Ok ((x,_)) - | t_Result_Err ((x,_)) => + | Result_Ok ((x,_)) + | Result_Err ((x,_)) => x end. + Definition equivalent (x : (t_i32*t_Option ((t_i32)))) : t_i32 := match x with - | (1,t_Option_Some (3)) - | (1,t_Option_Some (4)) - | (2,t_Option_Some (3)) - | (2,t_Option_Some (4)) => + | (1,Option_Some (3)) + | (1,Option_Some (4)) + | (2,Option_Some (3)) + | (2,Option_Some (4)) => 0 | (x,_) => x end. + Definition nested (x : t_Option ((t_i32))) : t_i32 := match x with - | t_Option_Some (1 + | Option_Some (1 | 2) => 1 - | t_Option_Some (x) => + | Option_Some (x) => x - | t_Option_None => + | Option_None => 0 - end.''' + end. +''' diff --git a/test-harness/src/snapshots/toolchain__reordering into-coq.snap b/test-harness/src/snapshots/toolchain__reordering into-coq.snap index ddbd8546e..d3b0567d8 100644 --- a/test-harness/src/snapshots/toolchain__reordering into-coq.snap +++ b/test-harness/src/snapshots/toolchain__reordering into-coq.snap @@ -40,33 +40,42 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + Inductive t_Foo : Type := -| t_Foo_A -| t_Foo_B. +| Foo_A +| Foo_B. Arguments t_Foo:clear implicits. Arguments t_Foo. + Record t_Bar : Type := { - t_Bar_0 : t_Foo; + 0 : t_Foo; }. Arguments t_Bar:clear implicits. Arguments t_Bar. Arguments Build_t_Bar. #[export] Instance settable_t_Bar : Settable _ := - settable! (@Build_t_Bar) . + settable! (@Build_t_Bar) <0>. + Definition t_Foo_cast_to_repr (x : t_Foo) : t_isize := match x with - | t_Foo_A => + | Foo_A => 0 - | t_Foo_B => + | Foo_B => 1 end. + (* NotImplementedYet *) + Definition f (_ : t_u32) : t_Foo := - t_Foo_A. + Foo_A. + Definition g (_ : unit) : t_Bar := Build_t_Bar (f (32)). + Definition no_dependency_1_ (_ : unit) : unit := tt. + Definition no_dependency_2_ (_ : unit) : unit := - tt.''' + tt. +''' diff --git a/test-harness/src/snapshots/toolchain__slices into-coq.snap b/test-harness/src/snapshots/toolchain__slices into-coq.snap index 2846fe70d..93fa425b0 100644 --- a/test-harness/src/snapshots/toolchain__slices into-coq.snap +++ b/test-harness/src/snapshots/toolchain__slices into-coq.snap @@ -41,12 +41,18 @@ From RecordUpdate Require Import RecordSet. Import RecordSetNotations. + (* NotImplementedYet *) + Definition v_VERSION : t_Slice t_u8 := unsize ([118; 49]). + Definition do_something (_ : t_Slice t_u8) : unit := tt. + Definition r#unsized (_ : t_Array (t_Slice t_u8) (1)) : unit := tt. + Definition sized (x : t_Array (t_Array (t_u8) (4)) (1)) : unit := - r#unsized ([unsize (index (x) (0))]).''' + r#unsized ([unsize (index (x) (0))]). +''' From 408aad1afe6b53873e94711b1ea02addd3003042 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 11:28:35 +0100 Subject: [PATCH 206/253] feat(engine): profile each phase (mem usage, time, number of items) --- cli/subcommands/src/cargo_hax.rs | 4 ++++ engine/bin/lib.ml | 2 ++ engine/lib/hax_io.ml | 4 ++++ engine/lib/phase_utils.ml | 23 +++++++++++++++++++---- engine/lib/profiling.ml | 28 ++++++++++++++++++++++++++++ hax-types/src/engine_api.rs | 17 +++++++++++++++++ 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 engine/lib/profiling.ml diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index a2bf5e666..62fa71677 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -231,6 +231,7 @@ fn run_engine( diagnostics: vec![], files: vec![], debug_json: None, + profiling_data: vec![], }; { let mut rctx = hax_types::diagnostics::report::ReportCtx::default(); @@ -316,6 +317,9 @@ fn run_engine( }; send!(&ToEngine::PrettyPrintedRust(code)); } + FromEngine::ProfilingData(profiling_data) => { + output.profiling_data.push(profiling_data); + } FromEngine::Ping => { send!(&ToEngine::Pong); } diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index ce415c260..3168bb8ed 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -138,6 +138,8 @@ let run (options : Types.engine_options) : Types.output = diagnostics = List.map ~f:Diagnostics.to_thir_diagnostic diagnostics; files = Option.value ~default:[] files; debug_json = None; + profiling_data = []; + (* This data is sent interactively via Hax_io *) } (** Shallow parses a `id_table::Node` (or a raw `T`) JSON *) diff --git a/engine/lib/hax_io.ml b/engine/lib/hax_io.ml index af50a0615..0038375be 100644 --- a/engine/lib/hax_io.ml +++ b/engine/lib/hax_io.ml @@ -1,3 +1,7 @@ +(** +This module helps communicating with `cargo-hax`. +*) + open Prelude module type S = sig diff --git a/engine/lib/phase_utils.ml b/engine/lib/phase_utils.ml index 80eb807df..1085c86d4 100644 --- a/engine/lib/phase_utils.ml +++ b/engine/lib/phase_utils.ml @@ -248,10 +248,12 @@ module TracePhase (P : PHASE) = struct include P let name = [%show: Diagnostics.Phase.t] P.metadata.current_phase - let enable = Option.is_some P.metadata.previous_phase + (* We distinguish between composite phases (i.e. `BindPhase(_)(_)`) versus non-composite ones. *) + + let composite_phase = Option.is_some P.metadata.previous_phase let ditems = - if enable then P.ditems + if composite_phase then P.ditems else fun items -> Logs.info (fun m -> m "Entering phase [%s]" name); let items = P.ditems items in @@ -259,12 +261,25 @@ module TracePhase (P : PHASE) = struct items end +module ProfilePhase (P : PHASE) = struct + include P + + (* We distinguish between composite phases (i.e. `BindPhase(_)(_)`) versus non-composite ones. *) + let composite_phase = Option.is_some P.metadata.previous_phase + + let ditems items = + if composite_phase then P.ditems items + else + let ctx = Diagnostics.Context.Phase P.metadata.current_phase in + Profiling.profile ctx (List.length items) (fun () -> P.ditems items) +end + module BindPhase (D1 : PHASE) (D2 : PHASE with module FA = D1.FB and module A = D1.B) = struct - module D1' = TracePhase (D1) - module D2' = TracePhase (D2) + module D1' = ProfilePhase (TracePhase (D1)) + module D2' = ProfilePhase (TracePhase (D2)) module FA = D1.FA module FB = D2.FB module A = D1.A diff --git a/engine/lib/profiling.ml b/engine/lib/profiling.ml new file mode 100644 index 000000000..68e895889 --- /dev/null +++ b/engine/lib/profiling.ml @@ -0,0 +1,28 @@ +open Prelude + +(** Profiles the function `f`, that operates in a given context over a given quantity of things it is processing. *) +let profile (type b) (context : Diagnostics.Context.t) (quantity : int) + (f : unit -> b) : b = + let time0 = Core.Time_ns.now () in + let mem0 = Core.Gc.minor_words () in + let finalize () = + let time1 = Core.Time_ns.now () in + let mem1 = Core.Gc.minor_words () in + let time_ns = Core.Time_ns.diff time1 time0 in + let memory = mem1 - mem0 in + Hax_io.write + (Types.ProfilingData + { + context = Diagnostics.Context.display context; + time_ns = Core.Time_ns.Span.to_int63_ns time_ns |> Int63.to_string; + memory = Int.to_string memory; + quantity = Int.to_int64 quantity; + }) + in + try + let result = f () in + finalize (); + result + with e -> + finalize (); + raise e diff --git a/hax-types/src/engine_api.rs b/hax-types/src/engine_api.rs index 8b916fc18..9fbc5f317 100644 --- a/hax-types/src/engine_api.rs +++ b/hax-types/src/engine_api.rs @@ -56,6 +56,22 @@ pub struct Output { pub diagnostics: Vec, pub files: Vec, pub debug_json: Option, + pub profiling_data: Vec, +} + +#[derive_group(Serializers)] +#[derive(JsonSchema, Debug, Clone)] +pub struct ProfilingData { + /// What context are we profiling? + pub context: String, + /// How long this took? + pub time_ns: u64, + /// How much memory this took? This is using OCaml's + /// `Gc.minor_words`, and is probably not very precise. + pub memory: u64, + /// How many things were processed? (often, this is the number of + /// items a phase processes) + pub quantity: u32, } pub mod protocol { @@ -68,6 +84,7 @@ pub mod protocol { PrettyPrintDiagnostic(crate::diagnostics::Diagnostics), PrettyPrintRust(String), DebugString(String), + ProfilingData(ProfilingData), Exit, Ping, } From 34107cd840f05cbc71e8baaa1be9cf3709467301 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 12:36:45 +0100 Subject: [PATCH 207/253] feat(engine): generate phase names automatically --- engine/lib/diagnostics.ml | 35 +----- engine/lib/phases/phase_and_mut_defsite.ml | 2 +- engine/lib/phases/phase_cf_into_monads.ml | 2 +- engine/lib/phases/phase_direct_and_mut.ml | 2 +- engine/lib/phases/phase_drop_blocks.ml | 2 +- engine/lib/phases/phase_drop_match_guards.ml | 2 +- engine/lib/phases/phase_drop_references.ml | 2 +- .../phase_drop_return_break_continue.ml | 2 +- engine/lib/phases/phase_drop_sized_trait.ml | 2 +- .../lib/phases/phase_functionalize_loops.ml | 2 +- .../phase_hoist_disjunctive_patterns.ml | 2 +- engine/lib/phases/phase_local_mutation.ml | 2 +- .../lib/phases/phase_newtype_as_refinement.ml | 2 +- .../lib/phases/phase_reconstruct_asserts.ml | 2 +- .../phase_reconstruct_for_index_loops.ml | 2 +- .../lib/phases/phase_reconstruct_for_loops.ml | 2 +- .../phase_reconstruct_question_marks.ml | 2 +- .../phases/phase_reconstruct_while_loops.ml | 2 +- .../lib/phases/phase_rewrite_control_flow.ml | 2 +- engine/lib/phases/phase_simplify_hoisting.ml | 2 +- .../lib/phases/phase_simplify_match_return.ml | 2 +- .../phases/phase_simplify_question_marks.ml | 2 +- engine/lib/phases/phase_specialize.ml | 2 +- engine/lib/phases/phase_traits_specs.ml | 2 +- .../phases/phase_transform_hax_lib_inline.ml | 2 +- .../lib/phases/phase_trivialize_assign_lhs.ml | 2 +- .../ppx_phases_index/ppx_phases_index.ml | 100 +++++++++++++++--- 27 files changed, 114 insertions(+), 71 deletions(-) diff --git a/engine/lib/diagnostics.ml b/engine/lib/diagnostics.ml index 1a1889544..e5f8ed5b3 100644 --- a/engine/lib/diagnostics.ml +++ b/engine/lib/diagnostics.ml @@ -27,39 +27,8 @@ module Phase = struct | x -> [%show: t] x end - type t = - | DirectAndMut - | AndMutDefSite - | Identity - | DropReferences - | DropBlocks - | DropSizedTrait - | DropMatchGuards - | RefMut - | ResugarAsserts - | ResugarForLoops - | ResugarWhileLoops - | ResugarForIndexLoops - | ResugarQuestionMarks - | RewriteControlFlow - | SimplifyQuestionMarks - | Specialize - | HoistSideEffects - | HoistDisjunctions - | LocalMutation - | TrivializeAssignLhs - | CfIntoMonads - | FunctionalizeLoops - | TraitsSpecs - | SimplifyMatchReturn - | SimplifyHoisting - | DropReturnBreakContinue - | TransformHaxLibInline - | NewtypeAsRefinement - | DummyA - | DummyB - | DummyC - | Reject of Rejection.t + (** All names for phases defined in `lib/phases_*` are generated automatically *) + type%add_phase_names t = Identity | HoistSideEffects | Reject of Rejection.t [@@deriving show { with_path = false }, eq, yojson, compare, hash, sexp] let display = function diff --git a/engine/lib/phases/phase_and_mut_defsite.ml b/engine/lib/phases/phase_and_mut_defsite.ml index 88cfb8486..d640ef92e 100644 --- a/engine/lib/phases/phase_and_mut_defsite.ml +++ b/engine/lib/phases/phase_and_mut_defsite.ml @@ -14,7 +14,7 @@ struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.AndMutDefSite + let phase_id = [%auto_phase_name auto] end) module A = Ast.Make (FA) diff --git a/engine/lib/phases/phase_cf_into_monads.ml b/engine/lib/phases/phase_cf_into_monads.ml index 9cc170da0..54f8d035e 100644 --- a/engine/lib/phases/phase_cf_into_monads.ml +++ b/engine/lib/phases/phase_cf_into_monads.ml @@ -20,7 +20,7 @@ struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.CfIntoMonads + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_direct_and_mut.ml b/engine/lib/phases/phase_direct_and_mut.ml index 4d3ae8493..c33d18096 100644 --- a/engine/lib/phases/phase_direct_and_mut.ml +++ b/engine/lib/phases/phase_direct_and_mut.ml @@ -18,7 +18,7 @@ struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.RefMut + let phase_id = [%auto_phase_name auto] end) (** Reference to a fresh local ident (item-wise) *) diff --git a/engine/lib/phases/phase_drop_blocks.ml b/engine/lib/phases/phase_drop_blocks.ml index f92633194..45844e7eb 100644 --- a/engine/lib/phases/phase_drop_blocks.ml +++ b/engine/lib/phases/phase_drop_blocks.ml @@ -12,7 +12,7 @@ module%inlined_contents Make (F : Features.T) = struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.DropReferences + let phase_id = [%auto_phase_name auto] end) module UA = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_drop_match_guards.ml b/engine/lib/phases/phase_drop_match_guards.ml index d336e6ba1..b4cf7524d 100644 --- a/engine/lib/phases/phase_drop_match_guards.ml +++ b/engine/lib/phases/phase_drop_match_guards.ml @@ -45,7 +45,7 @@ module%inlined_contents Make (F : Features.T) = struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.DropMatchGuards + let phase_id = [%auto_phase_name auto] end) module UA = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_drop_references.ml b/engine/lib/phases/phase_drop_references.ml index ec21704e2..dcd7f36ad 100644 --- a/engine/lib/phases/phase_drop_references.ml +++ b/engine/lib/phases/phase_drop_references.ml @@ -18,7 +18,7 @@ struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.DropReferences + let phase_id = [%auto_phase_name auto] end) module UA = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index f9d0c0235..3be7e8b1f 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -22,7 +22,7 @@ module%inlined_contents Make (F : Features.T) = struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.DropReturnBreakContinue + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_drop_sized_trait.ml b/engine/lib/phases/phase_drop_sized_trait.ml index 569e0ce70..00df13185 100644 --- a/engine/lib/phases/phase_drop_sized_trait.ml +++ b/engine/lib/phases/phase_drop_sized_trait.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.DropSizedTrait + let phase_id = [%auto_phase_name auto] open Ast.Make (F) module U = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_functionalize_loops.ml b/engine/lib/phases/phase_functionalize_loops.ml index 28b3dff86..956952368 100644 --- a/engine/lib/phases/phase_functionalize_loops.ml +++ b/engine/lib/phases/phase_functionalize_loops.ml @@ -25,7 +25,7 @@ struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.FunctionalizeLoops + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_hoist_disjunctive_patterns.ml b/engine/lib/phases/phase_hoist_disjunctive_patterns.ml index cdec91d08..70e92d163 100644 --- a/engine/lib/phases/phase_hoist_disjunctive_patterns.ml +++ b/engine/lib/phases/phase_hoist_disjunctive_patterns.ml @@ -7,7 +7,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.HoistDisjunctions + let phase_id = [%auto_phase_name auto] open Ast.Make (F) module U = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_local_mutation.ml b/engine/lib/phases/phase_local_mutation.ml index 4a5dd6d1d..705c6624a 100644 --- a/engine/lib/phases/phase_local_mutation.ml +++ b/engine/lib/phases/phase_local_mutation.ml @@ -25,7 +25,7 @@ struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.LocalMutation + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_newtype_as_refinement.ml b/engine/lib/phases/phase_newtype_as_refinement.ml index e19ec748b..86a29ab6a 100644 --- a/engine/lib/phases/phase_newtype_as_refinement.ml +++ b/engine/lib/phases/phase_newtype_as_refinement.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.NewtypeAsRefinement + let phase_id = [%auto_phase_name auto] module A = Ast.Make (F) module Visitors = Ast_visitors.Make (F) diff --git a/engine/lib/phases/phase_reconstruct_asserts.ml b/engine/lib/phases/phase_reconstruct_asserts.ml index 43164106b..0dfacd364 100644 --- a/engine/lib/phases/phase_reconstruct_asserts.ml +++ b/engine/lib/phases/phase_reconstruct_asserts.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.ResugarAsserts + let phase_id = [%auto_phase_name auto] open Ast.Make (F) module U = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_reconstruct_for_index_loops.ml b/engine/lib/phases/phase_reconstruct_for_index_loops.ml index 4ecdfceca..15333d8aa 100644 --- a/engine/lib/phases/phase_reconstruct_for_index_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_index_loops.ml @@ -11,7 +11,7 @@ module%inlined_contents Make (FA : Features.T) = struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.ResugarForIndexLoops + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_reconstruct_for_loops.ml b/engine/lib/phases/phase_reconstruct_for_loops.ml index a08c9cf90..2c7df3b8f 100644 --- a/engine/lib/phases/phase_reconstruct_for_loops.ml +++ b/engine/lib/phases/phase_reconstruct_for_loops.ml @@ -15,7 +15,7 @@ struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.ResugarForLoops + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_reconstruct_question_marks.ml b/engine/lib/phases/phase_reconstruct_question_marks.ml index c7f88fd91..c1faf65c8 100644 --- a/engine/lib/phases/phase_reconstruct_question_marks.ml +++ b/engine/lib/phases/phase_reconstruct_question_marks.ml @@ -11,7 +11,7 @@ module%inlined_contents Make (FA : Features.T) = struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.ResugarQuestionMarks + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_reconstruct_while_loops.ml b/engine/lib/phases/phase_reconstruct_while_loops.ml index b95181bcf..53062c7ec 100644 --- a/engine/lib/phases/phase_reconstruct_while_loops.ml +++ b/engine/lib/phases/phase_reconstruct_while_loops.ml @@ -11,7 +11,7 @@ module%inlined_contents Make (FA : Features.T) = struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.ResugarWhileLoops + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_rewrite_control_flow.ml b/engine/lib/phases/phase_rewrite_control_flow.ml index d8c568fc3..d97f0b275 100644 --- a/engine/lib/phases/phase_rewrite_control_flow.ml +++ b/engine/lib/phases/phase_rewrite_control_flow.ml @@ -10,7 +10,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.RewriteControlFlow + let phase_id = [%auto_phase_name auto] open Ast.Make (F) module U = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_simplify_hoisting.ml b/engine/lib/phases/phase_simplify_hoisting.ml index 008f152fa..d0ab09bfc 100644 --- a/engine/lib/phases/phase_simplify_hoisting.ml +++ b/engine/lib/phases/phase_simplify_hoisting.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.SimplifyHoisting + let phase_id = [%auto_phase_name auto] open Ast.Make (F) module U = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_simplify_match_return.ml b/engine/lib/phases/phase_simplify_match_return.ml index 378aa7744..9fa762997 100644 --- a/engine/lib/phases/phase_simplify_match_return.ml +++ b/engine/lib/phases/phase_simplify_match_return.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.SimplifyMatchReturn + let phase_id = [%auto_phase_name auto] open Ast.Make (F) module U = Ast_utils.Make (F) diff --git a/engine/lib/phases/phase_simplify_question_marks.ml b/engine/lib/phases/phase_simplify_question_marks.ml index 67ab9dfe0..87ae111a4 100644 --- a/engine/lib/phases/phase_simplify_question_marks.ml +++ b/engine/lib/phases/phase_simplify_question_marks.ml @@ -11,7 +11,7 @@ module%inlined_contents Make (FA : Features.T) = struct include Phase_utils.MakeBase (FA) (FB) (struct - let phase_id = Diagnostics.Phase.ResugarQuestionMarks + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_specialize.ml b/engine/lib/phases/phase_specialize.ml index 17ed60370..5b5f0a6b2 100644 --- a/engine/lib/phases/phase_specialize.ml +++ b/engine/lib/phases/phase_specialize.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.Specialize + let phase_id = [%auto_phase_name auto] module A = Ast.Make (F) module FB = F diff --git a/engine/lib/phases/phase_traits_specs.ml b/engine/lib/phases/phase_traits_specs.ml index 2d2aa087f..6020266a4 100644 --- a/engine/lib/phases/phase_traits_specs.ml +++ b/engine/lib/phases/phase_traits_specs.ml @@ -4,7 +4,7 @@ module Make (F : Features.T) = Phase_utils.MakeMonomorphicPhase (F) (struct - let phase_id = Diagnostics.Phase.TraitsSpecs + let phase_id = [%auto_phase_name auto] module A = Ast.Make (F) module FB = F diff --git a/engine/lib/phases/phase_transform_hax_lib_inline.ml b/engine/lib/phases/phase_transform_hax_lib_inline.ml index c6e8d80a8..7122047aa 100644 --- a/engine/lib/phases/phase_transform_hax_lib_inline.ml +++ b/engine/lib/phases/phase_transform_hax_lib_inline.ml @@ -13,7 +13,7 @@ module%inlined_contents Make (F : Features.T) = struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.TransformHaxLibInline + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/lib/phases/phase_trivialize_assign_lhs.ml b/engine/lib/phases/phase_trivialize_assign_lhs.ml index e64a7baab..030b7528f 100644 --- a/engine/lib/phases/phase_trivialize_assign_lhs.ml +++ b/engine/lib/phases/phase_trivialize_assign_lhs.ml @@ -13,7 +13,7 @@ module%inlined_contents Make (F : Features.T) = struct include Phase_utils.MakeBase (F) (FB) (struct - let phase_id = Diagnostics.Phase.TrivializeAssignLhs + let phase_id = [%auto_phase_name auto] end) module Implem : ImplemT.T = struct diff --git a/engine/utils/ppx_phases_index/ppx_phases_index.ml b/engine/utils/ppx_phases_index/ppx_phases_index.ml index 48d1e58e0..5e4c25b75 100644 --- a/engine/utils/ppx_phases_index/ppx_phases_index.ml +++ b/engine/utils/ppx_phases_index/ppx_phases_index.ml @@ -1,7 +1,6 @@ open Base open Ppxlib -let name = "phases_index" let ( let* ) x f = Option.bind ~f x let map_first_letter (f : string -> string) (s : string) = @@ -25,7 +24,7 @@ let locate_phases_directory () : string = |> Option.value_exn ~message:"ppx_phases_index: could not locate folder [phases]" -let list_phases loc : (string * string * _ option) list = +let list_phases loc : (string * string * string * _ option) list = let dir = locate_phases_directory () in Stdlib.Sys.readdir dir |> Array.to_list |> List.filter_map ~f:(fun filename -> @@ -50,9 +49,9 @@ let list_phases loc : (string * string * _ option) list = str in match str with - | [ _ ] -> (module_name, phase_name, None) + | [ _ ] -> (filename, module_name, phase_name, None) | [ { psig_desc = Psig_attribute attr; _ }; _ ] -> - (module_name, phase_name, Some attr) + (filename, module_name, phase_name, Some attr) | [] -> failwith ("Empty phase" ^ filename) | _ -> failwith @@ -80,13 +79,13 @@ let rename (l : (string * string) list) = r end -let expand ~(ctxt : Expansion_context.Extension.t) (str : structure_item) : - structure_item = +let expand_phases_index ~(ctxt : Expansion_context.Extension.t) + (str : structure_item) : structure_item = let loc = Expansion_context.Extension.extension_point_loc ctxt in let (module S) = Ppxlib.Ast_builder.make loc in let modules = list_phases loc - |> List.map ~f:(fun (module_name, phase_name, attrs) -> + |> List.map ~f:(fun (_, module_name, phase_name, attrs) -> let h x = { txt = Lident x; loc } in let original = S.pmod_ident { txt = Ldot (Lident module_name, "Make"); loc } @@ -111,10 +110,85 @@ let expand ~(ctxt : Expansion_context.Extension.t) (str : structure_item) : in S.pstr_include (S.include_infos (S.pmod_structure modules)) -let ext = - Extension.V3.declare name Extension.Context.structure_item - Ast_pattern.(pstr (__ ^:: nil)) - expand +let chop_ml_or_mli str = + match String.chop_suffix ~suffix:".ml" str with + | Some result -> Some result + | None -> String.chop_suffix ~suffix:".mli" str -let rule = Ppxlib.Context_free.Rule.extension ext -let () = Ppxlib.Driver.register_transformation ~rules:[ rule ] name +let filename_to_phase_constructor file_name = + let phase_name = + file_name |> String.rsplit2 ~on:'/' |> Option.map ~f:snd + |> Option.value ~default:file_name + |> String.chop_prefix ~prefix:"phase_" + |> Option.value_exn + ~message: + ("`[%auto_phase_name]` can only be used in a phase, whose filename \ + starts with `phase_`. Current file is: [" ^ file_name ^ "]") + |> chop_ml_or_mli + |> Option.value_exn + ~message: + ("File name [" ^ file_name + ^ "] was expected to end with a `.ml` or `.mli`") + in + phase_name |> String.split ~on:'_' + |> List.map ~f:uppercase_first_char + |> String.concat + +let expand_add_phase_names ~(ctxt : Expansion_context.Extension.t) + (typ : type_declaration) : structure_item = + let loc = Expansion_context.Extension.extension_point_loc ctxt in + let (module S) = Ppxlib.Ast_builder.make loc in + let ptype_kind = + match typ.ptype_kind with + | Ptype_variant ctors -> + let phases = list_phases loc in + let extra = + List.map + ~f:(fun (filename, _, _, _) -> + let name = filename_to_phase_constructor filename in + let name = { txt = name; loc = S.loc } in + let args = Pcstr_tuple [] in + S.constructor_declaration ~name ~args ~res:None) + phases + in + Ptype_variant (ctors @ extra) + | _ -> failwith "expected variants" + in + let typ = { typ with ptype_kind } in + S.pstr_type Recursive [ typ ] + +let expand_auto_phase_name ~(ctxt : Expansion_context.Extension.t) + (str : structure_item) : expression = + let file_name = Expansion_context.Extension.input_name ctxt in + let constructor = filename_to_phase_constructor file_name in + let loc = Expansion_context.Extension.extension_point_loc ctxt in + let (module S) = Ppxlib.Ast_builder.make loc in + let txt = Astlib.Longident.parse ("Diagnostics.Phase." ^ constructor) in + S.pexp_construct { txt; loc = S.loc } None + +let () = + let rule_phases_index = + let name = "phases_index" in + Ppxlib.Context_free.Rule.extension + (Extension.V3.declare name Extension.Context.structure_item + Ast_pattern.(pstr (__ ^:: nil)) + expand_phases_index) + in + let rule_auto_phase_name = + let name = "auto_phase_name" in + Ppxlib.Context_free.Rule.extension + (Extension.V3.declare name Extension.Context.expression + Ast_pattern.(pstr (__ ^:: nil)) + expand_auto_phase_name) + in + let rule_expand_add_phase_names = + let name = "add_phase_names" in + Ppxlib.Context_free.Rule.extension + (Extension.V3.declare name Extension.Context.structure_item + Ast_pattern.(pstr (pstr_type drop (__ ^:: nil) ^:: nil)) + expand_add_phase_names) + in + Ppxlib.Driver.register_transformation + ~rules: + [ rule_phases_index; rule_auto_phase_name; rule_expand_add_phase_names ] + "ppx_phases_index" From fe3230fa3e5598d4924ed871dcb757c49b3d0326 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 13:40:28 +0100 Subject: [PATCH 208/253] feat(engine): profile `import_thir` and option parsing --- engine/bin/lib.ml | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index 3168bb8ed..0a113ac7a 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -99,7 +99,10 @@ let run (options : Types.engine_options) : Types.output = let include_clauses = options.backend.translation_options.include_namespaces in - let items = import_thir_items include_clauses options.input in + let items = + Profiling.profile ThirImport (List.length options.input) (fun _ -> + import_thir_items include_clauses options.input) + in let items = if options.backend.extract_type_aliases then items else @@ -175,17 +178,18 @@ let parse_id_table_node (json : Yojson.Safe.t) : in (table, value) +let parse_options () = + let table, json = + Hax_io.read_json () |> Option.value_exn |> parse_id_table_node + in + table + |> List.iter ~f:(fun (id, json) -> + Hashtbl.add_exn Types.cache_map ~key:id ~data:(`JSON json)); + Types.parse_engine_options json + (** Entrypoint of the engine. Assumes `Hax_io.init` was called. *) let main () = - let options = - let table, json = - Hax_io.read_json () |> Option.value_exn |> parse_id_table_node - in - table - |> List.iter ~f:(fun (id, json) -> - Hashtbl.add_exn Types.cache_map ~key:id ~data:(`JSON json)); - Types.parse_engine_options json - in + let options = Profiling.profile (Other "parse_options") 1 parse_options in Printexc.record_backtrace true; let result = try Ok (run options) with From 27263831e73e657767d3a6f2c0fee8db36e71259 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 14:09:25 +0100 Subject: [PATCH 209/253] feat: verbosity: print profiling data --- cli/subcommands/src/cargo_hax.rs | 19 +++++++++++++++++++ hax-types/src/diagnostics/message.rs | 1 + 2 files changed, 20 insertions(+) diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index 62fa71677..ea19531e9 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -182,6 +182,21 @@ impl HaxMessage { ); eprintln!("{}", renderer.render(Level::Error.title(&title))); } + Self::ProfilingData(data) => { + fn format_with_dot(shift: u32, n: u64) -> String { + let factor = 10u64.pow(shift); + format!("{}.{}", n / factor, n % factor) + } + let title = format!( + "profiling [{}]: {}ms, memory={}, {} item{}", + data.context, + format_with_dot(6, data.time_ns), + data.memory, + data.quantity, + if data.quantity > 1 { "s" } else { "" } + ); + eprintln!("{}", renderer.render(Level::Info.title(&title))); + } Self::CargoBuildFailure => { let title = "hax: running `cargo build` was not successful, continuing anyway.".to_string(); @@ -318,6 +333,10 @@ fn run_engine( send!(&ToEngine::PrettyPrintedRust(code)); } FromEngine::ProfilingData(profiling_data) => { + if backend.verbose > 0 { + HaxMessage::ProfilingData(profiling_data.clone()) + .report(message_format, None) + } output.profiling_data.push(profiling_data); } FromEngine::Ping => { diff --git a/hax-types/src/diagnostics/message.rs b/hax-types/src/diagnostics/message.rs index 2a94c0b56..99fe003b0 100644 --- a/hax-types/src/diagnostics/message.rs +++ b/hax-types/src/diagnostics/message.rs @@ -23,6 +23,7 @@ pub enum HaxMessage { WarnExperimentalBackend { backend: Backend<()>, } = 4, + ProfilingData(crate::engine_api::ProfilingData) = 5, } impl HaxMessage { From 6d1d0ebdfa84c2d71d26404fb1cff2b8018a45ce Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 14:09:55 +0100 Subject: [PATCH 210/253] feat(engine): profile translation --- engine/bin/lib.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index 0a113ac7a..ae04ff476 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -125,7 +125,10 @@ let run (options : Types.engine_options) : Types.output = Logs.info (fun m -> m "Translating items with backend %s" ([%show: Diagnostics.Backend.t] M.backend)); - let items = translate with_items backend_options items ~bundles in + let items = + Profiling.profile (Backend M.backend) (List.length items) (fun _ -> + translate with_items backend_options items ~bundles) + in items in let diagnostics, files = From 17d7bd8c7812ec9328a480efdb7d29f498ae6217 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 14:45:48 +0100 Subject: [PATCH 211/253] feat(engine): make bundle cycle a proper phase --- engine/backends/coq/coq/coq_backend.ml | 1 + .../backends/coq/ssprove/ssprove_backend.ml | 1 + .../backends/easycrypt/easycrypt_backend.ml | 3 ++- engine/backends/fstar/fstar_backend.ml | 1 + engine/backends/proverif/proverif_backend.ml | 1 + engine/bin/lib.ml | 7 ++++--- engine/lib/phases/phase_bundle_cycles.ml | 20 +++++++++++++++++++ engine/lib/phases/phase_bundle_cycles.mli | 6 ++++++ 8 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 engine/lib/phases/phase_bundle_cycles.ml create mode 100644 engine/lib/phases/phase_bundle_cycles.mli diff --git a/engine/backends/coq/coq/coq_backend.ml b/engine/backends/coq/coq/coq_backend.ml index a87d08a6e..2db7c6cee 100644 --- a/engine/backends/coq/coq/coq_backend.ml +++ b/engine/backends/coq/coq/coq_backend.ml @@ -800,6 +800,7 @@ module TransformToInputLanguage = |> Phases.Reject.As_pattern |> Phases.Reject.Dyn |> Phases.Reject.Trait_item_default + |> Phases.Bundle_cycles |> SubtypeToInputLanguage |> Identity ] diff --git a/engine/backends/coq/ssprove/ssprove_backend.ml b/engine/backends/coq/ssprove/ssprove_backend.ml index 6a8b47c28..54393f0dd 100644 --- a/engine/backends/coq/ssprove/ssprove_backend.ml +++ b/engine/backends/coq/ssprove/ssprove_backend.ml @@ -591,6 +591,7 @@ module TransformToInputLanguage (* : PHASE *) = |> Phases.Reject.As_pattern |> Phases.Reject.Dyn |> Phases.Reject.Trait_item_default + |> Phases.Bundle_cycles |> SubtypeToInputLanguage |> Identity ] diff --git a/engine/backends/easycrypt/easycrypt_backend.ml b/engine/backends/easycrypt/easycrypt_backend.ml index 9afc210a3..c0739d2b7 100644 --- a/engine/backends/easycrypt/easycrypt_backend.ml +++ b/engine/backends/easycrypt/easycrypt_backend.ml @@ -352,7 +352,8 @@ module TransformToInputLanguage = Phases.Reject.RawOrMutPointer Features.Rust |> Phases.Reject.Unsafe |> Phases.And_mut_defsite |> Phases.Reconstruct_asserts |> Phases.Reconstruct_for_loops |> Phases.Direct_and_mut |> Phases.Drop_blocks -|> Phases.Reject.Continue |> Phases.Drop_references |> RejectNotEC] +|> Phases.Reject.Continue |> Phases.Drop_references |> Phases.Bundle_cycles +|> RejectNotEC] let apply_phases (_bo : BackendOptions.t) (items : Ast.Rust.item list) : AST.item list = diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 5da9ad8de..96f97da8e 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -1761,6 +1761,7 @@ module TransformToInputLanguage = |> Phases.Simplify_hoisting |> Phases.Newtype_as_refinement |> Phases.Reject.Trait_item_default + |> Phases.Bundle_cycles |> SubtypeToInputLanguage |> Identity ] diff --git a/engine/backends/proverif/proverif_backend.ml b/engine/backends/proverif/proverif_backend.ml index 588121a8c..2be7b4348 100644 --- a/engine/backends/proverif/proverif_backend.ml +++ b/engine/backends/proverif/proverif_backend.ml @@ -900,6 +900,7 @@ module TransformToInputLanguage = |> Phases.Local_mutation |> Phases.Reject.Continue |> Phases.Reject.Dyn + |> Phases.Bundle_cycles |> SubtypeToInputLanguage |> Identity ] diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index ae04ff476..d94679267 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -115,9 +115,10 @@ let run (options : Types.engine_options) : Types.output = ([%show: Diagnostics.Backend.t] M.backend)); let items = apply_phases backend_options items in let with_items = Attrs.with_items items in - let module DepGraph = Dependencies.Make (InputLanguage) in - let items = DepGraph.bundle_cyclic_modules items in - let bundles, _ = DepGraph.recursive_bundles items in + let bundles, _ = + let module DepGraph = Dependencies.Make (InputLanguage) in + DepGraph.recursive_bundles items + in let items = List.filter items ~f:(fun (i : AST.item) -> Attrs.late_skip i.attrs |> not) diff --git a/engine/lib/phases/phase_bundle_cycles.ml b/engine/lib/phases/phase_bundle_cycles.ml new file mode 100644 index 000000000..b26891f9b --- /dev/null +++ b/engine/lib/phases/phase_bundle_cycles.ml @@ -0,0 +1,20 @@ +open! Prelude + +module Make (F : Features.T) = + Phase_utils.MakeMonomorphicPhase + (F) + (struct + let phase_id = [%auto_phase_name auto] + + module A = Ast.Make (F) + + module Error = Phase_utils.MakeError (struct + let ctx = Diagnostics.Context.Phase phase_id + end) + + module Attrs = Attr_payloads.MakeBase (Error) + + let ditems items = + let module DepGraph = Dependencies.Make (F) in + DepGraph.bundle_cyclic_modules items + end) diff --git a/engine/lib/phases/phase_bundle_cycles.mli b/engine/lib/phases/phase_bundle_cycles.mli new file mode 100644 index 000000000..b6db5be6c --- /dev/null +++ b/engine/lib/phases/phase_bundle_cycles.mli @@ -0,0 +1,6 @@ +(** This phase makes sure the items don't yield any cycle, +namespace-wise. It makes the namespaces a tree. It does so by creating +namespaces we call bundles, in which we regroup definitions that would +otherwise yield cycles. *) + +module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE From e4d90eacaaaa0224d586decf746a306a55f6284a Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 15:06:23 +0100 Subject: [PATCH 212/253] feat(engine): profile: keep track of action failure --- cli/subcommands/src/cargo_hax.rs | 9 +++++++-- hax-types/src/engine_api.rs | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index ea19531e9..ba6628736 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -188,12 +188,17 @@ impl HaxMessage { format!("{}.{}", n / factor, n % factor) } let title = format!( - "profiling [{}]: {}ms, memory={}, {} item{}", + "[profiling] {}: {}ms, memory={}, {} item{}{}", data.context, format_with_dot(6, data.time_ns), data.memory, data.quantity, - if data.quantity > 1 { "s" } else { "" } + if data.quantity > 1 { "s" } else { "" }, + if data.errored { + " (note: this failed!)" + } else { + "" + } ); eprintln!("{}", renderer.render(Level::Info.title(&title))); } diff --git a/hax-types/src/engine_api.rs b/hax-types/src/engine_api.rs index 9fbc5f317..4a81031d8 100644 --- a/hax-types/src/engine_api.rs +++ b/hax-types/src/engine_api.rs @@ -72,6 +72,10 @@ pub struct ProfilingData { /// How many things were processed? (often, this is the number of /// items a phase processes) pub quantity: u32, + /// Did the action errored? This is important since a failed + /// action might have exited very early, making the numbers + /// unusable. + pub errored: bool, } pub mod protocol { From f6223a951b3edd767b511d3f7e396bcff2d9ec65 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 15:06:46 +0100 Subject: [PATCH 213/253] feat: add a `profile` flag --- cli/subcommands/src/cargo_hax.rs | 7 +--- engine/bin/lib.ml | 6 ++-- engine/lib/profiling.ml | 55 +++++++++++++++++++------------- hax-types/src/cli_options/mod.rs | 4 +++ hax-types/src/engine_api.rs | 1 - 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/cli/subcommands/src/cargo_hax.rs b/cli/subcommands/src/cargo_hax.rs index ba6628736..a1952dc70 100644 --- a/cli/subcommands/src/cargo_hax.rs +++ b/cli/subcommands/src/cargo_hax.rs @@ -251,7 +251,6 @@ fn run_engine( diagnostics: vec![], files: vec![], debug_json: None, - profiling_data: vec![], }; { let mut rctx = hax_types::diagnostics::report::ReportCtx::default(); @@ -338,11 +337,7 @@ fn run_engine( send!(&ToEngine::PrettyPrintedRust(code)); } FromEngine::ProfilingData(profiling_data) => { - if backend.verbose > 0 { - HaxMessage::ProfilingData(profiling_data.clone()) - .report(message_format, None) - } - output.profiling_data.push(profiling_data); + HaxMessage::ProfilingData(profiling_data).report(message_format, None) } FromEngine::Ping => { send!(&ToEngine::Pong); diff --git a/engine/bin/lib.ml b/engine/bin/lib.ml index d94679267..e75c294d2 100644 --- a/engine/bin/lib.ml +++ b/engine/bin/lib.ml @@ -145,8 +145,6 @@ let run (options : Types.engine_options) : Types.output = diagnostics = List.map ~f:Diagnostics.to_thir_diagnostic diagnostics; files = Option.value ~default:[] files; debug_json = None; - profiling_data = []; - (* This data is sent interactively via Hax_io *) } (** Shallow parses a `id_table::Node` (or a raw `T`) JSON *) @@ -189,7 +187,9 @@ let parse_options () = table |> List.iter ~f:(fun (id, json) -> Hashtbl.add_exn Types.cache_map ~key:id ~data:(`JSON json)); - Types.parse_engine_options json + let options = Types.parse_engine_options json in + Profiling.enabled := options.backend.profile; + options (** Entrypoint of the engine. Assumes `Hax_io.init` was called. *) let main () = diff --git a/engine/lib/profiling.ml b/engine/lib/profiling.ml index 68e895889..819b3de35 100644 --- a/engine/lib/profiling.ml +++ b/engine/lib/profiling.ml @@ -1,28 +1,37 @@ open Prelude +(** Is profiling enabled? *) +let enabled = ref true + (** Profiles the function `f`, that operates in a given context over a given quantity of things it is processing. *) let profile (type b) (context : Diagnostics.Context.t) (quantity : int) (f : unit -> b) : b = - let time0 = Core.Time_ns.now () in - let mem0 = Core.Gc.minor_words () in - let finalize () = - let time1 = Core.Time_ns.now () in - let mem1 = Core.Gc.minor_words () in - let time_ns = Core.Time_ns.diff time1 time0 in - let memory = mem1 - mem0 in - Hax_io.write - (Types.ProfilingData - { - context = Diagnostics.Context.display context; - time_ns = Core.Time_ns.Span.to_int63_ns time_ns |> Int63.to_string; - memory = Int.to_string memory; - quantity = Int.to_int64 quantity; - }) - in - try - let result = f () in - finalize (); - result - with e -> - finalize (); - raise e + if !enabled (* `!` derefs, it's not a negation *) then ( + let time0 = Core.Time_ns.now () in + let mem0 = Core.Gc.minor_words () in + let finalize errored = + if !enabled (* `!` derefs, it's not a negation *) then + let time1 = Core.Time_ns.now () in + let mem1 = Core.Gc.minor_words () in + let time_ns = Core.Time_ns.diff time1 time0 in + let memory = mem1 - mem0 in + Hax_io.write + (Types.ProfilingData + { + context = Diagnostics.Context.display context; + time_ns = + Core.Time_ns.Span.to_int63_ns time_ns |> Int63.to_string; + memory = Int.to_string memory; + quantity = Int.to_int64 quantity; + errored; + }) + else () + in + try + let result = f () in + finalize false; + result + with e -> + finalize true; + raise e) + else f () diff --git a/hax-types/src/cli_options/mod.rs b/hax-types/src/cli_options/mod.rs index 4f275606a..6ef102e13 100644 --- a/hax-types/src/cli_options/mod.rs +++ b/hax-types/src/cli_options/mod.rs @@ -308,6 +308,10 @@ pub struct BackendOptions { #[arg(short, long, action = clap::ArgAction::Count)] pub verbose: u8, + /// Enables profiling for the engine + #[arg(short, long)] + pub profile: bool, + /// Enable engine debugging: dumps the AST at each phase. /// /// The value of `` can be either: diff --git a/hax-types/src/engine_api.rs b/hax-types/src/engine_api.rs index 4a81031d8..0f41211a2 100644 --- a/hax-types/src/engine_api.rs +++ b/hax-types/src/engine_api.rs @@ -56,7 +56,6 @@ pub struct Output { pub diagnostics: Vec, pub files: Vec, pub debug_json: Option, - pub profiling_data: Vec, } #[derive_group(Serializers)] From 385b8d2ff096e27a6e92ac9901e0419b27029923 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Wed, 30 Oct 2024 15:51:48 +0100 Subject: [PATCH 214/253] fix: can be a DAG --- engine/lib/phases/phase_bundle_cycles.mli | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/engine/lib/phases/phase_bundle_cycles.mli b/engine/lib/phases/phase_bundle_cycles.mli index b6db5be6c..2a8c3f80d 100644 --- a/engine/lib/phases/phase_bundle_cycles.mli +++ b/engine/lib/phases/phase_bundle_cycles.mli @@ -1,6 +1,5 @@ (** This phase makes sure the items don't yield any cycle, -namespace-wise. It makes the namespaces a tree. It does so by creating -namespaces we call bundles, in which we regroup definitions that would -otherwise yield cycles. *) +namespace-wise. It does so by creating namespaces we call bundles, in +which we regroup definitions that would otherwise yield cycles. *) module Make : Phase_utils.UNCONSTRAINTED_MONOMORPHIC_PHASE From 53ee2e0d6a8da5fede09cb7d4dc41ca6f476b0d4 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 30 Oct 2024 16:43:06 +0100 Subject: [PATCH 215/253] Keep late_skip attributes. --- engine/lib/dependencies.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/lib/dependencies.ml b/engine/lib/dependencies.ml index a54e28eeb..eb8819ac8 100644 --- a/engine/lib/dependencies.ml +++ b/engine/lib/dependencies.ml @@ -383,11 +383,11 @@ module Make (F : Features.T) = struct let aliases = List.map (old_new :: variants_renamings old_new) ~f:(fun (old_ident, new_ident) -> - { - item with - v = Alias { name = old_ident; item = new_ident }; - attrs = []; - }) + let attrs = + List.filter ~f:(fun att -> Attrs.late_skip [ att ]) item.attrs + in + + { item with v = Alias { name = old_ident; item = new_ident }; attrs }) in item' :: aliases From 5f1c5da13ec2ad22ad5d00f588791185796d26d0 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Wed, 30 Oct 2024 16:58:50 +0100 Subject: [PATCH 216/253] Add test for late_skip in bundles. --- .../toolchain__cyclic-modules into-fstar.snap | 27 +++++++++++++++++++ tests/Cargo.lock | 3 +++ tests/cyclic-modules/Cargo.toml | 1 + tests/cyclic-modules/src/lib.rs | 12 +++++++++ 4 files changed, 43 insertions(+) diff --git a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap index 3edbdc730..af07fc045 100644 --- a/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__cyclic-modules into-fstar.snap @@ -180,6 +180,33 @@ include Cyclic_modules.Enums_b.Rec_bundle_994866580 {U_C as U_C} include Cyclic_modules.Enums_b.Rec_bundle_994866580 {f as f} ''' +"Cyclic_modules.Late_skip_a.fst" = ''' +module Cyclic_modules.Late_skip_a +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.Late_skip_b.Rec_bundle_447022631 {f749016415 as f} +''' +"Cyclic_modules.Late_skip_b.Rec_bundle_447022631.fst" = ''' +module Cyclic_modules.Late_skip_b.Rec_bundle_447022631 +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let rec f749016415 (_: Prims.unit) : Prims.unit = f377825240 () + +and f377825240 (_: Prims.unit) : Prims.Pure Prims.unit (requires true) (fun _ -> Prims.l_True) = + f749016415 () +''' +"Cyclic_modules.Late_skip_b.fst" = ''' +module Cyclic_modules.Late_skip_b +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +include Cyclic_modules.Late_skip_b.Rec_bundle_447022631 {f377825240 as f} +''' "Cyclic_modules.M1.fst" = ''' module Cyclic_modules.M1 #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 09cd8e14b..3fd42cefa 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -224,6 +224,9 @@ dependencies = [ [[package]] name = "cyclic-modules" version = "0.1.0" +dependencies = [ + "hax-lib", +] [[package]] name = "dyn" diff --git a/tests/cyclic-modules/Cargo.toml b/tests/cyclic-modules/Cargo.toml index 092cfd078..480511746 100644 --- a/tests/cyclic-modules/Cargo.toml +++ b/tests/cyclic-modules/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +hax-lib = { path = "../../hax-lib" } [package.metadata.hax-tests] into."fstar" = { broken = false, snapshot = "stdout", issue_id = "396" } diff --git a/tests/cyclic-modules/src/lib.rs b/tests/cyclic-modules/src/lib.rs index b59be2d80..216a54812 100644 --- a/tests/cyclic-modules/src/lib.rs +++ b/tests/cyclic-modules/src/lib.rs @@ -166,3 +166,15 @@ pub mod variant_constructor_b { super::variant_constructor_a::Context::A(1) } } + +pub mod late_skip_a { + pub fn f() { + super::late_skip_b::f() + } +} +pub mod late_skip_b { + #[hax_lib::requires(true)] + pub fn f() { + super::late_skip_a::f() + } +} From b348472d35481b38e913bd07f1591f831fb781fe Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 12:07:13 +0100 Subject: [PATCH 217/253] feat(engine/ast_utils): `call`: add a `generic_args` parameter --- engine/lib/ast_utils.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 26e826bbf..9e3994e1e 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -890,7 +890,7 @@ module Make (F : Features.T) = struct (Concrete_ident.of_name (Constructor { is_struct }) constructor_name)) is_struct args span ret_typ - let call' ?impl f (args : expr list) span ret_typ = + let call' ?impl f ?(generic_args = []) (args : expr list) span ret_typ = let typ = TArrow (List.map ~f:(fun arg -> arg.typ) args, ret_typ) in let e = GlobalVar f in { @@ -899,7 +899,7 @@ module Make (F : Features.T) = struct { f = { e; typ; span }; args; - generic_args = []; + generic_args; bounds_impls = []; trait = Option.map ~f:(fun impl -> (impl, [])) impl; }; @@ -907,9 +907,9 @@ module Make (F : Features.T) = struct span; } - let call ?(kind : Concrete_ident.Kind.t = Value) ?impl + let call ?(kind : Concrete_ident.Kind.t = Value) ?(generic_args = []) ?impl (f_name : Concrete_ident.name) (args : expr list) span ret_typ = - call' ?impl + call' ?impl ~generic_args (`Concrete (Concrete_ident.of_name kind f_name)) args span ret_typ From 5e76ce50e4accb9790787a1b21bc7e60553d2ff2 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 12:56:13 +0100 Subject: [PATCH 218/253] feat(engine/ast_utils): `call`: add a `impl_generic_args` parameter --- engine/lib/ast_utils.ml | 8 ++++---- engine/lib/phases/phase_simplify_question_marks.ml | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 9e3994e1e..96b6bef98 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -890,7 +890,7 @@ module Make (F : Features.T) = struct (Concrete_ident.of_name (Constructor { is_struct }) constructor_name)) is_struct args span ret_typ - let call' ?impl f ?(generic_args = []) (args : expr list) span ret_typ = + let call' ?impl f ?(generic_args = []) ?(impl_generic_args = []) (args : expr list) span ret_typ = let typ = TArrow (List.map ~f:(fun arg -> arg.typ) args, ret_typ) in let e = GlobalVar f in { @@ -901,15 +901,15 @@ module Make (F : Features.T) = struct args; generic_args; bounds_impls = []; - trait = Option.map ~f:(fun impl -> (impl, [])) impl; + trait = Option.map ~f:(fun impl -> (impl, impl_generic_args)) impl; }; typ = ret_typ; span; } - let call ?(kind : Concrete_ident.Kind.t = Value) ?(generic_args = []) ?impl + let call ?(kind : Concrete_ident.Kind.t = Value) ?(generic_args = []) ?(impl_generic_args = []) ?impl (f_name : Concrete_ident.name) (args : expr list) span ret_typ = - call' ?impl ~generic_args + call' ?impl ~generic_args ~impl_generic_args (`Concrete (Concrete_ident.of_name kind f_name)) args span ret_typ diff --git a/engine/lib/phases/phase_simplify_question_marks.ml b/engine/lib/phases/phase_simplify_question_marks.ml index 87ae111a4..8398c5a34 100644 --- a/engine/lib/phases/phase_simplify_question_marks.ml +++ b/engine/lib/phases/phase_simplify_question_marks.ml @@ -87,8 +87,9 @@ module%inlined_contents Make (FA : Features.T) = struct let* impl = expect_residual_impl_result impl in let*? _ = [%eq: ty] error_src error_dest |> not in let from_typ = TArrow ([ error_src ], error_dest) in + let generic_args = [GType error_dest; GType error_src] in Some - (UA.call ~kind:(AssociatedItem Value) ~impl Core__convert__From__from + (UA.call ~generic_args ~kind:(AssociatedItem Value) ~impl Core__convert__From__from [ e ] e.span from_typ) (** [map_err e error_dest impl] creates the expression From 7f384e411168dd0cff4b8b937eee328a4dfaf031 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 12:56:46 +0100 Subject: [PATCH 219/253] fix(engine/simplify_question_marks): fix type arguments on `from` Fixes #1083 --- .../lib/phases/phase_simplify_question_marks.ml | 6 +++--- tests/side-effects/src/lib.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/engine/lib/phases/phase_simplify_question_marks.ml b/engine/lib/phases/phase_simplify_question_marks.ml index 8398c5a34..3cda9ad7f 100644 --- a/engine/lib/phases/phase_simplify_question_marks.ml +++ b/engine/lib/phases/phase_simplify_question_marks.ml @@ -87,10 +87,10 @@ module%inlined_contents Make (FA : Features.T) = struct let* impl = expect_residual_impl_result impl in let*? _ = [%eq: ty] error_src error_dest |> not in let from_typ = TArrow ([ error_src ], error_dest) in - let generic_args = [GType error_dest; GType error_src] in + let impl_generic_args = [ GType error_dest; GType error_src ] in Some - (UA.call ~generic_args ~kind:(AssociatedItem Value) ~impl Core__convert__From__from - [ e ] e.span from_typ) + (UA.call ~impl_generic_args ~kind:(AssociatedItem Value) ~impl + Core__convert__From__from [ e ] e.span from_typ) (** [map_err e error_dest impl] creates the expression [e.map_err(from)] with the proper types and impl diff --git a/tests/side-effects/src/lib.rs b/tests/side-effects/src/lib.rs index 7bef76cb4..c7db53f22 100644 --- a/tests/side-effects/src/lib.rs +++ b/tests/side-effects/src/lib.rs @@ -156,3 +156,20 @@ fn assign_non_trivial_lhs(mut foo: Foo) -> Foo { foo.y.1[3].b.0[5].0 = true; foo } + +mod issue_1083 { + trait MyFrom { + fn my_from(x: T) -> Self; + } + + impl MyFrom for u16 { + fn my_from(x: u8) -> u16 { + x as u16 + } + } + + fn f(x: u8) -> Result { + Err(1u8)?; + Ok(u16::my_from(x)) + } +} From 3695ea14be98c60945faaa3d7fde73f5f4ba702d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 28 Oct 2024 14:28:42 +0100 Subject: [PATCH 220/253] Intern `DefId`s --- engine/names/extract/build.rs | 48 ++++++++++++++++++++------- frontend/exporter/src/id_table.rs | 30 ++++++++++++++--- frontend/exporter/src/rustc_utils.rs | 23 ++++++------- frontend/exporter/src/types/def_id.rs | 32 ++++++++++++++---- 4 files changed, 97 insertions(+), 36 deletions(-) diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index 47e7fbc51..036a6abc2 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -10,6 +10,24 @@ use std::process::{Command, Stdio}; mod hax_frontend_exporter_def_id; use hax_frontend_exporter_def_id::*; +mod id_table { + //! Shim to make `def_id.rs` build. Replaces the `id_table` interner with a plain `Arc`. + use serde::{Deserialize, Serialize}; + use std::sync::Arc; + + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] + pub struct Node { + value: Arc, + } + + impl std::ops::Deref for Node { + type Target = T; + fn deref(&self) -> &Self::Target { + self.value.as_ref() + } + } +} + /// Name of the current crate const HAX_ENGINE_NAMES_CRATE: &str = "hax_engine_names"; /// Path `a::b` needs to be compiled to a OCaml variant name, `::` is @@ -53,23 +71,29 @@ fn def_path_item_to_str(path_item: DefPathItem) -> String { } } -fn disambiguated_def_path_item_to_str(defpath: DisambiguatedDefPathItem) -> String { - let data = def_path_item_to_str(defpath.data); +fn disambiguated_def_path_item_to_str(defpath: &DisambiguatedDefPathItem) -> String { + let data = def_path_item_to_str(defpath.data.clone()); let disambiguator = disambiguator_to_str(defpath.disambiguator); format!("{data}{disambiguator}") } -fn def_id_to_str(DefId { krate, path, .. }: &mut DefId) -> String { - if krate == HAX_ENGINE_NAMES_CRATE { - *krate = "rust_primitives".into(); +fn def_id_to_str(def_id: &DefId) -> (Value, String) { + let crate_name = if def_id.krate == HAX_ENGINE_NAMES_CRATE { + "rust_primitives" + } else { + &def_id.krate }; - let path = path - .clone() + // Update the crate name in the json output as well. + let mut json = serde_json::to_value(def_id).unwrap(); + json["krate"] = Value::String(crate_name.to_owned()); + + let crate_name = uppercase_first_letter(crate_name); + let path = [crate_name] .into_iter() - .map(disambiguated_def_path_item_to_str) + .chain(def_id.path.iter().map(disambiguated_def_path_item_to_str)) .collect::>() .join(SEPARATOR); - format!("{}{SEPARATOR}{path}", uppercase_first_letter(&krate)) + (json, path) } fn reader_to_str(s: String) -> String { @@ -82,9 +106,9 @@ fn reader_to_str(s: String) -> String { let def_ids = def_ids .into_iter() - .map(|mut did| { - let krate_name = def_id_to_str(&mut did); - (serde_json::to_string(&did).unwrap(), krate_name) + .map(|did| { + let (json, krate_name) = def_id_to_str(&did); + (serde_json::to_string(&json).unwrap(), krate_name) }) .collect::>(); diff --git a/frontend/exporter/src/id_table.rs b/frontend/exporter/src/id_table.rs index 70f503d0b..569199eec 100644 --- a/frontend/exporter/src/id_table.rs +++ b/frontend/exporter/src/id_table.rs @@ -47,6 +47,7 @@ impl Session { #[derive(Debug, Clone, Deserialize, Serialize)] pub enum Value { Ty(Arc), + DefId(Arc), } impl SupportedType for TyKind { @@ -56,6 +57,19 @@ impl SupportedType for TyKind { fn from_types(t: &Value) -> Option> { match t { Value::Ty(value) => Some(value.clone()), + _ => None, + } + } +} + +impl SupportedType for DefIdContents { + fn to_types(value: Arc) -> Value { + Value::DefId(value) + } + fn from_types(t: &Value) -> Option> { + match t { + Value::DefId(value) => Some(value.clone()), + _ => None, } } } @@ -69,6 +83,13 @@ pub struct Node> { value: Arc, } +impl> std::ops::Deref for Node { + type Target = T; + fn deref(&self) -> &Self::Target { + self.value.as_ref() + } +} + /// Hax relies on hashes being deterministic for predicates /// ids. Identifiers are not deterministic: we implement hash for /// `Node` manually, discarding the field `id`. @@ -158,13 +179,14 @@ impl Session { } } -impl> Node { +impl> Node { pub fn new(value: T, session: &mut Session) -> Self { let id = session.fresh_id(); - let kind = Arc::new(value); - session.table.0.insert(id.clone(), kind.clone()); - Self { id, value: kind } + let value = Arc::new(value); + session.table.0.insert(id.clone(), value.clone()); + Self { id, value } } + pub fn inner(&self) -> &Arc { &self.value } diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index 8d4c56628..9c4b345fd 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -39,19 +39,16 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( typ: constructs_type.clone(), variant: variant.sinto(s), kind, - type_namespace: DefId { - path: match constructs_type.path.as_slice() { - [init @ .., _] => init.to_vec(), - _ => { - let span = s.base().tcx.def_span(variant); - fatal!( - s[span], - "Type {:#?} appears to have no path", - constructs_type - ) - } - }, - ..constructs_type.clone() + type_namespace: match s.base().tcx.opt_parent((&constructs_type).into()) { + Some(parent) => parent.sinto(s), + None => { + let span = s.base().tcx.def_span(variant); + fatal!( + s[span], + "Type {:#?} appears to have no path", + constructs_type + ) + } }, } } diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index c0594ca6c..e9a4266aa 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -44,6 +44,13 @@ pub struct DisambiguatedDefPathItem { #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(not(feature = "extract_names_mode"), derive(JsonSchema))] pub struct DefId { + pub(crate) contents: crate::id_table::Node, +} + +#[derive_group(Serializers)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(not(feature = "extract_names_mode"), derive(JsonSchema))] +pub struct DefIdContents { pub krate: String, pub path: Vec, /// Rustc's `CrateNum` and `DefIndex` raw indexes. This can be @@ -58,6 +65,13 @@ pub struct DefId { pub is_local: bool, } +impl std::ops::Deref for DefId { + type Target = DefIdContents; + fn deref(&self) -> &Self::Target { + &self.contents + } +} + #[cfg(not(feature = "rustc"))] impl std::fmt::Debug for DefId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -78,12 +92,12 @@ impl std::fmt::Debug for DefId { impl std::hash::Hash for DefId { fn hash(&self, state: &mut H) { - let DefId { + let DefIdContents { krate, path, index: _, // intentionally discarding index is_local: _, // intentionally discarding is_local - } = self; + } = &**self; krate.hash(state); path.hash(state); } @@ -94,15 +108,18 @@ pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) let tcx = s.base().tcx; let def_path = tcx.def_path(def_id); let krate = tcx.crate_name(def_path.krate); - DefId { + let contents = DefIdContents { path: def_path.data.iter().map(|x| x.sinto(s)).collect(), - krate: format!("{}", krate), + krate: krate.to_string(), index: ( rustc_hir::def_id::CrateNum::as_u32(def_id.krate), rustc_hir::def_id::DefIndex::as_u32(def_id.index), ), is_local: def_id.is_local(), - } + }; + let contents = + s.with_global_cache(|cache| id_table::Node::new(contents, &mut cache.id_table_session)); + DefId { contents } } #[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] @@ -142,14 +159,15 @@ pub type Path = Vec; #[cfg(all(not(feature = "extract_names_mode"), feature = "rustc"))] impl std::convert::From for Path { fn from(v: DefId) -> Vec { - std::iter::once(v.krate) - .chain(v.path.into_iter().filter_map(|item| match item.data { + std::iter::once(&v.krate) + .chain(v.path.iter().filter_map(|item| match &item.data { DefPathItem::TypeNs(s) | DefPathItem::ValueNs(s) | DefPathItem::MacroNs(s) | DefPathItem::LifetimeNs(s) => Some(s), _ => None, })) + .cloned() .collect() } } From 03da74bbddf8c3d2e3b04768e865dc12c94c6361 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 28 Oct 2024 14:37:30 +0100 Subject: [PATCH 221/253] Add a convenience method --- frontend/exporter/src/rustc_utils.rs | 2 +- frontend/exporter/src/types/def_id.rs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index 9c4b345fd..e9e6c7e36 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -39,7 +39,7 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( typ: constructs_type.clone(), variant: variant.sinto(s), kind, - type_namespace: match s.base().tcx.opt_parent((&constructs_type).into()) { + type_namespace: match s.base().tcx.opt_parent(constructs_type.to_rust_def_id()) { Some(parent) => parent.sinto(s), None => { let span = s.base().tcx.def_span(variant); diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index e9a4266aa..7efac406e 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -134,17 +134,24 @@ impl<'s, S: BaseState<'s>> SInto for RDefId { } } -#[cfg(feature = "rustc")] -impl From<&DefId> for RDefId { - fn from<'tcx>(def_id: &DefId) -> Self { - let (krate, index) = def_id.index; - Self { +impl DefId { + #[cfg(feature = "rustc")] + pub fn to_rust_def_id(&self) -> RDefId { + let (krate, index) = self.index; + RDefId { krate: rustc_hir::def_id::CrateNum::from_u32(krate), index: rustc_hir::def_id::DefIndex::from_u32(index), } } } +#[cfg(feature = "rustc")] +impl From<&DefId> for RDefId { + fn from<'tcx>(def_id: &DefId) -> Self { + def_id.to_rust_def_id() + } +} + // Impl to be able to use hax's `DefId` for many rustc queries. #[cfg(feature = "rustc")] impl rustc_middle::query::IntoQueryParam for &DefId { From 0058e937e61a22851ce414ebdba387c841ae9021 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 31 Oct 2024 13:06:51 +0100 Subject: [PATCH 222/253] Add `parent` field to `DefId` --- frontend/exporter/src/rustc_utils.rs | 6 ++-- frontend/exporter/src/types/def_id.rs | 41 ++++++++++++++------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/frontend/exporter/src/rustc_utils.rs b/frontend/exporter/src/rustc_utils.rs index e9e6c7e36..1fcb671d9 100644 --- a/frontend/exporter/src/rustc_utils.rs +++ b/frontend/exporter/src/rustc_utils.rs @@ -39,13 +39,13 @@ pub(crate) fn get_variant_information<'s, S: UnderOwnerState<'s>>( typ: constructs_type.clone(), variant: variant.sinto(s), kind, - type_namespace: match s.base().tcx.opt_parent(constructs_type.to_rust_def_id()) { - Some(parent) => parent.sinto(s), + type_namespace: match &constructs_type.parent { + Some(parent) => parent.clone(), None => { let span = s.base().tcx.def_span(variant); fatal!( s[span], - "Type {:#?} appears to have no path", + "Type {:#?} appears to have no parent", constructs_type ) } diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index 7efac406e..2d1c5a835 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -53,6 +53,7 @@ pub struct DefId { pub struct DefIdContents { pub krate: String, pub path: Vec, + pub parent: Option, /// Rustc's `CrateNum` and `DefIndex` raw indexes. This can be /// useful if one needs to convert a [`DefId`] into a /// [`rustc_hir::def_id::DefId`]; there is a `From` instance for @@ -65,6 +66,22 @@ pub struct DefIdContents { pub is_local: bool, } +#[cfg(feature = "rustc")] +impl DefId { + pub fn to_rust_def_id(&self) -> RDefId { + let (krate, index) = self.index; + RDefId { + krate: rustc_hir::def_id::CrateNum::from_u32(krate), + index: rustc_hir::def_id::DefIndex::from_u32(index), + } + } + + /// Iterate over this element and its parents. + pub fn ancestry(&self) -> impl Iterator { + std::iter::successors(Some(self), |def| def.parent.as_ref()) + } +} + impl std::ops::Deref for DefId { type Target = DefIdContents; fn deref(&self) -> &Self::Target { @@ -92,14 +109,10 @@ impl std::fmt::Debug for DefId { impl std::hash::Hash for DefId { fn hash(&self, state: &mut H) { - let DefIdContents { - krate, - path, - index: _, // intentionally discarding index - is_local: _, // intentionally discarding is_local - } = &**self; - krate.hash(state); - path.hash(state); + // A `DefId` is basically an interned path; we only hash the path, discarding the rest of + // the information. + self.krate.hash(state); + self.path.hash(state); } } @@ -111,6 +124,7 @@ pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) let contents = DefIdContents { path: def_path.data.iter().map(|x| x.sinto(s)).collect(), krate: krate.to_string(), + parent: tcx.opt_parent(def_id).sinto(s), index: ( rustc_hir::def_id::CrateNum::as_u32(def_id.krate), rustc_hir::def_id::DefIndex::as_u32(def_id.index), @@ -134,17 +148,6 @@ impl<'s, S: BaseState<'s>> SInto for RDefId { } } -impl DefId { - #[cfg(feature = "rustc")] - pub fn to_rust_def_id(&self) -> RDefId { - let (krate, index) = self.index; - RDefId { - krate: rustc_hir::def_id::CrateNum::from_u32(krate), - index: rustc_hir::def_id::DefIndex::from_u32(index), - } - } -} - #[cfg(feature = "rustc")] impl From<&DefId> for RDefId { fn from<'tcx>(def_id: &DefId) -> Self { From 59899cfda6e94f0f2e5d5dab42baddc7072b5205 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 13:51:50 +0100 Subject: [PATCH 223/253] chore: update test snapshots --- .../toolchain__side-effects into-fstar.snap | 35 +++++++++++++- .../toolchain__side-effects into-ssprove.snap | 48 +++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap index a75b44a71..e03cc7117 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap @@ -27,6 +27,37 @@ stderr = 'Finished `dev` profile [unoptimized + debuginfo] target(s) in XXs' diagnostics = [] [stdout.files] +"Side_effects.Issue_1083_.fst" = ''' +module Side_effects.Issue_1083_ +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +class t_MyFrom (v_Self: Type0) (v_T: Type0) = { + f_my_from_pre:v_T -> Type0; + f_my_from_post:v_T -> v_Self -> Type0; + f_my_from:x0: v_T -> Prims.Pure v_Self (f_my_from_pre x0) (fun result -> f_my_from_post x0 result) +} + +[@@ FStar.Tactics.Typeclasses.tcinstance] +let impl: t_MyFrom u16 u8 = + { + f_my_from_pre = (fun (x: u8) -> true); + f_my_from_post = (fun (x: u8) (out: u16) -> true); + f_my_from = fun (x: u8) -> cast (x <: u8) <: u16 + } + +let f (x: u8) : Core.Result.t_Result u16 u16 = + match Core.Result.Result_Err 1uy <: Core.Result.t_Result Prims.unit u8 with + | Core.Result.Result_Ok _ -> + Core.Result.Result_Ok (f_my_from #u16 #u8 #FStar.Tactics.Typeclasses.solve x) + <: + Core.Result.t_Result u16 u16 + | Core.Result.Result_Err err -> + Core.Result.Result_Err (Core.Convert.f_from #u16 #u8 #FStar.Tactics.Typeclasses.solve err) + <: + Core.Result.t_Result u16 u16 +''' "Side_effects.fst" = ''' module Side_effects #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -156,7 +187,7 @@ let direct_result_question_mark_coercion (y: Core.Result.t_Result i8 u16) match y with | Core.Result.Result_Ok hoist1 -> Core.Result.Result_Ok hoist1 <: Core.Result.t_Result i8 u32 | Core.Result.Result_Err err -> - Core.Result.Result_Err (Core.Convert.f_from #FStar.Tactics.Typeclasses.solve err) + Core.Result.Result_Err (Core.Convert.f_from #u32 #u16 #FStar.Tactics.Typeclasses.solve err) <: Core.Result.t_Result i8 u32 @@ -397,7 +428,7 @@ let question_mark (x: u32) : Core.Result.t_Result u32 u32 = <: Core.Result.t_Result u32 u32 | Core.Result.Result_Err err -> - Core.Result.Result_Err (Core.Convert.f_from #FStar.Tactics.Typeclasses.solve err) + Core.Result.Result_Err (Core.Convert.f_from #u32 #u8 #FStar.Tactics.Typeclasses.solve err) <: Core.Result.t_Result u32 u32 else diff --git a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap index 401de5fc8..80a576172 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap @@ -126,6 +126,8 @@ Notation "'Build_t_Foo' '[' x ']' '(' 'f_bar' ':=' y ')'" := (Build_t_Foo (f_x : (*Not implemented yet? todo(item)*) +(*Not implemented yet? todo(item)*) + Equations add3 {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I1 : Interface} {I2 : Interface} {I3 : Interface} (x : both L1 I1 int32) (y : both L2 I2 int32) (z : both L3 I3 int32) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) int32 := add3 x y z := solve_lift (impl__u32__wrapping_add (impl__u32__wrapping_add x y) z) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) int32. @@ -301,3 +303,49 @@ Equations simplifiable_return {L1 : {fset Location}} {L2 : {fset Location}} {L3 ControlFlow_Continue x)) : both (L1 :|: L2 :|: L3 :|: fset [x_loc]) (I1 :|: I2 :|: I3) int32. Fail Next Obligation. ''' +"Side_effects_Issue_1083_.v" = ''' +(* File automatically generated by Hacspec *) +Set Warnings "-notation-overridden,-ambiguous-paths". +From Crypt Require Import choice_type Package Prelude. +Import PackageNotation. +From extructures Require Import ord fset. +From mathcomp Require Import word_ssrZ word. +From Jasmin Require Import word. + +From Coq Require Import ZArith. +From Coq Require Import Strings.String. +Import List.ListNotations. +Open Scope list_scope. +Open Scope Z_scope. +Open Scope bool_scope. + +From Hacspec Require Import ChoiceEquality. +From Hacspec Require Import LocationUtility. +From Hacspec Require Import Hacspec_Lib_Comparable. +From Hacspec Require Import Hacspec_Lib_Pre. +From Hacspec Require Import Hacspec_Lib. + +Open Scope hacspec_scope. +Import choice.Choice.Exports. + +Obligation Tactic := (* try timeout 8 *) solve_ssprove_obligations. + +Class t_MyFrom (Self : choice_type) := { + f_my_from_loc : {fset Location} ; + f_my_from : (forall {L1 I1}, both L1 I1 v_T -> both (L1 :|: f_my_from_loc) I1 v_Self) ; +}. +Hint Unfold f_my_from_loc. + +#[global] Program Instance int16_t_MyFrom : t_MyFrom int16 int8 := + let f_my_from := fun {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int8) => solve_lift (cast_int (WS2 := _) x) : both (L1 :|: fset []) I1 int16 in + {| f_my_from_loc := (fset [] : {fset Location}); + f_my_from := (@f_my_from)|}. +Fail Next Obligation. +Hint Unfold int16_t_MyFrom. + +Equations f {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int8) : both L1 I1 (t_Result int16 int16) := + f x := + solve_lift (run (letm[choice_typeMonad.result_bind_code int16] _ := impl__map_err (Result_Err (ret_both (1 : int8))) f_from in + Result_Ok (Result_Ok (f_my_from x)))) : both L1 I1 (t_Result int16 int16). +Fail Next Obligation. +''' From 527951b9042cd53bf82cd6679af882743fef870f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 31 Oct 2024 13:17:49 +0100 Subject: [PATCH 224/253] Store the crate name in `DefPathItem` --- engine/lib/concrete_ident/concrete_ident.ml | 2 +- engine/names/extract/build.rs | 2 +- frontend/exporter/src/types/def_id.rs | 55 +++++++++++++++------ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index c5bebf76f..5f4090270 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -27,7 +27,7 @@ module Imported = struct [@@deriving show, yojson, compare, sexp, eq, hash] let of_def_path_item : Types.def_path_item -> def_path_item = function - | CrateRoot -> CrateRoot + | CrateRoot _ -> CrateRoot | Impl -> Impl | ForeignMod -> ForeignMod | Use -> Use diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index 036a6abc2..abc2b7170 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -58,7 +58,7 @@ fn def_path_item_to_str(path_item: DefPathItem) -> String { | DefPathItem::ValueNs(s) | DefPathItem::MacroNs(s) | DefPathItem::LifetimeNs(s) => s, - DefPathItem::CrateRoot => "CrateRoot".into(), + DefPathItem::CrateRoot { name } => uppercase_first_letter(&name), DefPathItem::Impl => "Impl".into(), DefPathItem::ForeignMod => "ForeignMod".into(), DefPathItem::Use => "Use".into(), diff --git a/frontend/exporter/src/types/def_id.rs b/frontend/exporter/src/types/def_id.rs index 2d1c5a835..a777ceded 100644 --- a/frontend/exporter/src/types/def_id.rs +++ b/frontend/exporter/src/types/def_id.rs @@ -29,16 +29,6 @@ impl<'t, S> SInto for rustc_span::symbol::Symbol { } } -#[derive_group(Serializers)] -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] -#[cfg_attr(not(feature = "extract_names_mode"), args(<'a, S: BaseState<'a>>, from: rustc_hir::definitions::DisambiguatedDefPathData, state: S as s))] -/// Reflects [`rustc_hir::definitions::DisambiguatedDefPathData`] -pub struct DisambiguatedDefPathItem { - pub data: DefPathItem, - pub disambiguator: u32, -} - /// Reflects [`rustc_hir::def_id::DefId`] #[derive_group(Serializers)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -80,6 +70,19 @@ impl DefId { pub fn ancestry(&self) -> impl Iterator { std::iter::successors(Some(self), |def| def.parent.as_ref()) } + + /// The `PathItem` corresponding to this item. + pub fn path_item(&self) -> DisambiguatedDefPathItem { + self.path + .last() + .cloned() + .unwrap_or_else(|| DisambiguatedDefPathItem { + disambiguator: 0, + data: DefPathItem::CrateRoot { + name: self.krate.clone(), + }, + }) + } } impl std::ops::Deref for DefId { @@ -119,11 +122,18 @@ impl std::hash::Hash for DefId { #[cfg(feature = "rustc")] pub(crate) fn translate_def_id<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> DefId { let tcx = s.base().tcx; - let def_path = tcx.def_path(def_id); - let krate = tcx.crate_name(def_path.krate); + let path = { + // Set the def_id so the `CrateRoot` path item can fetch the crate name. + let state_with_id = with_owner_id(s.base(), (), (), def_id); + tcx.def_path(def_id) + .data + .iter() + .map(|x| x.sinto(&state_with_id)) + .collect() + }; let contents = DefIdContents { - path: def_path.data.iter().map(|x| x.sinto(s)).collect(), - krate: krate.to_string(), + path, + krate: tcx.crate_name(def_id.krate).to_string(), parent: tcx.opt_parent(def_id).sinto(s), index: ( rustc_hir::def_id::CrateNum::as_u32(def_id.krate), @@ -196,9 +206,12 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto for rustc_hir::def_id #[derive_group(Serializers)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] -#[cfg_attr(not(feature = "extract_names_mode"), args(<'ctx, S: BaseState<'ctx>>, from: rustc_hir::definitions::DefPathData, state: S as state))] +#[cfg_attr(not(feature = "extract_names_mode"), args(<'ctx, S: UnderOwnerState<'ctx>>, from: rustc_hir::definitions::DefPathData, state: S as s))] pub enum DefPathItem { - CrateRoot, + CrateRoot { + #[cfg_attr(not(feature = "extract_names_mode"), value(s.base().tcx.crate_name(s.owner_id().krate).sinto(s)))] + name: Symbol, + }, Impl, ForeignMod, Use, @@ -213,3 +226,13 @@ pub enum DefPathItem { OpaqueTy, AnonAdt, } + +#[derive_group(Serializers)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(not(feature = "extract_names_mode"), derive(AdtInto, JsonSchema))] +#[cfg_attr(not(feature = "extract_names_mode"), args(<'a, S: UnderOwnerState<'a>>, from: rustc_hir::definitions::DisambiguatedDefPathData, state: S as s))] +/// Reflects [`rustc_hir::definitions::DisambiguatedDefPathData`] +pub struct DisambiguatedDefPathItem { + pub data: DefPathItem, + pub disambiguator: u32, +} From 69a61cf919b3c3c5eefb20373e636bcfb763bdf5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 31 Oct 2024 14:06:55 +0100 Subject: [PATCH 225/253] Add horrible workaround for a query panic --- frontend/exporter/src/types/new/full_def.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 1583b8a21..322077811 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -39,7 +39,7 @@ where Body: IsBody + TypeMappable, { let tcx = s.base().tcx; - let def_kind = tcx.def_kind(def_id); + let def_kind = get_def_kind(tcx, def_id); let kind = { let state_with_id = with_owner_id(s.base(), (), (), def_id); def_kind.sinto(&state_with_id) @@ -438,9 +438,20 @@ impl FullDef { } } +/// Gets the kind of the definition. +#[cfg(feature = "rustc")] +pub fn get_def_kind<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> RDefKind { + if def_id == rustc_span::def_id::CRATE_DEF_ID.to_def_id() { + // Horrible hack: without this, `def_kind` crashes on the crate root. Presumably some table + // isn't properly initialized otherwise. + let _ = tcx.def_span(def_id); + }; + tcx.def_kind(def_id) +} + /// Gets the attributes of the definition. #[cfg(feature = "rustc")] -fn get_def_span<'tcx>( +pub fn get_def_span<'tcx>( tcx: ty::TyCtxt<'tcx>, def_id: RDefId, def_kind: RDefKind, From 46b76c01a5895a2b52e980b8ca4af00b8c11baf4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 31 Oct 2024 14:20:24 +0100 Subject: [PATCH 226/253] Fix another query panic --- frontend/exporter/src/types/new/full_def.rs | 26 ++++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 322077811..bfbbf6ee5 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -327,7 +327,7 @@ pub enum FullDefKind { }, /// An `extern` block. ForeignMod { - #[value(get_mod_children(s.base().tcx, s.owner_id()).sinto(s))] + #[value(get_foreign_mod_children(s.base().tcx, s.owner_id()).sinto(s))] items: Vec, }, @@ -538,14 +538,6 @@ fn get_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec .iter() .map(|item_id| item_id.owner_id.to_def_id()) .collect(), - - rustc_hir::Node::Item(rustc_hir::Item { - kind: rustc_hir::ItemKind::ForeignMod { items, .. }, - .. - }) => items - .iter() - .map(|foreign_item_ref| foreign_item_ref.id.owner_id.to_def_id()) - .collect(), node => panic!("DefKind::Module is an unexpected node: {node:?}"), }, None => tcx @@ -556,6 +548,22 @@ fn get_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec } } +/// Gets the children of an `extern` block. Empty if the block is not defined in the current crate. +#[cfg(feature = "rustc")] +fn get_foreign_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec { + match def_id.as_local() { + Some(ldid) => tcx + .hir_node_by_def_id(ldid) + .expect_item() + .expect_foreign_mod() + .1 + .iter() + .map(|foreign_item_ref| foreign_item_ref.id.owner_id.to_def_id()) + .collect(), + None => vec![], + } +} + /// This normalizes trait clauses before calling `sinto` on them. This is a bit of a hack required /// by charon for now. We can't normalize all clauses as this would lose region information in /// outlives clauses. From d64534c67962184b0ded55cafd10af0fd2f59779 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 30 Oct 2024 14:01:58 +0100 Subject: [PATCH 227/253] Avoid accidental name clash --- frontend/exporter/src/state.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/exporter/src/state.rs b/frontend/exporter/src/state.rs index 231af1496..810560e12 100644 --- a/frontend/exporter/src/state.rs +++ b/frontend/exporter/src/state.rs @@ -194,7 +194,7 @@ mod types { pub type MacroCalls = Rc>; pub type RcThir<'tcx> = Rc>; pub type RcMir<'tcx> = Rc>; - pub type Binder<'tcx> = rustc_middle::ty::Binder<'tcx, ()>; + pub type UnitBinder<'tcx> = rustc_middle::ty::Binder<'tcx, ()>; } mk!( @@ -203,7 +203,7 @@ mk!( thir: {'tcx} types::RcThir, mir: {'tcx} types::RcMir, owner_id: {} rustc_hir::def_id::DefId, - binder: {'tcx} types::Binder, + binder: {'tcx} types::UnitBinder, } ); @@ -212,7 +212,7 @@ pub use self::types::*; pub type StateWithBase<'tcx> = State, (), (), (), ()>; pub type StateWithOwner<'tcx> = State, (), (), rustc_hir::def_id::DefId, ()>; pub type StateWithBinder<'tcx> = - State, (), (), rustc_hir::def_id::DefId, types::Binder<'tcx>>; + State, (), (), rustc_hir::def_id::DefId, types::UnitBinder<'tcx>>; pub type StateWithThir<'tcx> = State, types::RcThir<'tcx>, (), rustc_hir::def_id::DefId, ()>; pub type StateWithMir<'tcx> = From a196c64900c6df5d0c0067b02cf5466aa7bbe809 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 30 Oct 2024 13:47:42 +0100 Subject: [PATCH 228/253] Split `FullDefKind::Impl` in two --- frontend/exporter/src/types/new/full_def.rs | 87 +++++++++++++++++---- frontend/exporter/src/types/ty.rs | 41 ---------- 2 files changed, 71 insertions(+), 57 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index bfbbf6ee5..65be4ade7 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -193,24 +193,31 @@ pub enum FullDefKind { }, /// Trait alias: `trait IntIterator = Iterator;` TraitAlias, - Impl { - #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] + #[custom_arm( + // Returns `TraitImpl` or `InherentImpl`. + RDefKind::Impl { .. } => get_impl_contents(s), + )] + TraitImpl { generics: TyGenerics, - #[value(get_generic_predicates(s, s.owner_id()))] predicates: GenericPredicates, - #[value(s.base().tcx.impl_subject(s.owner_id()).instantiate_identity().sinto(s))] - impl_subject: ImplSubject, + /// The trait that is implemented by this impl block. + trait_pred: TraitPredicate, + /// The `ImplExpr`s required to satisfy the predicates on the trait declaration. E.g.: + /// ```ignore + /// trait Foo: Bar {} + /// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`. + /// ``` + required_impl_exprs: Vec, + /// Associated items, in definition order. + items: Vec<(AssocItem, Arc>)>, + }, + #[disable_mapping] + InherentImpl { + generics: TyGenerics, + predicates: GenericPredicates, + /// The type to which this block applies. + ty: Ty, /// Associated items, in definition order. - #[value( - s - .base() - .tcx - .associated_items(s.owner_id()) - .in_definition_order() - .map(|assoc| (assoc, assoc.def_id)) - .collect::>() - .sinto(s) - )] items: Vec<(AssocItem, Arc>)>, }, @@ -428,7 +435,12 @@ impl FullDef { predicates, .. } - | Impl { + | TraitImpl { + generics, + predicates, + .. + } + | InherentImpl { generics, predicates, .. @@ -564,6 +576,49 @@ fn get_foreign_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec< } } +#[cfg(feature = "rustc")] +fn get_impl_contents<'tcx, S, Body>(s: &S) -> FullDefKind +where + S: UnderOwnerState<'tcx>, + Body: IsBody + TypeMappable, +{ + let tcx = s.base().tcx; + let def_id = s.owner_id(); + let generics = tcx.generics_of(def_id).sinto(s); + let predicates = get_generic_predicates(s, def_id); + let items = tcx + .associated_items(def_id) + .in_definition_order() + .map(|assoc| (assoc, assoc.def_id)) + .collect::>() + .sinto(s); + match tcx.impl_subject(def_id).instantiate_identity() { + ty::ImplSubject::Inherent(ty) => FullDefKind::InherentImpl { + generics, + predicates, + ty: ty.sinto(s), + items, + }, + ty::ImplSubject::Trait(trait_ref) => { + // Also record the polarity. + let polarity = tcx.impl_polarity(s.owner_id()); + let trait_pred = TraitPredicate { + trait_ref: trait_ref.sinto(s), + is_positive: matches!(polarity, ty::ImplPolarity::Positive), + }; + let required_impl_exprs = + solve_item_implied_traits(s, trait_ref.def_id, trait_ref.args); + FullDefKind::TraitImpl { + generics, + predicates, + trait_pred, + required_impl_exprs, + items, + } + } + } +} + /// This normalizes trait clauses before calling `sinto` on them. This is a bit of a hack required /// by charon for now. We can't normalize all clauses as this would lose region information in /// outlives clauses. diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index 72ad7f785..a026d7df3 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -1311,47 +1311,6 @@ pub enum PredicateKind { NormalizesTo(NormalizesTo), } -/// Reflects [`ty::ImplSubject`] -#[derive_group(Serializers)] -#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum ImplSubject { - Trait { - /// The trait that is implemented by this impl block. - trait_pred: TraitPredicate, - /// The `ImplExpr`s required to satisfy the predicates on the trait declaration. E.g.: - /// ```ignore - /// trait Foo: Bar {} - /// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`. - /// ``` - required_impl_exprs: Vec, - }, - Inherent(Ty), -} - -#[cfg(feature = "rustc")] -impl<'tcx, S: UnderOwnerState<'tcx>> SInto for ty::ImplSubject<'tcx> { - fn sinto(&self, s: &S) -> ImplSubject { - let tcx = s.base().tcx; - match self { - ty::ImplSubject::Inherent(ty) => ImplSubject::Inherent(ty.sinto(s)), - ty::ImplSubject::Trait(trait_ref) => { - // Also record the polarity. - let polarity = tcx.impl_polarity(s.owner_id()); - let trait_pred = TraitPredicate { - trait_ref: trait_ref.sinto(s), - is_positive: matches!(polarity, ty::ImplPolarity::Positive), - }; - let required_impl_exprs = - solve_item_implied_traits(s, trait_ref.def_id, trait_ref.args); - ImplSubject::Trait { - trait_pred, - required_impl_exprs, - } - } - } - } -} - #[cfg(feature = "rustc")] fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( s: &S, From 9fedadfa50dca829fc0af137aeb9490781e6e359 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 30 Oct 2024 13:58:05 +0100 Subject: [PATCH 229/253] Include defaulted items in `FullDefKind::TraitImpl` --- frontend/exporter/src/types/new/full_def.rs | 180 +++++++++++++++++--- frontend/exporter/src/types/ty.rs | 21 --- 2 files changed, 160 insertions(+), 41 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 65be4ade7..fe31e7d2f 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -208,8 +208,8 @@ pub enum FullDefKind { /// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`. /// ``` required_impl_exprs: Vec, - /// Associated items, in definition order. - items: Vec<(AssocItem, Arc>)>, + /// Associated items, in the order of the trait declaration. Includes defaulted items. + items: Vec>, }, #[disable_mapping] InherentImpl { @@ -366,7 +366,54 @@ pub enum FullDefKind { SyntheticCoroutineBody, } -impl FullDef { +/// An associated item in a trait impl. This can be an item provided by the trait impl, or an item +/// that reuses the trait decl default value. +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub struct ImplAssocItem { + pub name: Symbol, + /// The definition of the item from the trait declaration. + pub decl_def: Arc>, + /// The `ImplExpr`s required to satisfy the predicates on the associated type. E.g.: + /// ```ignore + /// trait Foo { + /// type Type: Clone, + /// } + /// impl Foo for () { + /// type Type: Arc; // would supply an `ImplExpr` for `Arc: Clone`. + /// } + /// ``` + /// Empty if this item is an associated const or fn. + pub required_impl_exprs: Vec, + /// The value of the implemented item. + pub value: ImplAssocItemValue, +} + +#[derive_group(Serializers)] +#[derive(Clone, Debug, JsonSchema)] +pub enum ImplAssocItemValue { + /// The item is provided by the trait impl. + Provided { + /// The definition of the item in the trait impl. + def: Arc>, + /// Whether the trait had a default value for this item (which is therefore overriden). + is_override: bool, + }, + /// This is an associated type that reuses the trait declaration default. + DefaultedTy { + /// The default type, with generics properly instantiated. Note that this can be a GAT; + /// relevant generics and predicates can be found in `decl_def`. + ty: Ty, + }, + /// This is a non-overriden default method. + /// FIXME: provide properly instantiated generics. + DefaultedFn {}, + /// This is an associated const that reuses the trait declaration default. The default const + /// value can be found in `decl_def`. + DefaultedConst, +} + +impl FullDef { #[cfg(feature = "rustc")] pub fn rust_def_id(&self) -> RDefId { (&self.def_id).into() @@ -450,6 +497,27 @@ impl FullDef { } } +impl ImplAssocItem { + /// The relevant definition: the provided implementation if any, otherwise the default + /// declaration from the trait declaration. + pub fn def(&self) -> &FullDef { + match &self.value { + ImplAssocItemValue::Provided { def, .. } => def.as_ref(), + _ => self.decl_def.as_ref(), + } + } + + /// The kind of item this is. + pub fn assoc_kind(&self) -> AssocKind { + match self.def().kind() { + FullDefKind::AssocTy { .. } => AssocKind::Type, + FullDefKind::AssocFn { .. } => AssocKind::Fn, + FullDefKind::AssocConst { .. } => AssocKind::Const, + _ => unreachable!(), + } + } +} + /// Gets the kind of the definition. #[cfg(feature = "rustc")] pub fn get_def_kind<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> RDefKind { @@ -582,32 +650,104 @@ where S: UnderOwnerState<'tcx>, Body: IsBody + TypeMappable, { + use std::collections::HashMap; let tcx = s.base().tcx; - let def_id = s.owner_id(); - let generics = tcx.generics_of(def_id).sinto(s); - let predicates = get_generic_predicates(s, def_id); - let items = tcx - .associated_items(def_id) - .in_definition_order() - .map(|assoc| (assoc, assoc.def_id)) - .collect::>() - .sinto(s); - match tcx.impl_subject(def_id).instantiate_identity() { - ty::ImplSubject::Inherent(ty) => FullDefKind::InherentImpl { - generics, - predicates, - ty: ty.sinto(s), - items, - }, + let impl_def_id = s.owner_id(); + let generics = tcx.generics_of(impl_def_id).sinto(s); + let predicates = get_generic_predicates(s, impl_def_id); + match tcx.impl_subject(impl_def_id).instantiate_identity() { + ty::ImplSubject::Inherent(ty) => { + let items = tcx + .associated_items(impl_def_id) + .in_definition_order() + .map(|assoc| (assoc, assoc.def_id)) + .collect::>() + .sinto(s); + FullDefKind::InherentImpl { + generics, + predicates, + ty: ty.sinto(s), + items, + } + } ty::ImplSubject::Trait(trait_ref) => { // Also record the polarity. - let polarity = tcx.impl_polarity(s.owner_id()); + let polarity = tcx.impl_polarity(impl_def_id); let trait_pred = TraitPredicate { trait_ref: trait_ref.sinto(s), is_positive: matches!(polarity, ty::ImplPolarity::Positive), }; + // Impl exprs required by the trait. let required_impl_exprs = solve_item_implied_traits(s, trait_ref.def_id, trait_ref.args); + + let mut item_map: HashMap = tcx + .associated_items(impl_def_id) + .in_definition_order() + .map(|assoc| (assoc.trait_item_def_id.unwrap(), assoc)) + .collect(); + let items = tcx + .associated_items(trait_ref.def_id) + .in_definition_order() + .map(|decl_assoc| { + let decl_def_id = decl_assoc.def_id; + let decl_def = decl_def_id.sinto(s); + // Impl exprs required by the item. + let required_impl_exprs; + let value = match item_map.remove(&decl_def_id) { + Some(impl_assoc) => { + required_impl_exprs = { + let item_args = + ty::GenericArgs::identity_for_item(tcx, impl_assoc.def_id); + // Subtlety: we have to add the GAT arguments (if any) to the trait ref arguments. + let args = item_args.rebase_onto(tcx, impl_def_id, trait_ref.args); + let state_with_id = + with_owner_id(s.base(), (), (), impl_assoc.def_id); + solve_item_implied_traits(&state_with_id, decl_def_id, args) + }; + + ImplAssocItemValue::Provided { + def: impl_assoc.def_id.sinto(s), + is_override: decl_assoc.defaultness(tcx).has_value(), + } + } + None => { + required_impl_exprs = if tcx.generics_of(decl_def_id).is_own_empty() { + // Non-GAT case. + let item_args = + ty::GenericArgs::identity_for_item(tcx, decl_def_id); + let args = item_args.rebase_onto(tcx, impl_def_id, trait_ref.args); + let state_with_id = with_owner_id(s.base(), (), (), impl_def_id); + solve_item_implied_traits(&state_with_id, decl_def_id, args) + } else { + // FIXME: For GATs, we need a param_env that has the arguments of + // the impl plus those of the associated type, but there's no + // def_id with that param_env. + vec![] + }; + match decl_assoc.kind { + ty::AssocKind::Type => { + let ty = tcx + .type_of(decl_def_id) + .instantiate(tcx, trait_ref.args) + .sinto(s); + ImplAssocItemValue::DefaultedTy { ty } + } + ty::AssocKind::Fn => ImplAssocItemValue::DefaultedFn {}, + ty::AssocKind::Const => ImplAssocItemValue::DefaultedConst {}, + } + } + }; + + ImplAssocItem { + name: decl_assoc.name.sinto(s), + value, + required_impl_exprs, + decl_def, + } + }) + .collect(); + assert!(item_map.is_empty()); FullDefKind::TraitImpl { generics, predicates, diff --git a/frontend/exporter/src/types/ty.rs b/frontend/exporter/src/types/ty.rs index a026d7df3..c254bb0b7 100644 --- a/frontend/exporter/src/types/ty.rs +++ b/frontend/exporter/src/types/ty.rs @@ -1329,21 +1329,11 @@ fn get_container_for_assoc_item<'tcx, S: BaseState<'tcx>>( .impl_trait_ref(container_id) .unwrap() .instantiate_identity(); - - // Resolve required impl exprs for this item. - let item_args = ty::GenericArgs::identity_for_item(tcx, item.def_id); - // Subtlety: we have to add the GAT arguments (if any) to the trait ref arguments. - let args = item_args.rebase_onto(tcx, container_id, implemented_trait_ref.args); - let state_with_id = with_owner_id(s.base(), (), (), item.def_id); - let required_impl_exprs = - solve_item_implied_traits(&state_with_id, implemented_trait_item, args); - AssocItemContainer::TraitImplContainer { impl_id: container_id.sinto(s), implemented_trait: implemented_trait_ref.def_id.sinto(s), implemented_trait_item: implemented_trait_item.sinto(s), overrides_default: tcx.defaultness(implemented_trait_item).has_value(), - required_impl_exprs, } } else { AssocItemContainer::InherentImplContainer { @@ -1401,17 +1391,6 @@ pub enum AssocItemContainer { /// Whether the corresponding trait item had a default (and therefore this one overrides /// it). overrides_default: bool, - /// The `ImplExpr`s required to satisfy the predicates on the associated type. E.g.: - /// ```ignore - /// trait Foo { - /// type Type: Clone, - /// } - /// impl Foo for () { - /// type Type: Arc; // would supply an `ImplExpr` for `Arc: Clone`. - /// } - /// ``` - /// Empty if this item is an associated const or fn. - required_impl_exprs: Vec, }, InherentImplContainer { impl_id: DefId, From 1c5d922b966d3df25f19f6e1a4f72c76decec360 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 31 Oct 2024 15:18:57 +0100 Subject: [PATCH 230/253] Add comments --- frontend/exporter/src/types/new/full_def.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index fe31e7d2f..eabdde186 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -143,6 +143,7 @@ pub enum FullDefKind { #[value(s.base().tcx.generics_of(s.owner_id()).sinto(s))] generics: TyGenerics, #[value(get_item_predicates(s, s.owner_id()))] + // FIXME: clarify implied vs required predicates predicates: GenericPredicates, #[value(s.base().tcx.associated_item(s.owner_id()).sinto(s))] associated_item: AssocItem, @@ -372,7 +373,8 @@ pub enum FullDefKind { #[derive(Clone, Debug, JsonSchema)] pub struct ImplAssocItem { pub name: Symbol, - /// The definition of the item from the trait declaration. + /// The definition of the item from the trait declaration. This is `AssocTy`, `AssocFn` or + /// `AssocConst`. pub decl_def: Arc>, /// The `ImplExpr`s required to satisfy the predicates on the associated type. E.g.: /// ```ignore @@ -394,7 +396,8 @@ pub struct ImplAssocItem { pub enum ImplAssocItemValue { /// The item is provided by the trait impl. Provided { - /// The definition of the item in the trait impl. + /// The definition of the item in the trait impl. This is `AssocTy`, `AssocFn` or + /// `AssocConst`. def: Arc>, /// Whether the trait had a default value for this item (which is therefore overriden). is_override: bool, From 1d9ae0f35a9835289d3752287c378d598a43b884 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 15:47:32 +0100 Subject: [PATCH 231/253] fmt --- engine/lib/ast_utils.ml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engine/lib/ast_utils.ml b/engine/lib/ast_utils.ml index 96b6bef98..1c149404f 100644 --- a/engine/lib/ast_utils.ml +++ b/engine/lib/ast_utils.ml @@ -890,7 +890,8 @@ module Make (F : Features.T) = struct (Concrete_ident.of_name (Constructor { is_struct }) constructor_name)) is_struct args span ret_typ - let call' ?impl f ?(generic_args = []) ?(impl_generic_args = []) (args : expr list) span ret_typ = + let call' ?impl f ?(generic_args = []) ?(impl_generic_args = []) + (args : expr list) span ret_typ = let typ = TArrow (List.map ~f:(fun arg -> arg.typ) args, ret_typ) in let e = GlobalVar f in { @@ -907,8 +908,9 @@ module Make (F : Features.T) = struct span; } - let call ?(kind : Concrete_ident.Kind.t = Value) ?(generic_args = []) ?(impl_generic_args = []) ?impl - (f_name : Concrete_ident.name) (args : expr list) span ret_typ = + let call ?(kind : Concrete_ident.Kind.t = Value) ?(generic_args = []) + ?(impl_generic_args = []) ?impl (f_name : Concrete_ident.name) + (args : expr list) span ret_typ = call' ?impl ~generic_args ~impl_generic_args (`Concrete (Concrete_ident.of_name kind f_name)) args span ret_typ From 0d87796556e989c921b319f5ec657a9c02e34ef0 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 15:59:12 +0100 Subject: [PATCH 232/253] feat(engine): factorize the logic for stateful deserializer --- .../ocaml_of_json_schema.js | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js index cb0c0fa67..f0bb3b3ef 100644 --- a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js +++ b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js @@ -574,36 +574,47 @@ open ParseError impl += ` and node_for__ty_kind = node_for_ty_kind_generated -let cache_map: (int64, ${"[ `TyKind of ty_kind | `JSON of Yojson.Safe.t ]"}) Base.Hashtbl.t = Base.Hashtbl.create (module Base.Int64) +type map_types = ${"[`TyKind of ty_kind]"} +let cache_map: (int64, ${"[ `Value of map_types | `JSON of Yojson.Safe.t ]"}) Base.Hashtbl.t = Base.Hashtbl.create (module Base.Int64) -`; - impl += (''); - impl += ('let rec ' + items.map(({name, type, parse}) => - `parse_${name} (o: Yojson.Safe.t): ${name} = ${parse}` - ).join('\nand ')); - impl += ` -and parse_node_for__ty_kind (o: Yojson.Safe.t): node_for__ty_kind = match o with +let parse_table_id_node (type t) (encode: t -> map_types) (decode: map_types -> t option) (parse: Yojson.Safe.t -> t) (o: Yojson.Safe.t): (t * int64) = match o with | \`Assoc alist -> begin let id = match List.assoc "cache_id" alist with | \`Int id -> Base.Int.to_int64 id | \`Intlit lit -> (try Base.Int64.of_string lit with | _ -> failwith ("Base.Int64.of_string failed for " ^ lit)) - | bad_json -> failwith ("parse_node_for__ty_kind: id was expected to be an int, got: " ^ Yojson.Safe.pretty_to_string bad_json ^ "\n\n\nfull json: " ^ Yojson.Safe.pretty_to_string o) + | bad_json -> failwith ("parse_table_id_node: id was expected to be an int, got: " ^ Yojson.Safe.pretty_to_string bad_json ^ "\n\n\nfull json: " ^ Yojson.Safe.pretty_to_string o) in + let decode v = decode v |> Base.Option.value_exn ~message:"parse_table_id_node: could not decode value (wrong type)" in match List.assoc_opt "value" alist with | Some json when (match json with \`Null -> false | _ -> true) -> - let value = parse_ty_kind json in - {value; id} + (parse json, id) | _ -> let value = match Base.Hashtbl.find cache_map id with - | None -> failwith ("parse_node_for__ty_kind: failed to lookup id " ^ Base.Int64.to_string id) - | Some (\`TyKind v) -> v + | None -> failwith ("parse_table_id_node: failed to lookup id " ^ Base.Int64.to_string id) + | Some (\`Value v) -> decode v | Some (\`JSON json) -> - let v = parse_ty_kind json in - Base.Hashtbl.set cache_map ~key:id ~data:(\`TyKind v); - v - in {value; id} + let value = parse json in + Base.Hashtbl.set cache_map ~key:id ~data:(\`Value (encode value)); + value + in (value, id) end - | _ -> failwith "parse_node_for__ty_kind: expected Assoc" + | _ -> failwith "parse_table_id_node: expected Assoc" + +`; + impl += (''); + impl += ('let rec ' + items.map(({name, type, parse}) => + `parse_${name} (o: Yojson.Safe.t): ${name} = ${parse}` + ).join('\nand ')); + impl += ` +and parse_node_for__ty_kind (o: Yojson.Safe.t): node_for__ty_kind = + let (value, id) = + parse_table_id_node + (fun value -> \`TyKind value) + (function | \`TyKind value -> Some value | _ -> None) + parse_ty_kind + o + in + {value; id} `; impl += (''); impl += ('let rec ' + items.map(({name, type, parse, to_json}) => From f46d31430af240b3c3a5ca7223e3930dac091bbd Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 16:25:23 +0100 Subject: [PATCH 233/253] fix(engine/name-crate): the field `cache_id` is important, the engine relies on it --- engine/names/extract/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index abc2b7170..2939464bc 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -18,6 +18,7 @@ mod id_table { #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Node { value: Arc, + cache_id: u32, } impl std::ops::Deref for Node { From ab0347cd784275cd618db5484b6eb43a99833a7c Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 16:26:23 +0100 Subject: [PATCH 234/253] feat(engine/table_id support): better debug info --- .../ocaml_of_json_schema.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js index f0bb3b3ef..e4a201932 100644 --- a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js +++ b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js @@ -577,20 +577,23 @@ and node_for__ty_kind = node_for_ty_kind_generated type map_types = ${"[`TyKind of ty_kind]"} let cache_map: (int64, ${"[ `Value of map_types | `JSON of Yojson.Safe.t ]"}) Base.Hashtbl.t = Base.Hashtbl.create (module Base.Int64) -let parse_table_id_node (type t) (encode: t -> map_types) (decode: map_types -> t option) (parse: Yojson.Safe.t -> t) (o: Yojson.Safe.t): (t * int64) = match o with +let parse_table_id_node (type t) (name: string) (encode: t -> map_types) (decode: map_types -> t option) (parse: Yojson.Safe.t -> t) (o: Yojson.Safe.t): (t * int64) = + let label = "parse_table_id_node:" ^ name ^ ": " in + match o with | \`Assoc alist -> begin - let id = match List.assoc "cache_id" alist with - | \`Int id -> Base.Int.to_int64 id - | \`Intlit lit -> (try Base.Int64.of_string lit with | _ -> failwith ("Base.Int64.of_string failed for " ^ lit)) - | bad_json -> failwith ("parse_table_id_node: id was expected to be an int, got: " ^ Yojson.Safe.pretty_to_string bad_json ^ "\n\n\nfull json: " ^ Yojson.Safe.pretty_to_string o) + let id = match List.assoc_opt "cache_id" alist with + | Some (\`Int id) -> Base.Int.to_int64 id + | Some (\`Intlit lit) -> (try Base.Int64.of_string lit with | _ -> failwith (label ^ "Base.Int64.of_string failed for " ^ lit)) + | Some bad_json -> failwith (label ^ "id was expected to be an int, got: " ^ Yojson.Safe.pretty_to_string bad_json ^ "\n\n\nfull json: " ^ Yojson.Safe.pretty_to_string o) + | None -> failwith (label ^ " could not find the key 'cache_id' in the following json: " ^ Yojson.Safe.pretty_to_string o) in - let decode v = decode v |> Base.Option.value_exn ~message:"parse_table_id_node: could not decode value (wrong type)" in + let decode v = decode v |> Base.Option.value_exn ~message:(label ^ "could not decode value (wrong type)") in match List.assoc_opt "value" alist with | Some json when (match json with \`Null -> false | _ -> true) -> (parse json, id) | _ -> let value = match Base.Hashtbl.find cache_map id with - | None -> failwith ("parse_table_id_node: failed to lookup id " ^ Base.Int64.to_string id) + | None -> failwith (label ^ "failed to lookup id " ^ Base.Int64.to_string id) | Some (\`Value v) -> decode v | Some (\`JSON json) -> let value = parse json in @@ -598,7 +601,7 @@ let parse_table_id_node (type t) (encode: t -> map_types) (decode: map_types -> value in (value, id) end - | _ -> failwith "parse_table_id_node: expected Assoc" + | _ -> failwith (label ^ "expected Assoc") `; impl += (''); From 738acdf43ca9fcc61a9d21b6b96fbd07d0a26696 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 16:26:54 +0100 Subject: [PATCH 235/253] fix(engine): interned `def_id` --- engine/lib/concrete_ident/concrete_ident.ml | 7 +++-- engine/lib/import_thir.ml | 28 +++++++++++-------- .../ocaml_of_json_schema.js | 19 ++++++++++--- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/engine/lib/concrete_ident/concrete_ident.ml b/engine/lib/concrete_ident/concrete_ident.ml index 5f4090270..b0d0cc160 100644 --- a/engine/lib/concrete_ident/concrete_ident.ml +++ b/engine/lib/concrete_ident/concrete_ident.ml @@ -50,7 +50,8 @@ module Imported = struct disambiguator = MyInt64.to_int_exn disambiguator; } - let of_def_id Types.{ krate; path; _ } = + let of_def_id + ({ contents = { value = { krate; path; _ }; _ } } : Types.def_id) = { krate; path = List.map ~f:of_disambiguated_def_path_item path } let parent { krate; path; _ } = { krate; path = List.drop_last_exn path } @@ -279,7 +280,7 @@ module View = struct namespace |> some_if_true in - let* last = List.last def_id.path in + let* last = List.last def_id.contents.value.path in let* () = some_if_true Int64.(last.disambiguator = zero) in last.data |> Imported.of_def_path_item |> string_of_def_path_item |> Option.map ~f:escape @@ -387,7 +388,7 @@ module View = struct namespace in let* typ = simple_ty_to_string ~namespace typ in - let* trait = List.last trait.path in + let* trait = List.last trait.contents.value.path in let* trait = Imported.of_def_path_item trait.data |> string_of_def_path_item in diff --git a/engine/lib/import_thir.ml b/engine/lib/import_thir.ml index 0fc1dd2de..c9dc1a8a4 100644 --- a/engine/lib/import_thir.ml +++ b/engine/lib/import_thir.ml @@ -1310,7 +1310,7 @@ let make ~krate : (module EXPR) = (module M) let c_trait_item (item : Thir.trait_item) : trait_item = - let open (val make ~krate:item.owner_id.krate : EXPR) in + let open (val make ~krate:item.owner_id.contents.value.krate : EXPR) in let { params; constraints } = c_generics item.generics in (* TODO: see TODO in impl items *) let ti_ident = Concrete_ident.of_def_id Field item.owner_id in @@ -1449,7 +1449,7 @@ let rec c_item ~ident ~drop_body (item : Thir.item) : item list = [ make_hax_error_item span ident error ] and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = - let open (val make ~krate:item.owner_id.krate : EXPR) in + let open (val make ~krate:item.owner_id.contents.value.krate : EXPR) in if should_skip item.attributes then [] else let span = Span.of_thir item.span in @@ -1758,15 +1758,21 @@ and c_item_unwrapped ~ident ~drop_body (item : Thir.item) : item list = (* TODO: is this DUMMY thing really needed? there's a `Use` segment (see #272) *) let def_id = item.owner_id in let def_id : Types.def_id = - { - def_id with - path = - def_id.path - @ [ - Types. - { data = ValueNs "DUMMY"; disambiguator = MyInt64.of_int 0 }; - ]; - } + let value = + { + def_id.contents.value with + path = + def_id.contents.value.path + @ [ + Types. + { + data = ValueNs "DUMMY"; + disambiguator = MyInt64.of_int 0; + }; + ]; + } + in + { contents = { def_id.contents with value } } in [ { span; v; ident = Concrete_ident.of_def_id Value def_id; attrs } ] | Union _ -> diff --git a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js index e4a201932..12ff7487d 100644 --- a/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js +++ b/engine/utils/ocaml_of_json_schema/ocaml_of_json_schema.js @@ -538,8 +538,8 @@ function run(str){ [@@@warning "-A"]`; let items = Object.entries(definitions) - .map(([name, def]) => - [name == 'Node_for_TyKind' ? 'node_for_ty_kind_generated' : name, def]) + .map(([name, def]) => ['Node_for_TyKind' == name ? 'node_for_ty_kind_generated' : name, def]) + .map(([name, def]) => ['Node_for_DefIdContents' == name ? 'node_for_def_id_contents_generated' : name, def]) .map( ([name, def]) => export_definition(name, def) ).filter(x => x instanceof Object); @@ -573,8 +573,9 @@ open ParseError ); impl += ` and node_for__ty_kind = node_for_ty_kind_generated +and node_for__def_id_contents = node_for_def_id_contents_generated -type map_types = ${"[`TyKind of ty_kind]"} +type map_types = ${"[`TyKind of ty_kind | `DefIdContents of def_id_contents]"} let cache_map: (int64, ${"[ `Value of map_types | `JSON of Yojson.Safe.t ]"}) Base.Hashtbl.t = Base.Hashtbl.create (module Base.Int64) let parse_table_id_node (type t) (name: string) (encode: t -> map_types) (decode: map_types -> t option) (parse: Yojson.Safe.t -> t) (o: Yojson.Safe.t): (t * int64) = @@ -611,13 +612,22 @@ let parse_table_id_node (type t) (name: string) (encode: t -> map_types) (decode impl += ` and parse_node_for__ty_kind (o: Yojson.Safe.t): node_for__ty_kind = let (value, id) = - parse_table_id_node + parse_table_id_node "TyKind" (fun value -> \`TyKind value) (function | \`TyKind value -> Some value | _ -> None) parse_ty_kind o in {value; id} +and parse_node_for__def_id_contents (o: Yojson.Safe.t): node_for__def_id_contents = + let (value, id) = + parse_table_id_node "DefIdContents" + (fun value -> \`DefIdContents value) + (function | \`DefIdContents value -> Some value | _ -> None) + parse_def_id_contents + o + in + {value; id} `; impl += (''); impl += ('let rec ' + items.map(({name, type, parse, to_json}) => @@ -625,6 +635,7 @@ and parse_node_for__ty_kind (o: Yojson.Safe.t): node_for__ty_kind = ).join('\nand ')); impl += ` and to_json_node_for__ty_kind {value; id} = to_json_node_for_ty_kind_generated {value; id} +and to_json_node_for__def_id_contents {value; id} = to_json_node_for_def_id_contents_generated {value; id} `; From 9ea77a30e9e470a806897a5e9b389e6e73a9b75b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 31 Oct 2024 16:57:50 +0100 Subject: [PATCH 236/253] Fix crate name renaming --- engine/names/extract/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/names/extract/build.rs b/engine/names/extract/build.rs index 2939464bc..aeff4063b 100644 --- a/engine/names/extract/build.rs +++ b/engine/names/extract/build.rs @@ -86,7 +86,7 @@ fn def_id_to_str(def_id: &DefId) -> (Value, String) { }; // Update the crate name in the json output as well. let mut json = serde_json::to_value(def_id).unwrap(); - json["krate"] = Value::String(crate_name.to_owned()); + json["contents"]["value"]["krate"] = Value::String(crate_name.to_owned()); let crate_name = uppercase_first_letter(crate_name); let path = [crate_name] From c69c4ede27c4c5808971cb6385b1f958bf0e0f89 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 17:38:33 +0100 Subject: [PATCH 237/253] feat(nix): rust by examples --- .utils/rust-by-example.js | 142 ++++++++++++++++++++++++++++++++++++++ flake.lock | 17 +++++ flake.nix | 16 +++++ 3 files changed, 175 insertions(+) create mode 100644 .utils/rust-by-example.js diff --git a/.utils/rust-by-example.js b/.utils/rust-by-example.js new file mode 100644 index 000000000..848693a22 --- /dev/null +++ b/.utils/rust-by-example.js @@ -0,0 +1,142 @@ +// This script expect Rust By Example to be in current directory + +const fs = require('fs'); +const SRC_DIR = 'src'; + +// Lists all markdown files under `SRC_DIR` +function getMarkdownFiles() { + return fs.readdirSync(SRC_DIR, { recursive: true }) + .filter(path => path.endsWith('.md')); +} + +// Code blocks from a file of given path +function extractCodeBlocks(path) { + let contents = fs.readFileSync(SRC_DIR + '/' + path).toString(); + let blocks = contents + .split(/^```/m) + .filter((_, i) => i % 2 == 1) + .map(s => { + let lines = s.split('\n'); + let modifiers = lines[0].split(',').map(x => x.trim()).filter(x => x); + let contents = lines.slice(1).join('\n'); + return {modifiers, contents}; + }) + .filter(x => x.modifiers.includes('rust')); + let name = path.replace(/[.]md$/, '').split('/').join('_'); + return {name, blocks}; +} + +let code = getMarkdownFiles() + .map(extractCodeBlocks) + .filter(({blocks}) => blocks.length); + +// Strips the comments of a rust snippet +let stripComments = rust_snippet => rust_snippet.replace(/[/][/]+.*/mg, ''); + +// Given a Rust snippet, returns `true` whenever we detect a top-level +// `let` binding: this means we need to wrap the snippet in a function. +let isDirectLet = rust_snippet => stripComments(rust_snippet).trim().startsWith('let '); + +// Wraps a Rust snippet inside a function +let protectSnippet = rust_snippet => `fn wrapper_fn() { let _ = {${rust_snippet}}; }`; + +function codeBlocksToModules(code_blocks) { + let denylist = [ + /unsafe_asm \d+/ + ]; + let modules = {}; + + for(let {name, blocks} of code_blocks) { + let mod_section = `section_${name}`; + modules[mod_section] = {}; + let nth = 0; + for(let {modifiers, contents} of blocks) { + nth += 1; + if(['edition2015', 'compile_fail', 'ignore'].some(m => modifiers.includes(m))) { + continue; + } + let id = `section_${name} ${nth}`; + // Remove top-level assertions + contents = contents.replace(/^# assert.*\n?/mg, ''); + // Strip `# ` (the mdbook marker to hide a line) + contents = contents.replace(/^# /mg, ''); + // Whenever we detect a `let` + if(isDirectLet(contents)) + contents = protectSnippet(contents); + if(denylist.some(re => id.match(re))) + continue; + let mod_snippet = `snippet_${nth}`; + // Replace `crate::` by a full path to the current module + contents = contents.replace(/crate::/g, 'crate::' + mod_section + '::' + mod_snippet + '::'); + modules[mod_section][mod_snippet] = `// modifiers: ${modifiers.join(', ')}\n` + contents; + } + } + + return modules; +} + +let modules = codeBlocksToModules(code); + +let OUTPUT_CRATE = 'rust-by-examples-crate'; +fs.rmSync(OUTPUT_CRATE, { recursive: true, force: true }); +fs.mkdirSync(OUTPUT_CRATE, { recursive: true }); +const { execSync } = require('child_process'); +execSync("cargo init --lib", { cwd: OUTPUT_CRATE }); + +let OUTPUT_CRATE_SRC = OUTPUT_CRATE + '/src/'; +fs.rmSync(OUTPUT_CRATE_SRC, { recursive: true, force: true }); +let root_mod = '#![allow(unused)]'; +for(let mod_name in modules) { + let submodules = modules[mod_name]; + fs.mkdirSync(OUTPUT_CRATE_SRC + mod_name, { recursive: true }); + let mod_contents = ''; + for (let submod_name in submodules) { + let contents = submodules[submod_name]; + fs.writeFileSync(OUTPUT_CRATE_SRC + mod_name + '/' + submod_name + '.rs', contents); + mod_contents += 'pub mod ' + submod_name + ';\n'; + } +fs.writeFileSync(OUTPUT_CRATE_SRC + mod_name + '.rs', mod_contents); + root_mod += 'pub mod ' + mod_name + ';\n'; +} +fs.writeFileSync(OUTPUT_CRATE_SRC + '/lib.rs', root_mod); + + +// A list of [, []] that are known not to be processed by hax +let cargo_hax_denylist = [ + ['error_iter_result', [3]], + ['error_option_unwrap_defaults', [3,4]], + ['flow_control_for', [1,2,3,5]], + ['flow_control_if_let', [3]], + ['flow_control_loop_nested', [1]], + ['flow_control_loop_return', [1]], + ['flow_control_loop', [1]], + ['flow_control_match_binding', [1,2]], + ['flow_control_match_destructuring_destructure_pointers', [1]], + ['flow_control_match_destructuring_destructure_slice', [1]], + ['flow_control_match', [1]], + ['flow_control_while_let', [1,2]], + ['fn_closures_capture', [1]], + ['fn_closures_input_parameters', [1]], + ['fn', [1]], + ['hello_print_fmt', [1]], + ['macros_dry', [1]], + ['scope_borrow_alias', [1]], + ['scope_borrow_ref', [1]], + ['scope_move_mut', [1]], + ['scope_raii', [1]], + ['std_arc', [1]], + ['std_hash', [1]], + ['std_misc_arg_matching', [1]], + ['std_misc_channels', [1]], + ['std_misc_file_read_lines', [3]], + ['std_misc_threads', [1]], + ['std_misc_threads_testcase_mapreduce', [1]], + ['std_str', [1]], + ['trait_iter', [1]], + ['trait', [1]], + ['unsafe', [1,2]], +].map(([module, snippets]) => snippets.map(n => `section_${module}::snippet_${n}`)).flat(); + +let include_clause = cargo_hax_denylist.map(path => `-*::${path}::**`).join(' '); + +execSync(`cargo hax into -i '${include_clause}' fstar`, { cwd: OUTPUT_CRATE, stdio: 'inherit' }); diff --git a/flake.lock b/flake.lock index afe019a9f..13161cb34 100644 --- a/flake.lock +++ b/flake.lock @@ -100,9 +100,26 @@ "fstar": "fstar", "hacl-star": "hacl-star", "nixpkgs": "nixpkgs", + "rust-by-examples": "rust-by-examples", "rust-overlay": "rust-overlay" } }, + "rust-by-examples": { + "flake": false, + "locked": { + "lastModified": 1729958822, + "narHash": "sha256-/X1dI2MPYSfOdqOOxpNFCykoJtVetQCOo7WfBa7XAyU=", + "owner": "rust-lang", + "repo": "rust-by-example", + "rev": "4e3881e0cb1b690158acca3c16e271fdadf736da", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "repo": "rust-by-example", + "type": "github" + } + }, "rust-overlay": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index a57e309fb..736de0705 100644 --- a/flake.nix +++ b/flake.nix @@ -23,6 +23,10 @@ url = "github:hacl-star/hacl-star"; flake = false; }; + rust-by-examples = { + url = "github:rust-lang/rust-by-example"; + flake = false; + }; }; outputs = { @@ -87,6 +91,18 @@ check-examples = checks.examples; check-readme-coherency = checks.readme-coherency; + rust-by-example-hax-extraction = pkgs.stdenv.mkDerivation { + name = "rust-by-example-hax-extraction"; + phases = ["installPhase"]; + buildInputs = [packages.hax pkgs.cargo]; + installPhase = '' + cp --no-preserve=mode -rf ${inputs.rust-by-examples} workdir + cd workdir + ${pkgs.nodejs}/bin/node ${./.utils/rust-by-example.js} + mv rust-by-examples-crate/proofs $out + ''; + }; + # The commit that corresponds to our nightly pin, helpful when updating rusrc. toolchain_commit = pkgs.runCommand "hax-toolchain-commit" { } '' # This is sad but I don't know a better way. From f28c77d7e081a92e6c0ab59b50e7f871514084bb Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 17:25:37 +0100 Subject: [PATCH 238/253] feat(engine/f*): add dummy support for floats This PR makes the F* backend accept floats. This will not typecheck at the end, since there is no model of floats in F*. The next step is to add a very opaque model of floats to F*. This is useful for putting rust by examples on CI: a lot of examples are using floats. --- engine/backends/fstar/fstar_backend.ml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/engine/backends/fstar/fstar_backend.ml b/engine/backends/fstar/fstar_backend.ml index 96f97da8e..845a90854 100644 --- a/engine/backends/fstar/fstar_backend.ml +++ b/engine/backends/fstar/fstar_backend.ml @@ -164,7 +164,8 @@ struct ( (match signedness with Signed -> Signed | Unsigned -> Unsigned), size ) ) | Float _ -> - Error.unimplemented ~issue_id:230 ~details:"pliteral: Float" span + Error.unimplemented ~issue_id:464 + ~details:"Matching on f32 or f64 literals is not yet supported." span | Bool b -> F.Const.Const_bool b let pliteral_as_expr span (e : literal) = @@ -179,6 +180,13 @@ struct | Int { value; kind = { size = S128; signedness = sn }; negative } -> let prefix = match sn with Signed -> "i" | Unsigned -> "u" in wrap_app ("pub_" ^ prefix ^ "128") value negative + | Float { value; negative; _ } -> + F.mk_e_app + (F.term_of_lid [ "mk_float" ]) + [ + mk_const + (F.Const.Const_string (pnegative negative ^ value, F.dummyRange)); + ] | _ -> mk_const @@ pliteral span e let pconcrete_ident (id : concrete_ident) = @@ -310,7 +318,7 @@ struct F.mk_e_app base args | TArrow (inputs, output) -> F.mk_e_arrow (List.map ~f:(pty span) inputs) (pty span output) - | TFloat _ -> Error.unimplemented ~issue_id:230 ~details:"pty: Float" span + | TFloat _ -> F.term_of_lid [ "float" ] | TArray { typ; length } -> F.mk_e_app (F.term_of_lid [ "t_Array" ]) [ pty span typ; pexpr length ] | TParam i -> F.term @@ F.AST.Var (F.lid_of_id @@ plocal_ident i) From 202599f90c46938d21cb7a7f2689c936757c5f02 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 17:48:50 +0100 Subject: [PATCH 239/253] feat(ci): test rust by examples Fixes #540 --- .github/workflows/install_and_test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/install_and_test.yml b/.github/workflows/install_and_test.yml index 67a34828c..267d21bff 100644 --- a/.github/workflows/install_and_test.yml +++ b/.github/workflows/install_and_test.yml @@ -40,6 +40,10 @@ jobs: run: | nix build .#check-examples -L + - name: Try to extract Rust By Examples + run: | + nix build .#rust-by-example-hax-extraction -L + - name: Checkout specifications uses: actions/checkout@v3 with: From a53177d47fdd662cada8f46a5f074b888655f01d Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Thu, 31 Oct 2024 17:49:51 +0100 Subject: [PATCH 240/253] Add coq stack example --- examples/Cargo.toml | 2 +- .../proofs/coq/extraction/Coq_example.v | 170 ++++++++++++++++++ examples/coq-example/src/lib.rs | 86 +++++++++ 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 examples/coq-example/proofs/coq/extraction/Coq_example.v create mode 100644 examples/coq-example/src/lib.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7a79b49ba..a5b3a521b 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -6,7 +6,7 @@ members = [ "barrett", "kyber_compress", "proverif-psk" -] +, "coq-example"] resolver = "2" [workspace.dependencies] diff --git a/examples/coq-example/proofs/coq/extraction/Coq_example.v b/examples/coq-example/proofs/coq/extraction/Coq_example.v new file mode 100644 index 000000000..6a99f8795 --- /dev/null +++ b/examples/coq-example/proofs/coq/extraction/Coq_example.v @@ -0,0 +1,170 @@ +(* File automatically generated by Hacspec *) +From Coq Require Import ZArith. +Require Import List. +Import List.ListNotations. +Open Scope Z_scope. +Open Scope bool_scope. +Require Import Ascii. +Require Import String. +Require Import Coq.Floats.Floats. +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. + +(* LIBRARY CODE *) +Definition t_isize := Z. +Notation "'t_Vec' T '((t_Global))'" := (list T). +Definition impl_1__push {A} (l : list A) (a : A) : list A := cons a l. +Definition impl_1__pop {A} (l : list A) : list A * option A := + match l with + | [] => ([], None) + | (x :: xs) => (xs, Some x) + end. +Definition impl__unwrap {A} (x : option A) `{H : x <> None} : A := + match x as k return k <> None -> _ with + | None => fun H => False_rect _ (H eq_refl) + | Some a => fun _ => a + end H. +Definition t_Add_f_add := (fun x y => x + y). +Definition t_Mul_f_mul := (fun x y => x * y). +Definition t_PartialEq_f_eq := (fun x y => x =? y). +Definition impl__isize__rem_euclid := fun x y => x mod y. +Definition cast := fun (x : Z) => x. +Definition ne := fun x y => negb (x =? y). +Definition impl_1__len {A} (l : list A) := Z.of_nat (List.length l). +Definition t_PartialOrd_f_lt := fun x y => x x - y. +Definition impl__new {A} (tt : unit) : list A := []. +Definition f_fold {A B} (l : list A) (i : B) (f : B -> A -> B) : B := List.fold_left f l i. +Definition f_into_iter {A} := @id A. +(* /LIBRARY CODE *) + + + +Inductive t_Instruction : Type := +| Instruction_Push : t_isize -> _ +| Instruction_Pop +| Instruction_Add +| Instruction_Sub +| Instruction_Mul +| Instruction_Not +| Instruction_Dup. +Arguments t_Instruction:clear implicits. +Arguments t_Instruction. + +(* NotImplementedYet *) + +Definition impl__Instruction__interpret (self : t_Instruction) (stack : t_Vec ((t_isize)) ((t_Global))) : t_Vec ((t_isize)) ((t_Global)) := + let (stack,hax_temp_output) := match self with + | Instruction_Push (v) => + (impl_1__push (stack) (v),tt) + | Instruction_Pop => + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let _ := out in + (stack,tt) + | Instruction_Add => + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist2 := out in + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist1 := out in + let hoist3 := (hoist2,hoist1) in + match hoist3 with + | (Option_Some (a),Option_Some (b)) => + (impl_1__push (stack) (t_Add_f_add (b) (a)),tt) + | _ => + (stack,tt) + end + | Instruction_Sub => + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist5 := out in + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist4 := out in + let hoist6 := (hoist5,hoist4) in + match hoist6 with + | (Option_Some (a),Option_Some (b)) => + (impl_1__push (stack) (sub (b) (a)),tt) + | _ => + (stack,tt) + end + | Instruction_Mul => + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist8 := out in + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist7 := out in + let hoist9 := (hoist8,hoist7) in + match hoist9 with + | (Option_Some (a),Option_Some (b)) => + (impl_1__push (stack) (t_Mul_f_mul (b) (a)),tt) + | _ => + (stack,tt) + end + | Instruction_Not => + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist10 := out in + match hoist10 with + | Option_Some (a) => + (impl_1__push (stack) (if + t_PartialEq_f_eq (a) (0) + then + 1 + else + 0),tt) + | _ => + (stack,tt) + end + | Instruction_Dup => + let (tmp0,out) := impl_1__pop (stack) in + let stack := tmp0 in + let hoist11 := out in + match hoist11 with + | Option_Some (a) => + let stack := impl_1__push (stack) (a) in + let stack := impl_1__push (stack) (a) in + (stack,tt) + | _ => + (stack,tt) + end + end in + stack. + +Definition example (_ : unit) : t_Vec ((t_isize)) ((t_Global)) := + let stk := impl__new (tt) in + let stk := f_fold (f_into_iter ([Instruction_Push (1); Instruction_Push (1); Instruction_Add; Instruction_Push (1); Instruction_Push (1); Instruction_Push (1); Instruction_Add; Instruction_Add; Instruction_Dup; Instruction_Mul; Instruction_Sub])) (stk) (fun stk cmd => + impl__Instruction__interpret (cmd) (stk)) in + stk. + +(* Handwritten Proofs *) + +(* Check example *) +Example is_example_correct : example tt = [-7]. Proof. reflexivity. Qed. + +(* Proof composite operations *) +Theorem dup_mul_is_square : forall x, + impl__Instruction__interpret Instruction_Mul ( + impl__Instruction__interpret Instruction_Dup [x]) + = [Z.pow x 2]. +Proof. + intros. + cbn. + rewrite Z.mul_1_r. + reflexivity. +Qed. + +Theorem push_pop_cancel : forall l x, + impl__Instruction__interpret Instruction_Pop ( + impl__Instruction__interpret (Instruction_Push x) l) + = l. +Proof. + intros. + cbn. + reflexivity. +Qed. diff --git a/examples/coq-example/src/lib.rs b/examples/coq-example/src/lib.rs new file mode 100644 index 000000000..2e44072c1 --- /dev/null +++ b/examples/coq-example/src/lib.rs @@ -0,0 +1,86 @@ +enum Instruction { + Push(isize), + Pop, + Add, + Sub, + Mul, + Not, + Dup, +} + +impl Instruction { + pub fn interpret( + self, + stack: &mut Vec, + ) { + match self { + Instruction::Push(v) => stack.push(v), + Instruction::Pop => { + stack.pop(); + } + Instruction::Add => { + match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => stack.push(b + a), + _ => (), + } + } + Instruction::Sub => { + match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => stack.push(b - a), + _ => (), + } + } + Instruction::Mul => { + match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => stack.push(b * a), + _ => (), + } + } + Instruction::Not => { + match stack.pop() { + Some(a) => stack.push(if a == 0 { 1 } else { 0 }), + _ => (), + } + } + Instruction::Dup => { + match stack.pop() { + Some(a) => { + stack.push(a); + stack.push(a); + } + _ => (), + } + } + } + } +} + +fn example () -> Vec { + let mut stk = Vec::new(); + for cmd in [ + Instruction::Push(1), + Instruction::Push(1), + Instruction::Add, + Instruction::Push(1), + Instruction::Push(1), + Instruction::Push(1), + Instruction::Add, + Instruction::Add, + Instruction::Dup, + Instruction::Mul, + Instruction::Sub] { + cmd.interpret(&mut stk) + } + stk +} +// Push 1: 1 +// Push 1: 1, 1 +// Add: 2 +// Push 1: 2, 1 +// Push 1: 2, 1, 1 +// Push 1: 2, 1, 1, 1 +// Add: 2, 1, 2 +// Add: 2, 3 +// Dup: 2, 3, 3 +// Mul: 2, 9 +// Sub: -7 From 9e97990feb515919acc0bc40b3af22ef213e6f57 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Thu, 31 Oct 2024 17:52:52 +0100 Subject: [PATCH 241/253] fmt --- examples/coq-example/src/lib.rs | 64 ++++++++++++++------------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/examples/coq-example/src/lib.rs b/examples/coq-example/src/lib.rs index 2e44072c1..93b5b8443 100644 --- a/examples/coq-example/src/lib.rs +++ b/examples/coq-example/src/lib.rs @@ -9,53 +9,40 @@ enum Instruction { } impl Instruction { - pub fn interpret( - self, - stack: &mut Vec, - ) { + pub fn interpret(self, stack: &mut Vec) { match self { Instruction::Push(v) => stack.push(v), Instruction::Pop => { stack.pop(); } - Instruction::Add => { - match (stack.pop(), stack.pop()) { - (Some(a), Some(b)) => stack.push(b + a), - _ => (), + Instruction::Add => match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => stack.push(b + a), + _ => (), + }, + Instruction::Sub => match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => stack.push(b - a), + _ => (), + }, + Instruction::Mul => match (stack.pop(), stack.pop()) { + (Some(a), Some(b)) => stack.push(b * a), + _ => (), + }, + Instruction::Not => match stack.pop() { + Some(a) => stack.push(if a == 0 { 1 } else { 0 }), + _ => (), + }, + Instruction::Dup => match stack.pop() { + Some(a) => { + stack.push(a); + stack.push(a); } - } - Instruction::Sub => { - match (stack.pop(), stack.pop()) { - (Some(a), Some(b)) => stack.push(b - a), - _ => (), - } - } - Instruction::Mul => { - match (stack.pop(), stack.pop()) { - (Some(a), Some(b)) => stack.push(b * a), - _ => (), - } - } - Instruction::Not => { - match stack.pop() { - Some(a) => stack.push(if a == 0 { 1 } else { 0 }), - _ => (), - } - } - Instruction::Dup => { - match stack.pop() { - Some(a) => { - stack.push(a); - stack.push(a); - } - _ => (), - } - } + _ => (), + }, } } } -fn example () -> Vec { +fn example() -> Vec { let mut stk = Vec::new(); for cmd in [ Instruction::Push(1), @@ -68,7 +55,8 @@ fn example () -> Vec { Instruction::Add, Instruction::Dup, Instruction::Mul, - Instruction::Sub] { + Instruction::Sub, + ] { cmd.interpret(&mut stk) } stk From 72aa38580e5fcc7f3f47862bf1562abc5aeb1c00 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Thu, 31 Oct 2024 18:15:16 +0100 Subject: [PATCH 242/253] Better description and structure --- examples/coq-example/Cargo.toml | 7 + examples/coq-example/README.md | 49 + .../proofs/coq/extraction/Coq_example.v | 60 +- .../proofs/coq/extraction/Coq_proofs.v | 33 + .../proofs/coq/extraction/Makefile | 989 ++++++++++++++++++ .../proofs/coq/extraction/dummy_core_lib.v | 34 + examples/coq-example/src/dummy_core_lib.rs | 0 examples/coq-example/src/lib.rs | 3 + 8 files changed, 1119 insertions(+), 56 deletions(-) create mode 100644 examples/coq-example/Cargo.toml create mode 100644 examples/coq-example/README.md create mode 100644 examples/coq-example/proofs/coq/extraction/Coq_proofs.v create mode 100644 examples/coq-example/proofs/coq/extraction/Makefile create mode 100644 examples/coq-example/proofs/coq/extraction/dummy_core_lib.v create mode 100644 examples/coq-example/src/dummy_core_lib.rs diff --git a/examples/coq-example/Cargo.toml b/examples/coq-example/Cargo.toml new file mode 100644 index 000000000..2a2f6d1aa --- /dev/null +++ b/examples/coq-example/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "coq-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +hax-lib = {path = "../../hax-lib" } \ No newline at end of file diff --git a/examples/coq-example/README.md b/examples/coq-example/README.md new file mode 100644 index 000000000..3a1fbc7db --- /dev/null +++ b/examples/coq-example/README.md @@ -0,0 +1,49 @@ +# Stack example +This example is a simple interpreter for a stack. + +## How to build +```sh +cargo hax into coq +``` + +## Coq +Now we have the file `proofs/coq/extraction/Coq_example.v`. +To run the files we first need to install some dependencies. + +### Dependencies for Coq +The coq backend depends on `coq-record-update` to implement Rust record updates. +This can be installed by +```sh +opam install coq-record-update +``` +or alternatively the import lines +```coq +From RecordUpdate Require Import RecordSet. +Import RecordSetNotations. +``` +can be commented out. + +## Library required to run +As Rust implicitly imports the `Core` library for a lot of the basic functionality, we will also require a core library for Coq. For this small example, we build a dummy library with the required definitions, to run the example. As a hack to get this to run we add +``` +mod dummy_core_lib; +use dummy_core_lib::*; +``` +to the Rust example file `src/lib.rs`. The definitions of the library are put into `proofs/coq/extraction/dummy_core_lib.v` to match this import. + +## Running the code and doing proofs +We can set up a Coq project by making a `_CoqProject` file in `proofs/coq/extraction/`. +``` +-R ./ Coq_example +-arg -w +-arg all + +./dummy_core_lib.v +./Coq_example.v +./Coq_proofs.v +``` +We then build a makefile from the project file by +```sh +coq_makefile -f _CoqProject -o Makefile +``` +and run `make` to build. Any tests and proofs, we put into a seperate file `proofs/coq/extraction/Coq_proofs.v`. which imports the generated file, such that we can update and regenerate the file, without overwriting the proofs. diff --git a/examples/coq-example/proofs/coq/extraction/Coq_example.v b/examples/coq-example/proofs/coq/extraction/Coq_example.v index 6a99f8795..9bcf0a4d4 100644 --- a/examples/coq-example/proofs/coq/extraction/Coq_example.v +++ b/examples/coq-example/proofs/coq/extraction/Coq_example.v @@ -10,37 +10,10 @@ Require Import Coq.Floats.Floats. From RecordUpdate Require Import RecordSet. Import RecordSetNotations. -(* LIBRARY CODE *) -Definition t_isize := Z. -Notation "'t_Vec' T '((t_Global))'" := (list T). -Definition impl_1__push {A} (l : list A) (a : A) : list A := cons a l. -Definition impl_1__pop {A} (l : list A) : list A * option A := - match l with - | [] => ([], None) - | (x :: xs) => (xs, Some x) - end. -Definition impl__unwrap {A} (x : option A) `{H : x <> None} : A := - match x as k return k <> None -> _ with - | None => fun H => False_rect _ (H eq_refl) - | Some a => fun _ => a - end H. -Definition t_Add_f_add := (fun x y => x + y). -Definition t_Mul_f_mul := (fun x y => x * y). -Definition t_PartialEq_f_eq := (fun x y => x =? y). -Definition impl__isize__rem_euclid := fun x y => x mod y. -Definition cast := fun (x : Z) => x. -Definition ne := fun x y => negb (x =? y). -Definition impl_1__len {A} (l : list A) := Z.of_nat (List.length l). -Definition t_PartialOrd_f_lt := fun x y => x x - y. -Definition impl__new {A} (tt : unit) : list A := []. -Definition f_fold {A B} (l : list A) (i : B) (f : B -> A -> B) : B := List.fold_left f l i. -Definition f_into_iter {A} := @id A. -(* /LIBRARY CODE *) +From Coq_example Require Import dummy_core_lib. +Export dummy_core_lib. Inductive t_Instruction : Type := | Instruction_Push : t_isize -> _ @@ -55,6 +28,8 @@ Arguments t_Instruction. (* NotImplementedYet *) +(* NotImplementedYet *) + Definition impl__Instruction__interpret (self : t_Instruction) (stack : t_Vec ((t_isize)) ((t_Global))) : t_Vec ((t_isize)) ((t_Global)) := let (stack,hax_temp_output) := match self with | Instruction_Push (v) => @@ -141,30 +116,3 @@ Definition example (_ : unit) : t_Vec ((t_isize)) ((t_Global)) := let stk := f_fold (f_into_iter ([Instruction_Push (1); Instruction_Push (1); Instruction_Add; Instruction_Push (1); Instruction_Push (1); Instruction_Push (1); Instruction_Add; Instruction_Add; Instruction_Dup; Instruction_Mul; Instruction_Sub])) (stk) (fun stk cmd => impl__Instruction__interpret (cmd) (stk)) in stk. - -(* Handwritten Proofs *) - -(* Check example *) -Example is_example_correct : example tt = [-7]. Proof. reflexivity. Qed. - -(* Proof composite operations *) -Theorem dup_mul_is_square : forall x, - impl__Instruction__interpret Instruction_Mul ( - impl__Instruction__interpret Instruction_Dup [x]) - = [Z.pow x 2]. -Proof. - intros. - cbn. - rewrite Z.mul_1_r. - reflexivity. -Qed. - -Theorem push_pop_cancel : forall l x, - impl__Instruction__interpret Instruction_Pop ( - impl__Instruction__interpret (Instruction_Push x) l) - = l. -Proof. - intros. - cbn. - reflexivity. -Qed. diff --git a/examples/coq-example/proofs/coq/extraction/Coq_proofs.v b/examples/coq-example/proofs/coq/extraction/Coq_proofs.v new file mode 100644 index 000000000..219ce53cc --- /dev/null +++ b/examples/coq-example/proofs/coq/extraction/Coq_proofs.v @@ -0,0 +1,33 @@ +(* Handwritten Proofs *) + +From Coq Require Import ZArith. +Require Import List. +Import List.ListNotations. + +From Coq_example Require Import Coq_example. + + +(* Check example *) +Example is_example_correct : example tt = [-7]. Proof. reflexivity. Qed. + +(* Proof composite operations *) +Theorem dup_mul_is_square : forall x, + impl__Instruction__interpret Instruction_Mul ( + impl__Instruction__interpret Instruction_Dup [x]) + = [Z.pow x 2]. +Proof. + intros. + cbn. + rewrite Z.mul_1_r. + reflexivity. +Qed. + +Theorem push_pop_cancel : forall l x, + impl__Instruction__interpret Instruction_Pop ( + impl__Instruction__interpret (Instruction_Push x) l) + = l. +Proof. + intros. + cbn. + reflexivity. +Qed. diff --git a/examples/coq-example/proofs/coq/extraction/Makefile b/examples/coq-example/proofs/coq/extraction/Makefile new file mode 100644 index 000000000..42626b668 --- /dev/null +++ b/examples/coq-example/proofs/coq/extraction/Makefile @@ -0,0 +1,989 @@ +########################################################################## +## # The Coq Proof Assistant / The Coq Development Team ## +## v # Copyright INRIA, CNRS and contributors ## +## /dev/null 2>/dev/null; echo $$?)) +STDTIME?=command time -f $(TIMEFMT) +else +ifeq (0,$(shell gtime -f "" true >/dev/null 2>/dev/null; echo $$?)) +STDTIME?=gtime -f $(TIMEFMT) +else +STDTIME?=command time +endif +endif +else +STDTIME?=command time -f $(TIMEFMT) +endif + +COQBIN?= +ifneq (,$(COQBIN)) +# add an ending / +COQBIN:=$(COQBIN)/ +endif + +# Coq binaries +COQC ?= "$(COQBIN)coqc" +COQTOP ?= "$(COQBIN)coqtop" +COQCHK ?= "$(COQBIN)coqchk" +COQNATIVE ?= "$(COQBIN)coqnative" +COQDEP ?= "$(COQBIN)coqdep" +COQDOC ?= "$(COQBIN)coqdoc" +COQPP ?= "$(COQBIN)coqpp" +COQMKFILE ?= "$(COQBIN)coq_makefile" +OCAMLLIBDEP ?= "$(COQBIN)ocamllibdep" + +# Timing scripts +COQMAKE_ONE_TIME_FILE ?= "$(COQCORELIB)/tools/make-one-time-file.py" +COQMAKE_BOTH_TIME_FILES ?= "$(COQCORELIB)/tools/make-both-time-files.py" +COQMAKE_BOTH_SINGLE_TIMING_FILES ?= "$(COQCORELIB)/tools/make-both-single-timing-files.py" +BEFORE ?= +AFTER ?= + +# OCaml binaries +CAMLC ?= "$(OCAMLFIND)" ocamlc -c +CAMLOPTC ?= "$(OCAMLFIND)" opt -c +CAMLLINK ?= "$(OCAMLFIND)" ocamlc -linkall +CAMLOPTLINK ?= "$(OCAMLFIND)" opt -linkall +CAMLDOC ?= "$(OCAMLFIND)" ocamldoc +CAMLDEP ?= "$(OCAMLFIND)" ocamldep -slash -ml-synonym .mlpack + +# DESTDIR is prepended to all installation paths +DESTDIR ?= + +# Debug builds, typically -g to OCaml, -debug to Coq. +CAMLDEBUG ?= +COQDEBUG ?= + +# Extra packages to be linked in (as in findlib -package) +CAMLPKGS ?= +FINDLIBPKGS = -package coq-core.plugins.ltac $(CAMLPKGS) + +# Option for making timing files +TIMING?= +# Option for changing sorting of timing output file +TIMING_SORT_BY ?= auto +# Option for changing the fuzz parameter on the output file +TIMING_FUZZ ?= 0 +# Option for changing whether to use real or user time for timing tables +TIMING_REAL?= +# Option for including the memory column(s) +TIMING_INCLUDE_MEM?= +# Option for sorting by the memory column +TIMING_SORT_BY_MEM?= +# Output file names for timed builds +TIME_OF_BUILD_FILE ?= time-of-build.log +TIME_OF_BUILD_BEFORE_FILE ?= time-of-build-before.log +TIME_OF_BUILD_AFTER_FILE ?= time-of-build-after.log +TIME_OF_PRETTY_BUILD_FILE ?= time-of-build-pretty.log +TIME_OF_PRETTY_BOTH_BUILD_FILE ?= time-of-build-both.log +TIME_OF_PRETTY_BUILD_EXTRA_FILES ?= - # also output to the command line + +TGTS ?= + +# Retro compatibility (DESTDIR is standard on Unix, DSTROOT is not) +ifdef DSTROOT +DESTDIR := $(DSTROOT) +endif + +# Substitution of the path by appending $(DESTDIR) if needed. +# The variable $(COQMF_WINDRIVE) can be needed for Cygwin environments. +windrive_path = $(if $(COQMF_WINDRIVE),$(subst $(COQMF_WINDRIVE),/,$(1)),$(1)) +destination_path = $(if $(DESTDIR),$(DESTDIR)/$(call windrive_path,$(1)),$(1)) + +# Installation paths of libraries and documentation. +COQLIBINSTALL ?= $(call destination_path,$(COQLIB)/user-contrib) +COQDOCINSTALL ?= $(call destination_path,$(DOCDIR)/coq/user-contrib) +COQPLUGININSTALL ?= $(call destination_path,$(COQCORELIB)/..) +COQTOPINSTALL ?= $(call destination_path,$(COQLIB)/toploop) # FIXME: Unused variable? + +# findlib files installation +FINDLIBPREINST= mkdir -p "$(COQPLUGININSTALL)/" +FINDLIBDESTDIR= -destdir "$(COQPLUGININSTALL)/" + +# we need to move out of sight $(METAFILE) otherwise findlib thinks the +# package is already installed +findlib_install = \ + $(HIDE)if [ "$(METAFILE)" ]; then \ + $(FINDLIBPREINST) && \ + mv "$(METAFILE)" "$(METAFILE).skip" ; \ + "$(OCAMLFIND)" install $(2) $(FINDLIBDESTDIR) $(FINDLIBPACKAGE) $(1); \ + rc=$$?; \ + mv "$(METAFILE).skip" "$(METAFILE)"; \ + exit $$rc; \ + fi +findlib_remove = \ + $(HIDE)if [ ! -z "$(METAFILE)" ]; then\ + "$(OCAMLFIND)" remove $(FINDLIBDESTDIR) $(FINDLIBPACKAGE); \ + fi + + +########## End of parameters ################################################## +# What follows may be relevant to you only if you need to +# extend this Makefile. If so, look for 'Extension point' here and +# put in Makefile.local double colon rules accordingly. +# E.g. to perform some work after the all target completes you can write +# +# post-all:: +# echo "All done!" +# +# in Makefile.local +# +############################################################################### + + + + +# Flags ####################################################################### +# +# We define a bunch of variables combining the parameters. +# To add additional flags to coq, coqchk or coqdoc, set the +# {COQ,COQCHK,COQDOC}EXTRAFLAGS variable to whatever you want to add. +# To overwrite the default choice and set your own flags entirely, set the +# {COQ,COQCHK,COQDOC}FLAGS variable. + +SHOW := $(if $(VERBOSE),@true "",@echo "") +HIDE := $(if $(VERBOSE),,@) + +TIMER=$(if $(TIMED), $(STDTIME), $(TIMECMD)) + +OPT?= + +# The DYNOBJ and DYNLIB variables are used by "coqdep -dyndep var" in .v.d +ifeq '$(OPT)' '-byte' +USEBYTE:=true +DYNOBJ:=.cma +DYNLIB:=.cma +else +USEBYTE:= +DYNOBJ:=.cmxs +DYNLIB:=.cmxs +endif + +# these variables are meant to be overridden if you want to add *extra* flags +COQEXTRAFLAGS?= +COQCHKEXTRAFLAGS?= +COQDOCEXTRAFLAGS?= + +# Find the last argument of the form "-native-compiler FLAG" +COQUSERNATIVEFLAG:=$(strip \ +$(subst -native-compiler-,,\ +$(lastword \ +$(filter -native-compiler-%,\ +$(subst -native-compiler ,-native-compiler-,\ +$(strip $(COQEXTRAFLAGS))))))) + +COQFILTEREDEXTRAFLAGS:=$(strip \ +$(filter-out -native-compiler-%,\ +$(subst -native-compiler ,-native-compiler-,\ +$(strip $(COQEXTRAFLAGS))))) + +COQACTUALNATIVEFLAG:=$(lastword $(COQMF_COQ_NATIVE_COMPILER_DEFAULT) $(COQMF_COQPROJECTNATIVEFLAG) $(COQUSERNATIVEFLAG)) + +ifeq '$(COQACTUALNATIVEFLAG)' 'yes' + COQNATIVEFLAG="-w" "-deprecated-native-compiler-option" "-native-compiler" "ondemand" + COQDONATIVE="yes" +else +ifeq '$(COQACTUALNATIVEFLAG)' 'ondemand' + COQNATIVEFLAG="-w" "-deprecated-native-compiler-option" "-native-compiler" "ondemand" + COQDONATIVE="no" +else + COQNATIVEFLAG="-w" "-deprecated-native-compiler-option" "-native-compiler" "no" + COQDONATIVE="no" +endif +endif + +# these flags do NOT contain the libraries, to make them easier to overwrite +COQFLAGS?=-q $(OTHERFLAGS) $(COQFILTEREDEXTRAFLAGS) $(COQNATIVEFLAG) +COQCHKFLAGS?=-silent -o $(COQCHKEXTRAFLAGS) +COQDOCFLAGS?=-interpolate -utf8 $(COQDOCEXTRAFLAGS) + +COQDOCLIBS?=$(COQLIBS_NOML) + +# The version of Coq being run and the version of coq_makefile that +# generated this makefile +COQ_VERSION:=$(shell $(COQC) --print-version | cut -d " " -f 1) +COQMAKEFILE_VERSION:=8.18.0 + +# COQ_SRC_SUBDIRS is for user-overriding, usually to add +# `user-contrib/Foo` to the includes, we keep COQCORE_SRC_SUBDIRS for +# Coq's own core libraries, which should be replaced by ocamlfind +# options at some point. +COQ_SRC_SUBDIRS?= +COQSRCLIBS?= $(foreach d,$(COQ_SRC_SUBDIRS), -I "$(COQLIB)/$(d)") + +CAMLFLAGS+=$(OCAMLLIBS) $(COQSRCLIBS) +# ocamldoc fails with unknown argument otherwise +CAMLDOCFLAGS:=$(filter-out -annot, $(filter-out -bin-annot, $(CAMLFLAGS))) +CAMLFLAGS+=$(OCAMLWARN) + +ifneq (,$(TIMING)) + ifeq (after,$(TIMING)) + TIMING_EXT=after-timing + else + ifeq (before,$(TIMING)) + TIMING_EXT=before-timing + else + TIMING_EXT=timing + endif + endif + TIMING_ARG=-time-file $<.$(TIMING_EXT) +else + TIMING_ARG= +endif + +# Files ####################################################################### +# +# We here define a bunch of variables about the files being part of the +# Coq project in order to ease the writing of build target and build rules + +VDFILE := .Makefile.d + +ALLSRCFILES := \ + $(MLGFILES) \ + $(MLFILES) \ + $(MLPACKFILES) \ + $(MLLIBFILES) \ + $(MLIFILES) + +# helpers +vo_to_obj = $(addsuffix .o,\ + $(filter-out Warning: Error:,\ + $(shell $(COQTOP) -q -noinit -batch -quiet -print-mod-uid $(1)))) +strip_dotslash = $(patsubst ./%,%,$(1)) + +# without this we get undefined variables in the expansion for the +# targets of the [deprecated,use-mllib-or-mlpack] rule +with_undef = $(if $(filter-out undefined, $(origin $(1))),$($(1))) + +VO = vo +VOS = vos + +VOFILES = $(VFILES:.v=.$(VO)) +GLOBFILES = $(VFILES:.v=.glob) +HTMLFILES = $(VFILES:.v=.html) +GHTMLFILES = $(VFILES:.v=.g.html) +BEAUTYFILES = $(addsuffix .beautified,$(VFILES)) +TEXFILES = $(VFILES:.v=.tex) +GTEXFILES = $(VFILES:.v=.g.tex) +CMOFILES = \ + $(MLGFILES:.mlg=.cmo) \ + $(MLFILES:.ml=.cmo) \ + $(MLPACKFILES:.mlpack=.cmo) +CMXFILES = $(CMOFILES:.cmo=.cmx) +OFILES = $(CMXFILES:.cmx=.o) +CMAFILES = $(MLLIBFILES:.mllib=.cma) $(MLPACKFILES:.mlpack=.cma) +CMXAFILES = $(CMAFILES:.cma=.cmxa) +CMIFILES = \ + $(CMOFILES:.cmo=.cmi) \ + $(MLIFILES:.mli=.cmi) +# the /if/ is because old _CoqProject did not list a .ml(pack|lib) but just +# a .mlg file +CMXSFILES = \ + $(MLPACKFILES:.mlpack=.cmxs) \ + $(CMXAFILES:.cmxa=.cmxs) \ + $(if $(MLPACKFILES)$(CMXAFILES),,\ + $(MLGFILES:.mlg=.cmxs) $(MLFILES:.ml=.cmxs)) + +# files that are packed into a plugin (no extension) +PACKEDFILES = \ + $(call strip_dotslash, \ + $(foreach lib, \ + $(call strip_dotslash, \ + $(MLPACKFILES:.mlpack=_MLPACK_DEPENDENCIES)),$(call with_undef,$(lib)))) +# files that are archived into a .cma (mllib) +LIBEDFILES = \ + $(call strip_dotslash, \ + $(foreach lib, \ + $(call strip_dotslash, \ + $(MLLIBFILES:.mllib=_MLLIB_DEPENDENCIES)),$(call with_undef,$(lib)))) +CMIFILESTOINSTALL = $(filter-out $(addsuffix .cmi,$(PACKEDFILES)),$(CMIFILES)) +CMOFILESTOINSTALL = $(filter-out $(addsuffix .cmo,$(PACKEDFILES)),$(CMOFILES)) +OBJFILES = $(call vo_to_obj,$(VOFILES)) +ALLNATIVEFILES = \ + $(OBJFILES:.o=.cmi) \ + $(OBJFILES:.o=.cmx) \ + $(OBJFILES:.o=.cmxs) +FINDLIBPACKAGE=$(patsubst .%,%,$(suffix $(METAFILE))) + +# trick: wildcard filters out non-existing files, so that `install` doesn't show +# warnings and `clean` doesn't pass to rm a list of files that is too long for +# the shell. +NATIVEFILES = $(wildcard $(ALLNATIVEFILES)) +FILESTOINSTALL = \ + $(VOFILES) \ + $(VFILES) \ + $(GLOBFILES) \ + $(NATIVEFILES) \ + $(CMXSFILES) # to be removed when we remove legacy loading +FINDLIBFILESTOINSTALL = \ + $(CMIFILESTOINSTALL) +ifeq '$(HASNATDYNLINK)' 'true' +DO_NATDYNLINK = yes +FINDLIBFILESTOINSTALL += $(CMXSFILES) $(CMXAFILES) $(CMOFILESTOINSTALL:.cmo=.cmx) +else +DO_NATDYNLINK = +endif + +ALLDFILES = $(addsuffix .d,$(ALLSRCFILES)) $(VDFILE) + +# Compilation targets ######################################################### + +all: + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" pre-all + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" real-all + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" post-all +.PHONY: all + +all.timing.diff: + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" pre-all + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" real-all.timing.diff TIME_OF_PRETTY_BUILD_EXTRA_FILES="" + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" post-all +.PHONY: all.timing.diff + +ifeq (0,$(TIMING_REAL)) +TIMING_REAL_ARG := +TIMING_USER_ARG := --user +else +ifeq (1,$(TIMING_REAL)) +TIMING_REAL_ARG := --real +TIMING_USER_ARG := +else +TIMING_REAL_ARG := +TIMING_USER_ARG := +endif +endif + +ifeq (0,$(TIMING_INCLUDE_MEM)) +TIMING_INCLUDE_MEM_ARG := --no-include-mem +else +TIMING_INCLUDE_MEM_ARG := +endif + +ifeq (1,$(TIMING_SORT_BY_MEM)) +TIMING_SORT_BY_MEM_ARG := --sort-by-mem +else +TIMING_SORT_BY_MEM_ARG := +endif + +make-pretty-timed-before:: TIME_OF_BUILD_FILE=$(TIME_OF_BUILD_BEFORE_FILE) +make-pretty-timed-after:: TIME_OF_BUILD_FILE=$(TIME_OF_BUILD_AFTER_FILE) +make-pretty-timed make-pretty-timed-before make-pretty-timed-after:: + $(HIDE)rm -f pretty-timed-success.ok + $(HIDE)($(MAKE) --no-print-directory -f "$(PARENT)" $(TGTS) TIMED=1 2>&1 && touch pretty-timed-success.ok) | tee -a $(TIME_OF_BUILD_FILE) + $(HIDE)rm pretty-timed-success.ok # must not be -f; must fail if the touch failed +print-pretty-timed:: + $(HIDE)$(COQMAKE_ONE_TIME_FILE) $(TIMING_INCLUDE_MEM_ARG) $(TIMING_SORT_BY_MEM_ARG) $(TIMING_REAL_ARG) $(TIME_OF_BUILD_FILE) $(TIME_OF_PRETTY_BUILD_FILE) $(TIME_OF_PRETTY_BUILD_EXTRA_FILES) +print-pretty-timed-diff:: + $(HIDE)$(COQMAKE_BOTH_TIME_FILES) --sort-by=$(TIMING_SORT_BY) $(TIMING_INCLUDE_MEM_ARG) $(TIMING_SORT_BY_MEM_ARG) $(TIMING_REAL_ARG) $(TIME_OF_BUILD_AFTER_FILE) $(TIME_OF_BUILD_BEFORE_FILE) $(TIME_OF_PRETTY_BOTH_BUILD_FILE) $(TIME_OF_PRETTY_BUILD_EXTRA_FILES) +ifeq (,$(BEFORE)) +print-pretty-single-time-diff:: + @echo 'Error: Usage: $(MAKE) print-pretty-single-time-diff AFTER=path/to/file.v.after-timing BEFORE=path/to/file.v.before-timing' + $(HIDE)false +else +ifeq (,$(AFTER)) +print-pretty-single-time-diff:: + @echo 'Error: Usage: $(MAKE) print-pretty-single-time-diff AFTER=path/to/file.v.after-timing BEFORE=path/to/file.v.before-timing' + $(HIDE)false +else +print-pretty-single-time-diff:: + $(HIDE)$(COQMAKE_BOTH_SINGLE_TIMING_FILES) --fuzz=$(TIMING_FUZZ) --sort-by=$(TIMING_SORT_BY) $(TIMING_USER_ARG) $(AFTER) $(BEFORE) $(TIME_OF_PRETTY_BUILD_FILE) $(TIME_OF_PRETTY_BUILD_EXTRA_FILES) +endif +endif +pretty-timed: + $(HIDE)$(MAKE) --no-print-directory -f "$(PARENT)" make-pretty-timed + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" print-pretty-timed +.PHONY: pretty-timed make-pretty-timed make-pretty-timed-before make-pretty-timed-after print-pretty-timed print-pretty-timed-diff print-pretty-single-time-diff + +# Extension points for actions to be performed before/after the all target +pre-all:: + @# Extension point + $(HIDE)if [ "$(COQMAKEFILE_VERSION)" != "$(COQ_VERSION)" ]; then\ + echo "W: This Makefile was generated by Coq $(COQMAKEFILE_VERSION)";\ + echo "W: while the current Coq version is $(COQ_VERSION)";\ + fi +.PHONY: pre-all + +post-all:: + @# Extension point +.PHONY: post-all + +real-all: $(VOFILES) $(if $(USEBYTE),bytefiles,optfiles) +.PHONY: real-all + +real-all.timing.diff: $(VOFILES:.vo=.v.timing.diff) +.PHONY: real-all.timing.diff + +bytefiles: $(CMOFILES) $(CMAFILES) +.PHONY: bytefiles + +optfiles: $(if $(DO_NATDYNLINK),$(CMXSFILES)) +.PHONY: optfiles + +# FIXME, see Ralf's bugreport +# quick is deprecated, now renamed vio +vio: $(VOFILES:.vo=.vio) +.PHONY: vio +quick: vio + $(warning "'make quick' is deprecated, use 'make vio' or consider using 'vos' files") +.PHONY: quick + +vio2vo: + $(TIMER) $(COQC) $(COQDEBUG) $(COQFLAGS) $(COQLIBS) \ + -schedule-vio2vo $(J) $(VOFILES:%.vo=%.vio) +.PHONY: vio2vo + +# quick2vo is undocumented +quick2vo: + $(HIDE)make -j $(J) vio + $(HIDE)VIOFILES=$$(for vofile in $(VOFILES); do \ + viofile="$$(echo "$$vofile" | sed "s/\.vo$$/.vio/")"; \ + if [ "$$vofile" -ot "$$viofile" -o ! -e "$$vofile" ]; then printf "$$viofile "; fi; \ + done); \ + echo "VIO2VO: $$VIOFILES"; \ + if [ -n "$$VIOFILES" ]; then \ + $(TIMER) $(COQC) $(COQDEBUG) $(COQFLAGS) $(COQLIBS) -schedule-vio2vo $(J) $$VIOFILES; \ + fi +.PHONY: quick2vo + +checkproofs: + $(TIMER) $(COQC) $(COQDEBUG) $(COQFLAGS) $(COQLIBS) \ + -schedule-vio-checking $(J) $(VOFILES:%.vo=%.vio) +.PHONY: checkproofs + +vos: $(VOFILES:%.vo=%.vos) +.PHONY: vos + +vok: $(VOFILES:%.vo=%.vok) +.PHONY: vok + +validate: $(VOFILES) + $(TIMER) $(COQCHK) $(COQCHKFLAGS) $(COQLIBS_NOML) $^ +.PHONY: validate + +only: $(TGTS) +.PHONY: only + +# Documentation targets ####################################################### + +html: $(GLOBFILES) $(VFILES) + $(SHOW)'COQDOC -d html $(GAL)' + $(HIDE)mkdir -p html + $(HIDE)$(COQDOC) \ + -toc $(COQDOCFLAGS) -html $(GAL) $(COQDOCLIBS) -d html $(VFILES) + +mlihtml: $(MLIFILES:.mli=.cmi) + $(SHOW)'CAMLDOC -d $@' + $(HIDE)mkdir $@ || rm -rf $@/* + $(HIDE)$(CAMLDOC) -html \ + -d $@ -m A $(CAMLDEBUG) $(CAMLDOCFLAGS) $(MLIFILES) $(FINDLIBPKGS) + +all-mli.tex: $(MLIFILES:.mli=.cmi) + $(SHOW)'CAMLDOC -latex $@' + $(HIDE)$(CAMLDOC) -latex \ + -o $@ -m A $(CAMLDEBUG) $(CAMLDOCFLAGS) $(MLIFILES) $(FINDLIBPKGS) + +all.ps: $(VFILES) + $(SHOW)'COQDOC -ps $(GAL)' + $(HIDE)$(COQDOC) \ + -toc $(COQDOCFLAGS) -ps $(GAL) $(COQDOCLIBS) \ + -o $@ `$(COQDEP) -sort $(VFILES)` + +all.pdf: $(VFILES) + $(SHOW)'COQDOC -pdf $(GAL)' + $(HIDE)$(COQDOC) \ + -toc $(COQDOCFLAGS) -pdf $(GAL) $(COQDOCLIBS) \ + -o $@ `$(COQDEP) -sort $(VFILES)` + +# FIXME: not quite right, since the output name is different +gallinahtml: GAL=-g +gallinahtml: html + +all-gal.ps: GAL=-g +all-gal.ps: all.ps + +all-gal.pdf: GAL=-g +all-gal.pdf: all.pdf + +# ? +beautify: $(BEAUTYFILES) + for file in $^; do mv $${file%.beautified} $${file%beautified}old && mv $${file} $${file%.beautified}; done + @echo 'Do not do "make clean" until you are sure that everything went well!' + @echo 'If there were a problem, execute "for file in $$(find . -name \*.v.old -print); do mv $${file} $${file%.old}; done" in your shell/' +.PHONY: beautify + +# Installation targets ######################################################## +# +# There rules can be extended in Makefile.local +# Extensions can't assume when they run. + +# We use $(file) to avoid generating a very long command string to pass to the shell +# (cf https://coq.zulipchat.com/#narrow/stream/250632-Coq-Platform-devs-.26-users/topic/Strange.20command.20length.20limit.20on.20Linux) +# However Apple ships old make which doesn't have $(file) so we need a fallback +$(file >.hasfile,1) +HASFILE:=$(shell if [ -e .hasfile ]; then echo 1; rm .hasfile; fi) + +MKFILESTOINSTALL= $(if $(HASFILE),$(file >.filestoinstall,$(FILESTOINSTALL)),\ + $(shell rm -f .filestoinstall) \ + $(foreach x,$(FILESTOINSTALL),$(shell printf '%s\n' "$x" >> .filestoinstall))) + +# findlib needs the package to not be installed, so we remove it before +# installing it (see the call to findlib_remove) +install: META + @$(MKFILESTOINSTALL) + $(HIDE)code=0; for f in $$(cat .filestoinstall); do\ + if ! [ -f "$$f" ]; then >&2 echo $$f does not exist; code=1; fi \ + done; exit $$code + $(HIDE)for f in $$(cat .filestoinstall); do\ + df="`$(COQMKFILE) -destination-of "$$f" $(COQLIBS)`";\ + if [ "$$?" != "0" -o -z "$$df" ]; then\ + echo SKIP "$$f" since it has no logical path;\ + else\ + install -d "$(COQLIBINSTALL)/$$df" &&\ + install -m 0644 "$$f" "$(COQLIBINSTALL)/$$df" &&\ + echo INSTALL "$$f" "$(COQLIBINSTALL)/$$df";\ + fi;\ + done + $(call findlib_remove) + $(call findlib_install, META $(FINDLIBFILESTOINSTALL)) + $(HIDE)$(MAKE) install-extra -f "$(SELF)" + @rm -f .filestoinstall +install-extra:: + @# Extension point +.PHONY: install install-extra + +META: $(METAFILE) + $(HIDE)if [ "$(METAFILE)" ]; then \ + cat "$(METAFILE)" | grep -v 'directory.*=.*' > META; \ + fi + +install-byte: + $(call findlib_install, $(CMAFILES) $(CMOFILESTOINSTALL), -add) + +install-doc:: html mlihtml + @# Extension point + $(HIDE)install -d "$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/html" + $(HIDE)for i in html/*; do \ + dest="$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/$$i";\ + install -m 0644 "$$i" "$$dest";\ + echo INSTALL "$$i" "$$dest";\ + done + $(HIDE)install -d \ + "$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/mlihtml" + $(HIDE)for i in mlihtml/*; do \ + dest="$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/$$i";\ + install -m 0644 "$$i" "$$dest";\ + echo INSTALL "$$i" "$$dest";\ + done +.PHONY: install-doc + +uninstall:: + @# Extension point + @$(MKFILESTOINSTALL) + $(call findlib_remove) + $(HIDE)for f in $$(cat .filestoinstall); do \ + df="`$(COQMKFILE) -destination-of "$$f" $(COQLIBS)`" &&\ + instf="$(COQLIBINSTALL)/$$df/`basename $$f`" &&\ + rm -f "$$instf" &&\ + echo RM "$$instf" ;\ + done + $(HIDE)for f in $$(cat .filestoinstall); do \ + df="`$(COQMKFILE) -destination-of "$$f" $(COQLIBS)`" &&\ + echo RMDIR "$(COQLIBINSTALL)/$$df/" &&\ + (rmdir "$(COQLIBINSTALL)/$$df/" 2>/dev/null || true); \ + done + @rm -f .filestoinstall + +.PHONY: uninstall + +uninstall-doc:: + @# Extension point + $(SHOW)'RM $(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/html' + $(HIDE)rm -rf "$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/html" + $(SHOW)'RM $(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/mlihtml' + $(HIDE)rm -rf "$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/mlihtml" + $(HIDE) rmdir "$(COQDOCINSTALL)/$(INSTALLCOQDOCROOT)/" || true +.PHONY: uninstall-doc + +# Cleaning #################################################################### +# +# There rules can be extended in Makefile.local +# Extensions can't assume when they run. + +clean:: + @# Extension point + $(SHOW)'CLEAN' + $(HIDE)rm -f $(CMOFILES) + $(HIDE)rm -f $(CMIFILES) + $(HIDE)rm -f $(CMAFILES) + $(HIDE)rm -f $(CMXFILES) + $(HIDE)rm -f $(CMXAFILES) + $(HIDE)rm -f $(CMXSFILES) + $(HIDE)rm -f $(OFILES) + $(HIDE)rm -f $(CMXAFILES:.cmxa=.a) + $(HIDE)rm -f $(MLGFILES:.mlg=.ml) + $(HIDE)rm -f $(CMXFILES:.cmx=.cmt) + $(HIDE)rm -f $(MLIFILES:.mli=.cmti) + $(HIDE)rm -f $(ALLDFILES) + $(HIDE)rm -f $(NATIVEFILES) + $(HIDE)find . -name .coq-native -type d -empty -delete + $(HIDE)rm -f $(VOFILES) + $(HIDE)rm -f $(VOFILES:.vo=.vio) + $(HIDE)rm -f $(VOFILES:.vo=.vos) + $(HIDE)rm -f $(VOFILES:.vo=.vok) + $(HIDE)rm -f $(BEAUTYFILES) $(VFILES:=.old) + $(HIDE)rm -f all.ps all-gal.ps all.pdf all-gal.pdf all.glob all-mli.tex + $(HIDE)rm -f $(VFILES:.v=.glob) + $(HIDE)rm -f $(VFILES:.v=.tex) + $(HIDE)rm -f $(VFILES:.v=.g.tex) + $(HIDE)rm -f pretty-timed-success.ok + $(HIDE)rm -f META + $(HIDE)rm -rf html mlihtml +.PHONY: clean + +cleanall:: clean + @# Extension point + $(SHOW)'CLEAN *.aux *.timing' + $(HIDE)rm -f $(foreach f,$(VFILES:.v=),$(dir $(f)).$(notdir $(f)).aux) + $(HIDE)rm -f $(TIME_OF_BUILD_FILE) $(TIME_OF_BUILD_BEFORE_FILE) $(TIME_OF_BUILD_AFTER_FILE) $(TIME_OF_PRETTY_BUILD_FILE) $(TIME_OF_PRETTY_BOTH_BUILD_FILE) + $(HIDE)rm -f $(VOFILES:.vo=.v.timing) + $(HIDE)rm -f $(VOFILES:.vo=.v.before-timing) + $(HIDE)rm -f $(VOFILES:.vo=.v.after-timing) + $(HIDE)rm -f $(VOFILES:.vo=.v.timing.diff) + $(HIDE)rm -f .lia.cache .nia.cache +.PHONY: cleanall + +archclean:: + @# Extension point + $(SHOW)'CLEAN *.cmx *.o' + $(HIDE)rm -f $(NATIVEFILES) + $(HIDE)rm -f $(CMOFILES:%.cmo=%.cmx) +.PHONY: archclean + + +# Compilation rules ########################################################### + +$(MLIFILES:.mli=.cmi): %.cmi: %.mli + $(SHOW)'CAMLC -c $<' + $(HIDE)$(TIMER) $(CAMLC) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) $< + +$(MLGFILES:.mlg=.ml): %.ml: %.mlg + $(SHOW)'COQPP $<' + $(HIDE)$(COQPP) $< + +# Stupid hack around a deficient syntax: we cannot concatenate two expansions +$(filter %.cmo, $(MLFILES:.ml=.cmo) $(MLGFILES:.mlg=.cmo)): %.cmo: %.ml + $(SHOW)'CAMLC -c $<' + $(HIDE)$(TIMER) $(CAMLC) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) $< + +# Same hack +$(filter %.cmx, $(MLFILES:.ml=.cmx) $(MLGFILES:.mlg=.cmx)): %.cmx: %.ml + $(SHOW)'CAMLOPT -c $(FOR_PACK) $<' + $(HIDE)$(TIMER) $(CAMLOPTC) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) $(FOR_PACK) $< + + +$(MLLIBFILES:.mllib=.cmxs): %.cmxs: %.cmxa + $(SHOW)'CAMLOPT -shared -o $@' + $(HIDE)$(TIMER) $(CAMLOPTLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) \ + -shared -o $@ $< + +$(MLLIBFILES:.mllib=.cma): %.cma: | %.mllib + $(SHOW)'CAMLC -a -o $@' + $(HIDE)$(TIMER) $(CAMLLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) -a -o $@ $^ + +$(MLLIBFILES:.mllib=.cmxa): %.cmxa: | %.mllib + $(SHOW)'CAMLOPT -a -o $@' + $(HIDE)$(TIMER) $(CAMLOPTLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) -a -o $@ $^ + + +$(MLPACKFILES:.mlpack=.cmxs): %.cmxs: %.cmxa + $(SHOW)'CAMLOPT -shared -o $@' + $(HIDE)$(TIMER) $(CAMLOPTLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) \ + -shared -o $@ $< + +$(MLPACKFILES:.mlpack=.cmxa): %.cmxa: %.cmx | %.mlpack + $(SHOW)'CAMLOPT -a -o $@' + $(HIDE)$(TIMER) $(CAMLOPTLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) -a -o $@ $< + +$(MLPACKFILES:.mlpack=.cma): %.cma: %.cmo | %.mlpack + $(SHOW)'CAMLC -a -o $@' + $(HIDE)$(TIMER) $(CAMLLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) -a -o $@ $^ + +$(MLPACKFILES:.mlpack=.cmo): %.cmo: | %.mlpack + $(SHOW)'CAMLC -pack -o $@' + $(HIDE)$(TIMER) $(CAMLLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) -pack -o $@ $^ + +$(MLPACKFILES:.mlpack=.cmx): %.cmx: | %.mlpack + $(SHOW)'CAMLOPT -pack -o $@' + $(HIDE)$(TIMER) $(CAMLOPTLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) -pack -o $@ $^ + +# This rule is for _CoqProject with no .mllib nor .mlpack +$(filter-out $(MLLIBFILES:.mllib=.cmxs) $(MLPACKFILES:.mlpack=.cmxs) $(addsuffix .cmxs,$(PACKEDFILES)) $(addsuffix .cmxs,$(LIBEDFILES)),$(MLFILES:.ml=.cmxs) $(MLGFILES:.mlg=.cmxs)): %.cmxs: %.cmx + $(SHOW)'[deprecated,use-mllib-or-mlpack] CAMLOPT -shared -o $@' + $(HIDE)$(TIMER) $(CAMLOPTLINK) $(CAMLDEBUG) $(CAMLFLAGS) $(FINDLIBPKGS) \ + -shared -o $@ $< + +# can't make +# https://www.gnu.org/software/make/manual/make.html#Static-Pattern +# work with multiple target rules +# so use eval in a loop instead +# with grouped targets https://www.gnu.org/software/make/manual/make.html#Multiple-Targets +# if available (GNU Make >= 4.3) +ifneq (,$(filter grouped-target,$(.FEATURES))) +define globvorule= + +# take care to $$ variables using $< etc + $(1).vo $(1).glob &: $(1).v | $(VDFILE) + $(SHOW)COQC $(1).v + $(HIDE)$$(TIMER) $(COQC) $(COQDEBUG) $$(TIMING_ARG) $(COQFLAGS) $(COQLIBS) $(1).v +ifeq ($(COQDONATIVE), "yes") + $(SHOW)COQNATIVE $(1).vo + $(HIDE)$(call TIMER,$(1).vo.native) $(COQNATIVE) $(COQLIBS) $(1).vo +endif + +endef +else + +$(VOFILES): %.vo: %.v | $(VDFILE) + $(SHOW)COQC $< + $(HIDE)$(TIMER) $(COQC) $(COQDEBUG) $(TIMING_ARG) $(COQFLAGS) $(COQLIBS) $< +ifeq ($(COQDONATIVE), "yes") + $(SHOW)COQNATIVE $@ + $(HIDE)$(call TIMER,$@.native) $(COQNATIVE) $(COQLIBS) $@ +endif + +# this is broken :( todo fix if we ever find a solution that doesn't need grouped targets +$(GLOBFILES): %.glob: %.v + $(SHOW)'COQC $< (for .glob)' + $(HIDE)$(TIMER) $(COQC) $(COQDEBUG) $(COQFLAGS) $(COQLIBS) $< + +endif + +$(foreach vfile,$(VFILES:.v=),$(eval $(call globvorule,$(vfile)))) + +$(VFILES:.v=.vio): %.vio: %.v + $(SHOW)COQC -vio $< + $(HIDE)$(TIMER) $(COQC) -vio $(COQDEBUG) $(COQFLAGS) $(COQLIBS) $< + +$(VFILES:.v=.vos): %.vos: %.v + $(SHOW)COQC -vos $< + $(HIDE)$(TIMER) $(COQC) -vos $(COQDEBUG) $(COQFLAGS) $(COQLIBS) $< + +$(VFILES:.v=.vok): %.vok: %.v + $(SHOW)COQC -vok $< + $(HIDE)$(TIMER) $(COQC) -vok $(COQDEBUG) $(COQFLAGS) $(COQLIBS) $< + +$(addsuffix .timing.diff,$(VFILES)): %.timing.diff : %.before-timing %.after-timing + $(SHOW)PYTHON TIMING-DIFF $*.{before,after}-timing + $(HIDE)$(MAKE) --no-print-directory -f "$(SELF)" print-pretty-single-time-diff BEFORE=$*.before-timing AFTER=$*.after-timing TIME_OF_PRETTY_BUILD_FILE="$@" + +$(BEAUTYFILES): %.v.beautified: %.v + $(SHOW)'BEAUTIFY $<' + $(HIDE)$(TIMER) $(COQC) $(COQDEBUG) $(COQFLAGS) $(COQLIBS) -beautify $< + +$(TEXFILES): %.tex: %.v + $(SHOW)'COQDOC -latex $<' + $(HIDE)$(COQDOC) $(COQDOCFLAGS) -latex $< -o $@ + +$(GTEXFILES): %.g.tex: %.v + $(SHOW)'COQDOC -latex -g $<' + $(HIDE)$(COQDOC) $(COQDOCFLAGS) -latex -g $< -o $@ + +$(HTMLFILES): %.html: %.v %.glob + $(SHOW)'COQDOC -html $<' + $(HIDE)$(COQDOC) $(COQDOCFLAGS) -html $< -o $@ + +$(GHTMLFILES): %.g.html: %.v %.glob + $(SHOW)'COQDOC -html -g $<' + $(HIDE)$(COQDOC) $(COQDOCFLAGS) -html -g $< -o $@ + +# Dependency files ############################################################ + +ifndef MAKECMDGOALS + -include $(ALLDFILES) +else + ifneq ($(filter-out archclean clean cleanall printenv make-pretty-timed make-pretty-timed-before make-pretty-timed-after print-pretty-timed print-pretty-timed-diff print-pretty-single-time-diff,$(MAKECMDGOALS)),) + -include $(ALLDFILES) + endif +endif + +.SECONDARY: $(ALLDFILES) + +redir_if_ok = > "$@" || ( RV=$$?; rm -f "$@"; exit $$RV ) + +GENMLFILES:=$(MLGFILES:.mlg=.ml) +$(addsuffix .d,$(ALLSRCFILES)): $(GENMLFILES) + +$(addsuffix .d,$(MLIFILES)): %.mli.d: %.mli + $(SHOW)'CAMLDEP $<' + $(HIDE)$(CAMLDEP) $(OCAMLLIBS) "$<" $(redir_if_ok) + +$(addsuffix .d,$(MLGFILES)): %.mlg.d: %.ml + $(SHOW)'CAMLDEP $<' + $(HIDE)$(CAMLDEP) $(OCAMLLIBS) "$<" $(redir_if_ok) + +$(addsuffix .d,$(MLFILES)): %.ml.d: %.ml + $(SHOW)'CAMLDEP $<' + $(HIDE)$(CAMLDEP) $(OCAMLLIBS) "$<" $(redir_if_ok) + +$(addsuffix .d,$(MLLIBFILES)): %.mllib.d: %.mllib + $(SHOW)'OCAMLLIBDEP $<' + $(HIDE)$(OCAMLLIBDEP) -c $(OCAMLLIBS) "$<" $(redir_if_ok) + +$(addsuffix .d,$(MLPACKFILES)): %.mlpack.d: %.mlpack + $(SHOW)'OCAMLLIBDEP $<' + $(HIDE)$(OCAMLLIBDEP) -c $(OCAMLLIBS) "$<" $(redir_if_ok) + +# If this makefile is created using a _CoqProject we have coqdep get +# options from it. This avoids argument length limits for pathological +# projects. Note that extra options might be on the command line. +VDFILE_FLAGS:=$(if _CoqProject,-f _CoqProject,) $(CMDLINE_COQLIBS) $(CMDLINE_VFILES) + +$(VDFILE): _CoqProject $(VFILES) + $(SHOW)'COQDEP VFILES' + $(HIDE)$(COQDEP) $(if $(strip $(METAFILE)),-m "$(METAFILE)") -vos -dyndep var $(VDFILE_FLAGS) $(redir_if_ok) + +# Misc ######################################################################## + +byte: + $(HIDE)$(MAKE) all "OPT:=-byte" -f "$(SELF)" +.PHONY: byte + +opt: + $(HIDE)$(MAKE) all "OPT:=-opt" -f "$(SELF)" +.PHONY: opt + +# This is deprecated. To extend this makefile use +# extension points and Makefile.local +printenv:: + $(warning printenv is deprecated) + $(warning write extensions in Makefile.local or include Makefile.conf) + @echo 'COQLIB = $(COQLIB)' + @echo 'COQCORELIB = $(COQCORELIB)' + @echo 'DOCDIR = $(DOCDIR)' + @echo 'OCAMLFIND = $(OCAMLFIND)' + @echo 'HASNATDYNLINK = $(HASNATDYNLINK)' + @echo 'SRC_SUBDIRS = $(SRC_SUBDIRS)' + @echo 'COQ_SRC_SUBDIRS = $(COQ_SRC_SUBDIRS)' + @echo 'COQCORE_SRC_SUBDIRS = $(COQCORE_SRC_SUBDIRS)' + @echo 'OCAMLFIND = $(OCAMLFIND)' + @echo 'PP = $(PP)' + @echo 'COQFLAGS = $(COQFLAGS)' + @echo 'COQLIB = $(COQLIBS)' + @echo 'COQLIBINSTALL = $(COQLIBINSTALL)' + @echo 'COQDOCINSTALL = $(COQDOCINSTALL)' +.PHONY: printenv + +# Generate a .merlin file. If you need to append directives to this +# file you can extend the merlin-hook target in Makefile.local +.merlin: + $(SHOW)'FILL .merlin' + $(HIDE)echo 'FLG $(COQMF_CAMLFLAGS)' > .merlin + $(HIDE)echo 'B $(COQCORELIB)' >> .merlin + $(HIDE)echo 'S $(COQCORELIB)' >> .merlin + $(HIDE)$(foreach d,$(COQCORE_SRC_SUBDIRS), \ + echo 'B $(COQCORELIB)$(d)' >> .merlin;) + $(HIDE)$(foreach d,$(COQ_SRC_SUBDIRS), \ + echo 'S $(COQLIB)$(d)' >> .merlin;) + $(HIDE)$(foreach d,$(SRC_SUBDIRS), echo 'B $(d)' >> .merlin;) + $(HIDE)$(foreach d,$(SRC_SUBDIRS), echo 'S $(d)' >> .merlin;) + $(HIDE)$(MAKE) merlin-hook -f "$(SELF)" +.PHONY: merlin + +merlin-hook:: + @# Extension point +.PHONY: merlin-hook + +# prints all variables +debug: + $(foreach v,\ + $(sort $(filter-out $(INITIAL_VARS) INITIAL_VARS,\ + $(.VARIABLES))),\ + $(info $(v) = $($(v)))) +.PHONY: debug + +.DEFAULT_GOAL := all + +# Users can create Makefile.local-late to hook into double-colon rules +# or add other needed Makefile code, using defined +# variables if necessary. +-include Makefile.local-late + +# Local Variables: +# mode: makefile-gmake +# End: diff --git a/examples/coq-example/proofs/coq/extraction/dummy_core_lib.v b/examples/coq-example/proofs/coq/extraction/dummy_core_lib.v new file mode 100644 index 000000000..e95813f30 --- /dev/null +++ b/examples/coq-example/proofs/coq/extraction/dummy_core_lib.v @@ -0,0 +1,34 @@ +From Coq Require Import ZArith. +Require Import List. +Import List.ListNotations. +Open Scope Z_scope. + +(* LIBRARY CODE *) +Definition t_isize := Z. +Notation "'t_Vec' T '((t_Global))'" := (list T). +Definition impl_1__push {A} (l : list A) (a : A) : list A := cons a l. +Definition impl_1__pop {A} (l : list A) : list A * option A := + match l with + | [] => ([], None) + | (x :: xs) => (xs, Some x) + end. +Definition impl__unwrap {A} (x : option A) `{H : x <> None} : A := + match x as k return k <> None -> _ with + | None => fun H => False_rect _ (H eq_refl) + | Some a => fun _ => a + end H. +Definition t_Add_f_add := (fun x y => x + y). +Definition t_Mul_f_mul := (fun x y => x * y). +Definition t_PartialEq_f_eq := (fun x y => x =? y). +Definition impl__isize__rem_euclid := fun x y => x mod y. +Definition cast := fun (x : Z) => x. +Definition ne := fun x y => negb (x =? y). +Definition impl_1__len {A} (l : list A) := Z.of_nat (List.length l). +Definition t_PartialOrd_f_lt := fun x y => x x - y. +Definition impl__new {A} (tt : unit) : list A := []. +Definition f_fold {A B} (l : list A) (i : B) (f : B -> A -> B) : B := List.fold_left f l i. +Definition f_into_iter {A} := @id A. +(* /LIBRARY CODE *) diff --git a/examples/coq-example/src/dummy_core_lib.rs b/examples/coq-example/src/dummy_core_lib.rs new file mode 100644 index 000000000..e69de29bb diff --git a/examples/coq-example/src/lib.rs b/examples/coq-example/src/lib.rs index 93b5b8443..1b1fdaa41 100644 --- a/examples/coq-example/src/lib.rs +++ b/examples/coq-example/src/lib.rs @@ -1,3 +1,6 @@ +mod dummy_core_lib; +use dummy_core_lib::*; + enum Instruction { Push(isize), Pop, From 0c7e455d1b17e366e21165079384f926eb198572 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Thu, 31 Oct 2024 18:16:45 +0100 Subject: [PATCH 243/253] fmt --- examples/coq-example/src/dummy_core_lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/coq-example/src/dummy_core_lib.rs b/examples/coq-example/src/dummy_core_lib.rs index e69de29bb..8b1378917 100644 --- a/examples/coq-example/src/dummy_core_lib.rs +++ b/examples/coq-example/src/dummy_core_lib.rs @@ -0,0 +1 @@ + From 12ee0fece3f281d58c2ed8c047ca4366239d8cfd Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Thu, 31 Oct 2024 18:18:29 +0100 Subject: [PATCH 244/253] Cargo --- examples/Cargo.lock | 9 ++++++++- examples/Cargo.toml | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index d2b20070e..af90ddc48 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "anyhow" @@ -144,6 +144,13 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "coq-example" +version = "0.1.0" +dependencies = [ + "hax-lib", +] + [[package]] name = "cpufeatures" version = "0.2.11" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index a5b3a521b..2c18893ce 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,8 +5,8 @@ members = [ "sha256", "barrett", "kyber_compress", - "proverif-psk" -, "coq-example"] + "proverif-psk", + "coq-example"] resolver = "2" [workspace.dependencies] From 1e18265aafb576fdbb7a277d0508ef608978b5dd Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 18:43:24 +0100 Subject: [PATCH 245/253] Update .utils/rust-by-example.js Co-authored-by: Franziskus Kiefer --- .utils/rust-by-example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.utils/rust-by-example.js b/.utils/rust-by-example.js index 848693a22..753254c7a 100644 --- a/.utils/rust-by-example.js +++ b/.utils/rust-by-example.js @@ -1,4 +1,4 @@ -// This script expect Rust By Example to be in current directory +// This script expects Rust By Example to be in current directory const fs = require('fs'); const SRC_DIR = 'src'; From 2524d85cae239aa683cbf51120a868bbb749e8e6 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 18:45:30 +0100 Subject: [PATCH 246/253] Update rust-by-example.js --- .utils/rust-by-example.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.utils/rust-by-example.js b/.utils/rust-by-example.js index 753254c7a..4e3fcff8f 100644 --- a/.utils/rust-by-example.js +++ b/.utils/rust-by-example.js @@ -1,4 +1,5 @@ // This script expects Rust By Example to be in current directory +// (clone the repo https://github.com/rust-lang/rust-by-example) const fs = require('fs'); const SRC_DIR = 'src'; From f3f59876ef039820ca2d344bb7870a0c1f9cf612 Mon Sep 17 00:00:00 2001 From: Lucas Franceschino Date: Thu, 31 Oct 2024 18:46:49 +0100 Subject: [PATCH 247/253] Update rust-by-example.js --- .utils/rust-by-example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.utils/rust-by-example.js b/.utils/rust-by-example.js index 4e3fcff8f..1dd0c6f70 100644 --- a/.utils/rust-by-example.js +++ b/.utils/rust-by-example.js @@ -1,5 +1,5 @@ // This script expects Rust By Example to be in current directory -// (clone the repo https://github.com/rust-lang/rust-by-example) +// (clone the repo https://github.com/rust-lang/rust-by-example, `cd` into it, and run `node rust-by-examples.js`) const fs = require('fs'); const SRC_DIR = 'src'; From 0e6ce983913b774269353d8ab1c0f3293327b262 Mon Sep 17 00:00:00 2001 From: Lasse Letager Hansen Date: Fri, 1 Nov 2024 13:25:50 +0100 Subject: [PATCH 248/253] Update examples/coq-example/Cargo.toml Co-authored-by: Franziskus Kiefer --- examples/coq-example/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/coq-example/Cargo.toml b/examples/coq-example/Cargo.toml index 2a2f6d1aa..45c3973f8 100644 --- a/examples/coq-example/Cargo.toml +++ b/examples/coq-example/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -hax-lib = {path = "../../hax-lib" } \ No newline at end of file +hax-lib = {path = "../../hax-lib" } From f98d902ec8d3eedc92975283115e7a02425b34e8 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Mon, 4 Nov 2024 14:23:25 +0100 Subject: [PATCH 249/253] Fix ml-kem ci job. --- .github/workflows/mlkem.yml | 60 +++++-------------------------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/.github/workflows/mlkem.yml b/.github/workflows/mlkem.yml index 267e1e9e5..0d59ce119 100644 --- a/.github/workflows/mlkem.yml +++ b/.github/workflows/mlkem.yml @@ -40,61 +40,15 @@ jobs: with: repository: hacl-star/hacl-star path: hacl-star - - - name: 🏃 Extract the Kyber reference code - run: | - eval $(opam env) - (cd proofs/fstar/extraction/ && ./clean.sh) - rm -f sys/platform/proofs/fstar/extraction/*.fst* - ./hax-driver.py --kyber-reference - - - name: 🏃 Regenerate `extraction-*` folders - run: ./proofs/fstar/patches.sh apply - - - name: 🏃 Make sure snapshots are up-to-date - run: git diff --exit-code - - - name: 🏃 Verify the Kyber reference code + - name: 🏃 Extract ML-KEM crate + working-directory: libcrux-ml-kem + run: ./hax.py extract + + - name: 🏃 Lax ML-KEM crate + working-directory: libcrux-ml-kem run: | env FSTAR_HOME=${{ github.workspace }}/fstar \ HACL_HOME=${{ github.workspace }}/hacl-star \ HAX_HOME=${{ github.workspace }}/hax \ PATH="${PATH}:${{ github.workspace }}/fstar/bin" \ - ./hax-driver.py --verify-extraction - - - name: 🏃 Verify Kyber `extraction-edited` F* code - run: | - env FSTAR_HOME=${{ github.workspace }}/fstar \ - HACL_HOME=${{ github.workspace }}/hacl-star \ - HAX_HOME=${{ github.workspace }}/hax \ - PATH="${PATH}:${{ github.workspace }}/fstar/bin" \ - make -C proofs/fstar/extraction-edited - - - name: 🏃 Verify Kyber `extraction-secret-independent` F* code - run: | - env FSTAR_HOME=${{ github.workspace }}/fstar \ - HACL_HOME=${{ github.workspace }}/hacl-star \ - HAX_HOME=${{ github.workspace }}/hax \ - PATH="${PATH}:${{ github.workspace }}/fstar/bin" \ - make -C proofs/fstar/extraction-secret-independent - - - name: 🏃 Extract the Kyber specification - run: | - eval $(opam env) - # Extract the functions in the compress module individually to test - # the function-extraction code. - # Extract functions from the remaining modules to test the - # module-extraction code. - ./hax-driver.py --crate-path specs/kyber \ - --functions hacspec_kyber::compress::compress \ - hacspec_kyber::compress::decompress \ - hacspec_kyber::compress::compress_d \ - hacspec::kyber::compress::decompress_d \ - --modules ind_cpa \ - hacspec_kyber \ - matrix \ - ntt \ - parameters \ - sampling \ - serialize \ - --exclude-modules libcrux::hacl::sha3 libcrux::digest + ./hax.py prove --admit From 3eee30e946ea68d317cd9e21cc3b661569a6b25e Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 5 Nov 2024 11:20:54 +0100 Subject: [PATCH 250/253] Fix spans in error reporting with unicode characters. --- hax-types/src/diagnostics/report.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hax-types/src/diagnostics/report.rs b/hax-types/src/diagnostics/report.rs index cf84959b6..a60c08f48 100644 --- a/hax-types/src/diagnostics/report.rs +++ b/hax-types/src/diagnostics/report.rs @@ -12,10 +12,10 @@ pub struct ReportCtx { /// Translates a line and column position into an absolute offset fn compute_offset(src: &str, mut line: usize, col: usize) -> usize { - let mut chars = src.chars().enumerate(); + let mut chars = src.bytes().enumerate(); while line > 1 { while let Some((_offset, ch)) = chars.next() { - if ch == '\n' { + if ch == b'\n' { break; } } @@ -28,7 +28,7 @@ fn compute_offset(src: &str, mut line: usize, col: usize) -> usize { .unwrap_or(0); let are_col_first_chars_blank = chars .take(col) - .all(|(_offset, ch)| matches!(ch, ' ' | '\t')); + .all(|(_offset, ch)| matches!(ch, b' ' | b'\t')); if are_col_first_chars_blank { offset } else { From ccff2d9ba31e8fd5e4e94b8228b287d518d1059d Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 5 Nov 2024 13:23:30 +0100 Subject: [PATCH 251/253] Use miette for offset computation. --- Cargo.lock | 26 +++++++++++++++++++++++++- hax-types/Cargo.toml | 1 + hax-types/src/diagnostics/report.rs | 26 +++----------------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c46631bc2..5daeaf35d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -604,6 +604,7 @@ dependencies = [ "hax-frontend-exporter", "hax-frontend-exporter-options", "itertools", + "miette", "path-clean", "schemars", "serde", @@ -851,6 +852,29 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miette" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" +dependencies = [ + "cfg-if", + "miette-derive", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "mio" version = "0.8.11" diff --git a/hax-types/Cargo.toml b/hax-types/Cargo.toml index 52d2c981e..caeba72f6 100644 --- a/hax-types/Cargo.toml +++ b/hax-types/Cargo.toml @@ -24,6 +24,7 @@ hax-adt-into.workspace = true tracing.workspace = true serde-brief ={ version = "*", features = ["std", "alloc"]} zstd = "0.13.1" +miette = "7.2.0" [features] rustc = ["hax-frontend-exporter/rustc"] diff --git a/hax-types/src/diagnostics/report.rs b/hax-types/src/diagnostics/report.rs index a60c08f48..e1cc96ef5 100644 --- a/hax-types/src/diagnostics/report.rs +++ b/hax-types/src/diagnostics/report.rs @@ -1,5 +1,6 @@ use super::Diagnostics; use annotate_snippets::*; +use miette::SourceOffset; use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -11,29 +12,8 @@ pub struct ReportCtx { } /// Translates a line and column position into an absolute offset -fn compute_offset(src: &str, mut line: usize, col: usize) -> usize { - let mut chars = src.bytes().enumerate(); - while line > 1 { - while let Some((_offset, ch)) = chars.next() { - if ch == b'\n' { - break; - } - } - line -= 1; - } - let offset = chars - .clone() - .next() - .map(|(offset, _ch)| offset) - .unwrap_or(0); - let are_col_first_chars_blank = chars - .take(col) - .all(|(_offset, ch)| matches!(ch, b' ' | b'\t')); - if are_col_first_chars_blank { - offset - } else { - offset + col - } +fn compute_offset(src: &str, line: usize, col: usize) -> usize { + SourceOffset::from_location(src, line, col).offset() + 1 } impl ReportCtx { From 28d8ffd55c9ae3da7756d198f1d209c398bc25c6 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 5 Nov 2024 15:15:09 +0100 Subject: [PATCH 252/253] Drop return/break/continue inside closures. --- .../phase_drop_return_break_continue.ml | 15 +- .../toolchain__side-effects into-fstar.snap | 119 ++++++++------ .../toolchain__side-effects into-ssprove.snap | 145 +++++++++++------- tests/side-effects/src/lib.rs | 6 + 4 files changed, 182 insertions(+), 103 deletions(-) diff --git a/engine/lib/phases/phase_drop_return_break_continue.ml b/engine/lib/phases/phase_drop_return_break_continue.ml index 3be7e8b1f..937bfeb69 100644 --- a/engine/lib/phases/phase_drop_return_break_continue.ml +++ b/engine/lib/phases/phase_drop_return_break_continue.ml @@ -118,6 +118,18 @@ module%inlined_contents Make (F : Features.T) = struct in exit nodes. **) end + let closure_visitor = + let module Visitors = Ast_visitors.Make (F) in + object + inherit [_] Visitors.map as super + + method! visit_expr' () e = + match e with + | Closure ({ body; _ } as closure) -> + Closure { closure with body = visitor#visit_expr None body } + | _ -> super#visit_expr' () e + end + [%%inline_defs dmutability + dsafety_kind] let rec dexpr' (span : span) (expr : A.expr') : B.expr' = @@ -157,7 +169,8 @@ module%inlined_contents Make (F : Features.T) = struct [%%inline_defs "Item.*" - ditems] let ditems (items : A.item list) : B.item list = - List.concat_map items ~f:(visitor#visit_item None >> ditem) + List.concat_map items + ~f:(visitor#visit_item None >> closure_visitor#visit_item () >> ditem) end include Implem diff --git a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap index e03cc7117..a2038278d 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-fstar.snap @@ -58,6 +58,27 @@ let f (x: u8) : Core.Result.t_Result u16 u16 = <: Core.Result.t_Result u16 u16 ''' +"Side_effects.Issue_1089_.fst" = ''' +module Side_effects.Issue_1089_ +#set-options "--fuel 0 --ifuel 1 --z3rlimit 15" +open Core +open FStar.Mul + +let test (x y: Core.Option.t_Option i32) : Core.Option.t_Option i32 = + match + Core.Option.impl__map #i32 + #(Core.Option.t_Option i32) + x + (fun i -> + let i:i32 = i in + match y with + | Core.Option.Option_Some hoist1 -> + Core.Option.Option_Some (i +! hoist1 <: i32) <: Core.Option.t_Option i32 + | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option i32) + with + | Core.Option.Option_Some some -> some + | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option i32 +''' "Side_effects.fst" = ''' module Side_effects #set-options "--fuel 0 --ifuel 1 --z3rlimit 15" @@ -185,7 +206,7 @@ let direct_result_question_mark (y: Core.Result.t_Result Prims.unit u32) let direct_result_question_mark_coercion (y: Core.Result.t_Result i8 u16) : Core.Result.t_Result i8 u32 = match y with - | Core.Result.Result_Ok hoist1 -> Core.Result.Result_Ok hoist1 <: Core.Result.t_Result i8 u32 + | Core.Result.Result_Ok hoist5 -> Core.Result.Result_Ok hoist5 <: Core.Result.t_Result i8 u32 | Core.Result.Result_Err err -> Core.Result.Result_Err (Core.Convert.f_from #u32 #u16 #FStar.Tactics.Typeclasses.solve err) <: @@ -201,12 +222,12 @@ let early_returns (x: u32) : u32 = match true with | true -> 34ul | _ -> - let x, hoist5:(u32 & u32) = x, 3ul <: (u32 & u32) in - Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul hoist5 <: u32) x + let x, hoist9:(u32 & u32) = x, 3ul <: (u32 & u32) in + Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul hoist9 <: u32) x else let x:u32 = x +! 9ul in - let x, hoist5:(u32 & u32) = x, x +! 1ul <: (u32 & u32) in - Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul hoist5 <: u32) x + let x, hoist9:(u32 & u32) = x, x +! 1ul <: (u32 & u32) in + Core.Num.impl__u32__wrapping_add (Core.Num.impl__u32__wrapping_add 123ul hoist9 <: u32) x /// Exercise local mutation with control flow and loops let local_mutation (x: u32) : u32 = @@ -234,7 +255,7 @@ let local_mutation (x: u32) : u32 = in Core.Num.impl__u32__wrapping_add x y else - let (x, y), hoist15:((u32 & u32) & u32) = + let (x, y), hoist19:((u32 & u32) & u32) = match x with | 12ul -> let y:u32 = Core.Num.impl__u32__wrapping_add x y in @@ -246,7 +267,7 @@ let local_mutation (x: u32) : u32 = ((u32 & u32) & u32) | _ -> (x, y <: (u32 & u32)), 0ul <: ((u32 & u32) & u32) in - let x:u32 = hoist15 in + let x:u32 = hoist19 in Core.Num.impl__u32__wrapping_add x y /// Combine `?` and early return @@ -254,39 +275,39 @@ let monad_lifting (x: u8) : Core.Result.t_Result t_A t_B = if x >. 123uy then match Core.Result.Result_Err (B <: t_B) <: Core.Result.t_Result t_A t_B with - | Core.Result.Result_Ok hoist16 -> Core.Result.Result_Ok hoist16 <: Core.Result.t_Result t_A t_B + | Core.Result.Result_Ok hoist20 -> Core.Result.Result_Ok hoist20 <: Core.Result.t_Result t_A t_B | Core.Result.Result_Err err -> Core.Result.Result_Err err <: Core.Result.t_Result t_A t_B else Core.Result.Result_Ok (A <: t_A) <: Core.Result.t_Result t_A t_B /// Test question mark on `Option`s with some control flow let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core.Option.t_Option u8 = match x with - | Core.Option.Option_Some hoist22 -> - if hoist22 >. 10uy + | Core.Option.Option_Some hoist26 -> + if hoist26 >. 10uy then match x with - | Core.Option.Option_Some hoist24 -> + | Core.Option.Option_Some hoist28 -> (match - Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist24 3uy) + Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist28 3uy) <: Core.Option.t_Option u8 with - | Core.Option.Option_Some hoist30 -> - (match hoist30 with + | Core.Option.Option_Some hoist34 -> + (match hoist34 with | 3uy -> (match Core.Option.Option_None <: Core.Option.t_Option u8 with | Core.Option.Option_Some some -> let v:u8 = some in (match x with - | Core.Option.Option_Some hoist31 -> + | Core.Option.Option_Some hoist35 -> (match y with - | Core.Option.Option_Some hoist32 -> + | Core.Option.Option_Some hoist36 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist31 + hoist35 <: u8) - hoist32) + hoist36) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -296,18 +317,18 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option u8) | 4uy -> (match z with - | Core.Option.Option_Some hoist19 -> - let v:u8 = 4uy +! (if hoist19 >. 4uL <: bool then 0uy else 3uy) in + | Core.Option.Option_Some hoist23 -> + let v:u8 = 4uy +! (if hoist23 >. 4uL <: bool then 0uy else 3uy) in (match x with - | Core.Option.Option_Some hoist31 -> + | Core.Option.Option_Some hoist35 -> (match y with - | Core.Option.Option_Some hoist32 -> + | Core.Option.Option_Some hoist36 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist31 + hoist35 <: u8) - hoist32) + hoist36) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -318,14 +339,14 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | _ -> let v:u8 = 12uy in match x with - | Core.Option.Option_Some hoist31 -> + | Core.Option.Option_Some hoist35 -> (match y with - | Core.Option.Option_Some hoist32 -> + | Core.Option.Option_Some hoist36 -> Core.Option.Option_Some - (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v hoist31 + (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v hoist35 <: u8) - hoist32) + hoist36) <: Core.Option.t_Option u8 | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option u8 @@ -335,30 +356,30 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option u8 else (match x with - | Core.Option.Option_Some hoist27 -> + | Core.Option.Option_Some hoist31 -> (match y with - | Core.Option.Option_Some hoist26 -> + | Core.Option.Option_Some hoist30 -> (match - Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist27 hoist26) + Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add hoist31 hoist30) <: Core.Option.t_Option u8 with - | Core.Option.Option_Some hoist30 -> - (match hoist30 with + | Core.Option.Option_Some hoist34 -> + (match hoist34 with | 3uy -> (match Core.Option.Option_None <: Core.Option.t_Option u8 with | Core.Option.Option_Some some -> let v:u8 = some in (match x with - | Core.Option.Option_Some hoist31 -> + | Core.Option.Option_Some hoist35 -> (match y with - | Core.Option.Option_Some hoist32 -> + | Core.Option.Option_Some hoist36 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist31 + hoist35 <: u8) - hoist32) + hoist36) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -369,18 +390,18 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. Core.Option.Option_None <: Core.Option.t_Option u8) | 4uy -> (match z with - | Core.Option.Option_Some hoist19 -> - let v:u8 = 4uy +! (if hoist19 >. 4uL <: bool then 0uy else 3uy) in + | Core.Option.Option_Some hoist23 -> + let v:u8 = 4uy +! (if hoist23 >. 4uL <: bool then 0uy else 3uy) in (match x with - | Core.Option.Option_Some hoist31 -> + | Core.Option.Option_Some hoist35 -> (match y with - | Core.Option.Option_Some hoist32 -> + | Core.Option.Option_Some hoist36 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist31 + hoist35 <: u8) - hoist32) + hoist36) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -392,15 +413,15 @@ let options (x y: Core.Option.t_Option u8) (z: Core.Option.t_Option u64) : Core. | _ -> let v:u8 = 12uy in match x with - | Core.Option.Option_Some hoist31 -> + | Core.Option.Option_Some hoist35 -> (match y with - | Core.Option.Option_Some hoist32 -> + | Core.Option.Option_Some hoist36 -> Core.Option.Option_Some (Core.Num.impl__u8__wrapping_add (Core.Num.impl__u8__wrapping_add v - hoist31 + hoist35 <: u8) - hoist32) + hoist36) <: Core.Option.t_Option u8 | Core.Option.Option_None -> @@ -440,8 +461,8 @@ let simplifiable_question_mark (c: bool) (x: Core.Option.t_Option i32) : Core.Op if c then match x with - | Core.Option.Option_Some hoist36 -> - let a:i32 = hoist36 +! 10l in + | Core.Option.Option_Some hoist40 -> + let a:i32 = hoist40 +! 10l in let b:i32 = 20l in Core.Option.Option_Some (a +! b) <: Core.Option.t_Option i32 | Core.Option.Option_None -> Core.Option.Option_None <: Core.Option.t_Option i32 diff --git a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap index 80a576172..2f2304adb 100644 --- a/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap +++ b/test-harness/src/snapshots/toolchain__side-effects into-ssprove.snap @@ -128,6 +128,8 @@ Notation "'Build_t_Foo' '[' x ']' '(' 'f_bar' ':=' y ')'" := (Build_t_Foo (f_x : (*Not implemented yet? todo(item)*) +(*Not implemented yet? todo(item)*) + Equations add3 {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I1 : Interface} {I2 : Interface} {I3 : Interface} (x : both L1 I1 int32) (y : both L2 I2 int32) (z : both L3 I3 int32) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) int32 := add3 x y z := solve_lift (impl__u32__wrapping_add (impl__u32__wrapping_add x y) z) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) int32. @@ -151,31 +153,31 @@ Fail Next Obligation. Equations direct_result_question_mark_coercion {L1 : {fset Location}} {I1 : Interface} (y : both L1 I1 (t_Result int8 int16)) : both L1 I1 (t_Result int8 int32) := direct_result_question_mark_coercion y := - solve_lift (run (letm[choice_typeMonad.result_bind_code int32] hoist1 := impl__map_err y f_from in - Result_Ok (Result_Ok hoist1))) : both L1 I1 (t_Result int8 int32). + solve_lift (run (letm[choice_typeMonad.result_bind_code int32] hoist5 := impl__map_err y f_from in + Result_Ok (Result_Ok hoist5))) : both L1 I1 (t_Result int8 int32). Fail Next Obligation. Equations early_returns {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int32) : both L1 I1 int32 := early_returns x := solve_lift (run (letm[choice_typeMonad.result_bind_code int32] _ := ifb x >.? (ret_both (3 : int32)) - then letm[choice_typeMonad.result_bind_code int32] hoist2 := ControlFlow_Break (ret_both (0 : int32)) in - ControlFlow_Continue (never_to_any hoist2) + then letm[choice_typeMonad.result_bind_code int32] hoist6 := ControlFlow_Break (ret_both (0 : int32)) in + ControlFlow_Continue (never_to_any hoist6) else () in - letb hoist3 := x >.? (ret_both (30 : int32)) in - letm[choice_typeMonad.result_bind_code int32] hoist5 := ifb hoist3 + letb hoist7 := x >.? (ret_both (30 : int32)) in + letm[choice_typeMonad.result_bind_code int32] hoist9 := ifb hoist7 then matchb ret_both (true : 'bool) with | true => - letm[choice_typeMonad.result_bind_code int32] hoist4 := ControlFlow_Break (ret_both (34 : int32)) in - ControlFlow_Continue (solve_lift (never_to_any hoist4)) + letm[choice_typeMonad.result_bind_code int32] hoist8 := ControlFlow_Break (ret_both (34 : int32)) in + ControlFlow_Continue (solve_lift (never_to_any hoist8)) | _ => ControlFlow_Continue (solve_lift (ret_both (3 : int32))) end else ControlFlow_Continue (letb _ := assign todo(term) in x .+ (ret_both (1 : int32))) in - letb hoist6 := impl__u32__wrapping_add (ret_both (123 : int32)) hoist5 in - letb hoist7 := impl__u32__wrapping_add hoist6 x in - letm[choice_typeMonad.result_bind_code int32] hoist8 := ControlFlow_Break hoist7 in - ControlFlow_Continue (never_to_any hoist8))) : both L1 I1 int32. + letb hoist10 := impl__u32__wrapping_add (ret_both (123 : int32)) hoist9 in + letb hoist11 := impl__u32__wrapping_add hoist10 x in + letm[choice_typeMonad.result_bind_code int32] hoist12 := ControlFlow_Break hoist11 in + ControlFlow_Continue (never_to_any hoist12))) : both L1 I1 int32. Fail Next Obligation. Definition y_loc : Location := @@ -186,27 +188,27 @@ Equations local_mutation {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 local_mutation x := letb y loc(y_loc) := ret_both (0 : int32) in letb _ := assign todo(term) in - letb hoist9 := x >.? (ret_both (3 : int32)) in - solve_lift (ifb hoist9 + letb hoist13 := x >.? (ret_both (3 : int32)) in + solve_lift (ifb hoist13 then letb _ := assign todo(term) in letb y loc(y_loc) := x ./ (ret_both (2 : int32)) in letb _ := assign todo(term) in - letb hoist10 := ret_both (0 : int32) in - letb hoist11 := Build_t_Range (f_start := hoist10) (f_end := ret_both (10 : int32)) in - letb hoist12 := f_into_iter hoist11 in - letb _ := foldi_both_list hoist12 (fun i => + letb hoist14 := ret_both (0 : int32) in + letb hoist15 := Build_t_Range (f_start := hoist14) (f_end := ret_both (10 : int32)) in + letb hoist16 := f_into_iter hoist15 in + letb _ := foldi_both_list hoist16 (fun i => ssp (fun _ => assign todo(term) : (both (*0*)(L1:|:fset []) (I1) 'unit))) (ret_both (tt : 'unit)) in impl__u32__wrapping_add x y - else letb hoist15 := matchb x with + else letb hoist19 := matchb x with | 12 => letb _ := assign todo(term) in solve_lift (ret_both (3 : int32)) | 13 => - letb hoist14 := x in + letb hoist18 := x in letb _ := assign todo(term) in - letb hoist13 := impl__u32__wrapping_add (ret_both (123 : int32)) x in - solve_lift (add3 hoist14 hoist13 x) + letb hoist17 := impl__u32__wrapping_add (ret_both (123 : int32)) x in + solve_lift (add3 hoist18 hoist17 x) | _ => solve_lift (ret_both (0 : int32)) end in @@ -217,44 +219,44 @@ Fail Next Obligation. Equations monad_lifting {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int8) : both L1 I1 (t_Result t_A t_B) := monad_lifting x := solve_lift (run (ifb x >.? (ret_both (123 : int8)) - then letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist16 := ControlFlow_Continue (Result_Err B) in - letb hoist17 := Result_Ok hoist16 in - letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist18 := ControlFlow_Break hoist17 in - ControlFlow_Continue (never_to_any hoist18) + then letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist20 := ControlFlow_Continue (Result_Err B) in + letb hoist21 := Result_Ok hoist20 in + letm[choice_typeMonad.result_bind_code (t_Result t_A t_B)] hoist22 := ControlFlow_Break hoist21 in + ControlFlow_Continue (never_to_any hoist22) else ControlFlow_Continue (Result_Ok A))) : both L1 I1 (t_Result t_A t_B). Fail Next Obligation. Equations options {L1 : {fset Location}} {L2 : {fset Location}} {L3 : {fset Location}} {I1 : Interface} {I2 : Interface} {I3 : Interface} (x : both L1 I1 (t_Option int8)) (y : both L2 I2 (t_Option int8)) (z : both L3 I3 (t_Option int64)) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) (t_Option int8) := options x y z := - solve_lift (run (letm[choice_typeMonad.option_bind_code] hoist22 := x in - letb hoist23 := hoist22 >.? (ret_both (10 : int8)) in - letm[choice_typeMonad.option_bind_code] hoist29 := ifb hoist23 - then letm[choice_typeMonad.option_bind_code] hoist24 := x in - Option_Some (letb hoist25 := impl__u8__wrapping_add hoist24 (ret_both (3 : int8)) in - Option_Some hoist25) - else letm[choice_typeMonad.option_bind_code] hoist27 := x in - letm[choice_typeMonad.option_bind_code] hoist26 := y in - Option_Some (letb hoist28 := impl__u8__wrapping_add hoist27 hoist26 in - Option_Some hoist28) in - letm[choice_typeMonad.option_bind_code] hoist30 := hoist29 in - letm[choice_typeMonad.option_bind_code] v := matchb hoist30 with + solve_lift (run (letm[choice_typeMonad.option_bind_code] hoist26 := x in + letb hoist27 := hoist26 >.? (ret_both (10 : int8)) in + letm[choice_typeMonad.option_bind_code] hoist33 := ifb hoist27 + then letm[choice_typeMonad.option_bind_code] hoist28 := x in + Option_Some (letb hoist29 := impl__u8__wrapping_add hoist28 (ret_both (3 : int8)) in + Option_Some hoist29) + else letm[choice_typeMonad.option_bind_code] hoist31 := x in + letm[choice_typeMonad.option_bind_code] hoist30 := y in + Option_Some (letb hoist32 := impl__u8__wrapping_add hoist31 hoist30 in + Option_Some hoist32) in + letm[choice_typeMonad.option_bind_code] hoist34 := hoist33 in + letm[choice_typeMonad.option_bind_code] v := matchb hoist34 with | 3 => Option_None | 4 => - letm[choice_typeMonad.option_bind_code] hoist19 := z in - Option_Some (letb hoist20 := hoist19 >.? (ret_both (4 : int64)) in - letb hoist21 := ifb hoist20 + letm[choice_typeMonad.option_bind_code] hoist23 := z in + Option_Some (letb hoist24 := hoist23 >.? (ret_both (4 : int64)) in + letb hoist25 := ifb hoist24 then ret_both (0 : int8) else ret_both (3 : int8) in - solve_lift ((ret_both (4 : int8)) .+ hoist21)) + solve_lift ((ret_both (4 : int8)) .+ hoist25)) | _ => Option_Some (solve_lift (ret_both (12 : int8))) end in - letm[choice_typeMonad.option_bind_code] hoist31 := x in - letb hoist33 := impl__u8__wrapping_add v hoist31 in - letm[choice_typeMonad.option_bind_code] hoist32 := y in - Option_Some (letb hoist34 := impl__u8__wrapping_add hoist33 hoist32 in - Option_Some hoist34))) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) (t_Option int8). + letm[choice_typeMonad.option_bind_code] hoist35 := x in + letb hoist37 := impl__u8__wrapping_add v hoist35 in + letm[choice_typeMonad.option_bind_code] hoist36 := y in + Option_Some (letb hoist38 := impl__u8__wrapping_add hoist37 hoist36 in + Option_Some hoist38))) : both (L1 :|: L2 :|: L3) (I1 :|: I2 :|: I3) (t_Option int8). Fail Next Obligation. Definition y_loc : Location := @@ -266,8 +268,8 @@ Equations question_mark {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 letb _ := assign todo(term) in letb _ := assign todo(term) in letb _ := assign todo(term) in - letb hoist35 := x >.? (ret_both (90 : int32)) in - ifb hoist35 + letb hoist39 := x >.? (ret_both (90 : int32)) in + ifb hoist39 then impl__map_err (Result_Err (ret_both (12 : int8))) f_from else () else () in @@ -277,8 +279,8 @@ Fail Next Obligation. Equations simplifiable_question_mark {L1 : {fset Location}} {L2 : {fset Location}} {I1 : Interface} {I2 : Interface} (c : both L1 I1 'bool) (x : both L2 I2 (t_Option int32)) : both (L1 :|: L2) (I1 :|: I2) (t_Option int32) := simplifiable_question_mark c x := solve_lift (run (letm[choice_typeMonad.option_bind_code] a := ifb c - then letm[choice_typeMonad.option_bind_code] hoist36 := x in - Option_Some (hoist36 .+ (ret_both (10 : int32))) + then letm[choice_typeMonad.option_bind_code] hoist40 := x in + Option_Some (hoist40 .+ (ret_both (10 : int32))) else Option_Some (ret_both (0 : int32)) in Option_Some (letb b := ret_both (20 : int32) in Option_Some (a .+ b)))) : both (L1 :|: L2) (I1 :|: I2) (t_Option int32). @@ -293,8 +295,8 @@ Equations simplifiable_return {L1 : {fset Location}} {L2 : {fset Location}} {L3 then letm[choice_typeMonad.result_bind_code int32] _ := ifb c2 then letb _ := assign todo(term) in ifb c3 - then letm[choice_typeMonad.result_bind_code int32] hoist37 := ControlFlow_Break (ret_both (1 : int32)) in - ControlFlow_Continue (never_to_any hoist37) + then letm[choice_typeMonad.result_bind_code int32] hoist41 := ControlFlow_Break (ret_both (1 : int32)) in + ControlFlow_Continue (never_to_any hoist41) else () else () in ControlFlow_Continue (letb _ := assign todo(term) in @@ -349,3 +351,40 @@ Equations f {L1 : {fset Location}} {I1 : Interface} (x : both L1 I1 int8) : both Result_Ok (Result_Ok (f_my_from x)))) : both L1 I1 (t_Result int16 int16). Fail Next Obligation. ''' +"Side_effects_Issue_1089_.v" = ''' +(* File automatically generated by Hacspec *) +Set Warnings "-notation-overridden,-ambiguous-paths". +From Crypt Require Import choice_type Package Prelude. +Import PackageNotation. +From extructures Require Import ord fset. +From mathcomp Require Import word_ssrZ word. +From Jasmin Require Import word. + +From Coq Require Import ZArith. +From Coq Require Import Strings.String. +Import List.ListNotations. +Open Scope list_scope. +Open Scope Z_scope. +Open Scope bool_scope. + +From Hacspec Require Import ChoiceEquality. +From Hacspec Require Import LocationUtility. +From Hacspec Require Import Hacspec_Lib_Comparable. +From Hacspec Require Import Hacspec_Lib_Pre. +From Hacspec Require Import Hacspec_Lib. + +Open Scope hacspec_scope. +Import choice.Choice.Exports. + +Obligation Tactic := (* try timeout 8 *) solve_ssprove_obligations. + +Equations test {L1 : {fset Location}} {L2 : {fset Location}} {I1 : Interface} {I2 : Interface} (x : both L1 I1 (t_Option int32)) (y : both L2 I2 (t_Option int32)) : both (L1 :|: L2) (I1 :|: I2) (t_Option int32) := + test x y := + solve_lift (run (letb hoist3 := fun i => + letm[choice_typeMonad.option_bind_code] hoist1 := y in + Option_Some (letb hoist2 := i .+ hoist1 in + Option_Some hoist2) in + letb hoist4 := impl__map x hoist3 in + hoist4)) : both (L1 :|: L2) (I1 :|: I2) (t_Option int32). +Fail Next Obligation. +''' diff --git a/tests/side-effects/src/lib.rs b/tests/side-effects/src/lib.rs index c7db53f22..6c8f45a19 100644 --- a/tests/side-effects/src/lib.rs +++ b/tests/side-effects/src/lib.rs @@ -173,3 +173,9 @@ mod issue_1083 { Ok(u16::my_from(x)) } } + +mod issue_1089 { + fn test(x: Option, y: Option) -> Option { + x.map(|i| Some(i + y?))? + } +} From f5146b0955286bca05895c966bb53367b0c06083 Mon Sep 17 00:00:00 2001 From: Maxime Buyse Date: Tue, 5 Nov 2024 17:31:20 +0100 Subject: [PATCH 253/253] Fix deprecated attribute for compatibility with ocaml 5.2. --- engine/lib/backend.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/lib/backend.ml b/engine/lib/backend.ml index 0dfb6ea26..9836708bf 100644 --- a/engine/lib/backend.ml +++ b/engine/lib/backend.ml @@ -71,6 +71,9 @@ module Make (InputLanguage : Features.T) (M : BackendMetadata) = struct end module Attrs = Attr_payloads.Make (InputLanguage) (Error) + [@@ocaml.deprecated + "Use more precise errors: Error.unimplemented, Error.assertion_failure or \ + a raw Error.t (with Error.raise)"] let failwith ?(span = Span.default) msg = Error.unimplemented @@ -78,7 +81,4 @@ module Make (InputLanguage : Features.T) (M : BackendMetadata) = struct ("[TODO: this error uses failwith, and thus leads to bad error \ messages, please update it using [Diagnostics.*] helpers] " ^ msg) span - [@@ocaml.deprecated - "Use more precise errors: Error.unimplemented, Error.assertion_failure \ - or a raw Error.t (with Error.raise)"] end
    + + + + + + + + + + + + + + + + + + + +
    + +
    + {{> header}} + + + + {{#if search_enabled}} + + {{/if}} + + + + +
    +
    + {{{ content }}} +
    + + +
    +
    + + + +
    + + {{#if live_reload_endpoint}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playground_line_numbers}} + + {{/if}} + + {{#if playground_copyable}} + + {{/if}} + + {{#if playground_js}} + + + + + + {{/if}} + + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + +