diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index bb45b0f1da0..e60f879a393 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -9,7 +9,7 @@ use ra_syntax::{ }; use crate::db::AstDatabase; -use crate::{name, quote, LazyMacroId, MacroDefId, MacroDefKind}; +use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; macro_rules! register_builtin { ( $($trait:ident => $expand:ident),* ) => { @@ -153,76 +153,113 @@ fn expand_simple_derive( Ok(expanded) } +fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { + // FIXME: make hygiene works for builtin derive macro + // such that $crate can be used here. + + let m: MacroCallId = id.into(); + let file_id = m.as_file().original_file(db); + let cg = db.crate_graph(); + let krates = db.relevant_crates(file_id); + let krate = match krates.get(0) { + Some(krate) => krate, + None => { + let tt = quote! { core }; + return tt.token_trees[0].clone(); + } + }; + + // XXX + // All crates except core itself should have a dependency on core, + // We detect `core` by seeing whether it doesn't have such a dependency. + let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { + quote! { core } + } else { + quote! { crate } + }; + + tt.token_trees[0].clone() +} + fn copy_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::marker::Copy }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::marker::Copy }) } fn clone_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::clone::Clone }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::clone::Clone }) } fn default_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::default::Default }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::default::Default }) } fn debug_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::fmt::Debug }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::fmt::Debug }) } fn hash_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::hash::Hash }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::hash::Hash }) } fn eq_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::cmp::Eq }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::cmp::Eq }) } fn partial_eq_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::cmp::PartialEq }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }) } fn ord_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::cmp::Ord }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::cmp::Ord }) } fn partial_ord_expand( - _db: &dyn AstDatabase, - _id: LazyMacroId, + db: &dyn AstDatabase, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { - expand_simple_derive(tt, quote! { std::cmp::PartialOrd }) + let krate = find_builtin_crate(db, id); + expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }) } #[cfg(test)] @@ -234,8 +271,18 @@ mod tests { fn expand_builtin_derive(s: &str, name: Name) -> String { let def = find_builtin_derive(&name).unwrap(); + let fixture = format!( + r#"//- /main.rs crate:main deps:core +<|> +{} +//- /lib.rs crate:core +// empty +"#, + s + ); - let (db, file_id) = TestDB::with_single_file(&s); + let (db, file_pos) = TestDB::with_position(&fixture); + let file_id = file_pos.file_id; let parsed = db.parse(file_id); let items: Vec<_> = parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); @@ -264,7 +311,7 @@ mod tests { known::Copy, ); - assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}"); + assert_eq!(expanded, "impl< >core::marker::CopyforFoo< >{}"); } #[test] @@ -279,7 +326,7 @@ mod tests { assert_eq!( expanded, - "implstd::marker::CopyforFoo{}" + "implcore::marker::CopyforFoo{}" ); } @@ -297,7 +344,7 @@ mod tests { assert_eq!( expanded, - "implstd::marker::CopyforFoo{}" + "implcore::marker::CopyforFoo{}" ); } @@ -313,7 +360,7 @@ mod tests { assert_eq!( expanded, - "implstd::clone::CloneforFoo{}" + "implcore::clone::CloneforFoo{}" ); } } diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 6b526723258..5ddecbdc680 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -622,14 +622,14 @@ fn main() { fn infer_derive_clone_simple() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core #[derive(Clone)] struct S; fn test() { S.clone()<|>; } -//- /lib.rs crate:std +//- /lib.rs crate:core #[prelude_import] use clone::*; mod clone { @@ -642,11 +642,36 @@ mod clone { assert_eq!("S", type_at_pos(&db, pos)); } +#[test] +fn infer_derive_clone_in_core() { + let (db, pos) = TestDB::with_position( + r#" +//- /lib.rs crate:core +#[prelude_import] +use clone::*; +mod clone { + trait Clone { + fn clone(&self) -> Self; + } +} +#[derive(Clone)] +pub struct S; + +//- /main.rs crate:main deps:core +use core::S; +fn test() { + S.clone()<|>; +} +"#, + ); + assert_eq!("S", type_at_pos(&db, pos)); +} + #[test] fn infer_derive_clone_with_params() { let (db, pos) = TestDB::with_position( r#" -//- /main.rs crate:main deps:std +//- /main.rs crate:main deps:core #[derive(Clone)] struct S; #[derive(Clone)] @@ -656,7 +681,7 @@ fn test() { (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; } -//- /lib.rs crate:std +//- /lib.rs crate:core #[prelude_import] use clone::*; mod clone {