diff --git a/Cargo.lock b/Cargo.lock index e51feff..472cf1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,7 @@ checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "argus-cli" -version = "0.1.17" +version = "0.1.18" dependencies = [ "anyhow", "argus-ext", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "argus-ext" -version = "0.1.17" +version = "0.1.18" dependencies = [ "anyhow", "itertools", @@ -104,7 +104,7 @@ dependencies = [ [[package]] name = "argus-lib" -version = "0.1.17" +version = "0.1.18" dependencies = [ "anyhow", "argus-ext", @@ -129,7 +129,7 @@ dependencies = [ [[package]] name = "argus-ser" -version = "0.1.17" +version = "0.1.18" dependencies = [ "anyhow", "argus-ext", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "argus-ser-macros" -version = "0.1.17" +version = "0.1.18" dependencies = [ "proc-macro2", "quote", diff --git a/crates/argus-cli/Cargo.toml b/crates/argus-cli/Cargo.toml index 0b6403c..0797e9e 100644 --- a/crates/argus-cli/Cargo.toml +++ b/crates/argus-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "argus-cli" -version = "0.1.17" +version = "0.1.18" edition = "2021" authors = ["Gavin Gray "] repository = "https://github.com/cognitive-engineering-lab/argus" @@ -10,8 +10,8 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -argus-lib = { version = "0.1.17", path = "../argus" } -argus-ext = { version = "0.1.17", path = "../argus-ext" } +argus-lib = { version = "0.1.18", path = "../argus" } +argus-ext = { version = "0.1.18", path = "../argus-ext" } rustc_plugin = "=0.13.0-nightly-2025-03-03" rustc_utils.workspace = true diff --git a/crates/argus-cli/tests/workspaces/diesel/src/main.rs b/crates/argus-cli/tests/workspaces/diesel/src/main.rs index 021abfa..df34800 100644 --- a/crates/argus-cli/tests/workspaces/diesel/src/main.rs +++ b/crates/argus-cli/tests/workspaces/diesel/src/main.rs @@ -1,8 +1,12 @@ -mod bad_insertable_field; -// mod bad_sql_query; // Currerently hangs rustc +//TODO `argus bundle` fails for this module, +//we're not "totally" sure why, but there are +//macros and lots of traits involved... +//mod bad_insertable_field; mod invalid_query; mod invalid_select; mod overflow; + +// mod bad_sql_query; // Currerently hangs rustc // mod queryable_order_mismatch; // Currerently hangs rustc fn main() {} diff --git a/crates/argus-ext/Cargo.toml b/crates/argus-ext/Cargo.toml index bf45f34..cf05a1a 100644 --- a/crates/argus-ext/Cargo.toml +++ b/crates/argus-ext/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "argus-ext" -version = "0.1.17" +version = "0.1.18" edition = "2021" authors = ["Gavin Gray "] repository = "https://github.com/cognitive-engineering-lab/argus" diff --git a/crates/argus-ext/src/rustc/mod.rs b/crates/argus-ext/src/rustc/mod.rs index 35cfa84..83dc311 100644 --- a/crates/argus-ext/src/rustc/mod.rs +++ b/crates/argus-ext/src/rustc/mod.rs @@ -94,10 +94,9 @@ pub trait InferCtxtExt<'tcx> { error: ty::Predicate<'tcx>, ) -> bool; - /// Private in TypeErrorCtxt - fn find_similar_impl_candidates( + fn all_impls( &self, - trait_pred: ty::PolyTraitPredicate<'tcx>, + def_id: rustc_span::def_id::DefId, ) -> Vec>; /// Public (wrapping for local `CandidateSimilarity`) @@ -250,13 +249,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { } } - fn find_similar_impl_candidates( + fn all_impls( &self, - trait_pred: ty::PolyTraitPredicate<'tcx>, + def_id: rustc_span::def_id::DefId, ) -> Vec> { - let mut candidates: Vec<_> = self + self .tcx - .all_impls(trait_pred.def_id()) + .all_impls(def_id) .filter_map(|def_id| { let imp = self.tcx.impl_trait_header(def_id).unwrap(); @@ -266,34 +265,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { return None; } - let imp = imp.trait_ref.skip_binder(); - - self - .fuzzy_match_tys( - trait_pred.skip_binder().self_ty(), - imp.self_ty(), - false, - ) - .map(|similarity| ImplCandidate { - trait_ref: imp, - similarity, - impl_def_id: def_id, - }) + Some(ImplCandidate { + trait_ref: imp.trait_ref.skip_binder(), + similarity: CandidateSimilarity::Other, + impl_def_id: def_id, + }) }) - .collect(); - - if candidates - .iter() - .any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) - { - // If any of the candidates is a perfect match, we don't want to show all of them. - // This is particularly relevant for the case of numeric types (as they all have the - // same category). - candidates - .retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })); - } - - candidates + .collect() } fn fuzzy_match_tys( diff --git a/crates/argus-ser-macros/Cargo.toml b/crates/argus-ser-macros/Cargo.toml index 8a0cd9d..cd86c9d 100644 --- a/crates/argus-ser-macros/Cargo.toml +++ b/crates/argus-ser-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "argus-ser-macros" -version = "0.1.17" +version = "0.1.18" edition = "2021" authors = ["Gavin Gray "] repository = "https://github.com/cognitive-engineering-lab/argus" diff --git a/crates/argus-ser/Cargo.toml b/crates/argus-ser/Cargo.toml index f102cd9..40840bb 100644 --- a/crates/argus-ser/Cargo.toml +++ b/crates/argus-ser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "argus-ser" -version = "0.1.17" +version = "0.1.18" edition = "2021" authors = ["Gavin Gray "] repository = "https://github.com/cognitive-engineering-lab/argus" @@ -28,8 +28,8 @@ ts-rs = { version = "7.1.1", features = [ "no-serde-warnings", ], optional = true } -argus-ser-macros = { version = "0.1.17", path = "../argus-ser-macros" } -argus-ext = { version = "0.1.17", path = "../argus-ext" } +argus-ser-macros = { version = "0.1.18", path = "../argus-ser-macros" } +argus-ext = { version = "0.1.18", path = "../argus-ext" } [dev-dependencies] argus-ser = { path = ".", features = ["testing"] } diff --git a/crates/argus-ser/src/argus.rs b/crates/argus-ser/src/argus.rs index 10fce45..20b5629 100644 --- a/crates/argus-ser/src/argus.rs +++ b/crates/argus-ser/src/argus.rs @@ -280,10 +280,9 @@ pub(crate) fn group_predicates_by_ty<'tcx>( pub fn get_opt_impl_header( tcx: ty::TyCtxt, - def_id: DefId, + impl_def_id: DefId, ) -> Option { use rustc_data_structures::fx::FxIndexSet; - let impl_def_id = def_id; let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity(); let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id); diff --git a/crates/argus-ser/src/interner.rs b/crates/argus-ser/src/interner.rs index 2415e5d..1685d76 100644 --- a/crates/argus-ser/src/interner.rs +++ b/crates/argus-ser/src/interner.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; // FIXME: change back to above use std::{ cell::RefCell, cmp::{Eq, PartialEq}, @@ -6,7 +5,7 @@ use std::{ }; use index_vec::{Idx, IndexVec}; -// use rustc_data_structures::fx::FxHashMap as HashMap; +use rustc_data_structures::fx::FxHashMap as HashMap; use rustc_middle::ty; crate::define_idx! { @@ -22,6 +21,8 @@ pub struct Interner { keys: HashMap, } +const DEFAULT_CAPACITY: usize = 1_000; + impl Default for Interner where K: PartialEq + Eq + Hash, @@ -29,8 +30,8 @@ where { fn default() -> Self { Self { - values: IndexVec::with_capacity(1_000_000), - keys: HashMap::with_capacity(1_000_000), + values: IndexVec::with_capacity(DEFAULT_CAPACITY), + keys: HashMap::with_capacity(DEFAULT_CAPACITY), } } } @@ -62,3 +63,13 @@ where self.values } } + +trait FxHashExt { + fn with_capacity(capacity: usize) -> Self; +} + +impl FxHashExt for HashMap { + fn with_capacity(capacity: usize) -> Self { + HashMap::with_capacity_and_hasher(capacity, Default::default()) + } +} diff --git a/crates/argus/Cargo.toml b/crates/argus/Cargo.toml index ac71f0b..834402c 100644 --- a/crates/argus/Cargo.toml +++ b/crates/argus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "argus-lib" -version = "0.1.17" +version = "0.1.18" edition = "2021" authors = ["Gavin Gray "] repository = "https://github.com/cognitive-engineering-lab/argus" @@ -22,8 +22,8 @@ serde.workspace = true serde_json.workspace = true itertools.workspace = true -argus-ext = { version = "0.1.17", path = "../argus-ext" } -argus-ser = { version = "0.1.17", path = "../argus-ser" } +argus-ext = { version = "0.1.18", path = "../argus-ext" } +argus-ser = { version = "0.1.18", path = "../argus-ser" } index_vec = { version = "0.1.3", features = ["serde"] } smallvec = "1.14.0" indexmap = { version = "2.2", features = ["serde"] } diff --git a/crates/argus/src/proof_tree/hash_map.rs b/crates/argus/src/proof_tree/hash_map.rs new file mode 100644 index 0000000..74642e9 --- /dev/null +++ b/crates/argus/src/proof_tree/hash_map.rs @@ -0,0 +1,85 @@ +//! Wrapper around `FxHashMap` that implements `ts_rs::TS` +use std::{ + fmt::Debug, + ops::{Deref, DerefMut}, +}; + +use rustc_data_structures::fx::FxHashMap; +use serde::Serialize; +#[cfg(feature = "testing")] +use ts_rs::TS; + +use super::topology::Idx; + +#[cfg(not(feature = "testing"))] +pub trait AllTheThings: Debug + Serialize {} + +#[cfg(not(feature = "testing"))] +impl AllTheThings for T where T: Debug + Serialize {} + +#[cfg(feature = "testing")] +pub trait AllTheThings: Debug + Serialize + TS {} + +#[cfg(feature = "testing")] +impl AllTheThings for T where T: Debug + Serialize + TS {} + +#[derive(Clone, Debug, Serialize)] +pub struct HashMap(FxHashMap); + +impl Deref for HashMap { + type Target = FxHashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for HashMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Default for HashMap { + fn default() -> Self { + HashMap(FxHashMap::default()) + } +} + +#[cfg(feature = "testing")] +impl TS for HashMap { + fn name() -> String { + "Record".to_owned() + } + + fn name_with_type_args(args: Vec) -> String { + assert_eq!( + args.len(), + 2, + "called HashMap::name_with_type_args with {} args", + args.len() + ); + format!("Record<{}, {}>", args[0], args[1]) + } + + fn inline() -> String { + format!("Record<{}, {}>", K::inline(), V::inline()) + } + + fn dependencies() -> Vec + where + Self: 'static, + { + [ + ts_rs::Dependency::from_ty::(), + ts_rs::Dependency::from_ty::(), + ] + .into_iter() + .flatten() + .collect() + } + + fn transparent() -> bool { + true + } +} diff --git a/crates/argus/src/proof_tree/interners.rs b/crates/argus/src/proof_tree/interners.rs index f8f8fe8..bbb2d1a 100644 --- a/crates/argus/src/proof_tree/interners.rs +++ b/crates/argus/src/proof_tree/interners.rs @@ -28,10 +28,18 @@ use crate::{ pub struct Interners { goals: Interner<(Hash64, ResultIdx), GoalIdx, GoalData>, + implementors: Interner, candidates: Interner, results: Interner, } +pub struct InternedData { + pub goals: IndexVec, + pub implementors: IndexVec, + pub candidates: IndexVec, + pub results: IndexVec, +} + #[derive(PartialEq, Eq, Hash)] enum CanKey { Impl(DefId), @@ -43,23 +51,19 @@ impl Interners { pub fn default() -> Self { Self { goals: Interner::default(), + implementors: Interner::default(), candidates: Interner::default(), results: Interner::default(), } } - pub fn take( - self, - ) -> ( - IndexVec, - IndexVec, - IndexVec, - ) { - ( - self.goals.consume(), - self.candidates.consume(), - self.results.consume(), - ) + pub fn take(self) -> InternedData { + InternedData { + goals: self.goals.consume(), + implementors: self.implementors.consume(), + candidates: self.candidates.consume(), + results: self.results.consume(), + } } // NOTE: used in `test_utils`. @@ -74,10 +78,6 @@ impl Interners { self.candidates.get_data(&c).expect("missing candidate idx") } - pub fn mk_result_node(&mut self, result: EvaluationResult) -> ProofNode { - ProofNode::pack(ProofNodeUnpacked::Result(self.intern_result(result))) - } - pub fn mk_goal_node(&mut self, goal: &InspectGoal) -> ProofNode { let infcx = goal.infcx(); let result_idx = self.intern_result(goal.result()); @@ -213,4 +213,63 @@ impl Interners { self.candidates.insert_no_key(CandidateData::from(string)) } + + pub(super) fn intern_implementors( + &mut self, + infcx: &InferCtxt, + def_id: DefId, + tp: ty::PolyTraitPredicate, + ) -> ImplementorsIdx { + use argus_ext::{rustc::InferCtxtExt, ty::ImplCandidateExt}; + + if let Some(i) = self.implementors.get_idx(&def_id) { + return i; + } + + let identity_trait_ref = + ty::TraitRef::identity(infcx.tcx, tp.skip_binder().trait_ref.def_id); + + let trait_ = ser::TraitRefPrintOnlyTraitPathDef(identity_trait_ref); + let trait_ = tls::unsafe_access_interner(|ty_interner| { + ser::to_value_expect(infcx, ty_interner, &trait_) + }); + + // Gather all impls + let mut impls = vec![]; + let mut inductive_impls = vec![]; + + let mut impl_candidates = infcx.all_impls(tp.def_id()); + + // HACK: Sort the `impl_candidates` by the number of *type* parameters. We use this + // as a proxy for complexity, that is, complexity of reading the impl, we want + // to show Argus users "simpler" impls first. + // This probably shouldn't happen here, as it's a concern of the frontend, but this is + // the last place we have all that information. + macro_rules! sort_by_count { + ($field:ident, $vec:expr) => { + $vec.sort_by_key(|c| { + infcx.tcx.generics_of(c.impl_def_id).own_counts().$field + }) + }; + } + sort_by_count!(types, impl_candidates); + sort_by_count!(lifetimes, impl_candidates); + + for can in impl_candidates { + let can_idx = self.intern_impl(infcx, can.impl_def_id); + if can.is_inductive(infcx.tcx) { + inductive_impls.push(can_idx); + } else { + impls.push(can_idx); + } + } + + let impls = Implementors { + trait_, + impls, + inductive_impls, + }; + + self.implementors.insert(def_id, impls) + } } diff --git a/crates/argus/src/proof_tree/mod.rs b/crates/argus/src/proof_tree/mod.rs index d48025d..7837cec 100644 --- a/crates/argus/src/proof_tree/mod.rs +++ b/crates/argus/src/proof_tree/mod.rs @@ -1,14 +1,14 @@ //! Proof tree types sent to the Argus frontend. mod format; +mod hash_map; mod interners; pub(super) mod serialize; pub mod topology; -use std::collections::HashMap; - use argus_ext::ty::PredicateExt; use argus_ser::{self as ser, interner::TyIdx}; +use hash_map::HashMap; use index_vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::ty; @@ -29,6 +29,7 @@ use crate::{ ser::define_idx! { u32, GoalIdx, + ImplementorsIdx, CandidateIdx, ResultIdx } @@ -140,9 +141,12 @@ pub struct SerializedTree { #[cfg_attr(feature = "testing", ts(type = "TyVal[]"))] pub tys: IndexVec, - pub projection_values: HashMap, + #[cfg_attr(feature = "testing", ts(type = "Implementors[]"))] + pub implementors: IndexVec, - pub all_impl_candidates: HashMap, + pub impls: HashMap, + + pub projection_values: HashMap, pub topology: GraphTopology, diff --git a/crates/argus/src/proof_tree/serialize.rs b/crates/argus/src/proof_tree/serialize.rs index e121b0a..1e380c2 100644 --- a/crates/argus/src/proof_tree/serialize.rs +++ b/crates/argus/src/proof_tree/serialize.rs @@ -1,8 +1,5 @@ use anyhow::{bail, Result}; -use argus_ext::{ - rustc::InferCtxtExt, - ty::{EvaluationResultExt, ImplCandidateExt, PredicateExt, TyExt}, -}; +use argus_ext::ty::{EvaluationResultExt, PredicateExt, TyExt}; use rustc_ast_ir::{try_visit, visit::VisitorResult}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; @@ -15,7 +12,10 @@ use rustc_trait_selection::{ traits::solve, }; -use super::{interners::Interners, *}; +use super::{ + interners::{InternedData, Interners}, + *, +}; use crate::aadebug; pub fn try_serialize<'tcx>( @@ -40,9 +40,8 @@ pub struct SerializedTreeVisitor<'tcx> { pub topology: GraphTopology, pub cycle: Option, pub projection_values: HashMap, - pub all_impl_candidates: HashMap, - deferred_leafs: Vec<(ProofNode, EvaluationResult)>, + impls: HashMap, interners: Interners, aadebug: aadebug::Storage<'tcx>, } @@ -55,9 +54,8 @@ impl SerializedTreeVisitor<'_> { topology: GraphTopology::new(), cycle: None, projection_values: HashMap::default(), - all_impl_candidates: HashMap::default(), - deferred_leafs: Vec::default(), + impls: HashMap::default(), interners: Interners::default(), aadebug: aadebug::Storage::new(maybe_ambiguous), } @@ -105,13 +103,12 @@ impl SerializedTreeVisitor<'_> { pub fn into_tree(self) -> Result { let SerializedTreeVisitor { root: Some(root), - mut topology, + topology, cycle, projection_values, - mut interners, + impls, + interners, aadebug, - deferred_leafs, - all_impl_candidates, .. } = self else { @@ -120,13 +117,12 @@ impl SerializedTreeVisitor<'_> { let analysis = aadebug.into_results(root, &topology); - // Handle the deferred leafs (an inconvenience we'll deal with later) - for (parent, res) in deferred_leafs { - let leaf = interners.mk_result_node(res); - topology.add(parent, leaf); - } - - let (goals, candidates, results) = interners.take(); + let InternedData { + goals, + implementors, + candidates, + results, + } = interners.take(); let tys = crate::tls::take_interned_tys(); Ok(SerializedTree { @@ -135,8 +131,9 @@ impl SerializedTreeVisitor<'_> { candidates, results, tys, + implementors, + impls, projection_values, - all_impl_candidates, topology, cycle, analysis, @@ -147,62 +144,15 @@ impl SerializedTreeVisitor<'_> { impl<'tcx> SerializedTreeVisitor<'tcx> { fn record_all_impls( &mut self, - proof_node: ProofNode, // FIXME: should this always be a GoalIdx instead? + goal_idx: GoalIdx, goal: &InspectGoal<'_, 'tcx>, ) { // If the Goal is a TraitPredicate we will cache *all* possible implementors if let Some(tp) = goal.goal().predicate.as_trait_predicate() { + let def_id = tp.def_id(); let infcx = goal.infcx(); - let tcx = infcx.tcx; - - let identity_trait_ref = - ty::TraitRef::identity(tcx, tp.skip_binder().trait_ref.def_id); - - let trait_ = ser::TraitRefPrintOnlyTraitPathDef(identity_trait_ref); - let trait_ = tls::unsafe_access_interner(|ty_interner| { - ser::to_value_expect(infcx, ty_interner, &trait_) - }); - - // Gather all impls - let mut impls = vec![]; - let mut inductive_impls = vec![]; - let mut impl_candidates = infcx.find_similar_impl_candidates(tp); - - // HACK: Sort the `impl_candidates` by the number of *type* parameters. We use this - // as a proxy for complexity, that is, complexity of reading the impl, we want - // to show Argus users "simpler" impls first. - // This probably shouldn't happen here, as it's a concern of the frontend, but this is - // the last place we have all that information. - macro_rules! sort_by_count { - ($field:ident, $vec:expr) => { - $vec.sort_by(|c1, c2| { - let c1 = tcx.generics_of(c1.impl_def_id).own_counts().$field; - let c2 = tcx.generics_of(c2.impl_def_id).own_counts().$field; - c1.cmp(&c2) - }) - }; - } - sort_by_count!(types, impl_candidates); - sort_by_count!(lifetimes, impl_candidates); - - for can in impl_candidates { - let can_idx = self.interners.intern_impl(infcx, can.impl_def_id); - if can.is_inductive(tcx) { - inductive_impls.push(can_idx); - } else { - impls.push(can_idx); - } - } - - if !inductive_impls.is_empty() { - log::trace!("inductive impls: {inductive_impls:?}"); - } - - self.all_impl_candidates.insert(proof_node, Implementors { - trait_, - impls, - inductive_impls, - }); + let impls_idx = self.interners.intern_implementors(infcx, def_id, tp); + self.impls.insert(goal_idx, impls_idx); } } } @@ -220,7 +170,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for SerializedTreeVisitor<'tcx> { let here_node = self.interners.mk_goal_node(goal); // Record all the possible candidate impls for this goal. - self.record_all_impls(here_node, goal); + if let ProofNodeUnpacked::Goal(goal_idx) = here_node.unpack() { + self.record_all_impls(goal_idx, goal); + } // Push node into the analysis tree. self.aadebug.push_goal(here_node, goal); @@ -239,12 +191,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for SerializedTreeVisitor<'tcx> { let here_parent = self.previous; - let add_result_if_empty = |this: &mut Self, n: ProofNode| { - if this.topology.is_leaf(n) { - this.deferred_leafs.push((n, goal.result())); - } - }; - for c in goal.candidates() { let here_candidate = self.interners.mk_candidate_node(&c); if self.topology.children.contains_key(&here_candidate) { @@ -256,12 +202,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for SerializedTreeVisitor<'tcx> { self.previous = Some(here_candidate); c.visit_nested_roots(self); - - // FIXME: is this necessary now that we store all nodes? - add_result_if_empty(self, here_candidate); } - add_result_if_empty(self, here_node); self.previous = here_parent; } } diff --git a/examples/to-string/Cargo.toml b/examples/to-string/Cargo.toml new file mode 100644 index 0000000..57bc2e4 --- /dev/null +++ b/examples/to-string/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "to-string" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/examples/to-string/src/main.rs b/examples/to-string/src/main.rs new file mode 100644 index 0000000..0088b66 --- /dev/null +++ b/examples/to-string/src/main.rs @@ -0,0 +1,29 @@ +trait ToString { + fn to_string(&self) -> String; +} + +impl ToString for i32 { + fn to_string(&self) -> String { + todo!() + } +} + +impl ToString for (S, T) +where + S: ToString, + T: ToString, +{ + fn to_string(&self) -> String { + format!("({}, {})", self.0.to_string(), self.1.to_string()) + } +} + +fn print_items(items: &[T]) { + for item in items { + println!("{}", item.to_string()); + } +} + +pub fn foo() { + print_items(&[("a", "b")]); +} diff --git a/ide/packages/common/src/TreeInfo.ts b/ide/packages/common/src/TreeInfo.ts index 9e47e2c..64db8bf 100644 --- a/ide/packages/common/src/TreeInfo.ts +++ b/ide/packages/common/src/TreeInfo.ts @@ -426,7 +426,11 @@ export class TreeInfo { } public implCandidates(node: ProofNode): Implementors | undefined { - return this.tree.allImplCandidates[node]; + const unpacked = unpackProofNode(node); + if ("Goal" in unpacked) { + const implIdx = this.tree.impls[unpacked.Goal]; + return this.tree.implementors[implIdx]; + } } } diff --git a/ide/packages/extension/package.json b/ide/packages/extension/package.json index 78be7c0..82b86af 100644 --- a/ide/packages/extension/package.json +++ b/ide/packages/extension/package.json @@ -5,7 +5,7 @@ "description": "A trait debugger for Rust", "license": "MIT", "icon": "argus-logo-128.png", - "version": "0.1.17", + "version": "0.1.18", "engines": { "vscode": "^1.99.1" }, @@ -17,12 +17,8 @@ "url": "https://github.com/cognitive-engineering-lab/argus", "type": "git" }, - "categories": [ - "Programming Languages" - ], - "activationEvents": [ - "onLanguage:rust" - ], + "categories": ["Programming Languages"], + "activationEvents": ["onLanguage:rust"], "contributes": { "commands": [ { @@ -55,12 +51,7 @@ } ] }, - "files": [ - "dist", - "argus-logo-128.png", - "LICENSE", - "README.md" - ], + "files": ["dist", "argus-logo-128.png", "LICENSE", "README.md"], "main": "./dist/argus.js", "exports": { ".": {