diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index e3d750d33c..1b77de575c 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -698,24 +698,22 @@ impl<'a> AssocItemCollector<'a> { match item { AssocItem::Function(id) => { let item = &item_tree[id]; - let def = FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); self.items.push((item.name.clone(), def.into())); } + AssocItem::TypeAlias(id) => { + let item = &item_tree[id]; + let def = + TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); + self.items.push((item.name.clone(), def.into())); + } AssocItem::Const(id) => { let item = &item_tree[id]; let Some(name) = item.name.clone() else { return }; let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); self.items.push((name, def.into())); } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; - - let def = - TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((item.name.clone(), def.into())); - } AssocItem::MacroCall(call) => { let file_id = self.expander.current_file_id(); let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index bf728a7107..4e57845a69 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -1177,6 +1177,8 @@ pub mod fmt { //- /main.rs crate:main deps:alloc,std #![no_std] +extern crate alloc; + $0 //- /std.rs crate:std deps:alloc diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index acc60e1d9e..7a701a48bf 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -20,7 +20,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, expander::Expander, - item_tree::{GenericsItemTreeNode, ItemTree}, + item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree}, lower::LowerCtx, nameres::{DefMap, MacroSubNs}, type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, @@ -456,56 +456,67 @@ impl GenericParams { let cfg_options = &cfg_options[krate].cfg_options; // Returns the generic parameters that are enabled under the current `#[cfg]` options - let enabled_params = |params: &Interned, item_tree: &ItemTree| { - let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + let enabled_params = + |params: &Interned, item_tree: &ItemTree, parent: GenericModItem| { + let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param); + let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); - // In the common case, no parameters will by disabled by `#[cfg]` attributes. - // Therefore, make a first pass to check if all parameters are enabled and, if so, - // clone the `Interned` instead of recreating an identical copy. - let all_type_or_consts_enabled = - params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into())); - let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into())); + // In the common case, no parameters will by disabled by `#[cfg]` attributes. + // Therefore, make a first pass to check if all parameters are enabled and, if so, + // clone the `Interned` instead of recreating an identical copy. + let all_type_or_consts_enabled = + params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx))); + let all_lifetimes_enabled = + params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx))); - if all_type_or_consts_enabled && all_lifetimes_enabled { - params.clone() - } else { - Interned::new(GenericParams { - type_or_consts: all_type_or_consts_enabled - .then(|| params.type_or_consts.clone()) - .unwrap_or_else(|| { - params - .type_or_consts - .iter() - .filter(|(idx, _)| enabled((*idx).into())) - .map(|(_, param)| param.clone()) - .collect() - }), - lifetimes: all_lifetimes_enabled - .then(|| params.lifetimes.clone()) - .unwrap_or_else(|| { - params - .lifetimes - .iter() - .filter(|(idx, _)| enabled((*idx).into())) - .map(|(_, param)| param.clone()) - .collect() - }), - where_predicates: params.where_predicates.clone(), - }) - } - }; + if all_type_or_consts_enabled && all_lifetimes_enabled { + params.clone() + } else { + Interned::new(GenericParams { + type_or_consts: all_type_or_consts_enabled + .then(|| params.type_or_consts.clone()) + .unwrap_or_else(|| { + params + .type_or_consts + .iter() + .filter(|&(idx, _)| enabled(attr_owner_ct(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + lifetimes: all_lifetimes_enabled + .then(|| params.lifetimes.clone()) + .unwrap_or_else(|| { + params + .lifetimes + .iter() + .filter(|&(idx, _)| enabled(attr_owner_lt(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + where_predicates: params.where_predicates.clone(), + }) + } + }; fn id_to_generics( db: &dyn DefDatabase, id: impl for<'db> Lookup< Database<'db> = dyn DefDatabase + 'db, Data = impl ItemTreeLoc, >, - enabled_params: impl Fn(&Interned, &ItemTree) -> Interned, - ) -> Interned { + enabled_params: impl Fn( + &Interned, + &ItemTree, + GenericModItem, + ) -> Interned, + ) -> Interned + where + FileItemTreeId: Into, + { let id = id.lookup(db).item_tree_id(); let tree = id.item_tree(db); let item = &tree[id.value]; - enabled_params(item.generic_params(), &tree) + enabled_params(item.generic_params(), &tree, id.value.into()) } match def { @@ -514,7 +525,8 @@ impl GenericParams { let tree = loc.id.item_tree(db); let item = &tree[loc.id.value]; - let enabled_params = enabled_params(&item.explicit_generic_params, &tree); + let enabled_params = + enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into()); let module = loc.container.module(db); let func_data = db.function_data(id); diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 4bf4bc768f..226a457c90 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -57,11 +57,11 @@ use triomphe::Arc; use crate::{ attr::Attrs, db::DefDatabase, - generics::{GenericParams, LifetimeParamData, TypeOrConstParamData}, + generics::GenericParams, path::{GenericArgs, ImportAlias, ModPath, Path, PathKind}, type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, visibility::{RawVisibility, VisibilityExplicitness}, - BlockId, Lookup, + BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, }; #[derive(Copy, Clone, Eq, PartialEq)] @@ -293,8 +293,8 @@ pub enum AttrOwner { Variant(FileItemTreeId), Field(Idx), Param(Idx), - TypeOrConstParamData(Idx), - LifetimeParamData(Idx), + TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId), + LifetimeParamData(GenericModItem, LocalLifetimeParamId), } macro_rules! from_attrs { @@ -314,8 +314,6 @@ from_attrs!( Variant(FileItemTreeId), Field(Idx), Param(Idx), - TypeOrConstParamData(Idx), - LifetimeParamData(Idx), ); /// Trait implemented by all nodes in the item tree. @@ -465,12 +463,49 @@ macro_rules! mod_items { )+ } + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] + pub enum GenericModItem { + $( + $( + #[cfg_attr(FALSE, $generic_params)] + $typ(FileItemTreeId<$typ>), + )? + )+ + } + + impl From for ModItem { + fn from(id: GenericModItem) -> ModItem { + match id { + $( + $( + #[cfg_attr(FALSE, $generic_params)] + GenericModItem::$typ(id) => ModItem::$typ(id), + )? + )+ + } + } + } + + impl From for AttrOwner { + fn from(t: GenericModItem) -> AttrOwner { + AttrOwner::ModItem(t.into()) + } + } + $( impl From> for ModItem { fn from(id: FileItemTreeId<$typ>) -> ModItem { ModItem::$typ(id) } } + $( + #[cfg_attr(FALSE, $generic_params)] + impl From> for GenericModItem { + fn from(id: FileItemTreeId<$typ>) -> GenericModItem { + GenericModItem::$typ(id) + } + } + )? )+ $( diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 4b5ef56d78..6aa5a63d62 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -4,6 +4,7 @@ use std::collections::hash_map::Entry; use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId}; use la_arena::Arena; +use rustc_hash::FxHashMap; use span::{AstIdMap, SyntaxContextId}; use syntax::{ ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString}, @@ -16,11 +17,11 @@ use crate::{ generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, item_tree::{ AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId, - Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias, - Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, - ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs, - RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, - Use, UseTree, UseTreeKind, Variant, + Fields, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, IdxRange, + Impl, ImportAlias, Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, + MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, + Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, + TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, }, path::AssociatedTypeBinding, type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef}, @@ -36,6 +37,8 @@ pub(super) struct Ctx<'a> { db: &'a dyn DefDatabase, tree: ItemTree, source_ast_id_map: Arc, + generic_param_attr_buffer: + FxHashMap, RawAttrs>, body_ctx: crate::lower::LowerCtx<'a>, } @@ -44,6 +47,7 @@ impl<'a> Ctx<'a> { Self { db, tree: ItemTree::default(), + generic_param_attr_buffer: FxHashMap::default(), source_ast_id_map: db.ast_id_map(file), body_ctx: crate::lower::LowerCtx::new(db, file), } @@ -56,6 +60,7 @@ impl<'a> Ctx<'a> { pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { self.tree.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); + assert!(self.generic_param_attr_buffer.is_empty()); self.tree } @@ -89,6 +94,7 @@ impl<'a> Ctx<'a> { } } + assert!(self.generic_param_attr_buffer.is_empty()); self.tree } @@ -117,6 +123,7 @@ impl<'a> Ctx<'a> { } } + assert!(self.generic_param_attr_buffer.is_empty()); self.tree } @@ -185,10 +192,12 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(strukt); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let fields = self.lower_fields(&strukt.kind()); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let res = Struct { name, visibility, generic_params, fields, ast_id }; - Some(id(self.data().structs.alloc(res))) + let id = id(self.data().structs.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { @@ -252,28 +261,32 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let fields = match union.record_field_list() { Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())), }; + let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let res = Union { name, visibility, generic_params, fields, ast_id }; - Some(id(self.data().unions.alloc(res))) + let id = id(self.data().unions.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_enum(&mut self, enum_: &ast::Enum) -> Option> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(enum_); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let variants = match &enum_.variant_list() { Some(variant_list) => self.lower_variants(variant_list), None => { FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) } }; + let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let res = Enum { name, visibility, generic_params, variants, ast_id }; - Some(id(self.data().enums.alloc(res))) + let id = id(self.data().enums.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_variants(&mut self, variants: &ast::VariantList) -> Range> { @@ -414,7 +427,9 @@ impl<'a> Ctx<'a> { flags, }; - Some(id(self.data().functions.alloc(res))) + let id = id(self.data().functions.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_type_alias( @@ -428,7 +443,9 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(type_alias); let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; - Some(id(self.data().type_aliases.alloc(res))) + let id = id(self.data().type_aliases.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_static(&mut self, static_: &ast::Static) -> Option> { @@ -475,8 +492,6 @@ impl<'a> Ctx<'a> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); let ast_id = self.source_ast_id_map.ast_id(trait_def); - let generic_params = - self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let is_auto = trait_def.auto_token().is_some(); let is_unsafe = trait_def.unsafe_token().is_some(); @@ -487,8 +502,12 @@ impl<'a> Ctx<'a> { .filter_map(|item_node| self.lower_assoc_item(&item_node)) .collect(); + let generic_params = + self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; - Some(id(self.data().traits.alloc(def))) + let id = id(self.data().traits.alloc(def)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_trait_alias( @@ -504,19 +523,18 @@ impl<'a> Ctx<'a> { ); let alias = TraitAlias { name, visibility, generic_params, ast_id }; - Some(id(self.data().trait_aliases.alloc(alias))) + let id = id(self.data().trait_aliases.alloc(alias)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option> { let ast_id = self.source_ast_id_map.ast_id(impl_def); - // Note that trait impls don't get implicit `Self` unlike traits, because here they are a - // type alias rather than a type parameter, so this is handled by the resolver. - let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only // equals itself. - let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); let self_ty = self.lower_type_ref(&impl_def.self_ty()?); + let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); let is_negative = impl_def.excl_token().is_some(); let is_unsafe = impl_def.unsafe_token().is_some(); @@ -527,9 +545,14 @@ impl<'a> Ctx<'a> { .flat_map(|it| it.assoc_items()) .filter_map(|item| self.lower_assoc_item(&item)) .collect(); + // Note that trait impls don't get implicit `Self` unlike traits, because here they are a + // type alias rather than a type parameter, so this is handled by the resolver. + let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); let res = Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id }; - Some(id(self.data().impls.alloc(res))) + let id = id(self.data().impls.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_use(&mut self, use_item: &ast::Use) -> Option> { @@ -616,11 +639,30 @@ impl<'a> Ctx<'a> { id(self.data().extern_blocks.alloc(res)) } + fn write_generic_params_attributes(&mut self, parent: GenericModItem) { + self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| { + self.tree.attrs.insert( + match idx { + Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id), + Either::Right(id) => AttrOwner::LifetimeParamData(parent, id), + }, + attrs, + ); + }) + } + fn lower_generic_params( &mut self, has_implicit_self: HasImplicitSelf, node: &dyn ast::HasGenericParams, ) -> Interned { + debug_assert!(self.generic_param_attr_buffer.is_empty(),); + let add_param_attrs = |item: Either, + param| { + let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map()); + debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none()); + }; + let mut generics = GenericParamsCollector::default(); if let HasImplicitSelf::Yes(bounds) = has_implicit_self { @@ -635,28 +677,13 @@ impl<'a> Ctx<'a> { ); // add super traits as bounds on Self // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar` - let self_param = TypeRef::Path(name![Self].into()); - generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param)); + generics.fill_bounds( + &self.body_ctx, + bounds, + Either::Left(TypeRef::Path(name![Self].into())), + ); } - let add_param_attrs = |item: Either, - param| { - let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map()); - // This is identical to the body of `Ctx::add_attrs()` but we can't call that here - // because it requires `&mut self` and the call to `generics.fill()` below also - // references `self`. - match self.tree.attrs.entry(match item { - Either::Right(id) => id.into(), - Either::Left(id) => id.into(), - }) { - Entry::Occupied(mut entry) => { - *entry.get_mut() = entry.get().merge(attrs); - } - Entry::Vacant(entry) => { - entry.insert(attrs); - } - } - }; generics.fill(&self.body_ctx, node, add_param_attrs); Interned::new(generics.finish()) diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index cef2a3fb86..2803678a33 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -8,8 +8,8 @@ use crate::{ generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, item_tree::{ AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields, - FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2, - MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs, + FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, Interned, ItemTree, + Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union, Use, UseTree, UseTreeKind, Variant, }, @@ -276,7 +276,7 @@ impl Printer<'_> { w!(self, "extern \"{}\" ", abi); } w!(self, "fn {}", name.display(self.db.upcast())); - self.print_generic_params(explicit_generic_params); + self.print_generic_params(explicit_generic_params, it.into()); w!(self, "("); if !params.is_empty() { self.indented(|this| { @@ -316,7 +316,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "struct {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { wln!(self); @@ -329,7 +329,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "union {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { wln!(self); @@ -342,7 +342,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "enum {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for variant in FileItemTreeId::range_iter(variants.clone()) { @@ -394,7 +394,7 @@ impl Printer<'_> { w!(self, "auto "); } w!(self, "trait {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for item in &**items { @@ -408,7 +408,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "trait {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); w!(self, " = "); self.print_where_clause(generic_params); w!(self, ";"); @@ -429,7 +429,7 @@ impl Printer<'_> { w!(self, "unsafe"); } w!(self, "impl"); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); w!(self, " "); if *is_negative { w!(self, "!"); @@ -453,7 +453,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "type {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); if !bounds.is_empty() { w!(self, ": "); self.print_type_bounds(bounds); @@ -525,7 +525,7 @@ impl Printer<'_> { print_path(self.db, path, self).unwrap(); } - fn print_generic_params(&mut self, params: &GenericParams) { + fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) { if params.is_empty() { return; } @@ -537,7 +537,7 @@ impl Printer<'_> { w!(self, ", "); } first = false; - self.print_attrs_of(idx, " "); + self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " "); w!(self, "{}", lt.name.display(self.db.upcast())); } for (idx, x) in params.type_or_consts.iter() { @@ -545,7 +545,7 @@ impl Printer<'_> { w!(self, ", "); } first = false; - self.print_attrs_of(idx, " "); + self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " "); match x { TypeOrConstParamData::TypeParamData(ty) => match &ty.name { Some(name) => w!(self, "{}", name.display(self.db.upcast())), diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index 48da876ac1..79bab11998 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -427,10 +427,18 @@ fn generics_with_attributes() { check( r#" struct S<#[cfg(never)] T>; +struct S; +struct S; "#, expect![[r#" // AstId: 1 pub(self) struct S<#[cfg(never)] T>; + + // AstId: 2 + pub(self) struct S; + + // AstId: 3 + pub(self) struct S; "#]], ) } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 0a6cd0fe9e..a3b6a65238 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -5,7 +5,7 @@ use std::{cmp::Ordering, iter, mem, ops::Not}; -use base_db::{CrateId, Dependency, FileId}; +use base_db::{CrateId, CrateOrigin, Dependency, FileId, LangCrateOrigin}; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -279,7 +279,8 @@ impl DefCollector<'_> { fn seed_with_top_level(&mut self) { let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered(); - let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; + let crate_graph = self.db.crate_graph(); + let file_id = crate_graph[self.def_map.krate].root_file_id; let item_tree = self.db.file_item_tree(file_id.into()); let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); @@ -318,8 +319,43 @@ impl DefCollector<'_> { self.is_proc_macro = true; } } - () if *attr_name == hir_expand::name![no_core] => crate_data.no_core = true, - () if *attr_name == hir_expand::name![no_std] => crate_data.no_std = true, + () if *attr_name == hir_expand::name![no_core] => { + if let Some((core, _)) = + crate_data.extern_prelude.iter().find(|(_, (root, _))| { + matches!( + crate_graph[root.krate].origin, + CrateOrigin::Lang(LangCrateOrigin::Core) + ) + }) + { + crate_data.extern_prelude.remove(&core.clone()); + } + + crate_data.no_core = true + } + () if *attr_name == hir_expand::name![no_std] => { + if let Some((alloc, _)) = + crate_data.extern_prelude.iter().find(|(_, (root, _))| { + matches!( + crate_graph[root.krate].origin, + CrateOrigin::Lang(LangCrateOrigin::Alloc) + ) + }) + { + crate_data.extern_prelude.remove(&alloc.clone()); + } + if let Some((std, _)) = + crate_data.extern_prelude.iter().find(|(_, (root, _))| { + matches!( + crate_graph[root.krate].origin, + CrateOrigin::Lang(LangCrateOrigin::Std) + ) + }) + { + crate_data.extern_prelude.remove(&std.clone()); + } + crate_data.no_std = true + } () if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") => { crate_data.rustc_coherence_is_core = true; } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 4d0516ead6..7423c9ed32 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1056,23 +1056,7 @@ impl<'a> TyLoweringContext<'a> { let clause = match bound.as_ref() { TypeBound::Path(path, TraitBoundModifier::None) => { trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); - trait_ref - .clone() - .filter(|tr| { - // ignore `T: Drop` or `T: Destruct` bounds. - // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement. - // (So ideally, we'd only ignore `~const Drop` here) - // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until - // the builtin impls are supported by Chalk, we ignore them here. - if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) { - if matches!(lang, LangItem::Drop | LangItem::Destruct) { - return false; - } - } - true - }) - .map(WhereClause::Implemented) - .map(crate::wrap_empty_binders) + trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 43fe14126e..69c7a81548 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1599,85 +1599,6 @@ fn f(s: S) { ); } -#[test] -fn rust_161_option_clone() { - check_types( - r#" -//- minicore: option, drop - -fn test(o: &Option) { - o.my_clone(); - //^^^^^^^^^^^^ Option -} - -pub trait MyClone: Sized { - fn my_clone(&self) -> Self; -} - -impl const MyClone for Option -where - T: ~const MyClone + ~const Drop + ~const Destruct, -{ - fn my_clone(&self) -> Self { - match self { - Some(x) => Some(x.my_clone()), - None => None, - } - } -} - -impl const MyClone for i32 { - fn my_clone(&self) -> Self { - *self - } -} - -pub trait Destruct {} - -impl const Destruct for T {} -"#, - ); -} - -#[test] -fn rust_162_option_clone() { - check_types( - r#" -//- minicore: option, drop - -fn test(o: &Option) { - o.my_clone(); - //^^^^^^^^^^^^ Option -} - -pub trait MyClone: Sized { - fn my_clone(&self) -> Self; -} - -impl const MyClone for Option -where - T: ~const MyClone + ~const Destruct, -{ - fn my_clone(&self) -> Self { - match self { - Some(x) => Some(x.my_clone()), - None => None, - } - } -} - -impl const MyClone for i32 { - fn my_clone(&self) -> Self { - *self - } -} - -#[lang = "destruct"] -pub trait Destruct {} -"#, - ); -} - #[test] fn tuple_struct_pattern_with_unmatched_args_crash() { check_infer( @@ -2040,3 +1961,17 @@ fn main() { "#, ) } + +#[test] +fn cfg_first_trait_param_16141() { + check_no_mismatches( + r#" +//- minicore: sized, coerce_unsized +trait Bar { + fn bar(&self) {} +} + +impl<#[cfg(feature = "a-feature")] A> Bar for (){} +"#, + ) +} diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index eb2c609501..4bc3e121ac 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -238,6 +238,7 @@ fn infer_for_loop() { //- minicore: iterator //- /main.rs crate:main deps:alloc #![no_std] +extern crate alloc; use alloc::collections::Vec; fn test() {