Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
| -rw-r--r-- | crates/hir/src/lib.rs | 2264 |
1 files changed, 1412 insertions, 852 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index f2faf99fc9..1ab57c4489 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -35,6 +35,9 @@ pub mod term_search; mod display; +#[doc(hidden)] +pub use hir_def::ModuleId; + use std::{ fmt, mem::discriminant, @@ -45,17 +48,20 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin}; use either::Either; use hir_def::{ - AdtId, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, - CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, SyntheticSyntax, - TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, + DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, + MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, + attrs::AttrFlags, + builtin_derive::BuiltinDeriveImplMethod, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, item_tree::ImportAlias, + lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, nameres::{ assoc::TraitItems, @@ -63,43 +69,47 @@ use hir_def::{ }, per_ns::PerNs, resolver::{HasResolver, Resolver}, - signatures::{ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, + signatures::{EnumSignature, ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, src::HasSource as _, visibility::visibility_from_ast, }; use hir_expand::{ - AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs, + AstId, MacroCallKind, RenderedExpandError, ValueResult, builtin::BuiltinDeriveExpander, proc_macro::ProcMacroKind, }; use hir_ty::{ - TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, - check_orphan_rules, + GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic, + ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, consteval::try_const_usize, db::{InternedClosureId, InternedCoroutineId}, diagnostics::BodyValidationDiagnostic, direct_super_traits, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, - method_resolution, + method_resolution::{ + self, InherentImpls, MethodResolutionContext, MethodResolutionUnstableFeatures, + }, mir::{MutBorrowKind, interpret_mir}, next_solver::{ - AliasTy, Canonical, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, - GenericArgs, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, + AliasTy, AnyImplId, ClauseKind, ConstKind, DbInterner, EarlyBinder, EarlyParamRegion, + ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Region, + RegionKind, SolverDefId, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, - traits::{self, FnTrait, structurally_normalize_ty}, + traits::{self, is_inherent_impl_coherent, structurally_normalize_ty}, }; use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor, + AliasTyKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitor, fast_reject, inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _}, }; use smallvec::SmallVec; use span::{AstIdNode, Edition, FileId}; -use stdx::{format_to, impl_from, never}; +use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime}; use syntax::{ - AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, - ast::{self, HasAttrs as _, HasName, HasVisibility as _}, + AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, + ast::{self, HasName as _, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -107,12 +117,12 @@ use triomphe::{Arc, ThinArc}; use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ - attrs::{HasAttrs, resolve_doc_path_on}, + attrs::{AttrsWithOwner, HasAttrs, resolve_doc_path_on}, diagnostics::*, has_source::HasSource, semantics::{ - PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, - VisibleTraits, + LintAttr, PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, + TypeInfo, VisibleTraits, }, }; @@ -130,10 +140,10 @@ pub use { hir_def::{ Complete, FindPathConfig, - attr::{AttrSourceMap, Attrs, AttrsWithOwner}, + attrs::{Docs, IsInnerDoc}, find_path::PrefixKind, import_map, - lang_item::LangItem, + lang_item::{LangItemEnum as LangItem, crate_lang_items}, nameres::{DefMap, ModuleSource, crate_def_map}, per_ns::Namespace, type_ref::{Mutability, TypeRef}, @@ -144,7 +154,6 @@ pub use { }, hir_expand::{ EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind, - attrs::{Attr, AttrId}, change::ChangeWithProcMacros, files::{ FilePosition, FilePositionWrapper, FileRange, FileRangeWrapper, HirFilePosition, @@ -168,11 +177,12 @@ pub use { drop::DropGlue, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, - method_resolution::TyFingerprint, mir::{MirEvalError, MirLowerError}, next_solver::abi::Safety, - next_solver::clear_tls_solver_cache, + next_solver::{clear_tls_solver_cache, collect_ty_garbage}, }, + // FIXME: These are needed for import assets, properly encapsulate them. + hir_ty::{method_resolution::TraitImpls, next_solver::SimplifiedType}, intern::{Symbol, sym}, }; @@ -241,16 +251,24 @@ impl Crate { self, db: &dyn HirDatabase, ) -> impl Iterator<Item = Crate> { - db.transitive_rev_deps(self.id).into_iter().map(|id| Crate { id }) + self.id.transitive_rev_deps(db).into_iter().map(|id| Crate { id }) } - pub fn root_module(self) -> Module { - Module { id: CrateRootModuleId::from(self.id).into() } + pub fn notable_traits_in_deps(self, db: &dyn HirDatabase) -> impl Iterator<Item = &TraitId> { + self.id + .transitive_deps(db) + .into_iter() + .filter_map(|krate| db.crate_notable_traits(krate)) + .flatten() + } + + pub fn root_module(self, db: &dyn HirDatabase) -> Module { + Module { id: crate_def_map(db, self.id).root_module_id() } } pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> { let def_map = crate_def_map(db, self.id); - def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect() + def_map.modules().map(|(id, _)| id.into()).collect() } pub fn root_file(self, db: &dyn HirDatabase) -> FileId { @@ -291,11 +309,10 @@ impl Crate { } /// Try to get the root URL of the documentation of a crate. - pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { + pub fn get_html_root_url(self, db: &dyn HirDatabase) -> Option<String> { // Look for #![doc(html_root_url = "...")] - let attrs = db.attrs(AttrDefId::ModuleId(self.root_module().into())); - let doc_url = attrs.by_key(sym::doc).find_string_value_in_tt(sym::html_root_url); - doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") + let doc_url = AttrFlags::doc_html_root_url(db, self.id); + doc_url.as_ref().map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") } pub fn cfg<'db>(&self, db: &'db dyn HirDatabase) -> &'db CfgOptions { @@ -427,7 +444,10 @@ impl ModuleDef { Adt::Union(it) => it.id.into(), }, ModuleDef::Trait(it) => it.id.into(), - ModuleDef::Function(it) => it.id.into(), + ModuleDef::Function(it) => match it.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Vec::new(), + }, ModuleDef::TypeAlias(it) => it.id.into(), ModuleDef::Module(it) => it.id.into(), ModuleDef::Const(it) => it.id.into(), @@ -491,7 +511,7 @@ impl ModuleDef { pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> { Some(match self { ModuleDef::Module(it) => it.attrs(db), - ModuleDef::Function(it) => it.attrs(db), + ModuleDef::Function(it) => HasAttrs::attrs(*it, db), ModuleDef::Adt(it) => it.attrs(db), ModuleDef::Variant(it) => it.attrs(db), ModuleDef::Const(it) => it.attrs(db), @@ -507,7 +527,7 @@ impl ModuleDef { impl HasCrate for ModuleDef { fn krate(&self, db: &dyn HirDatabase) -> Crate { match self.module(db) { - Some(module) => module.krate(), + Some(module) => module.krate(db), None => Crate::core(db).unwrap_or_else(|| db.all_crates()[0].into()), } } @@ -537,29 +557,29 @@ impl Module { } /// Returns the crate this module is part of. - pub fn krate(self) -> Crate { - Crate { id: self.id.krate() } + pub fn krate(self, db: &dyn HirDatabase) -> Crate { + Crate { id: self.id.krate(db) } } /// Topmost parent of this module. Every module has a `crate_root`, but some /// might be missing `krate`. This can happen if a module's file is not included /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &dyn HirDatabase) -> Module { - let def_map = crate_def_map(db, self.id.krate()); - Module { id: def_map.crate_root().into() } + let def_map = crate_def_map(db, self.id.krate(db)); + Module { id: def_map.crate_root(db) } } - pub fn is_crate_root(self) -> bool { - DefMap::ROOT == self.id.local_id + pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool { + self.crate_root(db) == self } /// Iterates over all child modules. pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { let def_map = self.id.def_map(db); - let children = def_map[self.id.local_id] + let children = def_map[self.id] .children .values() - .map(|module_id| Module { id: def_map.module_id(*module_id) }) + .map(|module_id| Module { id: *module_id }) .collect::<Vec<_>>(); children.into_iter() } @@ -567,14 +587,14 @@ impl Module { /// Finds a parent module. pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { let def_map = self.id.def_map(db); - let parent_id = def_map.containing_module(self.id.local_id)?; + let parent_id = def_map.containing_module(self.id)?; Some(Module { id: parent_id }) } /// Finds nearest non-block ancestor `Module` (`self` included). pub fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module { let mut id = self.id; - while id.is_block_module() { + while id.is_block_module(db) { id = id.containing_module(db).expect("block without parent module"); } Module { id } @@ -596,7 +616,7 @@ impl Module { db: &dyn HirDatabase, visible_from: Option<Module>, ) -> Vec<(Name, ScopeDef)> { - self.id.def_map(db)[self.id.local_id] + self.id.def_map(db)[self.id] .scope .entries() .filter_map(|(name, def)| { @@ -633,19 +653,19 @@ impl Module { style_lints: bool, ) { let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered(); - let edition = self.id.krate().data(db).edition; + let edition = self.id.krate(db).data(db).edition; let def_map = self.id.def_map(db); for diag in def_map.diagnostics() { - if diag.in_module != self.id.local_id { + if diag.in_module != self.id { // FIXME: This is accidentally quadratic. continue; } - emit_def_diagnostic(db, acc, diag, edition); + emit_def_diagnostic(db, acc, diag, edition, def_map.krate()); } - if !self.id.is_block_module() { + if !self.id.is_block_module(db) { // These are reported by the body of block modules - let scope = &def_map[self.id.local_id].scope; + let scope = &def_map[self.id].scope; scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc)); } @@ -653,14 +673,15 @@ impl Module { match def { ModuleDef::Module(m) => { // Only add diagnostics from inline modules - if def_map[m.id.local_id].origin.is_inline() { + if def_map[m.id].origin.is_inline() { m.diagnostics(db, acc, style_lints) } acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Trait(t) => { + let krate = t.krate(db); for diag in TraitItems::query_with_diagnostics(db, t.id).1.iter() { - emit_def_diagnostic(db, acc, diag, edition); + emit_def_diagnostic(db, acc, diag, edition, krate.id); } for item in t.items(db) { @@ -683,7 +704,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(s.id.into()).1, + db.field_types_with_diagnostics(s.id.into()).1.clone(), source_map, ); } @@ -695,7 +716,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(u.id.into()).1, + db.field_types_with_diagnostics(u.id.into()).1.clone(), source_map, ); } @@ -725,7 +746,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(v.into()).1, + db.field_types_with_diagnostics(v.into()).1.clone(), source_map, ); expr_store_diagnostics(db, acc, source_map); @@ -751,17 +772,18 @@ impl Module { } self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m)); - let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); - - let interner = DbInterner::new_with(db, Some(self.id.krate()), self.id.containing_block()); + let interner = DbInterner::new_with(db, self.id.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let mut impl_assoc_items_scratch = vec![]; for impl_def in self.impl_defs(db) { GenericDef::Impl(impl_def).diagnostics(db, acc); - let loc = impl_def.id.lookup(db); - let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_def.id); + let AnyImplId::ImplId(impl_id) = impl_def.id else { + continue; + }; + let loc = impl_id.lookup(db); + let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_id); expr_store_diagnostics(db, acc, &source_map); let file_id = loc.id.file_id; @@ -777,11 +799,13 @@ impl Module { let ast_id_map = db.ast_id_map(file_id); - for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() { - emit_def_diagnostic(db, acc, diag, edition); + for diag in impl_id.impl_items_with_diagnostics(db).1.iter() { + emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db)); } - if inherent_impls.invalid_impls().contains(&impl_def.id) { + if impl_signature.target_trait.is_none() + && !is_inherent_impl_coherent(db, def_map, impl_id) + { acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } @@ -804,26 +828,15 @@ impl Module { let drop_maybe_dangle = (|| { // FIXME: This can be simplified a lot by exposing hir-ty's utils.rs::Generics helper let trait_ = trait_?; - let drop_trait = LangItem::Drop.resolve_trait(db, self.krate().into())?; + let drop_trait = interner.lang_items().Drop?; if drop_trait != trait_.into() { return None; } - let parent = impl_def.id.into(); - let generic_params = db.generic_params(parent); - let lifetime_params = generic_params.iter_lt().map(|(local_id, _)| { - GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }) - }); - let type_params = generic_params - .iter_type_or_consts() - .filter(|(_, it)| it.type_param().is_some()) - .map(|(local_id, _)| { - GenericParamId::TypeParamId(TypeParamId::from_unchecked( - TypeOrConstParamId { parent, local_id }, - )) - }); - let res = type_params.chain(lifetime_params).any(|p| { - db.attrs(AttrDefId::GenericParamId(p)).by_key(sym::may_dangle).exists() - }); + let parent = impl_id.into(); + let (lifetimes_attrs, type_and_consts_attrs) = + AttrFlags::query_generic_params(db, parent); + let res = lifetimes_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE)) + || type_and_consts_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE)); Some(res) })() .unwrap_or(false); @@ -848,7 +861,7 @@ impl Module { AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(), }); - impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned()); + impl_assoc_items_scratch.extend(impl_id.impl_items(db).items.iter().cloned()); let redundant = impl_assoc_items_scratch .iter() @@ -880,11 +893,11 @@ impl Module { .collect(); if !missing.is_empty() { - let self_ty = db.impl_self_ty(impl_def.id).instantiate_identity(); + let self_ty = db.impl_self_ty(impl_id).instantiate_identity(); let self_ty = structurally_normalize_ty( &infcx, self_ty, - db.trait_environment(impl_def.id.into()), + db.trait_environment(impl_id.into()), ); let self_ty_is_guaranteed_unsized = matches!( self_ty.kind(), @@ -893,7 +906,13 @@ impl Module { if self_ty_is_guaranteed_unsized { missing.retain(|(_, assoc_item)| { let assoc_item = match *assoc_item { - AssocItem::Function(it) => it.id.into(), + AssocItem::Function(it) => match it.id { + AnyFunctionId::FunctionId(id) => id.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => { + never!("should not have an `AnyFunctionId::BuiltinDeriveImplMethod` here"); + return false; + }, + }, AssocItem::Const(it) => it.id.into(), AssocItem::TypeAlias(it) => it.id.into(), }; @@ -915,20 +934,15 @@ impl Module { impl_assoc_items_scratch.clear(); } + push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, &source_map); push_ty_diagnostics( db, acc, - db.impl_self_ty_with_diagnostics(impl_def.id).1, - &source_map, - ); - push_ty_diagnostics( - db, - acc, - db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), + db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1), &source_map, ); - for &(_, item) in impl_def.id.impl_items(db).items.iter() { + for &(_, item) in impl_id.impl_items(db).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } } @@ -936,7 +950,7 @@ impl Module { pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { let def_map = self.id.def_map(db); - let scope = &def_map[self.id.local_id].scope; + let scope = &def_map[self.id].scope; scope .declarations() .map(ModuleDef::from) @@ -946,13 +960,14 @@ impl Module { pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> { let def_map = self.id.def_map(db); - let scope = &def_map[self.id.local_id].scope; + let scope = &def_map[self.id].scope; scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| it.into()).collect() } pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { let def_map = self.id.def_map(db); - def_map[self.id.local_id].scope.impls().map(Impl::from).collect() + let scope = &def_map[self.id].scope; + scope.impls().map(Impl::from).chain(scope.builtin_derive_impls().map(Impl::from)).collect() } /// Finds a path that can be used to refer to the given item from within @@ -965,7 +980,7 @@ impl Module { ) -> Option<ModPath> { hir_def::find_path::find_path( db, - item.into().into(), + item.into().try_into().ok()?, self.into(), PrefixKind::Plain, false, @@ -982,7 +997,25 @@ impl Module { prefix_kind: PrefixKind, cfg: FindPathConfig, ) -> Option<ModPath> { - hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg) + hir_def::find_path::find_path( + db, + item.into().try_into().ok()?, + self.into(), + prefix_kind, + true, + cfg, + ) + } + + #[inline] + pub fn doc_keyword(self, db: &dyn HirDatabase) -> Option<Symbol> { + AttrFlags::doc_keyword(db, self.id) + } + + /// Whether it has `#[path = "..."]` attribute. + #[inline] + pub fn has_path(&self, db: &dyn HirDatabase) -> bool { + self.attrs(db).attrs.contains(AttrFlags::HAS_PATH) } } @@ -998,31 +1031,19 @@ fn macro_call_diagnostics<'db>( if let Some(err) = err { let loc = db.lookup_intern_macro_call(macro_call_id); let file_id = loc.kind.file_id(); - let node = - InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id())); + let mut range = precise_macro_call_location(&loc.kind, db, loc.krate); let RenderedExpandError { message, error, kind } = err.render_to_string(db); - let editioned_file_id = EditionedFileId::from_span(db, err.span().anchor.file_id); - let precise_location = if editioned_file_id == file_id { - Some( - err.span().range - + db.ast_id_map(editioned_file_id.into()) - .get_erased(err.span().anchor.ast_id) - .text_range() - .start(), - ) - } else { - None - }; - acc.push(MacroError { node, precise_location, message, error, kind }.into()); + if Some(err.span().anchor.file_id) == file_id.file_id().map(|it| it.editioned_file_id(db)) { + range.value = err.span().range + + db.ast_id_map(file_id).get_erased(err.span().anchor.ast_id).text_range().start(); + } + acc.push(MacroError { range, message, error, kind }.into()); } if !parse_errors.is_empty() { let loc = db.lookup_intern_macro_call(macro_call_id); - let (node, precise_location) = precise_macro_call_location(&loc.kind, db); - acc.push( - MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() } - .into(), - ) + let range = precise_macro_call_location(&loc.kind, db, loc.krate); + acc.push(MacroExpansionParseError { range, errors: parse_errors.clone() }.into()) } } @@ -1046,6 +1067,7 @@ fn emit_macro_def_diagnostics<'db>( acc, &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, edition, + m.krate(db).id, ); } } @@ -1055,8 +1077,9 @@ fn emit_def_diagnostic<'db>( acc: &mut Vec<AnyDiagnostic<'db>>, diag: &DefDiagnostic, edition: Edition, + krate: base_db::Crate, ) { - emit_def_diagnostic_(db, acc, &diag.kind, edition) + emit_def_diagnostic_(db, acc, &diag.kind, edition, krate) } fn emit_def_diagnostic_<'db>( @@ -1064,6 +1087,7 @@ fn emit_def_diagnostic_<'db>( acc: &mut Vec<AnyDiagnostic<'db>>, diag: &DefDiagnosticKind, edition: Edition, + krate: base_db::Crate, ) { match diag { DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { @@ -1086,8 +1110,7 @@ fn emit_def_diagnostic_<'db>( let RenderedExpandError { message, error, kind } = err.render_to_string(db); acc.push( MacroError { - node: InFile::new(ast.file_id, item.syntax_node_ptr()), - precise_location: None, + range: InFile::new(ast.file_id, item.text_range()), message: format!("{}: {message}", path.display(db, edition)), error, kind, @@ -1117,11 +1140,10 @@ fn emit_def_diagnostic_<'db>( ); } DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { - let (node, precise_location) = precise_macro_call_location(ast, db); + let location = precise_macro_call_location(ast, db, krate); acc.push( UnresolvedMacroCall { - macro_call: node, - precise_location, + range: location, path: path.clone(), is_bang: matches!(ast, MacroCallKind::FnLike { .. }), } @@ -1140,34 +1162,12 @@ fn emit_def_diagnostic_<'db>( ); } DefDiagnosticKind::InvalidDeriveTarget { ast, id } => { - let node = ast.to_node(db); - let derive = node.attrs().nth(*id); - match derive { - Some(derive) => { - acc.push( - InvalidDeriveTarget { - node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))), - } - .into(), - ); - } - None => stdx::never!("derive diagnostic on item without derive attribute"), - } + let derive = id.find_attr_range(db, krate, *ast).3.path_range(); + acc.push(InvalidDeriveTarget { range: ast.with_value(derive) }.into()); } DefDiagnosticKind::MalformedDerive { ast, id } => { - let node = ast.to_node(db); - let derive = node.attrs().nth(*id); - match derive { - Some(derive) => { - acc.push( - MalformedDerive { - node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))), - } - .into(), - ); - } - None => stdx::never!("derive diagnostic on item without derive attribute"), - } + let derive = id.find_attr_range(db, krate, *ast).2; + acc.push(MalformedDerive { range: ast.with_value(derive) }.into()); } DefDiagnosticKind::MacroDefError { ast, message } => { let node = ast.to_node(db); @@ -1186,61 +1186,28 @@ fn emit_def_diagnostic_<'db>( fn precise_macro_call_location( ast: &MacroCallKind, db: &dyn HirDatabase, -) -> (InFile<SyntaxNodePtr>, Option<TextRange>) { + krate: base_db::Crate, +) -> InFile<TextRange> { // FIXME: maybe we actually want slightly different ranges for the different macro diagnostics // - e.g. the full attribute for macro errors, but only the name for name resolution match ast { MacroCallKind::FnLike { ast_id, .. } => { let node = ast_id.to_node(db); - ( - ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), - node.path() - .and_then(|it| it.segment()) - .and_then(|it| it.name_ref()) - .map(|it| it.syntax().text_range()), - ) + let range = node + .path() + .and_then(|it| it.segment()) + .and_then(|it| it.name_ref()) + .map(|it| it.syntax().text_range()); + let range = range.unwrap_or_else(|| node.syntax().text_range()); + ast_id.with_value(range) } MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { - let node = ast_id.to_node(db); - // Compute the precise location of the macro name's token in the derive - // list. - let token = (|| { - let derive_attr = collect_attrs(&node) - .nth(derive_attr_index.ast_index()) - .and_then(|x| Either::left(x.1))?; - let token_tree = derive_attr.meta()?.token_tree()?; - let chunk_by = token_tree - .syntax() - .children_with_tokens() - .filter_map(|elem| match elem { - syntax::NodeOrToken::Token(tok) => Some(tok), - _ => None, - }) - .chunk_by(|t| t.kind() == T![,]); - let (_, mut group) = chunk_by - .into_iter() - .filter(|&(comma, _)| !comma) - .nth(*derive_index as usize)?; - group.find(|t| t.kind() == T![ident]) - })(); - ( - ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), - token.as_ref().map(|tok| tok.text_range()), - ) + let range = derive_attr_index.find_derive_range(db, krate, *ast_id, *derive_index); + ast_id.with_value(range) } - MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { - let node = ast_id.to_node(db); - let attr = collect_attrs(&node) - .nth(invoc_attr_index.ast_index()) - .and_then(|x| Either::left(x.1)) - .unwrap_or_else(|| { - panic!("cannot find attribute #{}", invoc_attr_index.ast_index()) - }); - - ( - ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), - Some(attr.syntax().text_range()), - ) + MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => { + let attr_range = attr_ids.invoc_attr().find_attr_range(db, krate, *ast_id).2; + ast_id.with_value(attr_range) } } } @@ -1248,7 +1215,7 @@ fn precise_macro_call_location( impl HasVisibility for Module { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let def_map = self.id.def_map(db); - let module_data = &def_map[self.id.local_id]; + let module_data = &def_map[self.id]; module_data.visibility } } @@ -1268,11 +1235,10 @@ pub struct InstantiatedField<'db> { impl<'db> InstantiatedField<'db> { /// Returns the type as in the signature of the struct. pub fn ty(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { - let krate = self.inner.krate(db); - let interner = DbInterner::new_with(db, Some(krate.base()), None); + let interner = DbInterner::new_no_crate(db); let var_id = self.inner.parent.into(); - let field = db.field_types(var_id)[self.inner.id]; + let field = db.field_types(var_id)[self.inner.id].get(); let ty = field.instantiate(interner, self.args); TypeNs::new(db, var_id, ty) } @@ -1291,15 +1257,14 @@ impl TupleField { } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - let interner = DbInterner::new_with(db, None, None); - let ty = db - .infer(self.owner) + let interner = DbInterner::new_no_crate(db); + let ty = InferenceResult::for_body(db, self.owner) .tuple_field_access_type(self.tuple) .as_slice() .get(self.index as usize) .copied() .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)); - Type { env: db.trait_environment_for_body(self.owner), ty } + Type { env: body_param_env_from_has_crate(db, self.owner), ty } } } @@ -1351,7 +1316,7 @@ impl Field { /// context of the field definition. pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { let var_id = self.parent.into(); - let ty = db.field_types(var_id)[self.id].skip_binder(); + let ty = db.field_types(var_id)[self.id].get().skip_binder(); TypeNs::new(db, var_id, ty) } @@ -1367,22 +1332,26 @@ impl Field { VariantDef::Union(it) => it.id.into(), VariantDef::Variant(it) => it.parent_enum(db).id.into(), }; - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty)); - let ty = db.field_types(var_id)[self.id].instantiate(interner, args); + let ty = db.field_types(var_id)[self.id].get().instantiate(interner, args); Type::new(db, var_id, ty) } pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { db.layout_of_ty( - self.ty(db).ty, - db.trait_environment(match hir_def::VariantId::from(self.parent) { - hir_def::VariantId::EnumVariantId(id) => { - GenericDefId::AdtId(id.lookup(db).parent.into()) - } - hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), - hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()), - }), + self.ty(db).ty.store(), + param_env_from_has_crate( + db, + match hir_def::VariantId::from(self.parent) { + hir_def::VariantId::EnumVariantId(id) => { + GenericDefId::AdtId(id.lookup(db).parent.into()) + } + hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), + hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()), + }, + ) + .store(), ) .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) } @@ -1438,7 +1407,7 @@ impl Struct { } pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { - db.struct_signature(self.id).repr + AttrFlags::repr(db, self.id.into()) } pub fn kind(self, db: &dyn HirDatabase) -> StructKind { @@ -1454,7 +1423,7 @@ impl Struct { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_unstable() + AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedStruct<'db> { @@ -1492,8 +1461,7 @@ impl<'db> InstantiatedStruct<'db> { } pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { - let krate = self.inner.krate(db); - let interner = DbInterner::new_with(db, Some(krate.base()), None); + let interner = DbInterner::new_no_crate(db); let ty = db.ty(self.inner.id.into()); TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) @@ -1543,7 +1511,7 @@ impl Union { .collect() } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_unstable() + AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } } @@ -1578,7 +1546,7 @@ impl Enum { } pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { - db.enum_signature(self.id).repr + AttrFlags::repr(db, self.id.into()) } pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { @@ -1591,10 +1559,10 @@ impl Enum { /// The type of the enum variant bodies. pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); Type::new_for_crate( - self.id.lookup(db).container.krate(), - match db.enum_signature(self.id).variant_body_type() { + self.id.lookup(db).container.krate(db), + match EnumSignature::variant_body_type(db, self.id) { layout::IntegerType::Pointer(sign) => match sign { true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize), false => Ty::new_uint(interner, rustc_type_ir::UintTy::Usize), @@ -1635,7 +1603,7 @@ impl Enum { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_unstable() + AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } } @@ -1655,8 +1623,7 @@ pub struct InstantiatedEnum<'db> { impl<'db> InstantiatedEnum<'db> { pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { - let krate = self.inner.krate(db); - let interner = DbInterner::new_with(db, Some(krate.base()), None); + let interner = DbInterner::new_no_crate(db); let ty = db.ty(self.inner.id.into()); TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) @@ -1715,7 +1682,7 @@ impl Variant { self.source(db)?.value.expr() } - pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError<'_>> { + pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError> { db.const_eval_discriminant(self.into()) } @@ -1736,7 +1703,7 @@ impl Variant { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_unstable() + AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedVariant<'db> { @@ -1801,13 +1768,12 @@ impl Adt { } pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { - let env = db.trait_environment(self.into()); - let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let interner = DbInterner::new_no_crate(db); let adt_id = AdtId::from(self); let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| { GenericArg::error_from_id(interner, id) }); - db.layout_of_adt(adt_id, args, env) + db.layout_of_adt(adt_id, args.store(), param_env_from_has_crate(db, adt_id).store()) .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) } @@ -1827,7 +1793,7 @@ impl Adt { args: impl IntoIterator<Item = Type<'db>>, ) -> Type<'db> { let id = AdtId::from(self); - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let ty = Ty::new_adt( interner, id, @@ -1916,9 +1882,9 @@ impl VariantDef { pub fn name(&self, db: &dyn HirDatabase) -> Name { match self { - VariantDef::Struct(s) => s.name(db), - VariantDef::Union(u) => u.name(db), - VariantDef::Variant(e) => e.name(db), + VariantDef::Struct(s) => (*s).name(db), + VariantDef::Union(u) => (*u).name(db), + VariantDef::Variant(e) => (*e).name(db), } } } @@ -1962,26 +1928,35 @@ impl DefWithBody { } } - fn id(&self) -> DefWithBodyId { - match self { - DefWithBody::Function(it) => it.id.into(), + fn id(&self) -> Option<DefWithBodyId> { + Some(match self { + DefWithBody::Function(it) => match it.id { + AnyFunctionId::FunctionId(id) => id.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None, + }, DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), DefWithBody::Variant(it) => it.into(), - } + }) } /// A textual representation of the HIR of this def's body for debugging purposes. pub fn debug_hir(self, db: &dyn HirDatabase) -> String { - let body = db.body(self.id()); - body.pretty_print(db, self.id(), Edition::CURRENT) + let Some(id) = self.id() else { + return String::new(); + }; + let body = db.body(id); + body.pretty_print(db, id, Edition::CURRENT) } /// A textual representation of the MIR of this def's body for debugging purposes. pub fn debug_mir(self, db: &dyn HirDatabase) -> String { - let body = db.mir_body(self.id()); + let Some(id) = self.id() else { + return String::new(); + }; + let body = db.mir_body(id); match body { - Ok(body) => body.pretty_print(db, self.module(db).krate().to_display_target(db)), + Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)), Err(e) => format!("error:\n{e:?}"), } } @@ -1992,11 +1967,17 @@ impl DefWithBody { acc: &mut Vec<AnyDiagnostic<'db>>, style_lints: bool, ) { - let krate = self.module(db).id.krate(); + let Ok(id) = self.try_into() else { + return; + }; + let krate = self.module(db).id.krate(db); - let (body, source_map) = db.body_with_source_map(self.into()); + let (body, source_map) = db.body_with_source_map(id); let sig_source_map = match self { - DefWithBody::Function(id) => db.function_signature_with_source_map(id.into()).1, + DefWithBody::Function(id) => match id.id { + AnyFunctionId::FunctionId(id) => db.function_signature_with_source_map(id).1, + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return, + }, DefWithBody::Static(id) => db.static_signature_with_source_map(id.into()).1, DefWithBody::Const(id) => db.const_signature_with_source_map(id.into()).1, DefWithBody::Variant(variant) => { @@ -2006,16 +1987,16 @@ impl DefWithBody { }; for (_, def_map) in body.blocks(db) { - Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); + Module { id: def_map.root_module_id() }.diagnostics(db, acc, style_lints); } expr_store_diagnostics(db, acc, &source_map); - let infer = db.infer(self.into()); + let infer = InferenceResult::for_body(db, id); for d in infer.diagnostics() { acc.extend(AnyDiagnostic::inference_diagnostic( db, - self.into(), + id, d, &source_map, &sig_source_map, @@ -2042,14 +2023,14 @@ impl DefWithBody { acc.push( TypeMismatch { expr_or_pat, - expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected), - actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual), + expected: Type::new(db, id, mismatch.expected.as_ref()), + actual: Type::new(db, id, mismatch.actual.as_ref()), } .into(), ); } - let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, self.into()); + let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, id); for (node, reason) in missing_unsafe.unsafe_exprs { match source_map.expr_or_pat_syntax(node) { Ok(node) => acc.push( @@ -2084,7 +2065,7 @@ impl DefWithBody { } } - if let Ok(borrowck_results) = db.borrowck(self.into()) { + if let Ok(borrowck_results) = db.borrowck(id) { for borrowck_result in borrowck_results.iter() { let mir_body = &borrowck_result.mir_body; for moof in &borrowck_result.moved_out_of_ref { @@ -2113,7 +2094,10 @@ impl DefWithBody { } mir::MirSpan::Unknown => continue, }; - acc.push(MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty), span }.into()) + acc.push( + MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.as_ref()), span } + .into(), + ) } let mol = &borrowck_result.mutability_of_locals; for (binding_id, binding_data) in body.bindings() { @@ -2138,7 +2122,7 @@ impl DefWithBody { { need_mut = &mir::MutabilityReason::Not; } - let local = Local { parent: self.into(), binding_id }; + let local = Local { parent: id, binding_id }; let is_mut = body[binding_id].mode == BindingAnnotation::Mutable; match (need_mut, is_mut) { @@ -2194,17 +2178,11 @@ impl DefWithBody { } } - for diagnostic in BodyValidationDiagnostic::collect(db, self.into(), style_lints) { + for diagnostic in BodyValidationDiagnostic::collect(db, id, style_lints) { acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map)); } - let def: ModuleDef = match self { - DefWithBody::Function(it) => it.into(), - DefWithBody::Static(it) => it.into(), - DefWithBody::Const(it) => it.into(), - DefWithBody::Variant(it) => it.into(), - }; - for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) { + for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) { acc.push(diag.into()) } } @@ -2221,8 +2199,7 @@ fn expr_store_diagnostics<'db>( InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into() } ExpressionStoreDiagnostics::UnresolvedMacroCall { node, path } => UnresolvedMacroCall { - macro_call: (*node).map(|ast_ptr| ast_ptr.into()), - precise_location: None, + range: node.map(|ptr| ptr.text_range()), path: path.clone(), is_bang: true, } @@ -2243,45 +2220,181 @@ fn expr_store_diagnostics<'db>( .macro_calls() .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id, acc)); } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum AnyFunctionId { + FunctionId(FunctionId), + BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId }, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Function { - pub(crate) id: FunctionId, + pub(crate) id: AnyFunctionId, +} + +impl fmt::Debug for Function { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.id, f) + } } impl Function { pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.module(db).into() + match self.id { + AnyFunctionId::FunctionId(id) => id.module(db).into(), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => impl_.module(db).into(), + } } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.function_signature(self.id).name.clone() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).name.clone(), + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => { + Name::new_symbol_root(method.name()) + } + } } pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_value_def(db, self.id) + match self.id { + AnyFunctionId::FunctionId(id) => Type::from_value_def(db, id), + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + // Get the type for the trait function, as we can't get the type for the impl function + // because it has not `CallableDefId`. + let krate = impl_.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let param_env = hir_ty::builtin_derive::param_env(interner, impl_); + let env = ParamEnvAndCrate { param_env, krate }; + let Some(trait_method) = method.trait_method(db, impl_) else { + return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) }; + }; + Function::from(trait_method).ty(db) + } + } } pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.resolver(db); - let interner = DbInterner::new_with(db, None, None); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity(); - let ty = Ty::new_fn_ptr(interner, callable_sig); - Type::new_with_resolver_inner(db, &resolver, ty) + match self.id { + AnyFunctionId::FunctionId(id) => { + let resolver = id.resolver(db); + let interner = DbInterner::new_no_crate(db); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let callable_sig = db.callable_item_signature(id.into()).instantiate_identity(); + let ty = Ty::new_fn_ptr(interner, callable_sig); + Type::new_with_resolver_inner(db, &resolver, ty) + } + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + struct ParamsShifter<'db> { + interner: DbInterner<'db>, + shift_by: i32, + } + + impl<'db> TypeFolder<DbInterner<'db>> for ParamsShifter<'db> { + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { + if let TyKind::Param(param) = ty.kind() { + Ty::new_param( + self.interner, + param.id, + param.index.checked_add_signed(self.shift_by).unwrap(), + ) + } else { + ty.super_fold_with(self) + } + } + + fn fold_const( + &mut self, + ct: hir_ty::next_solver::Const<'db>, + ) -> hir_ty::next_solver::Const<'db> { + if let ConstKind::Param(param) = ct.kind() { + hir_ty::next_solver::Const::new_param( + self.interner, + ParamConst { + id: param.id, + index: param.index.checked_add_signed(self.shift_by).unwrap(), + }, + ) + } else { + ct.super_fold_with(self) + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + if let RegionKind::ReEarlyParam(param) = r.kind() { + Region::new_early_param( + self.interner, + EarlyParamRegion { + id: param.id, + index: param.index.checked_add_signed(self.shift_by).unwrap(), + }, + ) + } else { + r + } + } + } + + // Get the type for the trait function, as we can't get the type for the impl function + // because it has not `CallableDefId`. + let krate = impl_.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let param_env = hir_ty::builtin_derive::param_env(interner, impl_); + let env = ParamEnvAndCrate { param_env, krate }; + let Some(trait_method) = method.trait_method(db, impl_) else { + return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) }; + }; + // The procedure works as follows: the method may have additional generic parameters (e.g. `Hash::hash()`), + // and we want them to be params of the impl method as well. So we start with the trait method identity + // args and extract from them the trait method own args. In parallel, we retrieve the impl trait ref. + // Now we can put our args as [...impl_trait_ref.args, ...trait_method_own_args], but we have one problem: + // the args in `trait_method_own_args` use indices appropriate for the trait method, which are not necessarily + // good for the impl method. So we shift them by `impl_generics_len - trait_generics_len`, which is essentially + // `impl_generics_len - impl_trait_ref.args.len()`. + let trait_method_fn_ptr = Ty::new_fn_ptr( + interner, + db.callable_item_signature(trait_method.into()).instantiate_identity(), + ); + let impl_trait_ref = + hir_ty::builtin_derive::impl_trait(interner, impl_).instantiate_identity(); + let trait_method_args = + GenericArgs::identity_for_item(interner, trait_method.into()); + let trait_method_own_args = GenericArgs::new_from_iter( + interner, + trait_method_args.iter().skip(impl_trait_ref.args.len()), + ); + let impl_params_count = hir_ty::builtin_derive::generic_params_count(db, impl_); + let shift_args_by = impl_params_count as i32 - impl_trait_ref.args.len() as i32; + let shifted_trait_method_own_args = trait_method_own_args + .fold_with(&mut ParamsShifter { interner, shift_by: shift_args_by }); + let impl_method_args = GenericArgs::new_from_iter( + interner, + impl_trait_ref.args.iter().chain(shifted_trait_method_own_args), + ); + let impl_method_fn_ptr = + EarlyBinder::bind(trait_method_fn_ptr).instantiate(interner, impl_method_args); + Type { env, ty: impl_method_fn_ptr } + } + } + } + + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (ParamEnvAndCrate<'db>, PolyFnSig<'db>) { + let fn_ptr = self.fn_ptr_type(db); + let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.kind() else { + unreachable!(); + }; + (fn_ptr.env, sig_tys.with(hdr)) } // FIXME: Find a better API to express all combinations here, perhaps we should have `PreInstantiationType`? /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.resolver(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let ty = db - .callable_item_signature(self.id.into()) - .instantiate_identity() - .skip_binder() - .output(); - Type::new_with_resolver_inner(db, &resolver, ty) + let (env, sig) = self.fn_sig(db); + Type { env, ty: sig.skip_binder().output() } } // FIXME: Find better API to also handle const generics @@ -2290,30 +2403,41 @@ impl Function { db: &'db dyn HirDatabase, generics: impl Iterator<Item = Type<'db>>, ) -> Type<'db> { - let resolver = self.id.resolver(db); - let interner = DbInterner::new_with(db, None, None); - let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); - - let interner = DbInterner::new_with(db, None, None); - let ty = db - .callable_item_signature(self.id.into()) - .instantiate(interner, args) - .skip_binder() - .output(); - Type::new_with_resolver_inner(db, &resolver, ty) + let ret_type = self.ret_type(db); + let interner = DbInterner::new_no_crate(db); + let args = self.adapt_generic_args(interner, generics); + ret_type.derived(EarlyBinder::bind(ret_type.ty).instantiate(interner, args)) + } + + fn adapt_generic_args<'db>( + self, + interner: DbInterner<'db>, + generics: impl Iterator<Item = Type<'db>>, + ) -> GenericArgs<'db> { + let generics = generics.map(|ty| ty.ty); + match self.id { + AnyFunctionId::FunctionId(id) => generic_args_from_tys(interner, id.into(), generics), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + let impl_args = GenericArgs::identity_for_item(interner, impl_.into()); + GenericArgs::new_from_iter( + interner, + impl_args.iter().chain(generics.map(Into::into)), + ) + } + } } pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> { + let AnyFunctionId::FunctionId(id) = self.id else { + return None; + }; if !self.is_async(db) { return None; } - let resolver = self.id.resolver(db); + let resolver = id.resolver(db); // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let ret_ty = db - .callable_item_signature(self.id.into()) - .instantiate_identity() - .skip_binder() - .output(); + let ret_ty = + db.callable_item_signature(id.into()).instantiate_identity().skip_binder().output(); for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { if let ClauseKind::Projection(projection) = pred.kind().skip_binder() && let Some(output_ty) = projection.term.as_type() @@ -2325,31 +2449,47 @@ impl Function { } pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).has_self_param() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).has_self_param(), + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { + BuiltinDeriveImplMethod::clone + | BuiltinDeriveImplMethod::fmt + | BuiltinDeriveImplMethod::hash + | BuiltinDeriveImplMethod::cmp + | BuiltinDeriveImplMethod::partial_cmp + | BuiltinDeriveImplMethod::eq => true, + BuiltinDeriveImplMethod::default => false, + }, + } } pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { - self.has_self_param(db).then_some(SelfParam { func: self.id }) + self.has_self_param(db).then_some(SelfParam { func: self }) } pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> { - let environment = db.trait_environment(self.id.into()); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = - db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); - callable_sig + let (env, sig) = self.fn_sig(db); + let func = match self.id { + AnyFunctionId::FunctionId(id) => Callee::Def(CallableDefId::FunctionId(id)), + AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { + Callee::BuiltinDeriveImplMethod { method, impl_ } + } + }; + sig.skip_binder() .inputs() .iter() .enumerate() - .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty }; - Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } - }) + .map(|(idx, &ty)| Param { func: func.clone(), ty: Type { env, ty }, idx }) .collect() } pub fn num_params(self, db: &dyn HirDatabase) -> usize { - db.function_signature(self.id).params.len() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).params.len(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => { + self.fn_sig(db).1.skip_binder().inputs().len() + } + } } pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param<'_>>> { @@ -2358,21 +2498,11 @@ impl Function { } pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> { - let environment = db.trait_environment(self.id.into()); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = - db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder(); - let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; - callable_sig - .inputs() - .iter() - .enumerate() - .skip(skip) - .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty }; - Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } - }) - .collect() + let mut params = self.assoc_fn_params(db); + if self.has_self_param(db) { + params.remove(0); + } + params } // FIXME: Find better API to also handle const generics @@ -2381,40 +2511,50 @@ impl Function { db: &'db dyn HirDatabase, generics: impl Iterator<Item = Type<'db>>, ) -> Vec<Param<'db>> { - let environment = db.trait_environment(self.id.into()); - let interner = DbInterner::new_with(db, None, None); - let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); - let callable_sig = - db.callable_item_signature(self.id.into()).instantiate(interner, args).skip_binder(); - let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 }; - callable_sig - .inputs() - .iter() - .enumerate() - .skip(skip) - .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty }; - Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } + let interner = DbInterner::new_no_crate(db); + let args = self.adapt_generic_args(interner, generics); + let params = self.params_without_self(db); + params + .into_iter() + .map(|param| Param { + func: param.func, + idx: param.idx, + ty: Type { + env: param.ty.env, + ty: EarlyBinder::bind(param.ty.ty).instantiate(interner, args), + }, }) .collect() } pub fn is_const(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).is_const() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).is_const(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } } pub fn is_async(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).is_async() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).is_async(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } } pub fn is_varargs(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).is_varargs() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).is_varargs(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } } pub fn extern_block(self, db: &dyn HirDatabase) -> Option<ExternBlock> { - match self.id.lookup(db).container { - ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }), - _ => None, + match self.id { + AnyFunctionId::FunctionId(id) => match id.lookup(db).container { + ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }), + _ => None, + }, + AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, } } @@ -2425,11 +2565,11 @@ impl Function { let ret_type = self.ret_type(db); let Some(impl_traits) = ret_type.as_impl_traits(db) else { return false }; - let Some(future_trait_id) = LangItem::Future.resolve_trait(db, self.ty(db).env.krate) - else { + let lang_items = hir_def::lang_item::lang_items(db, self.krate(db).id); + let Some(future_trait_id) = lang_items.Future else { return false; }; - let Some(sized_trait_id) = LangItem::Sized.resolve_trait(db, self.ty(db).env.krate) else { + let Some(sized_trait_id) = lang_items.Sized else { return false; }; @@ -2447,33 +2587,46 @@ impl Function { /// Does this function have `#[test]` attribute? pub fn is_test(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_test() + self.attrs(db).contains(AttrFlags::IS_TEST) } /// is this a `fn main` or a function with an `export_name` of `main`? pub fn is_main(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).export_name() == Some(&sym::main) - || self.module(db).is_crate_root() && db.function_signature(self.id).name == sym::main + match self.id { + AnyFunctionId::FunctionId(id) => { + self.exported_main(db) + || self.module(db).is_crate_root(db) + && db.function_signature(id).name == sym::main + } + AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, + } + } + + fn attrs(self, db: &dyn HirDatabase) -> AttrFlags { + match self.id { + AnyFunctionId::FunctionId(id) => AttrFlags::query(db, id.into()), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrFlags::empty(), + } } /// Is this a function with an `export_name` of `main`? pub fn exported_main(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).export_name() == Some(&sym::main) + self.attrs(db).contains(AttrFlags::IS_EXPORT_NAME_MAIN) } /// Does this function have the ignore attribute? pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_ignore() + self.attrs(db).contains(AttrFlags::IS_IGNORE) } /// Does this function have `#[bench]` attribute? pub fn is_bench(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_bench() + self.attrs(db).contains(AttrFlags::IS_BENCH) } /// Is this function marked as unstable with `#[feature]` attribute? pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(self.id.into()).is_unstable() + self.attrs(db).contains(AttrFlags::IS_UNSTABLE) } pub fn is_unsafe_to_call( @@ -2482,10 +2635,17 @@ impl Function { caller: Option<Function>, call_edition: Edition, ) -> bool { + let AnyFunctionId::FunctionId(id) = self.id else { + return false; + }; let (target_features, target_feature_is_safe_in_target) = caller .map(|caller| { - let target_features = - hir_ty::TargetFeatures::from_attrs(&db.attrs(caller.id.into())); + let target_features = match caller.id { + AnyFunctionId::FunctionId(id) => hir_ty::TargetFeatures::from_fn(db, id), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => { + hir_ty::TargetFeatures::default() + } + }; let target_feature_is_safe_in_target = match &caller.krate(db).id.workspace_data(db).target { Ok(target) => hir_ty::target_feature_is_safe_in_target(target), @@ -2499,7 +2659,7 @@ impl Function { matches!( hir_ty::is_fn_unsafe_to_call( db, - self.id, + id, &target_features, call_edition, target_feature_is_safe_in_target @@ -2512,32 +2672,39 @@ impl Function { /// /// This is false in the case of required (not provided) trait methods. pub fn has_body(self, db: &dyn HirDatabase) -> bool { - db.function_signature(self.id).has_body() + match self.id { + AnyFunctionId::FunctionId(id) => db.function_signature(id).has_body(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => true, + } } pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> { - let attrs = db.attrs(self.id.into()); - // FIXME: Store this in FunctionData flags? - if !(attrs.is_proc_macro() - || attrs.is_proc_macro_attribute() - || attrs.is_proc_macro_derive()) - { + let AnyFunctionId::FunctionId(id) = self.id else { return None; - } - let def_map = crate_def_map(db, HasModule::krate(&self.id, db)); - def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) + }; + let def_map = crate_def_map(db, HasModule::krate(&id, db)); + def_map.fn_as_proc_macro(id).map(|id| Macro { id: id.into() }) } pub fn eval( self, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, - ) -> Result<String, ConstEvalError<'_>> { - let interner = DbInterner::new_with(db, None, None); + ) -> Result<String, ConstEvalError> { + let AnyFunctionId::FunctionId(id) = self.id else { + return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported( + "evaluation of builtin derive impl methods is not supported".to_owned(), + ))); + }; + let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( - self.id.into(), - GenericArgs::new_from_iter(interner, []), - db.trait_environment(self.id.into()), + id.into(), + GenericArgs::empty(interner).store(), + ParamEnvAndCrate { + param_env: db.trait_environment(id.into()), + krate: id.module(db).krate(db), + } + .store(), )?; let (result, output) = interpret_mir(db, body, false, None)?; let mut text = match result { @@ -2652,36 +2819,47 @@ impl<'db> Param<'db> { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SelfParam { - func: FunctionId, + func: Function, } impl SelfParam { pub fn access(self, db: &dyn HirDatabase) -> Access { - let func_data = db.function_signature(self.func); - func_data - .params - .first() - .map(|¶m| match &func_data.store[param] { - TypeRef::Reference(ref_) => match ref_.mutability { - hir_def::type_ref::Mutability::Shared => Access::Shared, - hir_def::type_ref::Mutability::Mut => Access::Exclusive, - }, - _ => Access::Owned, - }) - .unwrap_or(Access::Owned) + match self.func.id { + AnyFunctionId::FunctionId(id) => { + let func_data = db.function_signature(id); + func_data + .params + .first() + .map(|¶m| match &func_data.store[param] { + TypeRef::Reference(ref_) => match ref_.mutability { + hir_def::type_ref::Mutability::Shared => Access::Shared, + hir_def::type_ref::Mutability::Mut => Access::Exclusive, + }, + _ => Access::Owned, + }) + .unwrap_or(Access::Owned) + } + AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { + BuiltinDeriveImplMethod::clone + | BuiltinDeriveImplMethod::fmt + | BuiltinDeriveImplMethod::hash + | BuiltinDeriveImplMethod::cmp + | BuiltinDeriveImplMethod::partial_cmp + | BuiltinDeriveImplMethod::eq => Access::Shared, + BuiltinDeriveImplMethod::default => { + unreachable!("this function does not have a self param") + } + }, + } } pub fn parent_fn(&self) -> Function { - Function::from(self.func) + self.func } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let callable_sig = - db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder(); - let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.inputs().as_slice()[0]; - Type { env: environment, ty } + let (env, sig) = self.func.fn_sig(db); + Type { env, ty: sig.skip_binder().inputs()[0] } } // FIXME: Find better API to also handle const generics @@ -2690,19 +2868,19 @@ impl SelfParam { db: &'db dyn HirDatabase, generics: impl Iterator<Item = Type<'db>>, ) -> Type<'db> { - let interner = DbInterner::new_with(db, None, None); - let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty)); - let callable_sig = - db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder(); - let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.inputs().as_slice()[0]; - Type { env: environment, ty } + let interner = DbInterner::new_no_crate(db); + let args = self.func.adapt_generic_args(interner, generics); + let Type { env, ty } = self.ty(db); + Type { env, ty: EarlyBinder::bind(ty).instantiate(interner, args) } } } impl HasVisibility for Function { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.assoc_visibility(self.id.into()) + match self.id { + AnyFunctionId::FunctionId(id) => db.assoc_visibility(id.into()), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => Visibility::Public, + } } } @@ -2718,7 +2896,7 @@ impl ExternCrateDecl { pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> { let loc = self.id.lookup(db); - let krate = loc.container.krate(); + let krate = loc.container.krate(db); let name = self.name(db); if name == sym::self_ { Some(krate.into()) @@ -2789,11 +2967,14 @@ impl Const { } /// Evaluate the constant. - pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError<'_>> { - let interner = DbInterner::new_with(db, None, None); + pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError> { + let interner = DbInterner::new_no_crate(db); let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity(); - db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None) - .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty }) + db.const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { + const_: it, + def: self.id.into(), + ty, + }) } } @@ -2814,7 +2995,7 @@ impl<'db> EvaluatedConst<'db> { format!("{}", self.const_.display(db, display_target)) } - pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result<String, MirEvalError<'db>> { + pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result<String, MirEvalError> { let kind = self.const_.kind(); if let ConstKind::Value(c) = kind && let ty = c.ty.kind() @@ -2870,11 +3051,13 @@ impl Static { } /// Evaluate the static initializer. - pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError<'_>> { - let interner = DbInterner::new_with(db, None, None); + pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError> { let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity(); - db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None) - .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty }) + db.const_eval_static(self.id).map(|it| EvaluatedConst { + const_: it, + def: self.id.into(), + ty, + }) } } @@ -2892,8 +3075,12 @@ pub struct Trait { } impl Trait { - pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> { - LangItem::from_name(name)?.resolve_trait(db, krate.into()).map(Into::into) + pub fn lang(db: &dyn HirDatabase, krate: Crate, lang_item: LangItem) -> Option<Trait> { + let lang_items = hir_def::lang_item::lang_items(db, krate.id); + match lang_item.from_lang_items(lang_items)? { + LangItemTarget::TraitId(it) => Some(it.into()), + _ => None, + } } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -2917,7 +3104,7 @@ impl Trait { pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> { self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it { - AssocItemId::FunctionId(id) => Some(Function { id }), + AssocItemId::FunctionId(id) => Some(id.into()), _ => None, }) } @@ -2976,7 +3163,7 @@ impl Trait { /// `#[rust_analyzer::completions(...)]` mode. pub fn complete(self, db: &dyn HirDatabase) -> Complete { - Complete::extract(true, &self.attrs(db)) + Complete::extract(true, self.attrs(db).attrs) } } @@ -3060,7 +3247,7 @@ impl BuiltinType { pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]); - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); Type::new_for_crate(core, Ty::from_builtin_type(interner, self.inner)) } @@ -3147,10 +3334,10 @@ impl Macro { let loc = id.lookup(db); let source = loc.source(db); match loc.kind { - ProcMacroKind::CustomDerive => db - .attrs(id.into()) - .parse_proc_macro_derive() - .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it), + ProcMacroKind::CustomDerive => AttrFlags::derive_info(db, self.id).map_or_else( + || as_name_opt(source.value.name()), + |info| Name::new_symbol_root(info.trait_name.clone()), + ), ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()), } } @@ -3158,7 +3345,7 @@ impl Macro { } pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool { - matches!(self.id, MacroId::MacroRulesId(_) if db.attrs(self.id.into()).by_key(sym::macro_export).exists()) + matches!(self.id, MacroId::MacroRulesId(_) if AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_MACRO_EXPORT)) } pub fn is_proc_macro(self) -> bool { @@ -3168,7 +3355,7 @@ impl Macro { pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind { match self.id { MacroId::Macro2Id(it) => match it.lookup(db).expander { - MacroExpander::Declarative => MacroKind::Declarative, + MacroExpander::Declarative { .. } => MacroKind::Declarative, MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => { MacroKind::DeclarativeBuiltIn } @@ -3176,7 +3363,7 @@ impl Macro { MacroExpander::BuiltInDerive(_) => MacroKind::DeriveBuiltIn, }, MacroId::MacroRulesId(it) => match it.lookup(db).expander { - MacroExpander::Declarative => MacroKind::Declarative, + MacroExpander::Declarative { .. } => MacroKind::Declarative, MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => { MacroKind::DeclarativeBuiltIn } @@ -3198,15 +3385,15 @@ impl Macro { ) } - pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool { - match self.id { - MacroId::Macro2Id(it) => { - matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_)) - } - MacroId::MacroRulesId(it) => { - matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_)) - } - MacroId::ProcMacroId(_) => false, + pub fn builtin_derive_kind(&self, db: &dyn HirDatabase) -> Option<BuiltinDeriveMacroKind> { + let expander = match self.id { + MacroId::Macro2Id(it) => it.lookup(db).expander, + MacroId::MacroRulesId(it) => it.lookup(db).expander, + MacroId::ProcMacroId(_) => return None, + }; + match expander { + MacroExpander::BuiltInDerive(kind) => Some(BuiltinDeriveMacroKind(kind)), + _ => None, } } @@ -3242,8 +3429,55 @@ impl Macro { pub fn is_derive(&self, db: &dyn HirDatabase) -> bool { matches!(self.kind(db), MacroKind::Derive | MacroKind::DeriveBuiltIn) } + + pub fn preferred_brace_style(&self, db: &dyn HirDatabase) -> Option<MacroBraces> { + let attrs = self.attrs(db); + MacroBraces::extract(attrs.attrs) + } +} + +// Feature: Macro Brace Style Attribute +// Crate authors can declare the preferred brace style for their macro. This will affect how completion +// insert calls to it. +// +// This is only supported on function-like macros. +// +// To do that, insert the `#[rust_analyzer::macro_style(style)]` attribute on the macro (for proc macros, +// insert it for the macro's function). `style` can be one of: +// +// - `braces` for `{...}` style. +// - `brackets` for `[...]` style. +// - `parentheses` for `(...)` style. +// +// Malformed attributes will be ignored without warnings. +// +// Note that users have no way to override this attribute, so be careful and only include things +// users definitely do not want to be completed! + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MacroBraces { + Braces, + Brackets, + Parentheses, +} + +impl MacroBraces { + fn extract(attrs: AttrFlags) -> Option<Self> { + if attrs.contains(AttrFlags::MACRO_STYLE_BRACES) { + Some(Self::Braces) + } else if attrs.contains(AttrFlags::MACRO_STYLE_BRACKETS) { + Some(Self::Brackets) + } else if attrs.contains(AttrFlags::MACRO_STYLE_PARENTHESES) { + Some(Self::Parentheses) + } else { + None + } + } } +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct BuiltinDeriveMacroKind(BuiltinDeriveExpander); + impl HasVisibility for Macro { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { match self.id { @@ -3294,8 +3528,8 @@ impl ItemInNs { /// Returns the crate defining this item (or `None` if `self` is built-in). pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> { match self { - ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()), - ItemInNs::Macros(id) => Some(id.module(db).krate()), + ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate(db)), + ItemInNs::Macros(id) => Some(id.module(db).krate(db)), } } @@ -3322,7 +3556,10 @@ pub trait AsExternAssocItem { impl AsExternAssocItem for Function { fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> { - as_extern_assoc_item(db, ExternAssocItem::Function, self.id) + let AnyFunctionId::FunctionId(id) = self.id else { + return None; + }; + as_extern_assoc_item(db, ExternAssocItem::Function, id) } } @@ -3347,6 +3584,15 @@ pub enum AssocItem { TypeAlias(TypeAlias), } +impl From<method_resolution::CandidateId> for AssocItem { + fn from(value: method_resolution::CandidateId) -> Self { + match value { + method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(id.into()), + method_resolution::CandidateId::ConstId(id) => AssocItem::Const(Const { id }), + } + } +} + #[derive(Debug, Clone)] pub enum AssocItemContainer { Trait(Trait), @@ -3359,7 +3605,10 @@ pub trait AsAssocItem { impl AsAssocItem for Function { fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { - as_assoc_item(db, AssocItem::Function, self.id) + match self.id { + AnyFunctionId::FunctionId(id) => as_assoc_item(db, AssocItem::Function, id), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => Some(AssocItem::Function(self)), + } } } @@ -3488,7 +3737,14 @@ impl AssocItem { pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { let container = match self { - AssocItem::Function(it) => it.id.lookup(db).container, + AssocItem::Function(it) => match it.id { + AnyFunctionId::FunctionId(id) => id.lookup(db).container, + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + return AssocItemContainer::Impl(Impl { + id: AnyImplId::BuiltinDeriveImplId(impl_), + }); + } + }, AssocItem::Const(it) => it.id.lookup(db).container, AssocItem::TypeAlias(it) => it.id.lookup(db).container, }; @@ -3625,9 +3881,13 @@ impl_from!( impl GenericDef { pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> { - let generics = db.generic_params(self.into()); + let Ok(id) = self.try_into() else { + // Let's pretend builtin derive impls don't have generic parameters. + return Vec::new(); + }; + let generics = db.generic_params(id); let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| { - let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } }; + let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: id, local_id } }; match toc.split(db) { Either::Left(it) => GenericParam::ConstParam(it), Either::Right(it) => GenericParam::TypeParam(it), @@ -3641,39 +3901,51 @@ impl GenericDef { } pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> { - let generics = db.generic_params(self.into()); + let Ok(id) = self.try_into() else { + // Let's pretend builtin derive impls don't have generic parameters. + return Vec::new(); + }; + let generics = db.generic_params(id); generics .iter_lt() - .map(|(local_id, _)| LifetimeParam { - id: LifetimeParamId { parent: self.into(), local_id }, - }) + .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: id, local_id } }) .collect() } pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> { - let generics = db.generic_params(self.into()); + let Ok(id) = self.try_into() else { + // Let's pretend builtin derive impls don't have generic parameters. + return Vec::new(); + }; + let generics = db.generic_params(id); generics .iter_type_or_consts() .map(|(local_id, _)| TypeOrConstParam { - id: TypeOrConstParamId { parent: self.into(), local_id }, + id: TypeOrConstParamId { parent: id, local_id }, }) .collect() } - fn id(self) -> GenericDefId { - match self { - GenericDef::Function(it) => it.id.into(), + fn id(self) -> Option<GenericDefId> { + Some(match self { + GenericDef::Function(it) => match it.id { + AnyFunctionId::FunctionId(it) => it.into(), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None, + }, GenericDef::Adt(it) => it.into(), GenericDef::Trait(it) => it.id.into(), GenericDef::TypeAlias(it) => it.id.into(), - GenericDef::Impl(it) => it.id.into(), + GenericDef::Impl(it) => match it.id { + AnyImplId::ImplId(it) => it.into(), + AnyImplId::BuiltinDeriveImplId(_) => return None, + }, GenericDef::Const(it) => it.id.into(), GenericDef::Static(it) => it.id.into(), - } + }) } pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec<AnyDiagnostic<'db>>) { - let def = self.id(); + let Some(def) = self.id() else { return }; let generics = db.generic_params(def); @@ -3698,7 +3970,7 @@ impl GenericDef { push_ty_diagnostics( db, acc, - db.generic_predicates_without_parent_with_diagnostics(def).1, + GenericPredicates::query_with_diagnostics(db, def).1.clone(), &source_map, ); for (param_id, param) in generics.iter_type_or_consts() { @@ -3738,14 +4010,25 @@ impl GenericDef { pub struct GenericSubstitution<'db> { def: GenericDefId, subst: GenericArgs<'db>, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, env: Arc<TraitEnvironment<'db>>) -> Self { + fn new(def: GenericDefId, subst: GenericArgs<'db>, env: ParamEnvAndCrate<'db>) -> Self { Self { def, subst, env } } + fn new_from_fn( + def: Function, + subst: GenericArgs<'db>, + env: ParamEnvAndCrate<'db>, + ) -> Option<Self> { + match def.id { + AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, env)), + AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, + } + } + pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { let container = match self.def { GenericDefId::ConstId(id) => Some(id.lookup(db).container), @@ -3788,9 +4071,7 @@ impl<'db> GenericSubstitution<'db> { .zip(type_params); container_params .chain(self_params) - .filter_map(|(ty, name)| { - Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) - }) + .filter_map(|(ty, name)| Some((name?.symbol().clone(), Type { ty, env: self.env }))) .collect() } } @@ -3860,7 +4141,9 @@ impl Local { pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { match self.parent { - DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }), + DefWithBodyId::FunctionId(func) if self.is_self(db) => { + Some(SelfParam { func: func.into() }) + } _ => None, } } @@ -3894,8 +4177,8 @@ impl Local { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; - let infer = db.infer(def); - let ty = infer[self.binding_id]; + let infer = InferenceResult::for_body(db, def); + let ty = infer.binding_ty(self.binding_id); Type::new(db, def, ty) } @@ -3982,18 +4265,10 @@ impl DeriveHelper { } pub fn name(&self, db: &dyn HirDatabase) -> Name { - match self.derive { - makro @ MacroId::Macro2Id(_) => db - .attrs(makro.into()) - .parse_rustc_builtin_macro() - .and_then(|(_, helpers)| helpers.get(self.idx as usize).cloned()), - MacroId::MacroRulesId(_) => None, - makro @ MacroId::ProcMacroId(_) => db - .attrs(makro.into()) - .parse_proc_macro_derive() - .and_then(|(_, helpers)| helpers.get(self.idx as usize).cloned()), - } - .unwrap_or_else(Name::missing) + AttrFlags::derive_info(db, self.derive) + .and_then(|it| it.helpers.get(self.idx as usize)) + .map(|helper| Name::new_symbol_root(helper.clone())) + .unwrap_or_else(Name::missing) } } @@ -4183,7 +4458,7 @@ impl TypeParam { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.parent().resolver(db); - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let index = hir_ty::param_idx(db, self.id.into()).unwrap(); let ty = Ty::new_param(interner, self.id, index as u32); Type::new_with_resolver_inner(db, &resolver, ty) @@ -4193,10 +4468,13 @@ impl TypeParam { /// parameter, not additional bounds that might be added e.g. by a method if /// the parameter comes from an impl! pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { - db.generic_predicates_for_param(self.id.parent(), self.id.into(), None) - .iter() + let self_ty = self.ty(db).ty; + GenericPredicates::query_explicit(db, self.id.parent()) + .iter_identity_copied() .filter_map(|pred| match &pred.kind().skip_binder() { - ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)), + ClauseKind::Trait(trait_ref) if trait_ref.self_ty() == self_ty => { + Some(Trait::from(trait_ref.def_id().0)) + } _ => None, }) .collect() @@ -4205,8 +4483,8 @@ impl TypeParam { pub fn default(self, db: &dyn HirDatabase) -> Option<Type<'_>> { let ty = generic_arg_from_param(db, self.id.into())?; let resolver = self.id.parent().resolver(db); - match ty { - GenericArg::Ty(it) if !it.is_ty_error() => { + match ty.kind() { + rustc_type_ir::GenericArgKind::Type(it) if !it.is_ty_error() => { Some(Type::new_with_resolver_inner(db, &resolver, it)) } _ => None, @@ -4214,7 +4492,7 @@ impl TypeParam { } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(GenericParamId::from(self.id).into()).is_unstable() + self.attrs(db).is_unstable() } } @@ -4353,175 +4631,215 @@ impl TypeOrConstParam { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Impl { - pub(crate) id: ImplId, + pub(crate) id: AnyImplId, } impl Impl { pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> { - let inherent = db.inherent_impls_in_crate(krate.id); - let trait_ = db.trait_impls_in_crate(krate.id); - - inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() + let mut result = Vec::new(); + extend_with_def_map(db, crate_def_map(db, krate.id), &mut result); + return result; + + fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec<Impl>) { + for (_, module) in def_map.modules() { + result.extend(module.scope.impls().map(Impl::from)); + result.extend(module.scope.builtin_derive_impls().map(Impl::from)); + + for unnamed_const in module.scope.unnamed_consts() { + for (_, block_def_map) in db.body(unnamed_const.into()).blocks(db) { + extend_with_def_map(db, block_def_map, result); + } + } + } + } } pub fn all_in_module(db: &dyn HirDatabase, module: Module) -> Vec<Impl> { - module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect() + module.impl_defs(db) } + /// **Note:** This is an **approximation** that strives to give the *human-perceived notion* of an "impl for type", + /// **not** answer the technical question "what are all impls applying to this type". In particular, it excludes + /// blanket impls, and only does a shallow type constructor check. In fact, this should've probably been on `Adt` + /// etc., and not on `Type`. If you would want to create a precise list of all impls applying to a type, + /// you would need to include blanket impls, and try to prove to predicates for each candidate. pub fn all_for_type<'db>(db: &'db dyn HirDatabase, Type { ty, env }: Type<'db>) -> Vec<Impl> { - let def_crates = match method_resolution::def_crates(db, ty, env.krate) { - Some(def_crates) => def_crates, - None => return Vec::new(), - }; - - let filter = |impl_def: &Impl| { - let self_ty = impl_def.self_ty(db); - let rref = self_ty.remove_ref(); - ty.equals_ctor(rref.as_ref().map_or(self_ty.ty, |it| it.ty)) + let mut result = Vec::new(); + let interner = DbInterner::new_no_crate(db); + let Some(simplified_ty) = + fast_reject::simplify_type(interner, ty, fast_reject::TreatParams::AsRigid) + else { + return Vec::new(); }; - - let fp = TyFingerprint::for_inherent_impl(ty); - let fp = match fp { - Some(fp) => fp, - None => return Vec::new(), + let mut extend_with_impls = |impls: Either<&[ImplId], &[BuiltinDeriveImplId]>| match impls { + Either::Left(impls) => result.extend(impls.iter().copied().map(Impl::from)), + Either::Right(impls) => result.extend(impls.iter().copied().map(Impl::from)), }; - - let mut all = Vec::new(); - def_crates.iter().for_each(|&id| { - all.extend( - db.inherent_impls_in_crate(id) - .for_self_ty(ty) - .iter() - .cloned() - .map(Self::from) - .filter(filter), - ) + method_resolution::with_incoherent_inherent_impls(db, env.krate, &simplified_ty, |impls| { + extend_with_impls(Either::Left(impls)) }); - - for id in def_crates - .iter() - .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db)) - .map(|Crate { id }| id) - { - all.extend( - db.trait_impls_in_crate(id) - .for_self_ty_without_blanket_impls(fp) - .map(Self::from) - .filter(filter), + if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) { + InherentImpls::for_each_crate_and_block( + db, + module.krate(db), + module.block(db), + &mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))), ); - } - - if let Some(block) = ty.as_adt().and_then(|(def, _)| def.module(db).containing_block()) { - if let Some(inherent_impls) = db.inherent_impls_in_block(block) { - all.extend( - inherent_impls.for_self_ty(ty).iter().cloned().map(Self::from).filter(filter), - ); + std::iter::successors(module.block(db), |block| block.loc(db).module.block(db)) + .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) + .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls)); + for &krate in &**db.all_crates() { + TraitImpls::for_crate(db, krate) + .for_self_ty(&simplified_ty, &mut extend_with_impls); } - if let Some(trait_impls) = db.trait_impls_in_block(block) { - all.extend( - trait_impls - .for_self_ty_without_blanket_impls(fp) - .map(Self::from) - .filter(filter), - ); + } else { + for &krate in &**db.all_crates() { + TraitImpls::for_crate(db, krate) + .for_self_ty(&simplified_ty, &mut extend_with_impls); } } - - all + result } pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> { - let module = trait_.module(db); - let krate = module.krate(); + let module = trait_.module(db).id; let mut all = Vec::new(); - for Crate { id } in krate.transitive_reverse_dependencies(db) { - let impls = db.trait_impls_in_crate(id); - all.extend(impls.for_trait(trait_.id).map(Self::from)) + let mut handle_impls = |impls: &TraitImpls| { + impls.for_trait(trait_.id, |impls| match impls { + Either::Left(impls) => all.extend(impls.iter().copied().map(Impl::from)), + Either::Right(impls) => all.extend(impls.iter().copied().map(Impl::from)), + }); + }; + for krate in module.krate(db).transitive_rev_deps(db) { + handle_impls(TraitImpls::for_crate(db, krate)); } - if let Some(block) = module.id.containing_block() - && let Some(trait_impls) = db.trait_impls_in_block(block) + if let Some(block) = module.block(db) + && let Some(impls) = TraitImpls::for_block(db, block) { - all.extend(trait_impls.for_trait(trait_.id).map(Self::from)); + handle_impls(impls); } all } pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> { - let trait_ref = db.impl_trait(self.id)?; - let id = trait_ref.skip_binder().def_id; - Some(Trait { id: id.0 }) + match self.id { + AnyImplId::ImplId(id) => { + let trait_ref = db.impl_trait(id)?; + let id = trait_ref.skip_binder().def_id; + Some(Trait { id: id.0 }) + } + AnyImplId::BuiltinDeriveImplId(id) => { + let loc = id.loc(db); + let lang_items = hir_def::lang_item::lang_items(db, loc.adt.module(db).krate(db)); + loc.trait_.get_id(lang_items).map(Trait::from) + } + } } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> { - let trait_ref = db.impl_trait(self.id)?.instantiate_identity(); - let resolver = self.id.resolver(db); - Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) + match self.id { + AnyImplId::ImplId(id) => { + let trait_ref = db.impl_trait(id)?.instantiate_identity(); + let resolver = id.resolver(db); + Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) + } + AnyImplId::BuiltinDeriveImplId(id) => { + let loc = id.loc(db); + let krate = loc.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let env = ParamEnvAndCrate { + param_env: hir_ty::builtin_derive::param_env(interner, id), + krate, + }; + let trait_ref = + hir_ty::builtin_derive::impl_trait(interner, id).instantiate_identity(); + Some(TraitRef { env, trait_ref }) + } + } } pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.resolver(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. - let ty = db.impl_self_ty(self.id).instantiate_identity(); - Type::new_with_resolver_inner(db, &resolver, ty) + match self.id { + AnyImplId::ImplId(id) => { + let resolver = id.resolver(db); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + let ty = db.impl_self_ty(id).instantiate_identity(); + Type::new_with_resolver_inner(db, &resolver, ty) + } + AnyImplId::BuiltinDeriveImplId(id) => { + let loc = id.loc(db); + let krate = loc.module(db).krate(db); + let interner = DbInterner::new_with(db, krate); + let env = ParamEnvAndCrate { + param_env: hir_ty::builtin_derive::param_env(interner, id), + krate, + }; + let ty = hir_ty::builtin_derive::impl_trait(interner, id) + .instantiate_identity() + .self_ty(); + Type { env, ty } + } + } } pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { - self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect() + match self.id { + AnyImplId::ImplId(id) => { + id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect() + } + AnyImplId::BuiltinDeriveImplId(impl_) => impl_ + .loc(db) + .trait_ + .all_methods() + .iter() + .map(|&method| { + AssocItem::Function(Function { + id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ }, + }) + }) + .collect(), + } } pub fn is_negative(self, db: &dyn HirDatabase) -> bool { - db.impl_signature(self.id).flags.contains(ImplFlags::NEGATIVE) + match self.id { + AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::NEGATIVE), + AnyImplId::BuiltinDeriveImplId(_) => false, + } } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { - db.impl_signature(self.id).flags.contains(ImplFlags::UNSAFE) + match self.id { + AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::UNSAFE), + AnyImplId::BuiltinDeriveImplId(_) => false, + } } pub fn module(self, db: &dyn HirDatabase) -> Module { - self.id.lookup(db).container.into() - } - - pub fn as_builtin_derive_path(self, db: &dyn HirDatabase) -> Option<InMacroFile<ast::Path>> { - let src = self.source(db)?; - - let macro_file = src.file_id.macro_file()?; - let loc = macro_file.lookup(db); - let (derive_attr, derive_index) = match loc.kind { - MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { - let module_id = self.id.lookup(db).container; - ( - crate_def_map(db, module_id.krate())[module_id.local_id] - .scope - .derive_macro_invoc(ast_id, derive_attr_index)?, - derive_index, - ) - } - _ => return None, - }; - let path = db - .parse_macro_expansion(derive_attr) - .value - .0 - .syntax_node() - .children() - .nth(derive_index as usize) - .and_then(<ast::Attr as AstNode>::cast) - .and_then(|it| it.path())?; - Some(InMacroFile { file_id: derive_attr, value: path }) + match self.id { + AnyImplId::ImplId(id) => id.module(db).into(), + AnyImplId::BuiltinDeriveImplId(id) => id.module(db).into(), + } } pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool { - check_orphan_rules(db, self.id) + match self.id { + AnyImplId::ImplId(id) => check_orphan_rules(db, id), + AnyImplId::BuiltinDeriveImplId(_) => true, + } } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { - self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice() + match self.id { + AnyImplId::ImplId(id) => id.impl_items(db).macro_calls.to_vec().into_boxed_slice(), + AnyImplId::BuiltinDeriveImplId(_) => Box::default(), + } } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, trait_ref: hir_ty::next_solver::TraitRef<'db>, } @@ -4531,9 +4849,7 @@ impl<'db> TraitRef<'db> { resolver: &Resolver<'_>, trait_ref: hir_ty::next_solver::TraitRef<'db>, ) -> Self { - let env = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let env = param_env_from_resolver(db, resolver); TraitRef { env, trait_ref } } @@ -4543,7 +4859,7 @@ impl<'db> TraitRef<'db> { pub fn self_ty(&self) -> TypeNs<'_> { let ty = self.trait_ref.self_ty(); - TypeNs { env: self.env.clone(), ty } + TypeNs { env: self.env, ty } } /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the @@ -4554,7 +4870,7 @@ impl<'db> TraitRef<'db> { .as_slice() .get(idx) .and_then(|arg| arg.ty()) - .map(|ty| TypeNs { env: self.env.clone(), ty }) + .map(|ty| TypeNs { env: self.env, ty }) } } @@ -4572,7 +4888,7 @@ pub struct Closure<'db> { impl<'db> Closure<'db> { fn as_ty(&self, db: &'db dyn HirDatabase) -> Ty<'db> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); match self.id { AnyClosureId::ClosureId(id) => Ty::new_closure(interner, id.into(), self.subst), AnyClosureId::CoroutineClosureId(id) => { @@ -4601,12 +4917,17 @@ impl<'db> Closure<'db> { return Vec::new(); }; let owner = db.lookup_intern_closure(id).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let info = infer.closure_info(id); info.0 .iter() .cloned() - .map(|capture| ClosureCapture { owner, closure: id, capture }) + .map(|capture| ClosureCapture { + owner, + closure: id, + capture, + _marker: PhantomCovariantLifetime::new(), + }) .collect() } @@ -4616,22 +4937,19 @@ impl<'db> Closure<'db> { return Vec::new(); }; let owner = db.lookup_intern_closure(id).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let (captures, _) = infer.closure_info(id); - let env = db.trait_environment_for_body(owner); - captures - .iter() - .map(|capture| Type { env: env.clone(), ty: capture.ty(db, self.subst) }) - .collect() + let env = body_param_env_from_has_crate(db, owner); + captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect() } pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { match self.id { AnyClosureId::ClosureId(id) => { let owner = db.lookup_intern_closure(id).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let info = infer.closure_info(id); - info.1 + info.1.into() } AnyClosureId::CoroutineClosureId(_id) => { // FIXME: Infer kind for coroutine closures. @@ -4645,11 +4963,77 @@ impl<'db> Closure<'db> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum FnTrait { + FnOnce, + FnMut, + Fn, + + AsyncFnOnce, + AsyncFnMut, + AsyncFn, +} + +impl From<traits::FnTrait> for FnTrait { + fn from(value: traits::FnTrait) -> Self { + match value { + traits::FnTrait::FnOnce => FnTrait::FnOnce, + traits::FnTrait::FnMut => FnTrait::FnMut, + traits::FnTrait::Fn => FnTrait::Fn, + traits::FnTrait::AsyncFnOnce => FnTrait::AsyncFnOnce, + traits::FnTrait::AsyncFnMut => FnTrait::AsyncFnMut, + traits::FnTrait::AsyncFn => FnTrait::AsyncFn, + } + } +} + +impl fmt::Display for FnTrait { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FnTrait::FnOnce => write!(f, "FnOnce"), + FnTrait::FnMut => write!(f, "FnMut"), + FnTrait::Fn => write!(f, "Fn"), + FnTrait::AsyncFnOnce => write!(f, "AsyncFnOnce"), + FnTrait::AsyncFnMut => write!(f, "AsyncFnMut"), + FnTrait::AsyncFn => write!(f, "AsyncFn"), + } + } +} + +impl FnTrait { + pub const fn function_name(&self) -> &'static str { + match self { + FnTrait::FnOnce => "call_once", + FnTrait::FnMut => "call_mut", + FnTrait::Fn => "call", + FnTrait::AsyncFnOnce => "async_call_once", + FnTrait::AsyncFnMut => "async_call_mut", + FnTrait::AsyncFn => "async_call", + } + } + + pub fn lang_item(self) -> LangItem { + match self { + FnTrait::FnOnce => LangItem::FnOnce, + FnTrait::FnMut => LangItem::FnMut, + FnTrait::Fn => LangItem::Fn, + FnTrait::AsyncFnOnce => LangItem::AsyncFnOnce, + FnTrait::AsyncFnMut => LangItem::AsyncFnMut, + FnTrait::AsyncFn => LangItem::AsyncFn, + } + } + + pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option<Trait> { + Trait::lang(db, krate, self.lang_item()) + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { owner: DefWithBodyId, closure: InternedClosureId, - capture: hir_ty::CapturedItem<'db>, + capture: hir_ty::CapturedItem, + _marker: PhantomCovariantLifetime<'db>, } impl<'db> ClosureCapture<'db> { @@ -4765,7 +5149,7 @@ impl CaptureUsageSource { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Type<'db> { - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ty: Ty<'db>, } @@ -4783,26 +5167,22 @@ impl<'db> Type<'db> { resolver: &Resolver<'_>, ty: Ty<'db>, ) -> Self { - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, resolver); Type { env: environment, ty } } pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty<'db>) -> Self { - Type { env: TraitEnvironment::empty(krate), ty } + Type { env: empty_param_env(krate), ty } } fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self { let resolver = lexical_env.resolver(db); - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, &resolver); Type { env: environment, ty } } fn from_def(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let ty = db.ty(def.into()); let def = match def.into() { TyDefId::AdtId(it) => GenericDefId::AdtId(it), @@ -4825,7 +5205,7 @@ impl<'db> Type<'db> { db: &'db dyn HirDatabase, def: impl Into<ValueTyDefId> + HasResolver, ) -> Self { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let Some(ty) = db.value_ty(def.into()) else { return Type::new(db, def, Ty::new_error(interner, ErrorGuaranteed)); }; @@ -4853,7 +5233,7 @@ impl<'db> Type<'db> { pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self { let tys = tys.iter().map(|it| it.ty); let interner = DbInterner::conjure(); - Type { env: TraitEnvironment::empty(krate), ty: Ty::new_tup_from_iter(interner, tys) } + Type { env: empty_param_env(krate), ty: Ty::new_tup_from_iter(interner, tys) } } pub fn is_unit(&self) -> bool { @@ -4881,7 +5261,7 @@ impl<'db> Type<'db> { } pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); return self.ty.visit_with(&mut Visitor { interner }).is_break(); fn is_phantom_data(db: &dyn HirDatabase, adt_id: AdtId) -> bool { @@ -4920,7 +5300,7 @@ impl<'db> Type<'db> { .fields() .iter() .map(|(idx, _)| { - field_types[idx].instantiate(self.interner, args) + field_types[idx].get().instantiate(self.interner, args) }) .filter(|it| !it.references_non_lt_error()) .collect() @@ -5033,16 +5413,17 @@ impl<'db> Type<'db> { /// `std::future::Future` and returns the `Output` associated type. /// This function is used in `.await` syntax completion. pub fn into_future_output(&self, db: &'db dyn HirDatabase) -> Option<Type<'db>> { - let trait_ = LangItem::IntoFutureIntoFuture - .resolve_function(db, self.env.krate) + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let trait_ = lang_items + .IntoFutureIntoFuture .and_then(|into_future_fn| { let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?; let into_future_trait = assoc_item.container_or_implemented_trait(db)?; Some(into_future_trait.id) }) - .or_else(|| LangItem::Future.resolve_trait(db, self.env.krate))?; + .or(lang_items.Future)?; - if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { + if !traits::implements_trait_unique(self.ty, db, self.env, trait_) { return None; } @@ -5053,13 +5434,15 @@ impl<'db> Type<'db> { /// This does **not** resolve `IntoFuture`, only `Future`. pub fn future_output(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> { - let future_output = LangItem::FutureOutput.resolve_type_alias(db, self.env.krate)?; + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let future_output = lang_items.FutureOutput?; self.normalize_trait_assoc_type(db, &[], future_output.into()) } /// This does **not** resolve `IntoIterator`, only `Iterator`. pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> { - let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?; + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let iterator_trait = lang_items.Iterator?; let iterator_item = iterator_trait .trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Item))?; @@ -5067,23 +5450,23 @@ impl<'db> Type<'db> { } pub fn impls_iterator(self, db: &'db dyn HirDatabase) -> bool { - let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else { + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let Some(iterator_trait) = lang_items.Iterator else { return false; }; - traits::implements_trait_unique(self.ty, db, self.env.clone(), iterator_trait) + traits::implements_trait_unique(self.ty, db, self.env, iterator_trait) } /// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type pub fn into_iterator_iter(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> { - let trait_ = LangItem::IntoIterIntoIter.resolve_function(db, self.env.krate).and_then( - |into_iter_fn| { - let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; - let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; - Some(into_iter_trait.id) - }, - )?; - - if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let trait_ = lang_items.IntoIterIntoIter.and_then(|into_iter_fn| { + let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; + let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; + Some(into_iter_trait.id) + })?; + + if !traits::implements_trait_unique(self.ty, db, self.env, trait_) { return None; } @@ -5098,23 +5481,24 @@ impl<'db> Type<'db> { /// This function can be used to check if a particular type is callable, since FnOnce is a /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce. pub fn impls_fnonce(&self, db: &'db dyn HirDatabase) -> bool { - let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) { + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let fnonce_trait = match lang_items.FnOnce { Some(it) => it, None => return false, }; - traits::implements_trait_unique(self.ty, db, self.env.clone(), fnonce_trait) + traits::implements_trait_unique(self.ty, db, self.env, fnonce_trait) } // FIXME: Find better API that also handles const generics pub fn impls_trait(&self, db: &'db dyn HirDatabase, trait_: Trait, args: &[Type<'db>]) -> bool { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let args = generic_args_from_tys( interner, trait_.id.into(), std::iter::once(self.ty).chain(args.iter().map(|ty| ty.ty)), ); - traits::implements_trait_unique_with_args(db, self.env.clone(), trait_.id, args) + traits::implements_trait_unique_with_args(db, self.env, trait_.id, args) } pub fn normalize_trait_assoc_type( @@ -5123,7 +5507,7 @@ impl<'db> Type<'db> { args: &[Type<'db>], alias: TypeAlias, ) -> Option<Type<'db>> { - let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); + let interner = DbInterner::new_with(db, self.env.krate); let args = generic_args_from_tys( interner, alias.id.into(), @@ -5133,23 +5517,24 @@ impl<'db> Type<'db> { let projection = Ty::new_alias( interner, AliasTyKind::Projection, - AliasTy::new(interner, alias.id.into(), args), + AliasTy::new_from_args(interner, alias.id.into(), args), ); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = structurally_normalize_ty(&infcx, projection, self.env.clone()); + let ty = structurally_normalize_ty(&infcx, projection, self.env.param_env); if ty.is_ty_error() { None } else { Some(self.derived(ty)) } } pub fn is_copy(&self, db: &'db dyn HirDatabase) -> bool { - let Some(copy_trait) = LangItem::Copy.resolve_trait(db, self.env.krate) else { + let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let Some(copy_trait) = lang_items.Copy else { return false; }; self.impls_trait(db, copy_trait.into(), &[]) } pub fn as_callable(&self, db: &'db dyn HirDatabase) -> Option<Callable<'db>> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let callee = match self.ty.kind() { TyKind::Closure(id, subst) => Callee::Closure(id.0, subst), TyKind::CoroutineClosure(id, subst) => Callee::CoroutineClosure(id.0, subst), @@ -5158,8 +5543,7 @@ impl<'db> Type<'db> { // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db), _ => { - let (fn_trait, sig) = - hir_ty::callable_sig_from_fn_trait(self.ty, self.env.clone(), db)?; + let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(self.ty, self.env, db)?; return Some(Callable { ty: self.clone(), sig, @@ -5223,7 +5607,7 @@ impl<'db> Type<'db> { } pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let (variant_id, substs) = match self.ty.kind() { TyKind::Adt(adt_def, substs) => { let id = match adt_def.def_id().0 { @@ -5240,7 +5624,7 @@ impl<'db> Type<'db> { .iter() .map(|(local_id, ty)| { let def = Field { parent: variant_id.into(), id: local_id }; - let ty = ty.instantiate(interner, substs); + let ty = ty.get().instantiate(interner, substs); (def, self.derived(ty)) }) .collect() @@ -5262,13 +5646,12 @@ impl<'db> Type<'db> { } } - pub fn fingerprint_for_trait_impl(&self) -> Option<TyFingerprint> { - TyFingerprint::for_trait_impl(self.ty) - } - - pub(crate) fn canonical(&self, db: &'db dyn HirDatabase) -> Canonical<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); - hir_ty::replace_errors_with_variables(interner, &self.ty) + pub fn fingerprint_for_trait_impl(&self) -> Option<SimplifiedType> { + fast_reject::simplify_type( + DbInterner::conjure(), + self.ty, + fast_reject::TreatParams::AsRigid, + ) } /// Returns types that this type dereferences to (including this type itself). The returned @@ -5281,10 +5664,10 @@ impl<'db> Type<'db> { } fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); - autoderef(db, self.env.clone(), canonical) + autoderef(db, self.env, canonical) } // This would be nicer if it just returned an iterator, but that runs into @@ -5292,11 +5675,10 @@ impl<'db> Type<'db> { pub fn iterate_assoc_items<T>( &self, db: &'db dyn HirDatabase, - krate: Crate, mut callback: impl FnMut(AssocItem) -> Option<T>, ) -> Option<T> { let mut slot = None; - self.iterate_assoc_items_dyn(db, krate, &mut |assoc_item_id| { + self.iterate_assoc_items_dyn(db, &mut |assoc_item_id| { slot = callback(assoc_item_id.into()); slot.is_some() }); @@ -5306,24 +5688,41 @@ impl<'db> Type<'db> { fn iterate_assoc_items_dyn( &self, db: &'db dyn HirDatabase, - krate: Crate, callback: &mut dyn FnMut(AssocItemId) -> bool, ) { - let ty_ns = self.ty; - let def_crates = match method_resolution::def_crates(db, ty_ns, krate.id) { - Some(it) => it, - None => return, - }; - for krate in def_crates { - let impls = db.inherent_impls_in_crate(krate); - - for impl_def in impls.for_self_ty(ty_ns) { + let mut handle_impls = |impls: &[ImplId]| { + for &impl_def in impls { for &(_, item) in impl_def.impl_items(db).items.iter() { if callback(item) { return; } } } + }; + + let interner = DbInterner::new_no_crate(db); + let Some(simplified_type) = + fast_reject::simplify_type(interner, self.ty, fast_reject::TreatParams::AsRigid) + else { + return; + }; + + method_resolution::with_incoherent_inherent_impls( + db, + self.env.krate, + &simplified_type, + &mut handle_impls, + ); + + if let Some(module) = method_resolution::simplified_type_module(db, &simplified_type) { + InherentImpls::for_each_crate_and_block( + db, + module.krate(db), + module.block(db), + &mut |impls| { + handle_impls(impls.for_self_ty(&simplified_type)); + }, + ); } } @@ -5383,12 +5782,14 @@ impl<'db> Type<'db> { .as_adt() .into_iter() .flat_map(|(_, substs)| substs.iter()) - .filter_map(move |arg| match arg { - GenericArg::Ty(ty) => Some(format_smolstr!("{}", ty.display(db, display_target))), - GenericArg::Const(const_) => { + .filter_map(move |arg| match arg.kind() { + rustc_type_ir::GenericArgKind::Type(ty) => { + Some(format_smolstr!("{}", ty.display(db, display_target))) + } + rustc_type_ir::GenericArgKind::Const(const_) => { Some(format_smolstr!("{}", const_.display(db, display_target))) } - GenericArg::Lifetime(_) => None, + rustc_type_ir::GenericArgKind::Lifetime(_) => None, }) } @@ -5414,26 +5815,20 @@ impl<'db> Type<'db> { db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet<TraitId>, - with_local_impls: Option<Module>, name: Option<&Name>, mut callback: impl FnMut(Function) -> Option<T>, ) -> Option<T> { let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered(); let mut slot = None; - self.iterate_method_candidates_split_inherent( - db, - scope, - traits_in_scope, - with_local_impls, - name, - |f| match callback(f) { + self.iterate_method_candidates_split_inherent(db, scope, traits_in_scope, name, |f| { + match callback(f) { it @ Some(_) => { slot = it; ControlFlow::Break(()) } None => ControlFlow::Continue(()), - }, - ); + } + }); slot } @@ -5441,7 +5836,6 @@ impl<'db> Type<'db> { &self, db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, - with_local_impls: Option<Module>, name: Option<&Name>, callback: impl FnMut(Function) -> Option<T>, ) -> Option<T> { @@ -5449,12 +5843,35 @@ impl<'db> Type<'db> { db, scope, &scope.visible_traits().0, - with_local_impls, name, callback, ) } + fn with_method_resolution<R>( + &self, + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, + traits_in_scope: &FxHashSet<TraitId>, + f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R, + ) -> R { + let module = resolver.module(); + let interner = DbInterner::new_with(db, module.krate(db)); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let unstable_features = + MethodResolutionUnstableFeatures::from_def_map(resolver.top_level_def_map()); + let environment = param_env_from_resolver(db, resolver); + let ctx = MethodResolutionContext { + infcx: &infcx, + resolver, + param_env: environment.param_env, + traits_in_scope, + edition: resolver.krate().data(db).edition, + unstable_features: &unstable_features, + }; + f(&ctx) + } + /// Allows you to treat inherent and non-inherent methods differently. /// /// Note that inherent methods may actually be trait methods! For example, in `dyn Trait`, the trait's methods @@ -5464,67 +5881,77 @@ impl<'db> Type<'db> { db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet<TraitId>, - with_local_impls: Option<Module>, name: Option<&Name>, - callback: impl MethodCandidateCallback, + mut callback: impl MethodCandidateCallback, ) { - struct Callback<T>(T); - - impl<T: MethodCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> { - fn on_inherent_method( - &mut self, - _adjustments: method_resolution::ReceiverAdjustments, - item: AssocItemId, - _is_visible: bool, - ) -> ControlFlow<()> { - if let AssocItemId::FunctionId(func) = item { - self.0.on_inherent_method(func.into()) - } else { - ControlFlow::Continue(()) - } - } - - fn on_trait_method( - &mut self, - _adjustments: method_resolution::ReceiverAdjustments, - item: AssocItemId, - _is_visible: bool, - ) -> ControlFlow<()> { - if let AssocItemId::FunctionId(func) = item { - self.0.on_trait_method(func.into()) - } else { - ControlFlow::Continue(()) - } - } - } - let _p = tracing::info_span!( - "iterate_method_candidates_dyn", - with_local_impls = traits_in_scope.len(), + "iterate_method_candidates_split_inherent", traits_in_scope = traits_in_scope.len(), ?name, ) .entered(); - let interner = DbInterner::new_with(db, None, None); - // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); - let krate = scope.krate(); - let environment = scope - .resolver() - .generic_def() - .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); + self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| { + // There should be no inference vars in types passed here + let canonical = hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty); + let (self_ty, _) = ctx.infcx.instantiate_canonical(&canonical); - _ = method_resolution::iterate_method_candidates_dyn( - &canonical, - db, - environment, - traits_in_scope, - with_local_impls.and_then(|b| b.id.containing_block()).into(), - name, - method_resolution::LookupMode::MethodCall, - &mut Callback(callback), - ); + match name { + Some(name) => { + match ctx.probe_for_name( + method_resolution::Mode::MethodCall, + name.clone(), + self_ty, + ) { + Ok(candidate) + | Err(method_resolution::MethodError::PrivateMatch(candidate)) => { + let method_resolution::CandidateId::FunctionId(id) = candidate.item + else { + unreachable!("`Mode::MethodCall` can only return functions"); + }; + let id = Function { id: AnyFunctionId::FunctionId(id) }; + match candidate.kind { + method_resolution::PickKind::InherentImplPick(_) + | method_resolution::PickKind::ObjectPick(..) + | method_resolution::PickKind::WhereClausePick(..) => { + // Candidates from where clauses and trait objects are considered inherent. + _ = callback.on_inherent_method(id); + } + method_resolution::PickKind::TraitPick(..) => { + _ = callback.on_trait_method(id); + } + } + } + Err(_) => {} + }; + } + None => { + _ = ctx.probe_all(method_resolution::Mode::MethodCall, self_ty).try_for_each( + |candidate| { + let method_resolution::CandidateId::FunctionId(id) = + candidate.candidate.item + else { + unreachable!("`Mode::MethodCall` can only return functions"); + }; + let id = Function { id: AnyFunctionId::FunctionId(id) }; + match candidate.candidate.kind { + method_resolution::CandidateKind::InherentImplCandidate { + .. + } + | method_resolution::CandidateKind::ObjectCandidate(..) + | method_resolution::CandidateKind::WhereClauseCandidate(..) => { + // Candidates from where clauses and trait objects are considered inherent. + callback.on_inherent_method(id) + } + method_resolution::CandidateKind::TraitCandidate(..) => { + callback.on_trait_method(id) + } + } + }, + ); + } + } + }) } #[tracing::instrument(skip_all, fields(name = ?name))] @@ -5533,27 +5960,21 @@ impl<'db> Type<'db> { db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet<TraitId>, - with_local_impls: Option<Module>, name: Option<&Name>, mut callback: impl FnMut(AssocItem) -> Option<T>, ) -> Option<T> { let _p = tracing::info_span!("iterate_path_candidates").entered(); let mut slot = None; - self.iterate_path_candidates_split_inherent( - db, - scope, - traits_in_scope, - with_local_impls, - name, - |item| match callback(item) { + self.iterate_path_candidates_split_inherent(db, scope, traits_in_scope, name, |item| { + match callback(item) { it @ Some(_) => { slot = it; ControlFlow::Break(()) } None => ControlFlow::Continue(()), - }, - ); + } + }); slot } @@ -5568,50 +5989,68 @@ impl<'db> Type<'db> { db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet<TraitId>, - with_local_impls: Option<Module>, name: Option<&Name>, - callback: impl PathCandidateCallback, + mut callback: impl PathCandidateCallback, ) { - struct Callback<T>(T); - - impl<T: PathCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> { - fn on_inherent_method( - &mut self, - _adjustments: method_resolution::ReceiverAdjustments, - item: AssocItemId, - _is_visible: bool, - ) -> ControlFlow<()> { - self.0.on_inherent_item(item.into()) - } - - fn on_trait_method( - &mut self, - _adjustments: method_resolution::ReceiverAdjustments, - item: AssocItemId, - _is_visible: bool, - ) -> ControlFlow<()> { - self.0.on_trait_item(item.into()) - } - } - - let interner = DbInterner::new_with(db, None, None); - let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); + let _p = tracing::info_span!( + "iterate_path_candidates_split_inherent", + traits_in_scope = traits_in_scope.len(), + ?name, + ) + .entered(); - let krate = scope.krate(); - let environment = scope - .resolver() - .generic_def() - .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); + self.with_method_resolution(db, scope.resolver(), traits_in_scope, |ctx| { + // There should be no inference vars in types passed here + let canonical = hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty); + let (self_ty, _) = ctx.infcx.instantiate_canonical(&canonical); - _ = method_resolution::iterate_path_candidates( - &canonical, - db, - environment, - traits_in_scope, - with_local_impls.and_then(|b| b.id.containing_block()).into(), - name, - &mut Callback(callback), - ); + match name { + Some(name) => { + match ctx.probe_for_name( + method_resolution::Mode::MethodCall, + name.clone(), + self_ty, + ) { + Ok(candidate) + | Err(method_resolution::MethodError::PrivateMatch(candidate)) => { + let id = candidate.item.into(); + match candidate.kind { + method_resolution::PickKind::InherentImplPick(_) + | method_resolution::PickKind::ObjectPick(..) + | method_resolution::PickKind::WhereClausePick(..) => { + // Candidates from where clauses and trait objects are considered inherent. + _ = callback.on_inherent_item(id); + } + method_resolution::PickKind::TraitPick(..) => { + _ = callback.on_trait_item(id); + } + } + } + Err(_) => {} + }; + } + None => { + _ = ctx.probe_all(method_resolution::Mode::Path, self_ty).try_for_each( + |candidate| { + let id = candidate.candidate.item.into(); + match candidate.candidate.kind { + method_resolution::CandidateKind::InherentImplCandidate { + .. + } + | method_resolution::CandidateKind::ObjectCandidate(..) + | method_resolution::CandidateKind::WhereClauseCandidate(..) => { + // Candidates from where clauses and trait objects are considered inherent. + callback.on_inherent_item(id) + } + method_resolution::CandidateKind::TraitCandidate(..) => { + callback.on_trait_item(id) + } + } + }, + ); + } + } + }) } pub fn as_adt(&self) -> Option<Adt> { @@ -5646,7 +6085,13 @@ impl<'db> Type<'db> { .filter(|ty| matches!(ty.kind(), TyKind::Param(_))) .flat_map(|ty| { self.env - .traits_in_scope_from_clauses(ty) + .param_env + .clauses() + .iter() + .filter_map(move |pred| match pred.kind().skip_binder() { + ClauseKind::Trait(tr) if tr.self_ty() == ty => Some(tr.def_id().0), + _ => None, + }) .flat_map(|t| hir_ty::all_super_traits(db, t)) }) .map(Trait::from) @@ -5670,7 +6115,7 @@ impl<'db> Type<'db> { } fn derived(&self, ty: Ty<'db>) -> Self { - Type { env: self.env.clone(), ty } + Type { env: self.env, ty } } /// Visits every type, including generic arguments, in this type. `callback` is called with type @@ -5678,7 +6123,7 @@ impl<'db> Type<'db> { pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { struct Visitor<'db, F> { db: &'db dyn HirDatabase, - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, callback: F, visited: FxHashSet<Ty<'db>>, } @@ -5693,7 +6138,7 @@ impl<'db> Type<'db> { return; } - (self.callback)(Type { env: self.env.clone(), ty }); + (self.callback)(Type { env: self.env, ty }); if let Some(bounds) = ty.impl_trait_bounds(self.db) { bounds.visit_with(self); @@ -5703,8 +6148,7 @@ impl<'db> Type<'db> { } } - let mut visitor = - Visitor { db, env: self.env.clone(), callback, visited: FxHashSet::default() }; + let mut visitor = Visitor { db, env: self.env, callback, visited: FxHashSet::default() }; self.ty.visit_with(&mut visitor); } /// Check if type unifies with another type. @@ -5712,9 +6156,9 @@ impl<'db> Type<'db> { /// Note that we consider placeholder types to unify with everything. /// For example `Option<T>` and `Option<U>` unify although there is unresolved goal `T = U`. pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty)); - hir_ty::could_unify(db, self.env.clone(), &tys) + hir_ty::could_unify(db, self.env, &tys) } /// Check if type unifies with another type eagerly making sure there are no unresolved goals. @@ -5722,15 +6166,15 @@ impl<'db> Type<'db> { /// This means that placeholder types are not considered to unify if there are any bounds set on /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U` pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, other.ty)); - hir_ty::could_unify_deeply(db, self.env.clone(), &tys) + hir_ty::could_unify_deeply(db, self.env, &tys) } pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let tys = hir_ty::replace_errors_with_variables(interner, &(self.ty, to.ty)); - hir_ty::could_coerce(db, self.env.clone(), &tys) + hir_ty::could_coerce(db, self.env, &tys) } pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option<TypeParam> { @@ -5749,43 +6193,42 @@ impl<'db> Type<'db> { } pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> { - db.layout_of_ty(self.ty, self.env.clone()) + db.layout_of_ty(self.ty.store(), self.env.store()) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { - let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block); + let interner = DbInterner::new_with(db, self.env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.clone()) + hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.param_env) } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeNs<'db> { - env: Arc<TraitEnvironment<'db>>, + env: ParamEnvAndCrate<'db>, ty: Ty<'db>, } impl<'db> TypeNs<'db> { fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self { let resolver = lexical_env.resolver(db); - let environment = resolver - .generic_def() - .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); + let environment = param_env_from_resolver(db, &resolver); TypeNs { env: environment, ty } } pub fn to_type(&self, _db: &'db dyn HirDatabase) -> Type<'db> { - Type { env: self.env.clone(), ty: self.ty } + Type { env: self.env, ty: self.ty } } // FIXME: Find better API that also handles const generics pub fn impls_trait(&self, infcx: InferCtxt<'db>, trait_: Trait, args: &[TypeNs<'db>]) -> bool { let args = GenericArgs::new_from_iter( infcx.interner, - [self.ty].into_iter().chain(args.iter().map(|t| t.ty)).map(|t| t.into()), + [self.ty].into_iter().chain(args.iter().map(|t| t.ty)).map(GenericArg::from), ); - let trait_ref = hir_ty::next_solver::TraitRef::new(infcx.interner, trait_.id.into(), args); + let trait_ref = + hir_ty::next_solver::TraitRef::new_from_args(infcx.interner, trait_.id.into(), args); let pred_kind = rustc_type_ir::Binder::dummy(rustc_type_ir::PredicateKind::Clause( rustc_type_ir::ClauseKind::Trait(rustc_type_ir::TraitPredicate { @@ -5844,7 +6287,8 @@ enum Callee<'db> { Closure(InternedClosureId, GenericArgs<'db>), CoroutineClosure(InternedCoroutineId, GenericArgs<'db>), FnPtr, - FnImpl(FnTrait), + FnImpl(traits::FnTrait), + BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId }, } pub enum CallableKind<'db> { @@ -5860,6 +6304,9 @@ impl<'db> Callable<'db> { pub fn kind(&self) -> CallableKind<'db> { match self.callee { Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), + Callee::BuiltinDeriveImplMethod { method, impl_ } => CallableKind::Function(Function { + id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ }, + }), Callee::Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), Callee::Def(CallableDefId::EnumVariantId(it)) => { CallableKind::TupleEnumVariant(it.into()) @@ -5871,15 +6318,25 @@ impl<'db> Callable<'db> { CallableKind::Closure(Closure { id: AnyClosureId::CoroutineClosureId(id), subst }) } Callee::FnPtr => CallableKind::FnPtr, - Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_), + Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_.into()), + } + } + + fn as_function(&self) -> Option<Function> { + match self.callee { + Callee::Def(CallableDefId::FunctionId(it)) => Some(it.into()), + Callee::BuiltinDeriveImplMethod { method, impl_ } => { + Some(Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }) + } + _ => None, } } + pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> { - let func = match self.callee { - Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it, - _ => return None, - }; - let func = Function { id: func }; + if !self.is_bound_method { + return None; + } + let func = self.as_function()?; Some(( func.self_param(db)?, self.ty.derived(self.sig.skip_binder().inputs_and_output.inputs()[0]), @@ -6088,12 +6545,12 @@ impl ScopeDef { pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> { match self { - ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()), - ScopeDef::GenericParam(it) => Some(it.module(db).krate()), + ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate(db)), + ScopeDef::GenericParam(it) => Some(it.module(db).krate(db)), ScopeDef::ImplSelfType(_) => None, - ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()), - ScopeDef::Local(it) => Some(it.module(db).krate()), - ScopeDef::Label(it) => Some(it.module(db).krate()), + ScopeDef::AdtSelfType(it) => Some(it.module(db).krate(db)), + ScopeDef::Local(it) => Some(it.module(db).krate(db)), + ScopeDef::Label(it) => Some(it.module(db).krate(db)), ScopeDef::Unknown => None, } } @@ -6153,61 +6610,61 @@ pub trait HasCrate { impl<T: hir_def::HasModule> HasCrate for T { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate().into() + self.module(db).krate(db).into() } } impl HasCrate for AssocItem { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Struct { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Union { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Enum { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Field { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.parent_def(db).module(db).krate() + self.parent_def(db).module(db).krate(db) } } impl HasCrate for Variant { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Function { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Const { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for TypeAlias { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } @@ -6219,37 +6676,37 @@ impl HasCrate for Type<'_> { impl HasCrate for Macro { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Trait { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Static { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Adt { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Impl { fn krate(&self, db: &dyn HirDatabase) -> Crate { - self.module(db).krate() + self.module(db).krate(db) } } impl HasCrate for Module { - fn krate(&self, _: &dyn HirDatabase) -> Crate { - Module::krate(*self) + fn krate(&self, db: &dyn HirDatabase) -> Crate { + Module::krate(*self, db) } } @@ -6267,8 +6724,8 @@ impl HasContainer for Module { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { // FIXME: handle block expressions as modules (their parent is in a different DefMap) let def_map = self.id.def_map(db); - match def_map[self.id.local_id].parent { - Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }), + match def_map[self.id].parent { + Some(parent_id) => ItemContainer::Module(Module { id: parent_id }), None => ItemContainer::Crate(def_map.krate().into()), } } @@ -6276,7 +6733,12 @@ impl HasContainer for Module { impl HasContainer for Function { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { - container_id_to_hir(self.id.lookup(db).container) + match self.id { + AnyFunctionId::FunctionId(id) => container_id_to_hir(id.lookup(db).container), + AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { + ItemContainer::Impl(Impl { id: AnyImplId::BuiltinDeriveImplId(impl_) }) + } + } } } @@ -6328,11 +6790,79 @@ impl HasContainer for ExternBlock { } } +pub trait HasName { + fn name(&self, db: &dyn HirDatabase) -> Option<Name>; +} + +macro_rules! impl_has_name { + ( $( $ty:ident ),* $(,)? ) => { + $( + impl HasName for $ty { + fn name(&self, db: &dyn HirDatabase) -> Option<Name> { + (*self).name(db).into() + } + } + )* + }; +} + +impl_has_name!( + ModuleDef, + Module, + Field, + Struct, + Union, + Enum, + Variant, + Adt, + VariantDef, + DefWithBody, + Function, + ExternCrateDecl, + Const, + Static, + Trait, + TypeAlias, + Macro, + ExternAssocItem, + AssocItem, + Local, + DeriveHelper, + ToolModule, + Label, + GenericParam, + TypeParam, + LifetimeParam, + ConstParam, + TypeOrConstParam, + InlineAsmOperand, +); + +macro_rules! impl_has_name_no_db { + ( $( $ty:ident ),* $(,)? ) => { + $( + impl HasName for $ty { + fn name(&self, _db: &dyn HirDatabase) -> Option<Name> { + (*self).name().into() + } + } + )* + }; +} + +impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr); + +impl HasName for Param<'_> { + fn name(&self, db: &dyn HirDatabase) -> Option<Name> { + self.name(db) + } +} + fn container_id_to_hir(c: ItemContainerId) -> ItemContainer { match c { ItemContainerId::ExternBlockId(id) => ItemContainer::ExternBlock(ExternBlock { id }), ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }), - ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }), + ItemContainerId::ImplId(id) => ItemContainer::Impl(id.into()), ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }), } } @@ -6427,7 +6957,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>( .filter_map(|&krate| { let segments = segments.clone(); let mut def_map = crate_def_map(db, krate); - let mut module = &def_map[DefMap::ROOT]; + let mut module = &def_map[def_map.root_module_id()]; let mut segments = segments.with_position().peekable(); while let Some((_, segment)) = segments.next_if(|&(position, _)| { !matches!(position, itertools::Position::Last | itertools::Position::Only) @@ -6441,7 +6971,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>( _ => None, })?; def_map = res.def_map(db); - module = &def_map[res.local_id]; + module = &def_map[res]; } let (_, item_name) = segments.next()?; let res = module.scope.get(&Name::new_symbol_root(item_name)); @@ -6488,5 +7018,35 @@ fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) }) } +fn param_env_from_resolver<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'_>, +) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { + param_env: resolver + .generic_def() + .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def)), + krate: resolver.krate(), + } +} + +fn param_env_from_has_crate<'db>( + db: &'db dyn HirDatabase, + id: impl hir_def::HasModule + Into<GenericDefId> + Copy, +) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } +} + +fn body_param_env_from_has_crate<'db>( + db: &'db dyn HirDatabase, + id: impl hir_def::HasModule + Into<DefWithBodyId> + Copy, +) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: db.trait_environment_for_body(id.into()), krate: id.krate(db) } +} + +fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: ParamEnv::empty(), krate } +} + pub use hir_ty::next_solver; pub use hir_ty::setup_tracing; |