Skip to content

Commit

Permalink
doc(engine): add docstrings on span.ml
Browse files Browse the repository at this point in the history
  • Loading branch information
W95Psp committed Nov 12, 2024
1 parent 4291b19 commit a04f5ff
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 16 deletions.
29 changes: 28 additions & 1 deletion cli/subcommands/src/cargo_hax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use hax_types::driver_api::*;
use hax_types::engine_api::*;
use is_terminal::IsTerminal;
use serde_jsonlines::BufReadExt;
use std::collections::HashMap;
use std::fs;
use std::io::BufRead;
use std::io::Write;
Expand Down Expand Up @@ -188,7 +189,7 @@ impl HaxMessage {
format!("{}.{}", n / factor, n % factor)
}
let title = format!(
"[profiling] {}: {}ms, memory={}, {} item{}{}",
"hax[profiling]: {}: {}ms, memory={}, {} item{}{}",
data.context,
format_with_dot(6, data.time_ns),
data.memory,
Expand All @@ -202,6 +203,17 @@ impl HaxMessage {
);
eprintln!("{}", renderer.render(Level::Info.title(&title)));
}
Self::Stats { errors_per_item } => {
let success_items = errors_per_item.iter().filter(|(_, n)| *n == 0).count();
let total = errors_per_item.len();
let title = format!(
"hax: {}/{} items were successfully translated ({}% success rate)",
success_items,
total,
(success_items * 100) / total
);
eprintln!("{}", renderer.render(Level::Info.title(&title)));
}
Self::CargoBuildFailure => {
let title =
"hax: running `cargo build` was not successful, continuing anyway.".to_string();
Expand Down Expand Up @@ -285,6 +297,7 @@ fn run_engine(
});

let stdout = std::io::BufReader::new(engine_subprocess.stdout.take().unwrap());
let mut errors_per_item: HashMap<_, usize> = HashMap::new();
for msg in stdout.json_lines() {
let msg = msg.expect(
"Hax engine sent an invalid json value. \
Expand All @@ -299,6 +312,9 @@ fn run_engine(
if backend.dry_run {
output.diagnostics.push(diagnostic.clone())
}
if let Some(owner_id) = &diagnostic.owner_id {
*errors_per_item.entry(owner_id.clone()).or_default() += 1;
}
HaxMessage::Diagnostic {
diagnostic,
working_dir: working_dir.clone(),
Expand Down Expand Up @@ -339,11 +355,22 @@ fn run_engine(
FromEngine::ProfilingData(profiling_data) => {
HaxMessage::ProfilingData(profiling_data).report(message_format, None)
}
FromEngine::ItemProcessed(items) => {
for item in items {
errors_per_item.insert(item, 0);
}
}
FromEngine::Ping => {
send!(&ToEngine::Pong);
}
}
}
if backend.stats {
HaxMessage::Stats {
errors_per_item: errors_per_item.into_iter().collect(),
}
.report(message_format, None)
}
drop(stdin);
}

Expand Down
2 changes: 2 additions & 0 deletions engine/bin/lib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ let import_thir_items (include_clauses : Types.inclusion_clause list)
match Attrs.status i.attrs with Included _ -> true | _ -> false)
items
in
Hax_io.write
(ItemProcessed (List.filter_map ~f:(fun i -> Span.owner_hint i.span) items));
let items = Deps.sort items in
(* Extract error reports for the items we actually extract *)
let reports =
Expand Down
26 changes: 21 additions & 5 deletions engine/lib/diagnostics.ml
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,26 @@ type thir_span = T.span [@@deriving show, eq]
let compare_thir_span (a : thir_span) (b : thir_span) =
[%compare: string] ([%show: thir_span] a) ([%show: thir_span] b)

type t = { context : Context.t; kind : kind; span : thir_span list }
type thir_def_id = T.def_id [@@deriving show, eq]

let compare_thir_def_id (a : thir_def_id) (b : thir_def_id) =
[%compare: string] ([%show: thir_def_id] a) ([%show: thir_def_id] b)

type t = {
context : Context.t;
kind : kind;
span : thir_span list;
owner_id : thir_def_id option;
}
[@@deriving show, eq, compare]

let to_thir_diagnostic (d : t) : Types.diagnostics =
{ kind = d.kind; context = Context.display d.context; span = d.span }
{
kind = d.kind;
context = Context.display d.context;
span = d.span;
owner_id = d.owner_id;
}

(** Ask `cargo-hax` to pretty print a diagnostic *)
let ask_diagnostic_pretty_print diag : string =
Expand All @@ -86,7 +101,7 @@ let pretty_print : t -> string =
let pretty_print_context_kind : Context.t -> kind -> string =
fun context kind ->
let span = Span.to_thir (Span.dummy ()) in
pretty_print { context; kind; span }
pretty_print { context; kind; span; owner_id = None }

module Core : sig
val raise_fatal_error : 'never. t -> 'never
Expand Down Expand Up @@ -122,7 +137,8 @@ end
include Core

let failure ~context ~span kind =
Core.raise_fatal_error { context; kind; span = Span.to_thir span }
Core.raise_fatal_error
{ context; kind; span = Span.to_thir span; owner_id = Span.owner_hint span }

module SpanFreeError : sig
type t = private Data of Context.t * kind [@@deriving show]
Expand All @@ -142,6 +158,6 @@ end = struct
raise (Exn (Data (ctx, kind)))

let raise ?(span = []) (ctx : Context.t) (kind : kind) =
report { span; kind; context = ctx };
report { span; kind; context = ctx; owner_id = None };
raise_without_reporting ctx kind
end
4 changes: 3 additions & 1 deletion engine/lib/import_thir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1441,7 +1441,9 @@ let cast_of_enum typ_name generics typ thir_span
{ v; span; ident; attrs = [] }

let rec c_item ~ident ~drop_body (item : Thir.item) : item list =
try c_item_unwrapped ~ident ~drop_body item
try
Span.with_owner_hint item.owner_id (fun _ ->
c_item_unwrapped ~ident ~drop_body item)
with Diagnostics.SpanFreeError.Exn payload ->
let context, kind = Diagnostics.SpanFreeError.payload payload in
let error = Diagnostics.pretty_print_context_kind context kind in
Expand Down
1 change: 1 addition & 0 deletions engine/lib/print_rust.ml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ module Raw = struct
ident";
};
span = Span.to_thir span;
owner_id = Span.owner_hint span;
};
"print_rust_last_of_global_ident_error"

Expand Down
55 changes: 49 additions & 6 deletions engine/lib/span.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,69 @@ module Imported = struct
"<" ^ file ^ " " ^ display_loc s.lo ^ "" ^ display_loc s.hi ^ ">"
end

type t = { id : int; data : Imported.span list }
(* open struct *)
(* module DefId = struct *)
(* include Types *)
(* let def_id_of_yojson = Types.parse_def_id *)
(* let yojson_of_def_id = failwith "todo" *)
(* end *)
(* end *)

type owner_id = OwnerId of int
[@@deriving show, yojson, sexp, compare, eq, hash]

let display { id = _; data } =
let owner_id_list = ref []

let fresh_owner_id (owner : Types.def_id) : owner_id =
let next_id = OwnerId (List.length !owner_id_list) in
owner_id_list := owner :: !owner_id_list;
next_id

(** This state changes the behavior of `of_thir`: the hint placed into
this state will be inserted automatically by `of_thir`. The field
`owner_hint` shall be used solely for reporting to the user, not for
any logic within the engine. *)
let state_owner_hint : owner_id option ref = ref None

let with_owner_hint (type t) (owner : Types.def_id) (f : unit -> t) : t =
let previous = !state_owner_hint in
state_owner_hint := Some (fresh_owner_id owner);
let result = f () in
state_owner_hint := previous;
result

type t = { id : int; data : Imported.span list; owner_hint : owner_id option }
[@@deriving show, yojson, sexp, compare, eq, hash]

let display { id = _; data; _ } =
match data with
| [] -> "<dummy>"
| [ span ] -> Imported.display_span span
| spans -> List.map ~f:Imported.display_span spans |> String.concat ~sep:""

let of_thir span =
{ data = [ Imported.span_of_thir span ]; id = FreshId.make () }
{
data = [ Imported.span_of_thir span ];
id = FreshId.make ();
owner_hint = !state_owner_hint;
}

let to_thir { data; _ } = List.map ~f:Imported.span_to_thir data

let union_list spans =
let data = List.concat_map ~f:(fun { data; _ } -> data) spans in
{ data; id = FreshId.make () }
let owner_hint = List.hd spans |> Option.bind ~f:(fun s -> s.owner_hint) in
{ data; id = FreshId.make (); owner_hint }

let union x y = union_list [ x; y ]
let dummy () = { id = FreshId.make (); data = [] }

let dummy () =
{ id = FreshId.make (); data = []; owner_hint = !state_owner_hint }

let id_of { id; _ } = id
let refresh_id span = { span with id = FreshId.make () }
let default = { id = 0; data = [] }
let default = { id = 0; data = []; owner_hint = None }

let owner_hint span =
span.owner_hint
|> Option.bind ~f:(fun (OwnerId id) -> List.nth !owner_id_list id)
23 changes: 22 additions & 1 deletion engine/lib/span.mli
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
(* type loc [@@deriving show, yojson, sexp, compare, eq, hash] *)
type t [@@deriving show, yojson, sexp, compare, eq, hash]

val display : t -> string

(** Imports a THIR span as a hax span *)
val of_thir : Types.span -> t
(** Exports a hax span to THIR spans (a hax span might be a collection of spans) *)
val to_thir : t -> Types.span list

val union_list : t list -> t
val union : t -> t -> t

(** Generates a dummy span: this should be avoided at all cost. *)
val dummy : unit -> t
(** Lookup the internal unique identifier of a span. *)
val id_of : t -> int
(** Replaces the internal identifier by a fresh one. This can be useful for debugging. *)
val refresh_id : t -> t

(** A default span can be useful when a span is required in some
computation that never reports error and when we know the span will go
away. Using this should be avoided. *)
val default : t

(** Inserts a hint about the fact that, in function `f`, we're
translating spans that are "owned" by an item `owner`. This should be
used only in `import_thir`, also, the hint shall be used only to
enhance user reporting, not for any logic within the engine. *)
val with_owner_hint : Types.def_id -> (unit -> 't) -> 't

(** Looks up the owner hint for a span. This should be used for user
reports only. *)
val owner_hint: t -> Types.def_id option
10 changes: 8 additions & 2 deletions hax-types/src/cli_options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,14 @@ pub struct BackendOptions<E: Extension> {
#[arg(short, long, action = clap::ArgAction::Count)]
pub verbose: u8,

/// Enables profiling for the engine
#[arg(short, long)]
/// Prints statistics about how many items have been translated
/// successfully by the engine.
#[arg(long)]
pub stats: bool,

/// Enables profiling for the engine: for each phase of the
/// engine, time and memory usage are recorded and reported.
#[arg(long)]
pub profile: bool,

/// Enable engine debugging: dumps the AST at each phase.
Expand Down
3 changes: 3 additions & 0 deletions hax-types/src/diagnostics/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub enum HaxMessage {
backend: Backend<()>,
} = 4,
ProfilingData(crate::engine_api::ProfilingData) = 5,
Stats {
errors_per_item: Vec<(hax_frontend_exporter::DefId, usize)>,
} = 6,
}

impl HaxMessage {
Expand Down
1 change: 1 addition & 0 deletions hax-types/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct Diagnostics {
pub kind: Kind,
pub span: Vec<hax_frontend_exporter::Span>,
pub context: String,
pub owner_id: Option<hax_frontend_exporter::DefId>,
}

impl std::fmt::Display for Diagnostics {
Expand Down
3 changes: 3 additions & 0 deletions hax-types/src/engine_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub struct ProfilingData {

pub mod protocol {
use super::*;

#[derive_group(Serializers)]
#[derive(JsonSchema, Debug, Clone)]
pub enum FromEngine {
Expand All @@ -88,6 +89,8 @@ pub mod protocol {
PrettyPrintRust(String),
DebugString(String),
ProfilingData(ProfilingData),
/// Declares a list of items that will be processed by the engine
ItemProcessed(Vec<hax_frontend_exporter::DefId>),
Exit,
Ping,
}
Expand Down

0 comments on commit a04f5ff

Please sign in to comment.