From 7a2e449424227c7f6cebe0581513287023297999 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 28 Jan 2020 00:09:56 +0200 Subject: Prefer imports starting with std --- crates/ra_hir_def/src/find_path.rs | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 8cc2fb160..d9e67607f 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -7,7 +7,7 @@ use crate::{ visibility::Visibility, CrateId, ModuleDefId, ModuleId, }; -use hir_expand::name::Name; +use hir_expand::name::{known, Name}; const MAX_PATH_LEN: usize = 15; @@ -102,7 +102,7 @@ fn find_path_inner( let mut best_path = None; let mut best_path_len = max_len; for (module_id, name) in importable_locations { - let mut path = match find_path_inner( + let mut new_path = match find_path_inner( db, ItemInNs::Types(ModuleDefId::ModuleId(module_id)), from, @@ -111,15 +111,40 @@ fn find_path_inner( None => continue, Some(path) => path, }; - path.segments.push(name); - if path_len(&path) < best_path_len { - best_path_len = path_len(&path); - best_path = Some(path); + new_path.segments.push(name); + + if prefer_new_path(best_path_len, best_path.as_ref(), &new_path) { + best_path_len = path_len(&new_path); + best_path = Some(new_path); } } best_path } +fn prefer_new_path(old_path_len: usize, old_path: Option<&ModPath>, new_path: &ModPath) -> bool { + match (old_path.and_then(|mod_path| mod_path.segments.first()), new_path.segments.first()) { + (Some(old_path_start), Some(new_path_start)) + if old_path_start == &known::std && use_std_instead(new_path_start) => + { + false + } + (Some(old_path_start), Some(new_path_start)) + if new_path_start == &known::std && use_std_instead(old_path_start) => + { + true + } + (None, Some(_)) => true, + (Some(_), None) => false, + _ => path_len(new_path) < old_path_len, + } +} + +// When std library is present, paths starting with `std::` +// should be preferred over paths starting with `core::` and `alloc::` +fn use_std_instead(name: &Name) -> bool { + name == &known::core || name == &known::alloc +} + fn path_len(path: &ModPath) -> usize { path.segments.len() + match path.kind { -- cgit v1.2.3 From 762d2935818bbd2639a19b1994b2ddfeac5529b2 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 28 Jan 2020 17:19:41 +0200 Subject: Apply the proposed refactoring --- crates/ra_hir_def/src/find_path.rs | 81 ++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 38 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index d9e67607f..ebfd6e211 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -11,6 +11,34 @@ use hir_expand::name::{known, Name}; const MAX_PATH_LEN: usize = 15; +impl ModPath { + fn starts_with_std(&self) -> bool { + self.segments.first().filter(|&first_segment| first_segment == &known::std).is_some() + } + + // When std library is present, paths starting with `std::` + // should be preferred over paths starting with `core::` and `alloc::` + fn should_start_with_std(&self) -> bool { + self.segments + .first() + .filter(|&first_segment| { + first_segment == &known::alloc || first_segment == &known::core + }) + .is_some() + } + + fn len(&self) -> usize { + self.segments.len() + + match self.kind { + PathKind::Plain => 0, + PathKind::Super(i) => i as usize, + PathKind::Crate => 1, + PathKind::Abs => 0, + PathKind::DollarCrate(_) => 1, + } + } +} + // FIXME: handle local items /// Find a path that can be used to refer to a certain item. This can depend on @@ -102,7 +130,7 @@ fn find_path_inner( let mut best_path = None; let mut best_path_len = max_len; for (module_id, name) in importable_locations { - let mut new_path = match find_path_inner( + let mut path = match find_path_inner( db, ItemInNs::Types(ModuleDefId::ModuleId(module_id)), from, @@ -111,51 +139,28 @@ fn find_path_inner( None => continue, Some(path) => path, }; - new_path.segments.push(name); + path.segments.push(name); - if prefer_new_path(best_path_len, best_path.as_ref(), &new_path) { - best_path_len = path_len(&new_path); - best_path = Some(new_path); - } + let new_path = + if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path }; + best_path_len = new_path.len(); + best_path = Some(new_path); } best_path } -fn prefer_new_path(old_path_len: usize, old_path: Option<&ModPath>, new_path: &ModPath) -> bool { - match (old_path.and_then(|mod_path| mod_path.segments.first()), new_path.segments.first()) { - (Some(old_path_start), Some(new_path_start)) - if old_path_start == &known::std && use_std_instead(new_path_start) => - { - false - } - (Some(old_path_start), Some(new_path_start)) - if new_path_start == &known::std && use_std_instead(old_path_start) => - { - true - } - (None, Some(_)) => true, - (Some(_), None) => false, - _ => path_len(new_path) < old_path_len, +fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath { + if old_path.starts_with_std() && new_path.should_start_with_std() { + old_path + } else if new_path.starts_with_std() && old_path.should_start_with_std() { + new_path + } else if new_path.len() < old_path.len() { + new_path + } else { + old_path } } -// When std library is present, paths starting with `std::` -// should be preferred over paths starting with `core::` and `alloc::` -fn use_std_instead(name: &Name) -> bool { - name == &known::core || name == &known::alloc -} - -fn path_len(path: &ModPath) -> usize { - path.segments.len() - + match path.kind { - PathKind::Plain => 0, - PathKind::Super(i) => i as usize, - PathKind::Crate => 1, - PathKind::Abs => 0, - PathKind::DollarCrate(_) => 1, - } -} - fn find_importable_locations( db: &impl DefDatabase, item: ItemInNs, -- cgit v1.2.3 From 4b9e5d5dd9e4e477fdff9051056fd2be4bf4b538 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Jan 2020 16:29:31 +0100 Subject: Publicize debug printing of CrateDefMap --- crates/ra_hir_def/src/nameres.rs | 40 +++++++++++++++++++++++++++++++ crates/ra_hir_def/src/nameres/tests.rs | 43 ++-------------------------------- 2 files changed, 42 insertions(+), 41 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 27c12e46c..852304dd0 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -229,6 +229,46 @@ impl CrateDefMap { self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); (res.resolved_def, res.segment_index) } + + // FIXME: this can use some more human-readable format (ideally, an IR + // even), as this should be a great debugging aid. + pub fn dump(&self) -> String { + let mut buf = String::new(); + go(&mut buf, self, "\ncrate", self.root); + return buf.trim().to_string(); + + fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { + *buf += path; + *buf += "\n"; + + let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); + entries.sort_by_key(|(name, _)| name.clone()); + + for (name, def) in entries { + *buf += &format!("{}:", name); + + if def.types.is_some() { + *buf += " t"; + } + if def.values.is_some() { + *buf += " v"; + } + if def.macros.is_some() { + *buf += " m"; + } + if def.is_none() { + *buf += " _"; + } + + *buf += "\n"; + } + + for (name, child) in map.modules[module].children.iter() { + let path = path.to_string() + &format!("::{}", name); + go(buf, map, &path, *child); + } + } + } } impl ModuleData { diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 78bcdc850..82f0f835c 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs @@ -10,11 +10,10 @@ use insta::assert_snapshot; use ra_db::{fixture::WithFixture, SourceDatabase}; use test_utils::covers; -use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId}; +use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; fn def_map(fixture: &str) -> String { - let dm = compute_crate_def_map(fixture); - render_crate_def_map(&dm) + compute_crate_def_map(fixture).dump() } fn compute_crate_def_map(fixture: &str) -> Arc { @@ -23,44 +22,6 @@ fn compute_crate_def_map(fixture: &str) -> Arc { db.crate_def_map(krate) } -fn render_crate_def_map(map: &CrateDefMap) -> String { - let mut buf = String::new(); - go(&mut buf, map, "\ncrate", map.root); - return buf.trim().to_string(); - - fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { - *buf += path; - *buf += "\n"; - - let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); - entries.sort_by_key(|(name, _)| name.clone()); - - for (name, def) in entries { - *buf += &format!("{}:", name); - - if def.types.is_some() { - *buf += " t"; - } - if def.values.is_some() { - *buf += " v"; - } - if def.macros.is_some() { - *buf += " m"; - } - if def.is_none() { - *buf += " _"; - } - - *buf += "\n"; - } - - for (name, child) in map.modules[module].children.iter() { - let path = path.to_string() + &format!("::{}", name); - go(buf, map, &path, *child); - } - } -} - #[test] fn crate_def_map_smoke_test() { let map = def_map( -- cgit v1.2.3 From 713870ee0c51a11dc0d2a5b8eafbc2624d42c359 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 28 Jan 2020 18:03:24 +0200 Subject: Add the tests --- crates/ra_hir_def/src/find_path.rs | 41 ++++++++++++++++++++++++++++++++++++++ crates/ra_hir_def/src/marks.rs | 1 + 2 files changed, 42 insertions(+) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index ebfd6e211..43b9b124a 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs @@ -8,6 +8,7 @@ use crate::{ CrateId, ModuleDefId, ModuleId, }; use hir_expand::name::{known, Name}; +use test_utils::tested_by; const MAX_PATH_LEN: usize = 15; @@ -151,8 +152,10 @@ fn find_path_inner( fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath { if old_path.starts_with_std() && new_path.should_start_with_std() { + tested_by!(prefer_std_paths); old_path } else if new_path.starts_with_std() && old_path.should_start_with_std() { + tested_by!(prefer_std_paths); new_path } else if new_path.len() < old_path.len() { new_path @@ -231,6 +234,7 @@ mod tests { use hir_expand::hygiene::Hygiene; use ra_db::fixture::WithFixture; use ra_syntax::ast::AstNode; + use test_utils::covers; /// `code` needs to contain a cursor marker; checks that `find_path` for the /// item the `path` refers to returns that same path when called from the @@ -482,4 +486,41 @@ mod tests { "#; check_found_path(code, "crate::foo::S"); } + + #[test] + fn prefer_std_paths_over_alloc() { + covers!(prefer_std_paths); + let code = r#" + //- /main.rs crate:main deps:alloc,std + <|> + + //- /std.rs crate:std deps:alloc + pub mod sync { + pub use alloc::sync::Arc; + } + + //- /zzz.rs crate:alloc + pub mod sync { + pub struct Arc; + } + "#; + check_found_path(code, "std::sync::Arc"); + } + + #[test] + fn prefer_shorter_paths_if_not_alloc() { + let code = r#" + //- /main.rs crate:main deps:megaalloc,std + <|> + + //- /std.rs crate:std deps:megaalloc + pub mod sync { + pub use megaalloc::sync::Arc; + } + + //- /zzz.rs crate:megaalloc + pub struct Arc; + "#; + check_found_path(code, "megaalloc::Arc"); + } } diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs index 457ba4abe..daa49d5f1 100644 --- a/crates/ra_hir_def/src/marks.rs +++ b/crates/ra_hir_def/src/marks.rs @@ -13,4 +13,5 @@ test_utils::marks!( macro_dollar_crate_self macro_dollar_crate_other infer_resolve_while_let + prefer_std_paths ); -- cgit v1.2.3 From 6dae5cbb1190cde6a20aa1758c7d87e84933378e Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 2 Feb 2020 14:06:51 +0200 Subject: Require ModPath for importing --- crates/ra_hir_def/src/path.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index ab290e2c9..a150b899f 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -16,13 +16,13 @@ use ra_syntax::ast; use crate::{type_ref::TypeRef, InFile}; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ModPath { pub kind: PathKind, pub segments: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum PathKind { Plain, /// `self::` is `Super(0)` -- cgit v1.2.3 From 7d527159457420d55f1ee2f70615098a10176b91 Mon Sep 17 00:00:00 2001 From: zombiefungus Date: Thu, 30 Jan 2020 23:14:20 -0500 Subject: add new ImportAlias enum to differentiate no alias from an _ alias --- crates/ra_hir_def/src/nameres/collector.rs | 5 ++++- crates/ra_hir_def/src/nameres/raw.rs | 15 +++++++++++++-- crates/ra_hir_def/src/path.rs | 7 ++++++- crates/ra_hir_def/src/path/lower/lower_use.rs | 14 +++++++------- 4 files changed, 30 insertions(+), 11 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 7499dff31..193067f73 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -438,7 +438,10 @@ where } else { match import.path.segments.last() { Some(last_segment) => { - let name = import.alias.clone().unwrap_or_else(|| last_segment.clone()); + let name = match &import.alias { + raw::ImportAlias::Alias(name) => name.clone(), + _ => last_segment.clone(), // "use as ;" and "use as _;" are treated the same way + }; log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index fac1169ef..f068b4d4e 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -145,7 +145,7 @@ impl_arena_id!(Import); #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportData { pub(super) path: ModPath, - pub(super) alias: Option, + pub(super) alias: ImportAlias, pub(super) is_glob: bool, pub(super) is_prelude: bool, pub(super) is_extern_crate: bool, @@ -153,6 +153,13 @@ pub struct ImportData { pub(super) visibility: RawVisibility, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ImportAlias { + NoAlias, + Unnamed, // use Foo as _; + Alias(Name), +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(super) struct Def(RawId); impl_arena_id!(Def); @@ -353,7 +360,11 @@ impl RawItemsCollector { let path = ModPath::from_name_ref(&name_ref); let visibility = RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene); - let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); + let alias = extern_crate.alias().map_or(ImportAlias::NoAlias, |a| { + a.name() + .map(|it| it.as_name()) + .map_or(ImportAlias::Unnamed, |a| ImportAlias::Alias(a)) + }); let attrs = self.parse_attrs(&extern_crate); // FIXME: cfg_attr let is_macro_use = extern_crate.has_atom_attr("macro_use"); diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index ab290e2c9..27ccf6643 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -57,7 +57,12 @@ impl ModPath { pub(crate) fn expand_use_item( item_src: InFile, hygiene: &Hygiene, - mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option), + mut cb: impl FnMut( + ModPath, + &ast::UseTree, + /* is_glob */ bool, + crate::nameres::raw::ImportAlias, + ), ) { if let Some(tree) = item_src.value.use_tree() { lower::lower_use_tree(None, tree, hygiene, &mut cb); diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs index 531878174..f693cefbc 100644 --- a/crates/ra_hir_def/src/path/lower/lower_use.rs +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs @@ -4,20 +4,18 @@ use std::iter; use either::Either; -use hir_expand::{ - hygiene::Hygiene, - name::{AsName, Name}, -}; +use hir_expand::{hygiene::Hygiene, name::AsName}; use ra_syntax::ast::{self, NameOwner}; use test_utils::tested_by; +use crate::nameres::raw::ImportAlias; use crate::path::{ModPath, PathKind}; pub(crate) fn lower_use_tree( prefix: Option, tree: ast::UseTree, hygiene: &Hygiene, - cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option), + cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, ImportAlias), ) { if let Some(use_tree_list) = tree.use_tree_list() { let prefix = match tree.path() { @@ -34,7 +32,9 @@ pub(crate) fn lower_use_tree( lower_use_tree(prefix.clone(), child_tree, hygiene, cb); } } else { - let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); + let alias = tree.alias().map_or(ImportAlias::NoAlias, |a| { + a.name().map(|it| it.as_name()).map_or(ImportAlias::Unnamed, |a| ImportAlias::Alias(a)) + }); let is_glob = tree.has_star(); if let Some(ast_path) = tree.path() { // Handle self in a path. @@ -57,7 +57,7 @@ pub(crate) fn lower_use_tree( } else if is_glob { tested_by!(glob_enum_group); if let Some(prefix) = prefix { - cb(prefix, &tree, is_glob, None) + cb(prefix, &tree, is_glob, ImportAlias::NoAlias) } } } -- cgit v1.2.3 From f4f71e361ee632a7a09b633934a9c0a11f4a9be7 Mon Sep 17 00:00:00 2001 From: zombiefungus Date: Sun, 2 Feb 2020 08:04:06 -0500 Subject: include requested changes --- crates/ra_hir_def/src/nameres/collector.rs | 7 ++++--- crates/ra_hir_def/src/nameres/raw.rs | 20 ++++++++------------ crates/ra_hir_def/src/path.rs | 15 +++++++++------ crates/ra_hir_def/src/path/lower/lower_use.rs | 13 +++++++------ 4 files changed, 28 insertions(+), 27 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 193067f73..6352c71ef 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -22,7 +22,7 @@ use crate::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, }, - path::{ModPath, PathKind}, + path::{ImportAlias, ModPath, PathKind}, per_ns::PerNs, visibility::Visibility, AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, @@ -439,8 +439,9 @@ where match import.path.segments.last() { Some(last_segment) => { let name = match &import.alias { - raw::ImportAlias::Alias(name) => name.clone(), - _ => last_segment.clone(), // "use as ;" and "use as _;" are treated the same way + Some(ImportAlias::Alias(name)) => name.clone(), + Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 + None => last_segment.clone(), }; log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f068b4d4e..650cf1f98 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -22,8 +22,11 @@ use ra_syntax::{ use test_utils::tested_by; use crate::{ - attr::Attrs, db::DefDatabase, path::ModPath, visibility::RawVisibility, FileAstId, HirFileId, - InFile, + attr::Attrs, + db::DefDatabase, + path::{ImportAlias, ModPath}, + visibility::RawVisibility, + FileAstId, HirFileId, InFile, }; /// `RawItems` is a set of top-level items in a file (except for impls). @@ -145,7 +148,7 @@ impl_arena_id!(Import); #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportData { pub(super) path: ModPath, - pub(super) alias: ImportAlias, + pub(super) alias: Option, pub(super) is_glob: bool, pub(super) is_prelude: bool, pub(super) is_extern_crate: bool, @@ -153,13 +156,6 @@ pub struct ImportData { pub(super) visibility: RawVisibility, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ImportAlias { - NoAlias, - Unnamed, // use Foo as _; - Alias(Name), -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(super) struct Def(RawId); impl_arena_id!(Def); @@ -360,10 +356,10 @@ impl RawItemsCollector { let path = ModPath::from_name_ref(&name_ref); let visibility = RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene); - let alias = extern_crate.alias().map_or(ImportAlias::NoAlias, |a| { + let alias = extern_crate.alias().map(|a| { a.name() .map(|it| it.as_name()) - .map_or(ImportAlias::Unnamed, |a| ImportAlias::Alias(a)) + .map_or(ImportAlias::Underscore, |a| ImportAlias::Alias(a)) }); let attrs = self.parse_attrs(&extern_crate); // FIXME: cfg_attr diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 27ccf6643..fb7692191 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -34,6 +34,14 @@ pub enum PathKind { DollarCrate(CrateId), } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ImportAlias { + /// Unnamed alias, as in `use Foo as _;` + Underscore, + /// Named alias + Alias(Name), +} + impl ModPath { pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option { lower::lower_path(path, hygiene).map(|it| it.mod_path) @@ -57,12 +65,7 @@ impl ModPath { pub(crate) fn expand_use_item( item_src: InFile, hygiene: &Hygiene, - mut cb: impl FnMut( - ModPath, - &ast::UseTree, - /* is_glob */ bool, - crate::nameres::raw::ImportAlias, - ), + mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option), ) { if let Some(tree) = item_src.value.use_tree() { lower::lower_use_tree(None, tree, hygiene, &mut cb); diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs index f693cefbc..d2bc9d193 100644 --- a/crates/ra_hir_def/src/path/lower/lower_use.rs +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs @@ -8,14 +8,13 @@ use hir_expand::{hygiene::Hygiene, name::AsName}; use ra_syntax::ast::{self, NameOwner}; use test_utils::tested_by; -use crate::nameres::raw::ImportAlias; -use crate::path::{ModPath, PathKind}; +use crate::path::{ImportAlias, ModPath, PathKind}; pub(crate) fn lower_use_tree( prefix: Option, tree: ast::UseTree, hygiene: &Hygiene, - cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, ImportAlias), + cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option), ) { if let Some(use_tree_list) = tree.use_tree_list() { let prefix = match tree.path() { @@ -32,8 +31,10 @@ pub(crate) fn lower_use_tree( lower_use_tree(prefix.clone(), child_tree, hygiene, cb); } } else { - let alias = tree.alias().map_or(ImportAlias::NoAlias, |a| { - a.name().map(|it| it.as_name()).map_or(ImportAlias::Unnamed, |a| ImportAlias::Alias(a)) + let alias = tree.alias().map(|a| { + a.name() + .map(|it| it.as_name()) + .map_or(ImportAlias::Underscore, |a| ImportAlias::Alias(a)) }); let is_glob = tree.has_star(); if let Some(ast_path) = tree.path() { @@ -57,7 +58,7 @@ pub(crate) fn lower_use_tree( } else if is_glob { tested_by!(glob_enum_group); if let Some(prefix) = prefix { - cb(prefix, &tree, is_glob, ImportAlias::NoAlias) + cb(prefix, &tree, is_glob, None) } } } -- cgit v1.2.3 From 93aa166748eef9560df2435391dc3f3b53f8262d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 24 Jan 2020 19:35:09 +0100 Subject: wip lower impl trait to type args --- crates/ra_hir_def/src/generics.rs | 45 ++++++++++++++++++++++++++++++++++----- crates/ra_hir_def/src/resolver.rs | 10 +++++---- crates/ra_hir_def/src/type_ref.rs | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 9 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index e9c28c730..7553d8a87 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -27,8 +27,16 @@ use crate::{ /// Data about a generic parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug)] pub struct TypeParamData { - pub name: Name, + pub name: Option, pub default: Option, + pub provenance: TypeParamProvenance, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum TypeParamProvenance { + TypeParamList, + TraitSelf, + ArgumentImplTrait, } /// Data about the generic parameters of a function, struct, impl, etc. @@ -68,6 +76,11 @@ impl GenericParams { GenericDefId::FunctionId(it) => { let src = it.lookup(db).source(db); generics.fill(&mut sm, &src.value); + // lower `impl Trait` in arguments + let data = db.function_data(it); + for param in &data.params { + generics.fill_implicit_impl_trait_args(param); + } src.file_id } GenericDefId::AdtId(AdtId::StructId(it)) => { @@ -89,8 +102,11 @@ impl GenericParams { let src = it.lookup(db).source(db); // traits get the Self type as an implicit first type parameter - let self_param_id = - generics.types.alloc(TypeParamData { name: name![Self], default: None }); + let self_param_id = generics.types.alloc(TypeParamData { + name: Some(name![Self]), + default: None, + provenance: TypeParamProvenance::TraitSelf, + }); sm.insert(self_param_id, Either::Left(src.value.clone())); // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar @@ -142,7 +158,11 @@ impl GenericParams { let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); // FIXME: Use `Path::from_src` let default = type_param.default_type().map(TypeRef::from_ast); - let param = TypeParamData { name: name.clone(), default }; + let param = TypeParamData { + name: Some(name.clone()), + default, + provenance: TypeParamProvenance::TypeParamList, + }; let param_id = self.types.alloc(param); sm.insert(param_id, Either::Right(type_param.clone())); @@ -173,8 +193,23 @@ impl GenericParams { self.where_predicates.push(WherePredicate { type_ref, bound }); } + fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { + type_ref.walk(&mut |type_ref| { + if let TypeRef::ImplTrait(_) = type_ref { + let param = TypeParamData { + name: None, + default: None, + provenance: TypeParamProvenance::ArgumentImplTrait, + }; + let _param_id = self.types.alloc(param); + } + }); + } + pub fn find_by_name(&self, name: &Name) -> Option { - self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None }) + self.types + .iter() + .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) } } diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index f7bac5801..05cf4646a 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -490,10 +490,12 @@ impl Scope { } Scope::GenericParams { params, def } => { for (local_id, param) in params.types.iter() { - f( - param.name.clone(), - ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }), - ) + if let Some(name) = ¶m.name { + f( + name.clone(), + ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }), + ) + } } } Scope::ImplBlockScope(i) => { diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 5f10e9a88..109414770 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -124,6 +124,50 @@ impl TypeRef { pub(crate) fn unit() -> TypeRef { TypeRef::Tuple(Vec::new()) } + + pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { + go(self, f); + + fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { + f(type_ref); + match type_ref { + TypeRef::Fn(types) | TypeRef::Tuple(types) => { + types.iter().for_each(|t| go(t, f)) + } + TypeRef::RawPtr(type_ref, _) + | TypeRef::Reference(type_ref, _) + | TypeRef::Array(type_ref) + | TypeRef::Slice(type_ref) => go(&type_ref, f), + TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { + for bound in bounds { + match bound { + TypeBound::Path(path) => go_path(path, f), + TypeBound::Error => (), + } + } + } + TypeRef::Path(path) => go_path(path, f), + TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} + }; + } + + fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) { + if let Some(type_ref) = path.type_anchor() { + go(type_ref, f); + } + for segment in path.segments().iter() { + if let Some(args_and_bindings) = segment.args_and_bindings { + for arg in &args_and_bindings.args { + let crate::path::GenericArg::Type(type_ref) = arg; + go(type_ref, f); + } + for (_, type_ref) in &args_and_bindings.bindings { + go(type_ref, f); + } + } + } + } + } } pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option) -> Vec { -- cgit v1.2.3 From dbc14f9d570e5bc1ddae05e9ccd8f163082b3cac Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 31 Jan 2020 15:17:48 +0100 Subject: First stab at desugaring bounds for APIT --- crates/ra_hir_def/src/generics.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 7553d8a87..e4e616519 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -53,10 +53,17 @@ pub struct GenericParams { /// associated type bindings like `Iterator`. #[derive(Clone, PartialEq, Eq, Debug)] pub struct WherePredicate { - pub type_ref: TypeRef, + pub target: WherePredicateTarget, pub bound: TypeBound, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum WherePredicateTarget { + TypeRef(TypeRef), + /// For desugared where predicates that can directly refer to a type param. + TypeParam(LocalTypeParamId) +} + type SourceMap = ArenaMap>; impl GenericParams { @@ -190,18 +197,24 @@ impl GenericParams { return; } let bound = TypeBound::from_ast(bound); - self.where_predicates.push(WherePredicate { type_ref, bound }); + self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); } fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { type_ref.walk(&mut |type_ref| { - if let TypeRef::ImplTrait(_) = type_ref { + if let TypeRef::ImplTrait(bounds) = type_ref { let param = TypeParamData { name: None, default: None, provenance: TypeParamProvenance::ArgumentImplTrait, }; - let _param_id = self.types.alloc(param); + let param_id = self.types.alloc(param); + for bound in bounds { + self.where_predicates.push(WherePredicate { + target: WherePredicateTarget::TypeParam(param_id), + bound: bound.clone() + }); + } } }); } @@ -211,6 +224,12 @@ impl GenericParams { .iter() .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) } + + pub fn find_trait_self_param(&self) -> Option { + self.types + .iter() + .find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None }) + } } impl HasChildSource for GenericDefId { -- cgit v1.2.3 From dded90a748737c3661aad043524f2248e324c867 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 15:13:15 +0100 Subject: Formatting --- crates/ra_hir_def/src/generics.rs | 17 +++++++++++------ crates/ra_hir_def/src/type_ref.rs | 4 +--- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'crates/ra_hir_def/src') diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index e4e616519..f765e6edc 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -61,7 +61,7 @@ pub struct WherePredicate { pub enum WherePredicateTarget { TypeRef(TypeRef), /// For desugared where predicates that can directly refer to a type param. - TypeParam(LocalTypeParamId) + TypeParam(LocalTypeParamId), } type SourceMap = ArenaMap>; @@ -197,7 +197,8 @@ impl GenericParams { return; } let bound = TypeBound::from_ast(bound); - self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); + self.where_predicates + .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); } fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { @@ -212,7 +213,7 @@ impl GenericParams { for bound in bounds { self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeParam(param_id), - bound: bound.clone() + bound: bound.clone(), }); } } @@ -226,9 +227,13 @@ impl GenericParams { } pub fn find_trait_self_param(&self) -> Option { - self.types - .iter() - .find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None }) + self.types.iter().find_map(|(id, p)| { + if p.provenance == TypeParamProvenance::TraitSelf { + Some(id) + } else { + None + } + }) } } diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 109414770..102fdb13d 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -131,9 +131,7 @@ impl TypeRef { fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { f(type_ref); match type_ref { - TypeRef::Fn(types) | TypeRef::Tuple(types) => { - types.iter().for_each(|t| go(t, f)) - } + TypeRef::Fn(types) | TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), TypeRef::RawPtr(type_ref, _) | TypeRef::Reference(type_ref, _) | TypeRef::Array(type_ref) -- cgit v1.2.3