diff --git a/Cargo.lock b/Cargo.lock index b9969e02..f16fe3b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -522,12 +522,14 @@ dependencies = [ "ascent", "clap", "console", + "env_logger", "guppy", "ignore", "insta", "iter_tools", "lazy-regex", "libc", + "log", "pretty_assertions", "ramhorns", "rstest", @@ -800,6 +802,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1138,6 +1153,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "http-types-red-badger-temporary-fork" version = "2.12.0" @@ -1158,6 +1179,12 @@ dependencies = [ "url", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -1403,6 +1430,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -2405,6 +2443,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "termtree" version = "0.4.1" diff --git a/crux_cli/Cargo.toml b/crux_cli/Cargo.toml index 3f89940d..50f10c37 100644 --- a/crux_cli/Cargo.toml +++ b/crux_cli/Cargo.toml @@ -18,11 +18,13 @@ anyhow.workspace = true ascent = "0.7.0" clap = { version = "4.4.18", features = ["derive"] } console = "0.15.8" +env_logger = "0.10.2" guppy = "0.17.4" ignore = "0.4.23" iter_tools = "0.24.0" lazy-regex = "3.3.0" libc = "0.2.167" +log = "0.4.22" ramhorns = "1.0.1" rustdoc-json = "0.9.3" rustdoc-types = "0.33.0" diff --git a/crux_cli/src/codegen/filter.rs b/crux_cli/src/codegen/filter.rs index 48f25daa..80fbb886 100644 --- a/crux_cli/src/codegen/filter.rs +++ b/crux_cli/src/codegen/filter.rs @@ -1,9 +1,12 @@ use ascent::ascent; +use log::info; use rustdoc_types::Crate; +use super::item::*; use super::node::{CrateNode, ItemNode, SummaryNode}; ascent! { + #![measure_rule_times] pub struct Filter; // ------- facts ------------------ @@ -13,37 +16,33 @@ ascent! { // ------- rules ------------------ - // this is an optimization to reduce the number of nodes we need to consider - relation subset(ItemNode); - subset(a) <-- item(a), if a.is_subset(); - relation has_summary(ItemNode, SummaryNode); - has_summary(n, s) <-- subset(n), summary(s), if n.has_summary(s); + has_summary(n, s) <-- item(n), summary(s), if n.has_summary(s); relation is_struct(ItemNode); - is_struct(s) <-- subset(s), if s.is_struct(); + is_struct(s) <-- item(s), if is_struct(&s.item); relation is_enum(ItemNode); - is_enum(e) <-- subset(e), if e.is_enum(); + is_enum(e) <-- item(e), if is_enum(&e.item); relation variant(ItemNode, ItemNode); - variant(e, v) <-- is_enum(e), subset(v), if e.has_variant(v); + variant(e, v) <-- is_enum(e), item(v), if e.has_variant(v); relation field(ItemNode, ItemNode); - field(s, f) <-- is_struct(s), subset(f), if s.has_field(f); - field(v, f) <-- variant(e, v), subset(f), if v.has_field(f); + field(s, f) <-- is_struct(s), item(f), if s.has_field(f); + field(v, f) <-- variant(e, v), item(f), if v.has_field(f); relation local_type_of(ItemNode, ItemNode); - local_type_of(f, t) <-- subset(f), subset(t), if f.is_of_local_type(t); + local_type_of(f, t) <-- item(f), item(t), if f.is_of_local_type(t); relation remote_type_of(ItemNode, SummaryNode); - remote_type_of(f, t) <-- subset(f), summary(t), if f.is_of_remote_type(t); + remote_type_of(f, t) <-- item(f), summary(t), if f.is_of_remote_type(t); // app structs have an implementation of the App trait relation app(ItemNode, ItemNode); app(imp, app) <-- is_struct(app), - subset(imp), + item(imp), if imp.is_impl_for(app, "App"); // app hierarchy @@ -79,7 +78,7 @@ ascent! { effect(app, effect_ffi) <-- root_app(app_impl, app), is_enum(effect), - subset(effect_impl), + item(effect_impl), if effect_impl.is_impl_for(effect, "Effect"), has_summary(app, app_summary), has_summary(effect, effect_summary), @@ -90,8 +89,8 @@ ascent! { // Capability is a struct/enum with an implementation of the Capability trait relation capability(ItemNode, ItemNode); capability(cap, cap_impl) <-- - subset(cap), - subset(cap_impl), + item(cap), + item(cap_impl), if cap_impl.is_impl_for(cap, "Capability"); // Operation is an associated type of an impl of the Capability trait @@ -105,7 +104,7 @@ ascent! { relation output(ItemNode); output(out) <-- operation(op), - subset(op_impl), + item(op_impl), if op_impl.is_impl_for(op, "Operation"), local_type_of(item, out), if op_impl.has_associated_item(item, "Output"); @@ -123,7 +122,7 @@ ascent! { // roots that are unit structs edge(root, root) <-- root(root), - is_struct(root), if root.is_struct_unit(); + is_struct(root), if is_struct_unit(&root.item); // roots that have fields edge(root, field) <-- root(root), @@ -156,7 +155,7 @@ ascent! { impl Filter { pub fn update(&mut self, crate_name: &str, crate_: &Crate) { - println!("Updating filter for {}", crate_name); + info!("Updating filter for {}", crate_name); self.summary = crate_ .paths .iter() @@ -171,7 +170,13 @@ impl Filter { self.item = crate_ .index .values() - .map(|item| (ItemNode::new(crate_name.to_string(), item.clone()),)) + .filter_map(|item| { + if is_relevant(item) { + Some((ItemNode::new(crate_name.to_string(), item.clone()),)) + } else { + None + } + }) .collect::>(); self.ext_crate = crate_ .external_crates diff --git a/crux_cli/src/codegen/formatter.rs b/crux_cli/src/codegen/formatter.rs index e0cece41..e349d500 100644 --- a/crux_cli/src/codegen/formatter.rs +++ b/crux_cli/src/codegen/formatter.rs @@ -1,18 +1,20 @@ use std::collections::BTreeMap; use ascent::ascent; -use rustdoc_types::{GenericArg, GenericArgs, Item, ItemEnum, Type, Variant, VariantKind}; +use rustdoc_types::{GenericArg, GenericArgs, Item, ItemEnum, Type}; use crate::codegen::collect; use super::{ indexed::Indexed, + item::*, node::ItemNode, serde::case::RenameRule, serde_generate::format::{ContainerFormat, Format, Named, VariantFormat}, }; ascent! { + #![measure_rule_times] pub struct Formatter; // ------- facts ------------------ @@ -21,13 +23,13 @@ ascent! { // ------- rules ------------------ relation struct_unit(ItemNode); - struct_unit(s) <-- edge(s, _), if s.is_struct_unit(); + struct_unit(s) <-- edge(s, _), if is_struct_unit(&s.item); relation struct_plain(ItemNode); - struct_plain(s) <-- edge(s, _), if s.is_struct_plain(); + struct_plain(s) <-- edge(s, _), if is_struct_plain(&s.item); relation struct_tuple(ItemNode); - struct_tuple(s) <-- edge(s, _), if s.is_struct_tuple(); + struct_tuple(s) <-- edge(s, _), if is_struct_tuple(&s.item); relation field(ItemNode, ItemNode); field(x, f) <-- edge(x, f), if x.has_field(f); @@ -48,13 +50,13 @@ ascent! { let variants = e.variants(vs); relation variant_plain(ItemNode, ItemNode); - variant_plain(e, v) <-- variant(e, v), if is_plain_variant(&v); + variant_plain(e, v) <-- variant(e, v), if is_plain_variant(&v.item); relation variant_tuple(ItemNode, ItemNode); - variant_tuple(e, v) <-- variant(e, v), if is_tuple_variant(&v); + variant_tuple(e, v) <-- variant(e, v), if is_tuple_variant(&v.item); relation variant_struct(ItemNode, ItemNode); - variant_struct(e, v) <-- variant(e, v), if is_struct_variant(&v); + variant_struct(e, v) <-- variant(e, v), if is_struct_variant(&v.item); relation format(ItemNode, Indexed); format(x, format) <-- @@ -162,45 +164,6 @@ fn make_named_format( } } -fn is_plain_variant(variant: &ItemNode) -> bool { - matches!( - &variant.item, - Item { - inner: ItemEnum::Variant(Variant { - kind: VariantKind::Plain, - .. - }), - .. - } - ) -} - -fn is_struct_variant(variant: &ItemNode) -> bool { - matches!( - &variant.item, - Item { - inner: ItemEnum::Variant(Variant { - kind: VariantKind::Struct { .. }, - .. - }), - .. - } - ) -} - -fn is_tuple_variant(variant: &ItemNode) -> bool { - matches!( - &variant.item, - Item { - inner: ItemEnum::Variant(Variant { - kind: VariantKind::Tuple(_), - .. - }), - .. - } - ) -} - fn make_plain_variant_format( variant: &ItemNode, all_variants: &Vec, diff --git a/crux_cli/src/codegen/item.rs b/crux_cli/src/codegen/item.rs new file mode 100644 index 00000000..579b5108 --- /dev/null +++ b/crux_cli/src/codegen/item.rs @@ -0,0 +1,259 @@ +use iter_tools::Itertools; +use rustdoc_types::{ + Enum, Id, Impl, Item, ItemEnum, Path, Struct, StructKind, Type, Variant, VariantKind, +}; + +pub fn is_relevant(item: &Item) -> bool { + is_impl(item) + || is_struct_field(item) + || is_enum_variant(item) + || is_struct(item) + || is_enum(item) + || is_associated_type(item) +} + +pub fn is_struct(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Struct(_), + .. + } + ) +} + +pub fn is_struct_unit(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Struct(Struct { + kind: StructKind::Unit, + .. + }), + .. + } + ) +} + +pub fn is_struct_plain(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Struct(Struct { + kind: StructKind::Plain { .. }, + .. + }), + .. + } + ) +} + +pub fn is_struct_tuple(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Struct(Struct { + kind: StructKind::Tuple(_), + .. + }), + .. + } + ) +} + +pub fn has_field(item: &Item, field: &Item) -> bool { + match item { + Item { + inner: ItemEnum::Struct(Struct { kind, .. }), + .. + } => match kind { + StructKind::Unit => false, + StructKind::Tuple(fields) => fields.contains(&Some(field.id)), + StructKind::Plain { + fields, + has_stripped_fields: _, + } => fields.contains(&field.id), + }, + Item { + inner: ItemEnum::Variant(Variant { kind, .. }), + .. + } => match kind { + VariantKind::Plain => false, + VariantKind::Tuple(fields) => fields.contains(&Some(field.id)), + VariantKind::Struct { fields, .. } => fields.contains(&field.id), + }, + _ => false, + } +} + +pub fn field_ids(item: &Item) -> Vec { + match item { + Item { + inner: ItemEnum::Struct(Struct { kind, .. }), + .. + } => match kind { + StructKind::Plain { fields, .. } => fields.to_vec(), + StructKind::Tuple(fields) => fields + .iter() + .filter_map(|f| f.as_ref()) + .cloned() + .collect_vec(), + StructKind::Unit => vec![], + }, + Item { + inner: ItemEnum::Variant(Variant { kind, .. }), + .. + } => match kind { + VariantKind::Plain => vec![], + VariantKind::Tuple(fields) => fields + .iter() + .filter_map(|f| f.as_ref()) + .cloned() + .collect_vec(), + VariantKind::Struct { fields, .. } => fields.to_vec(), + }, + _ => vec![], + } +} + +fn is_struct_field(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::StructField(_), + .. + } + ) +} + +pub fn is_enum(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Enum(_), + .. + } + ) +} + +fn is_enum_variant(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Variant(_), + .. + } + ) +} + +pub fn has_variant(item: &Item, variant: &Item) -> bool { + match item { + Item { + inner: ItemEnum::Enum(Enum { variants, .. }), + .. + } => variants.contains(&variant.id), + _ => false, + } +} + +pub fn variant_ids(item: &Item) -> Vec { + match item { + Item { + inner: ItemEnum::Enum(Enum { variants, .. }), + .. + } => variants.to_vec(), + _ => vec![], + } +} + +pub fn is_plain_variant(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Variant(Variant { + kind: VariantKind::Plain, + .. + }), + .. + } + ) +} + +pub fn is_struct_variant(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Variant(Variant { + kind: VariantKind::Struct { .. }, + .. + }), + .. + } + ) +} + +pub fn is_tuple_variant(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Variant(Variant { + kind: VariantKind::Tuple(_), + .. + }), + .. + } + ) +} + +pub fn is_impl(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::Impl(Impl { + trait_: Some(Path { name, .. }), + .. + }), + .. + } if (&["App", "Effect", "Capability", "Operation"]).contains(&name.as_str()) + ) +} + +pub fn is_impl_for(item: &Item, for_: &Item, trait_name: &str) -> bool { + match item { + Item { + inner: + ItemEnum::Impl(Impl { + trait_: Some(Path { name, .. }), + for_: Type::ResolvedPath(Path { id, .. }), + .. + }), + .. + } if name == trait_name && id == &for_.id => true, + _ => false, + } +} + +fn is_associated_type(item: &Item) -> bool { + matches!( + item, + Item { + inner: ItemEnum::AssocType { .. }, + .. + } + ) +} + +pub fn has_associated_item(item: &Item, associated_item: &Item, with_name: &str) -> bool { + match item { + Item { + inner: ItemEnum::Impl(Impl { items, .. }), + .. + } => match &associated_item { + Item { + name: Some(name), .. + } if with_name == name => items.contains(&associated_item.id), + _ => false, + }, + _ => false, + } +} diff --git a/crux_cli/src/codegen/mod.rs b/crux_cli/src/codegen/mod.rs index a9168f1f..87ba7af2 100644 --- a/crux_cli/src/codegen/mod.rs +++ b/crux_cli/src/codegen/mod.rs @@ -1,6 +1,7 @@ mod filter; mod formatter; mod indexed; +mod item; mod node; mod serde; mod serde_generate; @@ -15,6 +16,7 @@ use std::{ use anyhow::{anyhow, bail, Result}; use guppy::{graph::PackageGraph, MetadataCommand}; +use log::{debug, info}; use rustdoc_types::Crate; use crate::args::CodegenArgs; @@ -40,7 +42,7 @@ pub fn codegen(args: &CodegenArgs) -> Result<()> { let registry = run(lib.name(), |name| load_crate(&name, &manifest_paths))?; - println!("{:#?}", registry); + info!("{:#?}", registry); Ok(()) } @@ -56,13 +58,13 @@ where let mut filter = Filter::default(); filter.update(crate_name, &shared_lib); filter.run(); + debug!("{}", filter.scc_times_summary()); previous.insert(crate_name.to_string(), shared_lib); let mut next: Vec = filter.get_crates(); - while !next.is_empty() { - let crate_name = next.pop().unwrap(); + while let Some(crate_name) = next.pop() { if previous.contains_key(&crate_name) { continue; } @@ -70,6 +72,7 @@ where filter.update(&crate_name, &crate_); filter.run(); + debug!("{}", filter.scc_times_summary()); // std::fs::write("edge.json", serde_json::to_string_pretty(&filter.edge)?)?; next = filter.get_crates(); @@ -83,6 +86,7 @@ fn format(edges: Vec<(ItemNode, ItemNode)>) -> Registry { let mut formatter = Formatter::default(); formatter.edge = edges; formatter.run(); + debug!("{}", formatter.scc_times_summary()); formatter.container.into_iter().collect() } @@ -103,7 +107,7 @@ fn load_crate(name: &str, manifest_paths: &BTreeMap<&str, &str>) -> Result bool { - // from most likely to least likely - self.is_impl() - || self.is_struct_field() - || self.is_enum_variant() - || self.is_struct() - || self.is_enum() - || self.is_associated_type() - } - - fn is_impl(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Impl(Impl { - trait_: Some(Path { name, .. }), - .. - }), - .. - } if (&["App", "Effect", "Capability", "Operation"]).contains(&name.as_str()) - ) - } - - fn is_associated_type(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::AssocType { .. }, - .. - } - ) - } - - fn is_struct_field(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::StructField(_), - .. - } - ) - } - - fn is_enum_variant(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Variant(_), - .. - } - ) - } - pub fn has_summary(&self, summary: &SummaryNode) -> bool { self.id == summary.id } - pub fn is_struct(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Struct(_), - .. - } - ) - } - - pub fn is_struct_unit(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Struct(Struct { - kind: StructKind::Unit, - .. - }), - .. - } - ) - } - - pub fn is_struct_plain(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Struct(Struct { - kind: StructKind::Plain { .. }, - .. - }), - .. - } - ) - } - - pub fn is_struct_tuple(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Struct(Struct { - kind: StructKind::Tuple(_), - .. - }), - .. - } - ) - } - - pub fn is_enum(&self) -> bool { - matches!( - &self.item, - Item { - inner: ItemEnum::Enum(_), - .. - } - ) - } - pub fn is_impl_for(&self, for_: &ItemNode, trait_name: &str) -> bool { if self.id.crate_ != for_.id.crate_ { return false; } - match &self.item { - Item { - inner: - ItemEnum::Impl(Impl { - trait_: Some(Path { name, .. }), - for_: Type::ResolvedPath(Path { id, .. }), - .. - }), - .. - } if name == trait_name && id == &for_.item.id => true, - _ => false, - } + + is_impl_for(&self.item, &for_.item, trait_name) } pub fn is_range(&self) -> bool { @@ -281,35 +160,12 @@ impl ItemNode { } pub fn fields(&self, fields: Vec<(&ItemNode,)>) -> Vec { - let field_ids = match &self.item { - Item { - inner: ItemEnum::Struct(Struct { kind, .. }), - .. - } => match kind { - StructKind::Plain { fields, .. } => fields.to_vec(), - StructKind::Tuple(fields) => { - fields.iter().filter_map(|f| f.as_ref()).cloned().collect() - } - StructKind::Unit => vec![], - }, - Item { - inner: ItemEnum::Variant(Variant { kind, .. }), - .. - } => match kind { - VariantKind::Plain => vec![], - VariantKind::Tuple(fields) => { - fields.iter().filter_map(|f| f.as_ref()).cloned().collect() - } - VariantKind::Struct { fields, .. } => fields.to_vec(), - }, - _ => vec![], - }; - field_ids + field_ids(&self.item) .iter() .filter_map(|id| { match fields .iter() - .find(|(f,)| !f.should_skip() && f.item.id == *id) + .find(|(f,)| !f.should_skip() && id == &f.item.id) { Some(found) => Some(found.0.clone()), None => None, @@ -322,50 +178,20 @@ impl ItemNode { if self.id.crate_ != field.id.crate_ || field.should_skip() { return false; } - - match &self.item { - Item { - inner: ItemEnum::Struct(Struct { kind, .. }), - .. - } => { - if field.name() == Some("__private_field") { - return false; - } - match kind { - StructKind::Unit => false, - StructKind::Tuple(fields) => fields.contains(&Some(field.item.id)), - StructKind::Plain { - fields, - has_stripped_fields: _, - } => fields.contains(&field.item.id), - } - } - Item { - inner: ItemEnum::Variant(Variant { kind, .. }), - .. - } => match kind { - VariantKind::Plain => false, - VariantKind::Tuple(fields) => fields.contains(&Some(field.item.id)), - VariantKind::Struct { fields, .. } => fields.contains(&field.item.id), - }, - _ => false, + if field.name() == Some("__private_field") { + return false; } + + has_field(&self.item, &field.item) } pub fn variants(&self, variants: Vec<(&ItemNode,)>) -> Vec { - let variant_ids = match &self.item { - Item { - inner: ItemEnum::Enum(Enum { variants, .. }), - .. - } => variants.to_vec(), - _ => vec![], - }; - variant_ids + variant_ids(&self.item) .iter() .filter_map(|id| { match variants .iter() - .find(|(v,)| !v.should_skip() && v.item.id == *id) + .find(|(v,)| !v.should_skip() && id == &v.item.id) { Some(found) => Some(found.0.clone()), None => None, @@ -379,13 +205,7 @@ impl ItemNode { return false; } - match &self.item { - Item { - inner: ItemEnum::Enum(Enum { variants, .. }), - .. - } => variants.contains(&variant.item.id), - _ => false, - } + has_variant(&self.item, &variant.item) } pub fn is_of_local_type(&self, type_node: &ItemNode) -> bool { @@ -400,6 +220,7 @@ impl ItemNode { if self.id.crate_ != id.crate_ { return false; } + match &self.item { Item { inner: ItemEnum::StructField(t), @@ -418,18 +239,11 @@ impl ItemNode { } pub fn has_associated_item(&self, associated_item: &ItemNode, with_name: &str) -> bool { - match &self.item { - Item { - inner: ItemEnum::Impl(Impl { items, .. }), - .. - } => match &associated_item.item { - Item { - name: Some(name), .. - } if with_name == name => items.contains(&associated_item.item.id), - _ => false, - }, - _ => false, + if self.id.crate_ != associated_item.id.crate_ { + return false; } + + has_associated_item(&self.item, &associated_item.item, with_name) } } diff --git a/crux_cli/src/codegen/tests.rs b/crux_cli/src/codegen/tests.rs index b084ce72..e04f67ab 100644 --- a/crux_cli/src/codegen/tests.rs +++ b/crux_cli/src/codegen/tests.rs @@ -65,7 +65,7 @@ fn load_expected(name: &str) -> Result { #[case::notes("notes")] #[case::simple_counter("simple_counter")] #[case::tap_to_pay("tap_to_pay")] -#[ignore = "not yet fully implemented"] +// #[ignore = "not yet fully implemented"] fn full(#[case] example: &str) { let actual = super::run(example, load_rustdoc).unwrap(); let expected: Registry = load_expected(example).expect("should deserialize"); diff --git a/crux_cli/src/main.rs b/crux_cli/src/main.rs index ad14581f..52857f8b 100644 --- a/crux_cli/src/main.rs +++ b/crux_cli/src/main.rs @@ -14,6 +14,8 @@ mod workspace; #[tokio::main] async fn main() -> Result<()> { + env_logger::init(); + let cli = Cli::parse(); match &cli.command { Some(Commands::Doctor(DoctorArgs {