From f40d7362b4b53c88ab07989c6a3f83f48fbc5e85 Mon Sep 17 00:00:00 2001 From: Evan Ovadia Date: Thu, 23 May 2024 17:10:54 -0400 Subject: [PATCH] Cleaned up old refactor, fixed a couple regressions, all tests pass! --- ValeRuster/src/indexer.rs | 230 +++++++++++++++++++------------- ValeRuster/src/main.rs | 251 +++++++++++++++++------------------ ValeRuster/src/resolve.rs | 54 +++++--- ValeRuster/src/resolve_id.rs | 179 ++++++++++++++++++++----- 4 files changed, 438 insertions(+), 276 deletions(-) diff --git a/ValeRuster/src/indexer.rs b/ValeRuster/src/indexer.rs index 3b4e1500f..ea9b959c2 100644 --- a/ValeRuster/src/indexer.rs +++ b/ValeRuster/src/indexer.rs @@ -1,8 +1,8 @@ use std::collections::{HashMap, HashSet}; -use rustdoc_types::{Crate, Enum, Item, ItemEnum, Primitive, Struct}; -use crate::{GenealogyKey, resolve_id, ResolveError, UId}; +use rustdoc_types::{Crate, Enum, Id, Item, ItemEnum, Primitive, Struct}; +use crate::{GenealogyKey, item_has_name, resolve_id, ResolveError, UId}; use crate::GenealogyKey::Normal; -use crate::resolve_id::{get_expanded_direct_child_uids, get_unexpanded_direct_child_uids, lookup_uid, resolve_uid}; +use crate::resolve_id::{collapse_children, get_expanded_direct_child_uids, get_unexpanded_direct_child_uids_exclude_impl_children, include_impls_children, lookup_uid, resolve_uid}; use crate::ResolveError::ResolveFatal; pub struct ItemIndex { @@ -52,8 +52,11 @@ pub fn genealogize( let child_uids = match &item.inner { ItemEnum::Module(_) => { - let direct_child_uids = - get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &self_uid)?; + let direct_child_uids_without_methods = + get_unexpanded_direct_child_uids_exclude_impl_children(crates, &primitive_name_to_uid, &self_uid)?; + let direct_child_keys = + include_impls_children(crates, &primitive_name_to_uid, direct_child_uids_without_methods)?; + let direct_child_uids = collapse_children(&direct_child_keys); direct_child_uids .into_iter() .map(|x| GenealogyKey::Normal(x.clone())) @@ -63,19 +66,24 @@ pub fn genealogize( ItemEnum::Struct(Struct { impls: impl_ids, .. }) | ItemEnum::Enum(Enum { impls: impl_ids, .. }) => { let mut result = Vec::new(); - for impl_uid in get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &self_uid)? { - result.push(GenealogyKey::ImplOrMethod { struct_uid: self_uid.clone(), child_uid: impl_uid.clone() }); - } - // Now add all the impls' children. - for impl_id in impl_ids { - let impl_uid = UId { crate_name: crate_name.clone(), id: impl_id.clone() }; - for method_uid in get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &impl_uid)? { - result.push(GenealogyKey::ImplOrMethod { struct_uid: self_uid.clone(), child_uid: method_uid.clone() }); - } + let direct_child_uids_without_methods = + get_unexpanded_direct_child_uids_exclude_impl_children(crates, &primitive_name_to_uid, &self_uid)?; + let direct_child_keys = + include_impls_children(crates, &primitive_name_to_uid, direct_child_uids_without_methods)?; + let direct_child_uids = collapse_children(&direct_child_keys); + for child_id in direct_child_uids { + result.push(GenealogyKey::ImplOrMethod { struct_uid: self_uid.clone(), child_uid: child_id.clone() }); } + // // Now add all the impls' children. + // for impl_id in impl_ids { + // let impl_uid = UId { crate_name: crate_name.clone(), id: impl_id.clone() }; + // for method_uid in get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &impl_uid, true)? { + // result.push(GenealogyKey::ImplOrMethod { struct_uid: self_uid.clone(), child_uid: method_uid.clone() }); + // } + // } result }, - ItemEnum::Import(import) => { + ItemEnum::Import(_import) => { continue; } _ => continue @@ -103,9 +111,11 @@ pub fn genealogize( UId { crate_name: crate_name.to_string(), id: self_id.clone() }; match &item.inner { ItemEnum::Module(_) => { - let direct_child_uids = - get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &self_uid)?; - + let direct_child_uids_without_methods = + get_unexpanded_direct_child_uids_exclude_impl_children(crates, &primitive_name_to_uid, &self_uid)?; + let direct_child_keys = + include_impls_children(crates, &primitive_name_to_uid, direct_child_uids_without_methods)?; + let direct_child_uids = collapse_children(&direct_child_keys); for direct_child_uid in &direct_child_uids { let direct_child_item = lookup_uid(crates, &direct_child_uid); match &direct_child_item.inner { @@ -131,7 +141,7 @@ pub fn genealogize( Err(ResolveFatal(e)) => return Err(e) }; match get_expanded_direct_child_uids( - crates, &primitive_name_to_uid, &target_module_uid) { + crates, &primitive_name_to_uid, &target_module_uid, true) { Ok(x) => { x }, @@ -145,8 +155,8 @@ pub fn genealogize( if !importee_uid_to_imports.contains_key(&importee_uid) { importee_uid_to_imports.insert(importee_uid.clone(), HashSet::new()); } - eprintln!("Noting importee {:?} imported by import {:?}", importee_uid, self_uid.clone()); - importee_uid_to_imports.get_mut(&importee_uid).unwrap().insert(self_uid.clone()); + // println!("Noting importee {:?} imported by {:?}", importee_uid, direct_child_uid.clone()); + importee_uid_to_imports.get_mut(&importee_uid).unwrap().insert(direct_child_uid.clone()); } } _ => {} @@ -239,14 +249,15 @@ fn search_owner_paths( return true; } } - if let Some(importer_uids) = importee_uid_to_imports.get(&this_uid) { + if let Some(import_uids) = importee_uid_to_imports.get(&this_uid) { // Nothing, we've hit a dead end. // This can happen for example in the regex crate, to the crate::string module which nobody // imports or ever mentions. // Instead, the root module imports crate::string's children directly. let mut found = false; - for importer_uid in importer_uids { + for import_uid in import_uids { + let importer_uid = child_key_to_parent_uid.get(&Normal(import_uid.clone())).unwrap(); let mut new_path = path_so_far_from_child.clone(); new_path.push(importer_uid.clone()); search_owner_paths(results, crates, child_key_to_parent_uid, importee_uid_to_imports, new_path); @@ -283,11 +294,11 @@ fn infer_missing_owners( // Sanity check: for (crate_name, crate_) in crates { - for (item_id, item) in &crate_.index { + for (item_id, _item) in &crate_.index { let item_uid = UId { crate_name: crate_name.to_string(), id: item_id.clone() }; if item_uid.id.0 == "0:462:2678" { - println!("lol"); + } let item = crate_.index.get(&item_uid.id).unwrap(); match &item.inner { @@ -298,58 +309,87 @@ fn infer_missing_owners( let parent_uid = match determine_ultimate_owner(crates, child_key_to_parent_uid, importee_uid_to_imports, &item_uid) { None => { - eprintln!("No owners or imports for {:?}", item_uid); + println!("No owners or imports for {:?}", item_uid); continue }, Some(value) => value, }; // let import_key = Normal(parent_uid); - eprintln!("Noting new owner for {:?}, import {:?}", item_uid.clone(), parent_uid); + // println!("{:?} Noting new owner, module {:?} parent import {:?}", result.len(), item_uid.clone(), parent_uid); + assert!(!result.contains_key(&Normal(item_uid.clone()))); result.insert(Normal(item_uid), parent_uid.clone()); } ItemEnum::Primitive(Primitive { impls: impl_ids, .. }) | ItemEnum::Struct(Struct { impls: impl_ids, .. }) | ItemEnum::Enum(Enum { impls: impl_ids, .. }) => { + if item_has_name(&item, "Chars") { + + } let parent_uid = match determine_ultimate_owner(crates, child_key_to_parent_uid, importee_uid_to_imports, &item_uid) { None => { - eprintln!("No owners or imports for {:?}", item_uid); + println!("No owners or imports for {:?}", item_uid); continue }, Some(value) => value, }; - eprintln!("Noting new owner for {:?}, import {:?}", item_uid.clone(), parent_uid); + // println!("{:?} Noting new owner for {:?}, parent {:?}", result.len(), item_uid.clone(), parent_uid); + assert!(!result.contains_key(&Normal(item_uid.clone()))); result.insert(Normal(item_uid.clone()), parent_uid.clone()); + let direct_child_uids_without_methods = + get_unexpanded_direct_child_uids_exclude_impl_children( + crates, &primitive_name_to_uid, &item_uid)?; + let direct_child_keys = + include_impls_children( + crates, &primitive_name_to_uid, direct_child_uids_without_methods)?; + println!("Direct child keys: {:?}", &direct_child_keys); + let direct_child_uids = collapse_children(&direct_child_keys); + println!("Direct child uids: {:?}", &direct_child_uids); // Now look for all their methods. let mut method_keys = Vec::new(); - for impl_uid in get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &item_uid)? { - method_keys.push(GenealogyKey::ImplOrMethod { struct_uid: item_uid.clone(), child_uid: impl_uid.clone() }); - } - // Now add all the impls' children. - for impl_id in impl_ids { - let impl_uid = UId { crate_name: crate_name.clone(), id: impl_id.clone() }; - for method_uid in get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &impl_uid)? { - method_keys.push(GenealogyKey::ImplOrMethod { struct_uid: item_uid.clone(), child_uid: method_uid.clone() }); - } + for direct_child_uid in direct_child_uids { + // println!("Pushing A {:?}", GenealogyKey::ImplOrMethod { struct_uid: item_uid.clone(), child_uid: direct_child_uid.clone() }); + method_keys.push(GenealogyKey::ImplOrMethod { struct_uid: item_uid.clone(), child_uid: direct_child_uid.clone() }); } + // // Now add all the impls' children. + // for impl_id in impl_ids { + // let impl_uid = UId { crate_name: crate_name.clone(), id: impl_id.clone() }; + // for method_uid in get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &impl_uid, true)? { + // println!("Pushing B {:?}", GenealogyKey::ImplOrMethod { struct_uid: item_uid.clone(), child_uid: method_uid.clone() }); + // method_keys.push(GenealogyKey::ImplOrMethod { struct_uid: item_uid.clone(), child_uid: method_uid.clone() }); + // } + // } for method_key in method_keys { + match &method_key { + GenealogyKey::ImplOrMethod { + struct_uid: UId { crate_name: _, id: Id(x) }, + child_uid: UId { crate_name: _, id: Id(y) }, + } if x == "0:3816:3157" && y == "1:3721:1799" => { + + } + _ => {} + } + + // println!("{:?} Noting impl-method {:?} has owner {:?}", result.len(), &method_key, &item_uid); + assert!(!result.contains_key(&method_key)); result.insert(method_key, item_uid.clone()); } } - ItemEnum::Function(func) => { + ItemEnum::Function(_func) => { if child_key_to_parent_uid.contains_key(&Normal(item_uid.clone())) { // Then it's a free function. let parent_uid = match determine_ultimate_owner(crates, child_key_to_parent_uid, importee_uid_to_imports, &item_uid) { None => { - eprintln!("No owners or imports for {:?}", &item_uid); + println!("No owners or imports for {:?}", &item_uid); continue }, Some(value) => value, }; // let import_key = Normal(parent_uid); - eprintln!("Noting new owner for {:?}, import {:?}", item_uid.clone(), parent_uid); + // println!("{:?} Noting new owner for free function {:?}, import {:?}", result.len(), item_uid.clone(), parent_uid); + assert!(!result.contains_key(&Normal(item_uid.clone()))); result.insert(Normal(item_uid), parent_uid.clone()); } else { // It's a method, skip it. We'll get it in the struct|trait|enum case. @@ -361,56 +401,60 @@ fn infer_missing_owners( } } - // Sanity check: - for (crate_name, crate_) in crates { - for (item_id, item) in &crate_.index { - let item_uid = - UId { crate_name: crate_name.to_string(), id: item_id.clone() }; - let item = crate_.index.get(&item_uid.id).unwrap(); - match item.inner { - ItemEnum::Module(_) | ItemEnum::Struct(_) | ItemEnum::Enum(_) | ItemEnum::Primitive(_) => { - let item_key = Normal(item_uid.clone()); - if !child_key_to_parent_uid.contains_key(&item_key) { - if let Some(unnarrowed_imports) = importee_uid_to_imports.get(item_key.uid()) { - let imports: Vec = - if unnarrowed_imports.len() == 0 { - eprintln!("No owners or imports for {:?}", item_key); - continue; - } else if unnarrowed_imports.len() > 1 { - // Narrow it down by the smallest path. For example, LineWriter - // is imported in two places: - // "library/std/src/io/buffered/mod.rs", - // "library/std/src/io/mod.rs", - // so we'll go with the second one. - // TODO: use a better resolution approach - let mut bork: Vec<(UId, &Item)> = - unnarrowed_imports.iter() - .map(|id| (id.clone(), lookup_uid(crates, id))) - .collect::>(); - bork.sort_by_key(|(uid, item)| item.span.as_ref().unwrap().filename.to_str().as_ref().unwrap().len()); - eprintln!("Heuristic, estimating owner for {:?} is {:?}", item_key, bork.iter().next().unwrap().clone()); - bork.into_iter().map(|x| x.0).collect() - } else { - unnarrowed_imports.iter().map(|x| x.clone()).collect() - }; - let import_key = Normal(imports.iter().next().unwrap().clone()); - if let Some(import_parent_id) = child_key_to_parent_uid.get(&import_key) { - eprintln!("Noting new owner for {:?}, import {:?}", item_key, import_key.uid()); - result.insert(item_key, import_parent_id.clone()); - } else { - eprintln!("New owner for {:?}, import {:?} has no owner itself!", item_key, import_key.uid()); - continue; - } - } else { - eprintln!("Orphan module: {:?}", item.name); - } - } - } - // ItemEnum::Function(_) => {} - _ => {} - } - } - } + // for (crate_name, crate_) in crates { + // for (item_id, _item) in &crate_.index { + // let item_uid = + // UId { crate_name: crate_name.to_string(), id: item_id.clone() }; + // let item = crate_.index.get(&item_uid.id).unwrap(); + // match item.inner { + // ItemEnum::Module(_) | ItemEnum::Struct(_) | ItemEnum::Enum(_) | ItemEnum::Primitive(_) => { + // let item_key = Normal(item_uid.clone()); + // if !result.contains_key(&item_key) { + // if let Some(unnarrowed_imports) = importee_uid_to_imports.get(item_key.uid()) { + // let imports: Vec = + // if unnarrowed_imports.len() == 0 { + // println!("No owners or imports for {:?}", item_key); + // continue; + // } else if unnarrowed_imports.len() > 1 { + // // Narrow it down by the smallest path. For example, LineWriter + // // is imported in two places: + // // "library/std/src/io/buffered/mod.rs", + // // "library/std/src/io/mod.rs", + // // so we'll go with the second one. + // // TODO: use a better resolution approach + // let mut bork: Vec<(UId, &Item)> = + // unnarrowed_imports.iter() + // .map(|id| (id.clone(), lookup_uid(crates, id))) + // .collect::>(); + // bork.sort_by_key(|(_uid, item)| item.span.as_ref().unwrap().filename.to_str().as_ref().unwrap().len()); + // println!("Heuristic, estimating owner for {:?} is {:?}", item_key, bork.iter().next().unwrap().clone()); + // bork.into_iter().map(|x| x.0).collect() + // } else { + // unnarrowed_imports.iter().map(|x| x.clone()).collect() + // }; + // let import_key = Normal(imports.iter().next().unwrap().clone()); + // if let Some(import_parent_id) = child_key_to_parent_uid.get(&import_key) { + // println!("{:?} Noting new owner for {:?}, import {:?}'s parent {:?}", result.len(), item_key, import_key.uid(), &import_parent_id); + // match result.get(&item_key) { + // None => {} + // Some(existing_id) => panic!("Already existing owner: {:?}", existing_id) + // } + // assert!(!result.contains_key(&item_key)); + // result.insert(item_key, import_parent_id.clone()); + // } else { + // println!("New owner for {:?}, import {:?} has no owner itself!", item_key, import_key.uid()); + // continue; + // } + // } else { + // println!("Orphan module: {:?}", item.name); + // } + // } + // } + // // ItemEnum::Function(_) => {} + // _ => {} + // } + // } + // } Ok(result) } @@ -453,8 +497,8 @@ fn determine_ultimate_owner( unnarrowed_parent_ids.iter() .map(|id| (id.clone(), lookup_uid(crates, id))) .collect::>(); - parent_uids_and_items.sort_by_key(|(uid, item)| item.span.as_ref().unwrap().filename.to_str().as_ref().unwrap().len()); - eprintln!("Heuristic, estimating owner for {:?} is {:?}", item_uid, parent_uids_and_items.iter().next().unwrap().clone()); + parent_uids_and_items.sort_by_key(|(_uid, item)| item.span.as_ref().unwrap().filename.to_str().as_ref().unwrap().len()); + println!("Heuristic, estimating owner for {:?} is {:?}", item_uid, parent_uids_and_items.iter().next().unwrap().clone()); parent_uids_and_items .into_iter() .map(|x| x.0) diff --git a/ValeRuster/src/main.rs b/ValeRuster/src/main.rs index afb15fceb..649c2c750 100644 --- a/ValeRuster/src/main.rs +++ b/ValeRuster/src/main.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] + extern crate toml; use std::collections::{HashMap, HashSet}; @@ -287,7 +289,7 @@ fn main() -> Result<(), anyhow::Error> { let simple_line_captures = Regex::new(r#"^\s*(#pragma\s+rsuse\s+)?(\S.+)\s*$"#).unwrap() .captures(&line) - .expect(&("Bad line: ".to_owned() + &line));; + .expect(&("Bad line: ".to_owned() + &line)); let target_type_str = simple_line_captures.get(2) .expect("Blork") @@ -302,7 +304,7 @@ fn main() -> Result<(), anyhow::Error> { type_to_alias.insert(target_type.valtype.clone(), alias.clone()); alias_to_type.insert(alias.clone(), target_type.valtype.clone()); } - eprintln!("Adding {:?}", target_type); + println!("Adding {:?}", target_type); type_and_original_line_and_type_str_and_maybe_alias.push( (target_type, line.clone(), maybe_alias)); } @@ -340,7 +342,7 @@ fn main() -> Result<(), anyhow::Error> { // TODO: Expensive call to string_path type_and_original_line_and_type_str_and_maybe_alias.sort_by_key(|x| x.0.valtype.id.id.0.clone()); - for (target_type, line, maybe_alias) in &type_and_original_line_and_type_str_and_maybe_alias { + for (target_type, _line, _maybe_alias) in &type_and_original_line_and_type_str_and_maybe_alias { let target_valtype = &target_type.valtype; // let target_name: String = unimplemented!(); let rustified_type = @@ -361,7 +363,7 @@ fn main() -> Result<(), anyhow::Error> { valtype_str.clone() }; // TODO: check duplicates, i think we're doing extra work here - eprintln!("Sizing primitive {}", &type_str); + println!("Sizing primitive {}", &type_str); sizer_strings.push(get_sizer_string(&valtype_str, &type_str)); } else { let item = resolve_id::lookup_uid(&crates, &unresolved_id); @@ -379,12 +381,12 @@ fn main() -> Result<(), anyhow::Error> { valtype_str.clone() }; // TODO: check duplicates, i think we're doing extra work here - eprintln!("Sizing non-primitive {}", &type_str); + println!("Sizing non-primitive {}", &type_str); sizer_strings.push(get_sizer_string(&valtype_str, &type_str)); } ItemEnum::Function(func) => { let mut signature_types: Vec<&Type> = Vec::new(); - for (name, type_) in &func.decl.inputs { + for (_name, type_) in &func.decl.inputs { signature_types.push(type_); } if let Some(thing) = &func.decl.output { @@ -397,7 +399,7 @@ fn main() -> Result<(), anyhow::Error> { let generics = assemble_generics(&crates, func, &target_valtype)?; - eprintln!("Doing things with type {:?}", target_valtype); + println!("Doing things with type {:?}", target_valtype); let signature_part_type = simplify_type(&crates, &item_index, /*Some(target_valtype),*/ &generics, &target_valtype.id.crate_name, &type_)?; let valtype_str = @@ -411,7 +413,7 @@ fn main() -> Result<(), anyhow::Error> { } else { valtype_str.clone() }; - eprintln!("Sizing {} from {}", &type_str, item.name.as_ref().unwrap_or(&"(none)".to_string())); + println!("Sizing {} from {}", &type_str, item.name.as_ref().unwrap_or(&"(none)".to_string())); // TODO: check duplicates, i think we're doing extra work here sizer_strings.push(get_sizer_string(&valtype_str, &type_str)); @@ -432,12 +434,12 @@ fn main() -> Result<(), anyhow::Error> { // Check first; we don't want to overwrite it in case the user requested it and // perhaps even aliased it. if type_and_original_line_and_type_str_and_maybe_alias.iter().find(|x| x.0 == type_).is_none() { - eprintln!("Adding {:?}", type_); + println!("Adding {:?}", type_); type_and_original_line_and_type_str_and_maybe_alias.push((type_, original_line, maybe_alias)); } } - eprintln!("Running sizer program on {} types...", sizer_strings.len()); + println!("Running sizer program on {} types...", sizer_strings.len()); let sizer_program_str = std::iter::once(common_preamble().to_owned()).into_iter() @@ -474,7 +476,7 @@ fn main() -> Result<(), anyhow::Error> { type_and_original_line_and_type_str_and_maybe_alias .sort_by_key(|x| x.0.valtype.id.id.0.clone()); - for (target_type, line, maybe_alias) in &type_and_original_line_and_type_str_and_maybe_alias { + for (target_type, _line, maybe_alias) in &type_and_original_line_and_type_str_and_maybe_alias { let target_valtype = &target_type.valtype; let target_rust_type_string = rustify_simple_type( @@ -523,7 +525,7 @@ fn main() -> Result<(), anyhow::Error> { } } ItemEnum::Function(func) => { - eprintln!("Instantiating function {}...", &target_rust_type_string); + println!("Instantiating function {}...", &target_rust_type_string); // let (needle_type, _) = // parse_type(crates, None, &needle_full_name_str)?; @@ -564,7 +566,7 @@ fn main() -> Result<(), anyhow::Error> { } let maybe_return_type: Option = if let Some(output) = &func.decl.output { - eprintln!("name {:?} Generics: {:?}", item.name, generics); + println!("name {:?} Generics: {:?}", item.name, generics); Some(simplify_type(&crates, &item_index, /*Some(target_valtype),*/ &generics, &target_valtype.id.crate_name, &output)?) } else { None @@ -818,7 +820,7 @@ fn assemble_generics( match &parent_concrete_item.inner { ItemEnum::Struct(struct_) => &struct_.generics.params, ItemEnum::Enum(enum_) => &enum_.generics.params, - ItemEnum::Primitive(prim) => &empty, + ItemEnum::Primitive(_prim) => &empty, _ => panic!("parent id not referring to a concrete?"), }; for (generic_param, generic_arg_type) in parent_concrete_generic_params.iter().zip(&parent.generic_args) { @@ -921,7 +923,7 @@ fn match_generic_arg_type( generic_param: &Type, current_height: i64 ) -> Option { - eprintln!("arg {:?} param {:?}", generic_arg, generic_param); + println!("arg {:?} param {:?}", generic_arg, generic_param); match (generic_arg, generic_param) { (_, Type::Generic(generic_param_name)) => { if let Some(existing) = generics.get(generic_param_name) { @@ -993,7 +995,7 @@ fn match_generic_arg_valtype( } ( _, - Type::ResolvedPath(rustdoc_types::Path { name: generic_param_name, args: generic_params, .. }) + Type::ResolvedPath(rustdoc_types::Path { name: generic_param_name, args: _generic_params, .. }) ) => { if is_primitive(&item_index.primitive_uid_to_name, &generic_arg.id) { return None; @@ -1071,7 +1073,8 @@ fn get_concrete_impls( result.push(uid); } } else { - eprintln!("Primitive not found: {}", name); + // DO NOT SUBMIT put this warning back in + // eprintln!("Primitive not found: {}", name); } } _ => {} @@ -1083,100 +1086,93 @@ fn get_concrete_impls( return result; } -// TODO: optimize: super expensive -// TODO: look for impls in other crates -// A concrete is a struct or an enum -fn get_concrete_impls_children( + +fn get_impl_children( crates: &HashMap, primitive_name_to_uid: &HashMap, - concrete_id: &UId -) -> Result> { - let mut result = Vec::new(); - for impl_uid in get_concrete_impls(crates, primitive_name_to_uid, concrete_id) { - let item = resolve_id::lookup_uid(crates, &impl_uid); - if let ItemEnum::Impl(impl_) = &item.inner { - if let Some(name) = &item.name { - if name == "Any" { - // Other crates seem to reference core::any::Any but don't have a path to it. - // If this becomes a problem with a lot of other things we might have to make - // lookup_uid return an optional. - continue; - } + impl_uid: &UId +) -> anyhow::Result>, ResolveError> { + let item = resolve_id::lookup_uid(crates, &impl_uid); + if let ItemEnum::Impl(impl_) = &item.inner { + if let Some(name) = &item.name { + if name == "Any" { + // Other crates seem to reference core::any::Any but don't have a path to it. + // If this becomes a problem with a lot of other things we might have to make + // lookup_uid return an optional. + return Ok(None); } + } - // This impl_.items won't actually have everything. - // some impls dont actually implement all the methods in their trait, they instead use the default implementation. for example, this - // impl<'a> Iterator for Chars<'a> { - // file:///Users/verdagon/.rustup/toolchains/nightly-aarch64-apple-darwin/share/doc/rust/html/src/core/str/iter.rs.html#38 - // only overrides 6 methods of Iterator. luckily the doc lists the names of them so we can bring them in from the trait. - // TODO: doc better - let mut impl_method_uids: Vec = - impl_.items - .iter() - .map(|x| UId { crate_name: concrete_id.crate_name.clone(), id: x.clone() }) - .collect(); - - let mut impl_methods_names = HashSet::new(); - for impl_method_uid_unresolved in &impl_method_uids { - let impl_method_item = - resolve_id::lookup_uid(crates, &impl_method_uid_unresolved); - if let Some(name) = &impl_method_item.name { - if matches!(impl_method_item.inner, ItemEnum::Function(_)) { - impl_methods_names.insert(name); - } else { - // There are sometimes associated types in there, maybe other things too - } + // This impl_.items won't actually have everything. + // some impls dont actually implement all the methods in their trait, they instead use the default implementation. for example, this + // impl<'a> Iterator for Chars<'a> { + // file:///Users/verdagon/.rustup/toolchains/nightly-aarch64-apple-darwin/share/doc/rust/html/src/core/str/iter.rs.html#38 + // only overrides 6 methods of Iterator. luckily the doc lists the names of them so we can bring them in from the trait. + // TODO: doc better + let mut impl_method_uids: Vec = + impl_.items + .iter() + .map(|x| UId { crate_name: impl_uid.crate_name.clone(), id: x.clone() }) + .collect(); + + let mut impl_methods_names = HashSet::new(); + for impl_method_uid_unresolved in &impl_method_uids { + let impl_method_item = + resolve_id::lookup_uid(crates, &impl_method_uid_unresolved); + if let Some(name) = &impl_method_item.name { + if matches!(impl_method_item.inner, ItemEnum::Function(_)) { + impl_methods_names.insert(name); + } else { + // There are sometimes associated types in there, maybe other things too } } - if let Some(trait_) = &impl_.trait_ { - let trait_id = &trait_.id; - let trait_unresolved_uid = UId { crate_name: impl_uid.crate_name.clone(), id: trait_id.clone() }; - let trait_uid = - match resolve_id::resolve_uid(crates, &primitive_name_to_uid, &trait_unresolved_uid) { - Ok(trait_uid) => trait_uid, - Err(ResolveError::NotFound) => { - resolve_id::resolve_uid(crates, &primitive_name_to_uid, &trait_unresolved_uid); - unimplemented!(); - } - Err(ResolveError::ResolveFatal(fatal)) => { - return Err(fatal) - } - }; - let trait_item = resolve_id::lookup_uid(crates, &trait_uid); - let trait_ = - match &trait_item.inner { - ItemEnum::Trait(trait_) => trait_, - _ => panic!("Not an impl!") - }; - // Here, we grab the rest from the parent trait. - let mut needed_names = HashSet::new(); - for name in &impl_.provided_trait_methods { - if impl_methods_names.contains(&name) { - continue; - } - // If we get here, then the impl didn't define this method, so it's - // inheriting it from the parent. - needed_names.insert(name); + } + if let Some(trait_) = &impl_.trait_ { + let trait_id = &trait_.id; + let trait_unresolved_uid = UId { crate_name: impl_uid.crate_name.clone(), id: trait_id.clone() }; + let trait_uid = + match resolve_id::resolve_uid(crates, &primitive_name_to_uid, &trait_unresolved_uid) { + Ok(trait_uid) => trait_uid, + Err(ResolveError::NotFound) => { + resolve_id::resolve_uid(crates, &primitive_name_to_uid, &trait_unresolved_uid); + unimplemented!(); + } + Err(ResolveError::ResolveFatal(fatal)) => { + return Err(ResolveError::ResolveFatal(fatal)) + } + }; + let trait_item = resolve_id::lookup_uid(crates, &trait_uid); + let trait_ = + match &trait_item.inner { + ItemEnum::Trait(trait_) => trait_, + _ => panic!("Not an impl!") + }; + // Here, we grab the rest from the parent trait. + let mut needed_names = HashSet::new(); + for name in &impl_.provided_trait_methods { + if impl_methods_names.contains(&name) { + continue; } + // If we get here, then the impl didn't define this method, so it's + // inheriting it from the parent. + needed_names.insert(name); + } - for trait_child_id in &trait_.items { - let trait_child_uid = UId { crate_name: trait_uid.crate_name.clone(), id: trait_child_id.clone() }; - let trait_child_item = resolve_id::lookup_uid(crates, &trait_child_uid); - if let Some(name) = &trait_child_item.name { - if needed_names.contains(name) { - impl_method_uids.push(trait_child_uid); - } + for trait_child_id in &trait_.items { + let trait_child_uid = UId { crate_name: trait_uid.crate_name.clone(), id: trait_child_id.clone() }; + let trait_child_item = resolve_id::lookup_uid(crates, &trait_child_uid); + if let Some(name) = &trait_child_item.name { + if needed_names.contains(name) { + impl_method_uids.push(trait_child_uid); } } - } - - result.append(&mut impl_method_uids); - } else { - panic!("Impl item id isn't impl."); } + + return Ok(Some(impl_method_uids)); + } else { + panic!("Impl item id isn't impl."); } - return Ok(result); } fn get_sizer_string(valtype_str: &str, needle_full_name: &str) -> String { @@ -1339,7 +1335,7 @@ fn list_struct_and_methods(v: &Crate, struct_name: &String) { ItemEnum::Struct(struuct) => { match &item.name { None => { - eprintln!("{:?}", "No name, skipping struct!") + eprintln!("No name, skipping struct!") } Some(name) => { if name == struct_name { @@ -1351,7 +1347,7 @@ fn list_struct_and_methods(v: &Crate, struct_name: &String) { ItemEnum::Impl(impl_) => { // println!("{:?}", impl_); match &impl_.for_ { - Type::QualifiedPath { name, args, self_type, trait_ } => { + Type::QualifiedPath { name, .. } => { if name == struct_name { // println!("{:?} {:?}", name, impl_); } @@ -1437,12 +1433,12 @@ fn list_struct_and_methods(v: &Crate, struct_name: &String) { } fn list_generics(v: &Crate) { - for (id, item) in &v.index { + for (_id, item) in &v.index { match &item.inner { ItemEnum::Struct(struuct) => { match &item.name { None => { - eprintln!("{:?}", "No name, skipping struct!") + eprintln!("No name, skipping struct!") } Some(name) => { if struuct.generics.params.len() > 0 { @@ -1453,7 +1449,7 @@ fn list_generics(v: &Crate) { } } } - ItemEnum::Function(func) => {} + ItemEnum::Function(_) => {} ItemEnum::Module(_) => {} ItemEnum::ExternCrate { .. } => {} ItemEnum::Import(_) => {} @@ -1493,7 +1489,7 @@ fn print_function( crates: &HashMap, item_index: &ItemIndex, crate_name: &str, - context_container: Option<&SimpleValType>, + _context_container: Option<&SimpleValType>, generics: &HashMap, item: &Item, func: &Function @@ -1803,7 +1799,7 @@ fn mangle_simple_type( // 1std_vec_Vec__Ref__std_ffi_OsString* is_root: bool ) -> String { - let mut type_ = original_type.clone(); + let type_ = original_type.clone(); let has_pointer = type_.imm_ref || type_.mut_ref; let unpointered = if is_primitive(&item_index.primitive_uid_to_name, &original_type.valtype.id) { @@ -1821,8 +1817,8 @@ fn mangle_simple_type( } } else { unimplemented!(); - // Then it's a primitive - original_type.valtype.id.id.0.clone() + // // Then it's a primitive + // original_type.valtype.id.id.0.clone() } } else { mangle_simple_valtype(crates, item_index, &type_.valtype, is_root) @@ -1852,9 +1848,9 @@ fn crustify_simple_type( // Then it's going to be a struct, not a pointer. "".to_owned() } else { - (if type_.imm_ref { "*const ".to_owned() } + if type_.imm_ref { "*const ".to_owned() } else if type_.mut_ref { "*mut ".to_owned() } - else { "".to_owned() }) + else { "".to_owned() } }) + &(if let Some(alias) = aliases.get(&type_.valtype) { alias.to_owned() @@ -1926,11 +1922,11 @@ fn rustify_simple_valtype( // So lets filter them out. func.generics.params.iter() .zip(&valtype.generic_args) - .filter(|(generic_param, generic_arg)| { + .filter(|(generic_param, _generic_arg)| { // Yeah, this seems to be the best way to find them... !generic_param.name.starts_with("impl ") }) - .map(|(generic_param, generic_arg)| generic_arg.clone()) + .map(|(_generic_param, generic_arg)| generic_arg.clone()) .collect::>() } else { valtype.generic_args.clone() @@ -2113,7 +2109,7 @@ fn simplify_type( let generic_args = if let Some(outer_args) = &path.args { match outer_args.deref() { - GenericArgs::AngleBracketed { args, bindings } => { + GenericArgs::AngleBracketed { args, .. } => { let mut result = Vec::new(); for arg in args { result.push( @@ -2121,17 +2117,18 @@ fn simplify_type( } result } - GenericArgs::Parenthesized { inputs, output } => { - let mut result = Vec::new(); - for arg in inputs { - result.push( - simplify_type(crates, &item_index, generics, unimplemented!(), arg)?); - } - for output in output { - result.push( - simplify_type(crates, &item_index, generics, unimplemented!(), output)?); - } - result + GenericArgs::Parenthesized { inputs: _, output: _ } => { + unimplemented!(); + // let mut result = Vec::new(); + // for arg in inputs { + // result.push( + // simplify_type(crates, &item_index, generics, unimplemented!(), arg)?); + // } + // for _output in output { + // result.push( + // simplify_type(crates, &item_index, generics, unimplemented!(), output)?); + // } + // result } } } else { @@ -2160,7 +2157,7 @@ fn simplify_type( } } } - Type::DynTrait(dynTrait) => { + Type::DynTrait(_dynTrait) => { println!("what"); unimplemented!(); } @@ -2169,7 +2166,7 @@ fn simplify_type( .expect(&("Unknown generic: ".to_owned() + &name)) .clone() } - Type::BorrowedRef { lifetime, mutable, type_ } => { + Type::BorrowedRef { mutable, type_, .. } => { let mut thing = simplify_type(crates, &item_index, generics, type_crate_name, type_)?; if *mutable { @@ -2210,8 +2207,8 @@ fn simplify_type( } } Type::Slice(inner) => { - eprintln!("generics: {:?}", generics); - eprintln!("slice inner: {:?}", inner); + println!("generics: {:?}", generics); + println!("slice inner: {:?}", inner); let inner_simple_type = simplify_type(crates, &item_index, generics, type_crate_name, inner)?; SimpleType { diff --git a/ValeRuster/src/resolve.rs b/ValeRuster/src/resolve.rs index e98815a64..30c96e03c 100644 --- a/ValeRuster/src/resolve.rs +++ b/ValeRuster/src/resolve.rs @@ -4,7 +4,8 @@ use crate::{resolve_id, ResolveError, SimpleType, SimpleValType, UId}; use crate::indexer::ItemIndex; use crate::ResolveError::{NotFound, ResolveFatal}; use crate::resolve_id::get_expanded_direct_child_uids; -use crate::resolve_id::get_unexpanded_direct_child_uids; +use crate::resolve_id::get_unexpanded_direct_child_uids_exclude_impl_children; +use crate::resolve_id::include_impls_children; // Recurses. pub fn resolve( @@ -100,22 +101,29 @@ pub fn resolve( let mut result_uid = foreign_crate_root_module_id.clone(); for next_foreign_crate_name in &path.path[1..] { - let mut maybe_found_child_id: Option = None; - let hay_child_uids = - match get_unexpanded_direct_child_uids(crates, &item_index.primitive_name_to_uid, &result_uid) { + let hey_direct_child_ids = + match get_unexpanded_direct_child_uids_exclude_impl_children(crates, &item_index.primitive_name_to_uid, &result_uid) { Ok(x) => x, Err(e) => return Err(ResolveFatal(e)) }; - for hay_child_id in hay_child_uids { - let hay_child = foreign_crate.index.get(&hay_child_id.id).unwrap(); + // let hay_child_keys = + // match include_impls_children(crates, &item_index.primitive_name_to_uid, hey_direct_child_ids) { + // Ok(x) => x, + // Err(e) => return Err(ResolveFatal(e)) + // }; + let mut maybe_found_child_ids: Vec = Vec::new(); + for hay_child_key in hey_direct_child_ids { + let hay_child = foreign_crate.index.get(&hay_child_key.id).unwrap(); if crate::item_has_name(&hay_child, next_foreign_crate_name) { - maybe_found_child_id = Some(hay_child_id); + maybe_found_child_ids.push(hay_child_key.clone()); } } - if maybe_found_child_id.is_none() { + if maybe_found_child_ids.len() == 0 { + unimplemented!(); + } else if maybe_found_child_ids.len() > 1 { unimplemented!(); } - result_uid = maybe_found_child_id.unwrap(); + result_uid = maybe_found_child_ids.get(0).unwrap().clone(); } // Recurse assert_ne!(&result_uid, tentative_item_id); // Otherwise infinite loop @@ -236,7 +244,7 @@ pub fn extend_and_resolve( let direct_child_uids = get_expanded_direct_child_uids( - &crates, &item_index.primitive_name_to_uid, &previous_container_id)?; + &crates, &item_index.primitive_name_to_uid, &previous_container_id, true)?; let mut found_items: Vec<(UId, &Item)> = Vec::new(); for direct_child_uid in direct_child_uids { let direct_child_item = @@ -272,8 +280,7 @@ pub fn extend_and_resolve( // Narrow down imports. Sometimes there are two imports pointing to the same place. // WARNING: THIS MODIFIES unnarrowed_impls which is read below. - let mut narrowed_imports: Vec<(UId, &Import)> = Vec::new(); - for (import_uid, import) in &unnarrowed_imports { + for (import_uid, _import) in &unnarrowed_imports { let resolved_import_uid = match resolve_id::resolve_uid(crates, &item_index.primitive_name_to_uid, import_uid) { Ok(thing) => thing, @@ -304,7 +311,7 @@ pub fn extend_and_resolve( for (item_uid, item) in unfiltered_unnarrowed_others { match &item.inner { ItemEnum::Import(_) | ItemEnum::TypeAlias(_) => panic!("Resolve didn't work!"), - ItemEnum::Impl(impl_) => panic!("Impl shouldnt be in this list"), + ItemEnum::Impl(_impl_) => panic!("Impl shouldnt be in this list"), ItemEnum::Module(_) | ItemEnum::Struct(_) | ItemEnum::Trait(_) | ItemEnum::Function(_) | ItemEnum::Enum(_) => { unnarrowed_others.push((item_uid, &item)); } @@ -315,8 +322,15 @@ pub fn extend_and_resolve( } } - unnarrowed_others.dedup_by_key(|(id, _)| id.clone()); - unnarrowed_impls.dedup_by_key(|(id, _)| id.clone()); + // Dedup + unnarrowed_others = + unnarrowed_others + .into_iter().collect::>() + .into_iter().collect(); + unnarrowed_impls = + unnarrowed_impls + .into_iter().collect::>() + .into_iter().collect(); // Narrow down impls let mut impl_matches: Vec<(UId, &Impl, i64, Vec)> = Vec::new(); @@ -325,13 +339,13 @@ pub fn extend_and_resolve( impl_matches.push((impl_uid.clone(), impl_, score, generics)); } } - if impl_matches.len() + narrowed_imports.len() > 1 && + if impl_matches.len() + unnarrowed_others.len() > 1 && impl_matches.len() > 0 { eprintln!("Too many matches! Doing impl overload resolution."); for m in &impl_matches { eprintln!("Candidate: {:?}", m); } - impl_matches.sort_by_key(|(id, impl_, score, generics)| { + impl_matches.sort_by_key(|(_id, _impl_, score, _generics)| { -score // We want highest first }); if impl_matches.len() > 1 { @@ -343,7 +357,7 @@ pub fn extend_and_resolve( impl_matches = vec![impl_matches.remove(0)]; } - if impl_matches.len() + narrowed_imports.len() > 1 { + if impl_matches.len() + unnarrowed_others.len() > 1 { let error = format!("Too many matches for name: {}", name); return Err(ResolveFatal(anyhow::Error::new(std::io::Error::new(std::io::ErrorKind::Other, error)))); } @@ -354,7 +368,7 @@ pub fn extend_and_resolve( } ( - narrowed_imports, + Vec::new(), narrowed_impls.into_iter() .map(|(uid, import, score, generics)| { (uid, import, Some((score, generics))) @@ -404,7 +418,7 @@ pub fn extend_and_resolve( let (perhaps_unresolved_uid, generics) = if impls.len() > 0 { let impl_id = impls[0].0.clone(); - if let Some((score, generics)) = &impls[0].2 { + if let Some((_score, generics)) = &impls[0].2 { (impl_id, generics.clone()) } else { (impl_id, Vec::new()) diff --git a/ValeRuster/src/resolve_id.rs b/ValeRuster/src/resolve_id.rs index 6b48075a2..3c27f93e2 100644 --- a/ValeRuster/src/resolve_id.rs +++ b/ValeRuster/src/resolve_id.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use rustdoc_types::{Crate, Import, Item, ItemEnum, Type}; -use crate::{get_concrete_impls, get_concrete_impls_children, ResolveError, UId}; +use crate::{GenealogyKey, get_concrete_impls, get_impl_children, ResolveError, UId}; use crate::ResolveError::{NotFound, ResolveFatal}; // Recurses. @@ -19,7 +19,8 @@ pub fn resolve_uid( Some(path) => { let foreign_crate_name = &path.path[0]; // let foreign_crate = crates.get(foreign_crate_name).unwrap(); - let mut current = extend_and_resolve_uid(crates, &primitive_name_to_uid, None, foreign_crate_name)?; + let mut current = + extend_and_resolve_uid(crates, &primitive_name_to_uid, None, foreign_crate_name)?; for i in 1.. path.path.len() { let step = &path.path[i]; current = @@ -86,9 +87,10 @@ pub fn resolve_uid( let mut result_uid = foreign_crate_root_module_id.clone(); for next_foreign_crate_name in &path.path[1..] { - let mut found_child_uids = Vec::new(); + let mut found_child_uids: Vec = Vec::new(); let hay_child_uids = - match get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &result_uid) { + match get_unexpanded_direct_child_uids_exclude_impl_children( + crates, &primitive_name_to_uid, &result_uid) { Ok(x) => x, Err(e) => return Err(ResolveFatal(e)) }; @@ -150,6 +152,7 @@ pub(crate) fn extend_and_resolve_uid( // because they have a special entry in the Type enum. // We'll just use the empty string. return Ok(crate::tuple_id(&primitive_name_to_uid)); + // return Ok(ChildKey::Normal { id: crate::tuple_id(&primitive_name_to_uid) }); } match previous { @@ -157,6 +160,7 @@ pub(crate) fn extend_and_resolve_uid( match name { "bool" | "char" | "f32" | "f64" | "f128" | "i128" | "i16" | "i32" | "i64" | "i8" | "isize" | "str" | "u128" | "u16" | "u32" | "u64" | "u8" | "usize" => { Ok(crate::primitive_id(&primitive_name_to_uid, name)) + // Ok(ChildKey::Normal { id: crate::primitive_id(&primitive_name_to_uid, name) }) } _ => { match crates.get(name) { @@ -167,6 +171,7 @@ pub(crate) fn extend_and_resolve_uid( Some(crate_) => { let root_module_id = &crate_.root; Ok(UId { crate_name: name.to_string(), id: root_module_id.clone() }) + // Ok(ChildKey::Normal { id: UId { crate_name: name.to_string(), id: root_module_id.clone() }}) } } } @@ -178,16 +183,21 @@ pub(crate) fn extend_and_resolve_uid( let previous_crate = crates.get(previous_crate_name).unwrap(); // let previous_container_item = previous_crate.index.get(&previous_container_id.id).unwrap(); - let direct_child_uids = - match get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &previous_container_id) { + let direct_child_uids_without_methods = + match get_unexpanded_direct_child_uids_exclude_impl_children(crates, &primitive_name_to_uid, &previous_container_id) { Ok(x) => x, Err(e) => return Err(ResolveFatal(e)) - };; + }; + let direct_child_keys = + match include_impls_children(crates, &primitive_name_to_uid, direct_child_uids_without_methods) { + Ok(x) => x, + Err(e) => return Err(ResolveFatal(e)) + }; + let direct_child_uids = collapse_children(&direct_child_keys); + let mut found_items: Vec<(UId, &Item)> = Vec::new(); for direct_child_uid in direct_child_uids { let direct_child_item = - // seems sus that we're looking in previous crate when we can just - // look in direct_child_uid.crate_name previous_crate.index.get(&direct_child_uid.id).unwrap(); if crate::item_has_name(&direct_child_item, name) { found_items.push((direct_child_uid, direct_child_item)); @@ -197,7 +207,7 @@ pub(crate) fn extend_and_resolve_uid( let mut new_found_items: Vec<(UId, &Item)> = Vec::new(); for (found_child_unresolved_uid, item) in &found_items { let found_child_uid = - match resolve_uid(crates, primitive_name_to_uid, found_child_unresolved_uid) { + match resolve_uid(crates, primitive_name_to_uid, &found_child_unresolved_uid) { Ok(found_child_id) => found_child_id, Err(ResolveError::NotFound) => { unimplemented!() @@ -232,7 +242,7 @@ pub(crate) fn extend_and_resolve_uid( // .map(|(a, b)| (a, b.clone())) // .collect())); } - let (found_item_uid, found_item) = found_items.remove(0); + let (found_item_uid, _found_item) = found_items.remove(0); let result_step = resolve_uid(crates, &primitive_name_to_uid, &found_item_uid)?; @@ -283,15 +293,15 @@ fn resolve_type_uid( Err(ResolveError::ResolveFatal(fatal)) => return Err(fatal) } } - Type::DynTrait(dynTrait) => { + Type::DynTrait(_dynTrait) => { println!("what"); unimplemented!(); } - Type::Generic(name) => unimplemented!(), + Type::Generic(_name) => unimplemented!(), Type::BorrowedRef { type_, .. } => resolve_type_uid(crates, primitive_name_to_uid, type_crate_name, type_)?, Type::Primitive(name) => crate::primitive_id(primitive_name_to_uid, name), Type::FunctionPointer(_) => unimplemented!(), - Type::Tuple(inners) => crate::tuple_id(&primitive_name_to_uid, ), + Type::Tuple(_inners) => crate::tuple_id(&primitive_name_to_uid, ), Type::Slice(_) => unimplemented!(), Type::Array { .. } => unimplemented!(), Type::Pat { .. } => unimplemented!(), @@ -305,13 +315,22 @@ fn resolve_type_uid( pub(crate) fn get_expanded_direct_child_uids( crates: &HashMap, primitive_name_to_uid: &HashMap, - previous_container_id: &UId + previous_container_id: &UId, + include_impls_children_: bool ) -> Result, ResolveError> { - let unexpanded_direct_child_uids: Vec = - match get_unexpanded_direct_child_uids(crates, &primitive_name_to_uid, &previous_container_id) { + let unexpanded_direct_child_uids_without_methods: Vec = + match get_unexpanded_direct_child_uids_exclude_impl_children(crates, &primitive_name_to_uid, &previous_container_id) { + Ok(x) => x, + Err(e) => return Err(ResolveFatal(e)) + }; + assert!(include_impls_children_); // false is unimplemented + let unexpanded_direct_child_keys = + match include_impls_children(crates, primitive_name_to_uid, unexpanded_direct_child_uids_without_methods) { Ok(x) => x, Err(e) => return Err(ResolveFatal(e)) }; + let unexpanded_direct_child_uids = collapse_children(&unexpanded_direct_child_keys); + let mut direct_child_uids: Vec = vec![]; for direct_child_uid in unexpanded_direct_child_uids.clone() { match &lookup_uid(crates, &direct_child_uid).inner { @@ -328,7 +347,7 @@ pub(crate) fn get_expanded_direct_child_uids( })?; direct_child_uids.append( &mut get_expanded_direct_child_uids( - crates, &primitive_name_to_uid, &target_module_uid)?); + crates, &primitive_name_to_uid, &target_module_uid, true)?); } _ => { direct_child_uids.push(direct_child_uid); @@ -338,41 +357,129 @@ pub(crate) fn get_expanded_direct_child_uids( Ok(direct_child_uids) } -pub(crate) fn get_unexpanded_direct_child_uids( +#[derive(Clone, Debug)] +pub(crate) enum ChildKey { + Normal { id: UId }, + ImplChild { impl_id: UId, child_id: UId } +} +impl ChildKey { + pub(crate) fn uid(&self) -> UId { + match self { + ChildKey::Normal { id: uid } => uid.clone(), + ChildKey::ImplChild { child_id, .. } => child_id.clone(), + } + } + fn expect_normal(&self) -> UId { + match self { + ChildKey::Normal { id: uid } => uid.clone(), + ChildKey::ImplChild { .. } => panic!("expect_normal failed!"), + } + } +} + +pub(crate) fn include_impls_children( crates: &HashMap, primitive_name_to_uid: &HashMap, - container_id: &UId, + original_ids: Vec +) -> anyhow::Result> { + let mut result= Vec::new(); + for direct_child_id in &original_ids { + result.push(ChildKey::Normal{ id: direct_child_id.clone() }); + } + + for original_id in original_ids { + match &lookup_uid(crates, &original_id).inner { + ItemEnum::Impl(_) => { + let impl_uid = original_id; + match get_impl_children(crates, &primitive_name_to_uid, &impl_uid) { + Ok(Some(impl_child_uids)) => { + for impl_child_uid in impl_child_uids { + // println!("Found impl {:?}'s direct child {:?}", impl_uid, impl_child_uid); + result.push( + ChildKey::ImplChild { + impl_id: impl_uid.clone(), + child_id: impl_child_uid.clone() + }); + } + }, + Ok(None) => {} + Err(ResolveError::NotFound) => unimplemented!(), + Err(ResolveFatal(e)) => return Err(e) + } + } + _ => {} + } + } + + Ok(result) +} + +pub(crate) fn collapse_children( + original_ids: &Vec +) -> Vec { + let mut result: Vec = Vec::new(); + for direct_child_id in original_ids { + result.push(direct_child_id.uid().clone()); + } + // std::io::Cursor: "0:8994:8529" + // has impls "0:2960", "0:2955", "0:2966", "0:2972", "0:2978": + // - impl Write for Cursor<&mut [u8]> + // - impl Write for Cursor<&mut Vec> where A: Allocator + // - impl Write for Cursor<[u8; N]> + // - impl Write for Cursor> where A: Allocator + // - impl Write for Cursor> where A: Allocator + // which all have method write_all "0:3610:7588" + // So here we dedup them. + result + .into_iter().collect::>() + .into_iter().collect::>() +} + +// Unexpanded refers to any potential glob imports. +pub(crate) fn get_unexpanded_direct_child_uids_exclude_impl_children( + crates: &HashMap, + primitive_name_to_uid: &HashMap, + container_id: &UId ) -> anyhow::Result> { + let include_impls_children = false; let container_item = crates .get(&container_id.crate_name).unwrap() .index.get(&container_id.id).unwrap(); match &container_item.inner { ItemEnum::Module(m) => { - Ok( - m.items.iter() - .map(|x| UId { crate_name: container_id.crate_name.clone(), id: x.clone() }) - .collect()) + let mut result = Vec::new(); + for child in &m.items { + // eprintln!("Found module's direct child {:?}", child); + result.push(UId { crate_name: container_id.crate_name.clone(), id: child.clone() }); + } + Ok(result) }, ItemEnum::Trait(t) => { - Ok( - t.items.iter() - .map(|x| UId { crate_name: container_id.crate_name.clone(), id: x.clone() }) - .collect()) + let mut result = Vec::new(); + for child in &t.items { + // eprintln!("Found trait's direct child {:?}", child); + result.push(UId { crate_name: container_id.crate_name.clone(), id: child.clone() }); + } + Ok(result) }, ItemEnum::Struct(_) | ItemEnum::Enum(_) | ItemEnum::Primitive(_) => { // TODO: optimize: get_concrete_impls_children is repeating get_concrete_impls's work - let mut result = Vec::new(); - for thing in get_concrete_impls(crates, primitive_name_to_uid, &container_id) { - result.push(thing); - } - for children in get_concrete_impls_children(crates, &primitive_name_to_uid, &container_id)? { - result.push(children); + let mut result: Vec = Vec::new(); + // eprintln!("Looking through things..."); + for impl_uid in get_concrete_impls(crates, primitive_name_to_uid, &container_id) { + // eprintln!("Found concrete's direct child {:?}", impl_uid); + result.push(impl_uid.clone()); } Ok(result) } ItemEnum::Impl(impl_) => { - Ok(impl_.items.iter().map(|x| UId { crate_name: container_id.crate_name.clone(), id: x.clone() }).collect()) + let mut result = Vec::new(); + for child in &impl_.items { + // eprintln!("Found standalone impl's direct child {:?}", container_id); + result.push(UId { crate_name: container_id.crate_name.clone(), id: child.clone() }); + } + Ok(result) } _ => unimplemented!() }