From 0d49da5e1845a3f1c3aff5d65239b08d8315f529 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Tue, 21 Sep 2021 15:36:52 +0200 Subject: [PATCH 1/3] Move `GenericParams`'s handling of `impl Trait` into `GenericParams::generic_params_query` --- crates/hir_def/src/generics.rs | 50 +++++++++++++++++++++----- crates/hir_def/src/item_tree.rs | 2 +- crates/hir_def/src/item_tree/lower.rs | 17 +++------ crates/hir_def/src/item_tree/pretty.rs | 6 ++-- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 0921ecea6f..8c5313fa45 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs @@ -7,13 +7,15 @@ use base_db::FileId; use either::Either; use hir_expand::{ name::{AsName, Name}, - HirFileId, InFile, + ExpandResult, HirFileId, InFile, }; use la_arena::{Arena, ArenaMap}; +use once_cell::unsync::Lazy; +use std::ops::DerefMut; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; use crate::{ - body::LowerCtx, + body::{Expander, LowerCtx}, child_by_source::ChildBySource, db::DefDatabase, dyn_map::DynMap, @@ -21,8 +23,8 @@ use crate::{ keys, src::{HasChildSource, HasSource}, type_ref::{LifetimeRef, TypeBound, TypeRef}, - AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId, - LocalTypeParamId, Lookup, TypeParamId, + AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalConstParamId, + LocalLifetimeParamId, LocalTypeParamId, Lookup, TypeParamId, }; /// Data about a generic type parameter (to a function, struct, impl, ...). @@ -99,10 +101,23 @@ impl GenericParams { match def { GenericDefId::FunctionId(id) => { - let id = id.lookup(db).id; - let tree = id.item_tree(db); - let item = &tree[id.value]; - item.generic_params.clone() + let loc = id.lookup(db); + let tree = loc.id.item_tree(db); + let item = &tree[loc.id.value]; + + let mut generic_params = GenericParams::clone(&item.explicit_generic_params); + + let module = loc.container.module(db); + let func_data = db.function_data(id); + + // Don't create an `Expander` nor call `loc.source(db)` if not needed since this + // causes a reparse after the `ItemTree` has been created. + let mut expander = Lazy::new(|| Expander::new(db, loc.source(db).file_id, module)); + for param in &func_data.params { + generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); + } + + Interned::new(generic_params) } GenericDefId::AdtId(AdtId::StructId(id)) => { let id = id.lookup(db).id; @@ -259,7 +274,12 @@ impl GenericParams { self.where_predicates.push(predicate); } - pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { + pub(crate) fn fill_implicit_impl_trait_args( + &mut self, + db: &dyn DefDatabase, + expander: &mut impl DerefMut, + type_ref: &TypeRef, + ) { type_ref.walk(&mut |type_ref| { if let TypeRef::ImplTrait(bounds) = type_ref { let param = TypeParamData { @@ -275,6 +295,18 @@ impl GenericParams { }); } } + if let TypeRef::Macro(mc) = type_ref { + let macro_call = mc.to_node(db.upcast()); + match expander.enter_expand::(db, macro_call) { + Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { + let ctx = LowerCtx::new(db, mc.file_id); + let type_ref = TypeRef::from_ast(&ctx, expanded); + self.fill_implicit_impl_trait_args(db, expander, &type_ref); + expander.exit(db, mark); + } + _ => {} + } + } }); } diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index df46ceeaee..3900e7e97c 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -605,7 +605,7 @@ pub struct ExternBlock { pub struct Function { pub name: Name, pub visibility: RawVisibilityId, - pub generic_params: Interned, + pub explicit_generic_params: Interned, pub abi: Option>, pub params: IdRange, pub ret_type: Interned, diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 6d34556b3e..9c278f5ac6 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -401,7 +401,7 @@ impl<'a> Ctx<'a> { let mut res = Function { name, visibility, - generic_params: Interned::new(GenericParams::default()), + explicit_generic_params: Interned::new(GenericParams::default()), abi, params, ret_type: Interned::new(ret_type), @@ -409,7 +409,8 @@ impl<'a> Ctx<'a> { ast_id, flags, }; - res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); + res.explicit_generic_params = + self.lower_generic_params(GenericsOwner::Function(&res), func); Some(id(self.data().functions.alloc(res))) } @@ -664,16 +665,8 @@ impl<'a> Ctx<'a> { ) -> Interned { let mut generics = GenericParams::default(); match owner { - GenericsOwner::Function(func) => { - generics.fill(&self.body_ctx, node); - // lower `impl Trait` in arguments - for id in func.params.clone() { - if let Param::Normal(ty) = &self.data().params[id] { - generics.fill_implicit_impl_trait_args(ty); - } - } - } - GenericsOwner::Struct + GenericsOwner::Function(_) + | GenericsOwner::Struct | GenericsOwner::Enum | GenericsOwner::Union | GenericsOwner::TypeAlias => { diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index 3e33b0c46c..49dc1eef18 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs @@ -234,7 +234,7 @@ impl<'a> Printer<'a> { let Function { name, visibility, - generic_params, + explicit_generic_params, abi, params, ret_type, @@ -250,7 +250,7 @@ impl<'a> Printer<'a> { w!(self, "extern \"{}\" ", abi); } w!(self, "fn {}", name); - self.print_generic_params(generic_params); + self.print_generic_params(explicit_generic_params); w!(self, "("); if !params.is_empty() { self.indented(|this| { @@ -271,7 +271,7 @@ impl<'a> Printer<'a> { } w!(self, ") -> "); self.print_type_ref(ret_type); - self.print_where_clause(generic_params); + self.print_where_clause(explicit_generic_params); wln!(self, ";"); } ModItem::Struct(it) => { From 7f76a73a38c5b12e24b2f790b3f3145559d1aec9 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Tue, 21 Sep 2021 15:03:34 +0200 Subject: [PATCH 2/3] Add regression test --- crates/hir_ty/src/tests/regression.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 618499fdc1..2f38d584a1 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs @@ -1177,3 +1177,24 @@ fn multiexp_inner() { "#, ); } + +#[test] +fn macro_expands_to_impl_trait() { + check_no_mismatches( + r#" +trait Foo {} + +macro_rules! ty { + () => { + impl Foo + } +} + +fn foo(_: ty!()) {} + +fn bar() { + foo(()); +} + "#, + ) +} From 49ba313679a1f7046fe183fd270e8f31ca3dc217 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Tue, 21 Sep 2021 15:37:47 +0200 Subject: [PATCH 3/3] Update failing test --- crates/hir_def/src/item_tree/tests.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index a153e17b17..7671ccefd1 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs @@ -340,12 +340,11 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} T: 'b { // flags = 0x2 - pub(self) fn f( + pub(self) fn f( _: impl Copy, ) -> impl Copy where - G: 'a, - _anon_1: Copy; + G: 'a; } pub(self) enum Enum<'a, T, const U: u8> {