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 | 2348 |
1 files changed, 1133 insertions, 1215 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 027a386abe..2146e4db77 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -35,7 +35,11 @@ pub mod term_search; mod display; +#[doc(hidden)] +pub use hir_def::ModuleId; + use std::{ + fmt, mem::discriminant, ops::{ControlFlow, Not}, }; @@ -44,17 +48,19 @@ 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, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, + DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, + GenericParamId, HasModule, ImplId, InternedModuleId, ItemContainerId, LifetimeParamId, + LocalFieldId, Lookup, MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + attrs::AttrFlags, 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, @@ -62,39 +68,44 @@ 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, - proc_macro::ProcMacroKind, + AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind, }; use hir_ty::{ - AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, - GenericArgData, Interner, ParamKind, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic, - ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules, - consteval::{ConstExt, try_const_usize, unknown_const_as_generic}, + GenericPredicates, InferenceResult, TraitEnvironment, TyDefId, TyLoweringDiagnostic, + ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, + consteval::try_const_usize, + db::{InternedClosureId, InternedCoroutineId}, diagnostics::BodyValidationDiagnostic, - direct_super_traits, error_lifetime, known_const_to_ast, + 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::{ - ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, mapping::ChalkToNextSolver, + AliasTy, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, + PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, }, - primitive::UintTy, - traits::FnTrait, + traits::{self, is_inherent_impl_coherent, structurally_normalize_ty}, }; use itertools::Itertools; use rustc_hash::FxHashSet; +use rustc_type_ir::{ + AliasTyKind, 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, variance::PhantomCovariantLifetime}; +use stdx::{format_to, impl_from, never}; 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, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -102,7 +113,7 @@ 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::{ @@ -110,7 +121,6 @@ pub use crate::{ VisibleTraits, }, }; -use rustc_type_ir::inherent::{IntoKind, SliceLike}; // Be careful with these re-exports. // @@ -126,10 +136,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}, @@ -140,7 +150,6 @@ pub use { }, hir_expand::{ EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind, - attrs::{Attr, AttrId}, change::ChangeWithProcMacros, files::{ FilePosition, FilePositionWrapper, FileRange, FileRangeWrapper, HirFilePosition, @@ -154,18 +163,22 @@ pub use { proc_macro::{ProcMacros, ProcMacrosBuilder}, tt, }, + // FIXME: Properly encapsulate mir + hir_ty::mir, hir_ty::{ - CastError, DropGlue, FnAbi, PointerCast, Safety, Variance, + CastError, FnAbi, PointerCast, attach_db, attach_db_allow_change, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, + drop::DropGlue, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, - method_resolution::TyFingerprint, mir::{MirEvalError, MirLowerError}, + next_solver::abi::Safety, + next_solver::clear_tls_solver_cache, }, - // FIXME: Properly encapsulate mir - hir_ty::{Interner as ChalkTyInterner, mir}, + // FIXME: These are needed for import assets, properly encapsulate them. + hir_ty::{method_resolution::TraitImpls, next_solver::SimplifiedType}, intern::{Symbol, sym}, }; @@ -234,7 +247,15 @@ 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 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) -> Module { @@ -284,11 +305,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 { @@ -633,7 +653,7 @@ impl Module { // 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() { @@ -652,8 +672,9 @@ impl Module { 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) { @@ -744,14 +765,15 @@ 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, self.id.krate()); + 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 source_map = db.impl_signature_with_source_map(impl_def.id).1; + let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_def.id); expr_store_diagnostics(db, acc, &source_map); let file_id = loc.id.file_id; @@ -768,10 +790,12 @@ 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); + emit_def_diagnostic(db, acc, diag, edition, loc.container.krate()); } - if inherent_impls.invalid_impls().contains(&impl_def.id) { + if impl_signature.target_trait.is_none() + && !is_inherent_impl_coherent(db, def_map, impl_def.id) + { acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } @@ -780,33 +804,29 @@ impl Module { } let trait_ = impl_def.trait_(db); - let trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db)); + let mut trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db)); let impl_is_negative = impl_def.is_negative(db); let impl_is_unsafe = impl_def.is_unsafe(db); + let trait_is_unresolved = trait_.is_none() && impl_signature.target_trait.is_some(); + if trait_is_unresolved { + // Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe, + // which may not be correct. + trait_is_unsafe = impl_is_unsafe; + } + 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 (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); @@ -863,23 +883,15 @@ impl Module { .collect(); if !missing.is_empty() { - let self_ty = db.impl_self_ty(impl_def.id).substitute( - Interner, - &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db), + let self_ty = db.impl_self_ty(impl_def.id).instantiate_identity(); + let self_ty = structurally_normalize_ty( + &infcx, + self_ty, + db.trait_environment(impl_def.id.into()), ); - let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) = - self_ty.kind(Interner) - { - db.normalize_projection( - projection.clone(), - db.trait_environment(impl_def.id.into()), - ) - } else { - self_ty - }; let self_ty_is_guaranteed_unsized = matches!( - self_ty.kind(Interner), - TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str + self_ty.kind(), + TyKind::Dynamic(..) | TyKind::Slice(..) | TyKind::Str ); if self_ty_is_guaranteed_unsized { missing.retain(|(_, assoc_item)| { @@ -975,6 +987,17 @@ impl Module { ) -> Option<ModPath> { hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg) } + + #[inline] + pub fn doc_keyword(self, db: &dyn HirDatabase) -> Option<Symbol> { + AttrFlags::doc_keyword(db, InternedModuleId::new(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) + } } fn macro_call_diagnostics<'db>( @@ -989,31 +1012,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()) } } @@ -1037,6 +1048,7 @@ fn emit_macro_def_diagnostics<'db>( acc, &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, edition, + m.krate(db).id, ); } } @@ -1046,8 +1058,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>( @@ -1055,6 +1068,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 } => { @@ -1077,8 +1091,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, @@ -1108,11 +1121,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 { .. }), } @@ -1131,34 +1143,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); @@ -1177,61 +1167,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) } } } @@ -1259,11 +1216,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_ns(var_id)[self.inner.id]; + let field = db.field_types(var_id)[self.inner.id]; let ty = field.instantiate(interner, self.args); TypeNs::new(db, var_id, ty) } @@ -1282,19 +1238,14 @@ impl TupleField { } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - 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(Interner) + .as_slice() .get(self.index as usize) - .and_then(|arg| arg.ty(Interner)) - .cloned() - .unwrap_or_else(|| TyKind::Error.intern(Interner)); - Type { - env: db.trait_environment_for_body(self.owner), - ty, - _pd: PhantomCovariantLifetime::new(), - } + .copied() + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)); + Type { env: db.trait_environment_for_body(self.owner), ty } } } @@ -1342,19 +1293,12 @@ impl Field { u32::from(self.id.into_raw()) as usize } - /// Returns the type as in the signature of the struct (i.e., with - /// placeholder types for type parameters). Only use this in the context of - /// the field definition. - pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { + /// Returns the type as in the signature of the struct. Only use this in the + /// context of the field definition. + pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { let var_id = self.parent.into(); - let generic_def_id: GenericDefId = match self.parent { - VariantDef::Struct(it) => it.id.into(), - VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.id.lookup(db).parent.into(), - }; - let substs = TyBuilder::placeholder_subst(db, generic_def_id); - let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); - Type::new(db, var_id, ty) + let ty = db.field_types(var_id)[self.id].skip_binder(); + TypeNs::new(db, var_id, ty) } // FIXME: Find better API to also handle const generics @@ -1369,24 +1313,15 @@ impl Field { VariantDef::Union(it) => it.id.into(), VariantDef::Variant(it) => it.parent_enum(db).id.into(), }; - let mut generics = generics.map(|it| it.ty); - let substs = TyBuilder::subst_for_def(db, def_id, None) - .fill(|x| match x { - ParamKind::Type => { - generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - .build(); - let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); + 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); Type::new(db, var_id, ty) } pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { - let interner = DbInterner::new_with(db, None, None); db.layout_of_ty( - self.ty(db).ty.to_nextsolver(interner), + 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()) @@ -1440,8 +1375,8 @@ impl Struct { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { + Type::from_def_params(db, self.id) } pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { @@ -1449,7 +1384,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 { @@ -1465,7 +1400,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> { @@ -1503,10 +1438,9 @@ 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_ns(self.inner.id.into()); + let ty = db.ty(self.inner.id.into()); TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) } } @@ -1529,8 +1463,8 @@ impl Union { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { + Type::from_def_params(db, self.id) } pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { @@ -1554,7 +1488,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) } } @@ -1589,47 +1523,50 @@ 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> { Type::from_def(db, self.id) } - pub fn ty_placeholders<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + Type::from_def_params(db, self.id) } /// The type of the enum variant bodies. pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + let interner = DbInterner::new_no_crate(db); Type::new_for_crate( self.id.lookup(db).container.krate(), - TyBuilder::builtin(match db.enum_signature(self.id).variant_body_type() { + match EnumSignature::variant_body_type(db, self.id) { layout::IntegerType::Pointer(sign) => match sign { - true => hir_def::builtin_type::BuiltinType::Int( - hir_def::builtin_type::BuiltinInt::Isize, - ), - false => hir_def::builtin_type::BuiltinType::Uint( - hir_def::builtin_type::BuiltinUint::Usize, - ), + true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize), + false => Ty::new_uint(interner, rustc_type_ir::UintTy::Usize), }, layout::IntegerType::Fixed(i, sign) => match sign { - true => hir_def::builtin_type::BuiltinType::Int(match i { - layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, - layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, - layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, - layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, - layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, - }), - false => hir_def::builtin_type::BuiltinType::Uint(match i { - layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, - layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, - layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, - layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, - layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, - }), + true => Ty::new_int( + interner, + match i { + layout::Integer::I8 => rustc_type_ir::IntTy::I8, + layout::Integer::I16 => rustc_type_ir::IntTy::I16, + layout::Integer::I32 => rustc_type_ir::IntTy::I32, + layout::Integer::I64 => rustc_type_ir::IntTy::I64, + layout::Integer::I128 => rustc_type_ir::IntTy::I128, + }, + ), + false => Ty::new_uint( + interner, + match i { + layout::Integer::I8 => rustc_type_ir::UintTy::U8, + layout::Integer::I16 => rustc_type_ir::UintTy::U16, + layout::Integer::I32 => rustc_type_ir::UintTy::U32, + layout::Integer::I64 => rustc_type_ir::UintTy::U64, + layout::Integer::I128 => rustc_type_ir::UintTy::U128, + }, + ), }, - }), + }, ) } @@ -1643,7 +1580,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) } } @@ -1663,10 +1600,9 @@ 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_ns(self.inner.id.into()); + let ty = db.ty(self.inner.id.into()); TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args)) } } @@ -1723,7 +1659,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()) } @@ -1744,7 +1680,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> { @@ -1805,26 +1741,18 @@ impl_from!(Struct, Union, Enum for Adt); impl Adt { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { - let subst = db.generic_defaults(self.into()); - (subst.is_empty() && db.generic_params(self.into()).len_type_or_consts() != 0) - || subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(it) => it.is_unknown(), - _ => false, - }) + has_non_default_type_params(db, self.into()) } 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); - db.layout_of_adt( - self.into(), - TyBuilder::adt(db, self.into()) - .fill_with_defaults(db, || TyKind::Error.intern(Interner)) - .build_into_subst() - .to_nextsolver(interner), - env, - ) - .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) + 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) + .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap())) } /// Turns this ADT into a type. Any type parameters of the ADT will be @@ -1843,17 +1771,12 @@ impl Adt { args: impl IntoIterator<Item = Type<'db>>, ) -> Type<'db> { let id = AdtId::from(self); - let mut it = args.into_iter().map(|t| t.ty); - let ty = TyBuilder::def_ty(db, id.into(), None) - .fill(|x| { - let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)); - match x { - ParamKind::Type => r.cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - } - }) - .build(); + let interner = DbInterner::new_no_crate(db); + let ty = Ty::new_adt( + interner, + id, + generic_args_from_tys(interner, id.into(), args.into_iter().map(|ty| ty.ty)), + ); Type::new(db, id, ty) } @@ -2032,7 +1955,7 @@ impl DefWithBody { expr_store_diagnostics(db, acc, &source_map); - let infer = db.infer(self.into()); + let infer = InferenceResult::for_body(db, self.into()); for d in infer.diagnostics() { acc.extend(AnyDiagnostic::inference_diagnostic( db, @@ -2063,8 +1986,8 @@ impl DefWithBody { acc.push( TypeMismatch { expr_or_pat, - expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()), - actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()), + expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected), + actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual), } .into(), ); @@ -2134,10 +2057,7 @@ impl DefWithBody { } mir::MirSpan::Unknown => continue, }; - acc.push( - MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.clone()), span } - .into(), - ) + acc.push(MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty), span }.into()) } let mol = &borrowck_result.mutability_of_locals; for (binding_id, binding_data) in body.bindings() { @@ -2245,8 +2165,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, } @@ -2287,18 +2206,24 @@ impl Function { pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner); + 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(self.id.into()).instantiate_identity(); + let ty = Ty::new_fn_ptr(interner, callable_sig); Type::new_with_resolver_inner(db, &resolver, ty) } + // 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); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ty = callable_sig.ret().clone(); + // 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) } @@ -2309,26 +2234,15 @@ impl Function { generics: impl Iterator<Item = Type<'db>>, ) -> Type<'db> { let resolver = self.id.resolver(db); - let parent_id: Option<GenericDefId> = match self.id.lookup(db).container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - }; - let mut generics = generics.map(|it| it.ty); - let mut filler = |x: &_| match x { - ParamKind::Type => { - generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }; + let interner = DbInterner::new_no_crate(db); + let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty)); - let parent_substs = - parent_id.map(|id| TyBuilder::subst_for_def(db, id, None).fill(&mut filler).build()); - let substs = TyBuilder::subst_for_def(db, self.id, parent_substs).fill(&mut filler).build(); - - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ty = callable_sig.ret().clone(); + let interner = DbInterner::new_no_crate(db); + let ty = db + .callable_item_signature(self.id.into()) + .instantiate(interner, args) + .skip_binder() + .output(); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -2337,12 +2251,17 @@ impl Function { return None; } let resolver = self.id.resolver(db); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); - let ret_ty = callable_sig.ret().clone(); + // 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(); for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { - if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 { - return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into(); + if let ClauseKind::Projection(projection) = pred.kind().skip_binder() + && let Some(output_ty) = projection.term.as_type() + { + return Type::new_with_resolver_inner(db, &resolver, output_ty).into(); } } None @@ -2358,18 +2277,15 @@ impl Function { pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> { let environment = db.trait_environment(self.id.into()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + // 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 - .params() + .inputs() .iter() .enumerate() .map(|(idx, ty)| { - let ty = Type { - env: environment.clone(), - ty: ty.clone(), - _pd: PhantomCovariantLifetime::new(), - }; + let ty = Type { env: environment.clone(), ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2386,20 +2302,17 @@ impl Function { pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> { let environment = db.trait_environment(self.id.into()); - let substs = TyBuilder::placeholder_subst(db, self.id); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + // 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 - .params() + .inputs() .iter() .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { - env: environment.clone(), - ty: ty.clone(), - _pd: PhantomCovariantLifetime::new(), - }; + let ty = Type { env: environment.clone(), ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2412,44 +2325,18 @@ impl Function { generics: impl Iterator<Item = Type<'db>>, ) -> Vec<Param<'db>> { let environment = db.trait_environment(self.id.into()); - let parent_id: Option<GenericDefId> = match self.id.lookup(db).container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - }; - let mut generics = generics.map(|it| it.ty); - let parent_substs = parent_id.map(|id| { - TyBuilder::subst_for_def(db, id, None) - .fill(|x| match x { - ParamKind::Type => generics - .next() - .unwrap_or_else(|| TyKind::Error.intern(Interner)) - .cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }) - .build() - }); - - let substs = TyBuilder::subst_for_def(db, self.id, parent_substs) - .fill(|_| { - let ty = generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)); - GenericArg::new(Interner, GenericArgData::Ty(ty)) - }) - .build(); - let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let interner = DbInterner::new_no_crate(db); + 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 - .params() + .inputs() .iter() .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { - env: environment.clone(), - ty: ty.clone(), - _pd: PhantomCovariantLifetime::new(), - }; + let ty = Type { env: environment.clone(), ty }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2481,11 +2368,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; }; @@ -2503,33 +2390,33 @@ 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).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.exported_main(db) || self.module(db).is_crate_root() && db.function_signature(self.id).name == sym::main } /// 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) + AttrFlags::query(db, self.id.into()).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() + AttrFlags::query(db, self.id.into()).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() + AttrFlags::query(db, self.id.into()).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() + AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } pub fn is_unsafe_to_call( @@ -2540,8 +2427,7 @@ impl Function { ) -> bool { 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 = hir_ty::TargetFeatures::from_fn(db, caller.id); 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), @@ -2572,14 +2458,6 @@ impl Function { } 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()) - { - 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() }) } @@ -2588,10 +2466,11 @@ impl Function { self, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, - ) -> Result<String, ConstEvalError> { + ) -> Result<String, ConstEvalError<'_>> { + let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( self.id.into(), - Substitution::empty(Interner), + GenericArgs::new_from_iter(interner, []), db.trait_environment(self.id.into()), )?; let (result, output) = interpret_mir(db, body, false, None)?; @@ -2630,18 +2509,18 @@ pub enum Access { Owned, } -impl From<hir_ty::Mutability> for Access { - fn from(mutability: hir_ty::Mutability) -> Access { +impl From<hir_ty::next_solver::Mutability> for Access { + fn from(mutability: hir_ty::next_solver::Mutability) -> Access { match mutability { - hir_ty::Mutability::Not => Access::Shared, - hir_ty::Mutability::Mut => Access::Exclusive, + hir_ty::next_solver::Mutability::Not => Access::Shared, + hir_ty::next_solver::Mutability::Mut => Access::Exclusive, } } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Param<'db> { - func: Callee, + func: Callee<'db>, /// The index in parameter list, including self parameter. idx: usize, ty: Type<'db>, @@ -2687,7 +2566,7 @@ impl<'db> Param<'db> { } } Callee::Closure(closure, _) => { - let c = db.lookup_intern_closure(closure.into()); + let c = db.lookup_intern_closure(closure); let body = db.body(c.0); if let Expr::Closure { args, .. } = &body[c.1] && let Pat::Bind { id, .. } = &body[args[self.idx]] @@ -2731,12 +2610,12 @@ impl SelfParam { } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - let substs = TyBuilder::placeholder_subst(db, self.func); + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let callable_sig = - db.callable_item_signature(self.func.into()).substitute(Interner, &substs); + db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder(); let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + let ty = callable_sig.inputs().as_slice()[0]; + Type { env: environment, ty } } // FIXME: Find better API to also handle const generics @@ -2745,31 +2624,13 @@ impl SelfParam { db: &'db dyn HirDatabase, generics: impl Iterator<Item = Type<'db>>, ) -> Type<'db> { - let parent_id: GenericDefId = match self.func.lookup(db).container { - ItemContainerId::ImplId(it) => it.into(), - ItemContainerId::TraitId(it) => it.into(), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { - panic!("Never get here") - } - }; - - let mut generics = generics.map(|it| it.ty); - let mut filler = |x: &_| match x { - ParamKind::Type => { - generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - }; - - let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build(); - let substs = - TyBuilder::subst_for_def(db, self.func, Some(parent_substs)).fill(&mut filler).build(); + let interner = DbInterner::new_no_crate(db); + 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()).substitute(Interner, &substs); + db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder(); let environment = db.trait_environment(self.func.into()); - let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + let ty = callable_sig.inputs().as_slice()[0]; + Type { env: environment, ty } } } @@ -2862,9 +2723,11 @@ impl Const { } /// Evaluate the constant. - pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst, ConstEvalError> { - db.const_eval(self.id.into(), Substitution::empty(Interner), None) - .map(|it| EvaluatedConst { const_: it, def: self.id.into() }) + 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, GenericArgs::new_from_iter(interner, []), None) + .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty }) } } @@ -2874,27 +2737,28 @@ impl HasVisibility for Const { } } -pub struct EvaluatedConst { +pub struct EvaluatedConst<'db> { def: DefWithBodyId, - const_: hir_ty::Const, + const_: hir_ty::next_solver::Const<'db>, + ty: Ty<'db>, } -impl EvaluatedConst { +impl<'db> EvaluatedConst<'db> { pub fn render(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { format!("{}", self.const_.display(db, display_target)) } - pub fn render_debug(&self, db: &dyn HirDatabase) -> Result<String, MirEvalError> { - let data = self.const_.data(Interner); - if let TyKind::Scalar(s) = data.ty.kind(Interner) - && matches!(s, Scalar::Int(_) | Scalar::Uint(_)) - && let hir_ty::ConstValue::Concrete(c) = &data.value - && let hir_ty::ConstScalar::Bytes(b, _) = &c.interned + pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result<String, MirEvalError<'db>> { + let kind = self.const_.kind(); + if let ConstKind::Value(c) = kind + && let ty = c.ty.kind() + && let TyKind::Int(_) | TyKind::Uint(_) = ty { + let b = &c.value.inner().memory; let value = u128::from_le_bytes(mir::pad16(b, false)); - let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); + let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(ty, TyKind::Int(_)))); let mut result = - if let Scalar::Int(_) = s { value_signed.to_string() } else { value.to_string() }; + if let TyKind::Int(_) = ty { value_signed.to_string() } else { value.to_string() }; if value >= 10 { format_to!(result, " ({value:#X})"); return Ok(result); @@ -2902,7 +2766,7 @@ impl EvaluatedConst { return Ok(result); } } - mir::render_const_using_debug_impl(db, self.def, &self.const_) + mir::render_const_using_debug_impl(db, self.def, self.const_, self.ty) } } @@ -2940,9 +2804,13 @@ impl Static { } /// Evaluate the static initializer. - pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst, ConstEvalError> { - db.const_eval(self.id.into(), Substitution::empty(Interner), None) - .map(|it| EvaluatedConst { const_: it, def: self.id.into() }) + pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError<'_>> { + let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity(); + db.const_eval_static(self.id).map(|it| EvaluatedConst { + const_: it, + def: self.id.into(), + ty, + }) } } @@ -2960,8 +2828,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 { @@ -3044,7 +2916,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) } } @@ -3063,12 +2935,7 @@ pub struct TypeAlias { impl TypeAlias { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { - let subst = db.generic_defaults(self.id.into()); - (subst.is_empty() && db.generic_params(self.id.into()).len_type_or_consts() != 0) - || subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(it) => it.is_unknown(), - _ => false, - }) + has_non_default_type_params(db, self.id.into()) } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -3079,8 +2946,8 @@ impl TypeAlias { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { - Type::from_def_placeholders(db, self.id) + pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { + Type::from_def_params(db, self.id) } pub fn name(self, db: &dyn HirDatabase) -> Name { @@ -3133,7 +3000,8 @@ 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]); - Type::new_for_crate(core, TyBuilder::builtin(self.inner)) + let interner = DbInterner::new_no_crate(db); + Type::new_for_crate(core, Ty::from_builtin_type(interner, self.inner)) } pub fn name(self) -> Name { @@ -3219,10 +3087,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()), } } @@ -3230,7 +3098,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 { @@ -3240,7 +3108,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 } @@ -3248,7 +3116,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 } @@ -3419,6 +3287,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(Function { id }), + method_resolution::CandidateId::ConstId(id) => AssocItem::Const(Const { id }), + } + } +} + #[derive(Debug, Clone)] pub enum AssocItemContainer { Trait(Trait), @@ -3770,7 +3647,7 @@ impl GenericDef { push_ty_diagnostics( db, acc, - db.generic_predicates_without_parent_with_diagnostics_ns(def).1, + GenericPredicates::query_with_diagnostics(db, def).1.clone(), &source_map, ); for (param_id, param) in generics.iter_type_or_consts() { @@ -3809,14 +3686,13 @@ impl GenericDef { #[derive(Debug)] pub struct GenericSubstitution<'db> { def: GenericDefId, - subst: Substitution, - env: Arc<TraitEnvironment>, - _pd: PhantomCovariantLifetime<'db>, + subst: GenericArgs<'db>, + env: Arc<TraitEnvironment<'db>>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self { - Self { def, subst, env, _pd: PhantomCovariantLifetime::new() } + fn new(def: GenericDefId, subst: GenericArgs<'db>, env: Arc<TraitEnvironment<'db>>) -> Self { + Self { def, subst, env } } pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { @@ -3846,26 +3722,23 @@ impl<'db> GenericSubstitution<'db> { TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()), TypeOrConstParamData::ConstParamData(_) => None, }); - let parent_len = self.subst.len(Interner) + let parent_len = self.subst.len() - generics .iter_type_or_consts() .filter(|g| matches!(g.1, TypeOrConstParamData::TypeParamData(..))) .count(); - let container_params = self.subst.as_slice(Interner)[..parent_len] + let container_params = self.subst.as_slice()[..parent_len] .iter() - .filter_map(|param| param.ty(Interner).cloned()) + .filter_map(|param| param.ty()) .zip(container_type_params.into_iter().flatten()); - let self_params = self.subst.as_slice(Interner)[parent_len..] + let self_params = self.subst.as_slice()[parent_len..] .iter() - .filter_map(|param| param.ty(Interner).cloned()) + .filter_map(|param| param.ty()) .zip(type_params); container_params .chain(self_params) .filter_map(|(ty, name)| { - Some(( - name?.symbol().clone(), - Type { ty, env: self.env.clone(), _pd: PhantomCovariantLifetime::new() }, - )) + Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) }) .collect() } @@ -3970,8 +3843,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].clone(); + let infer = InferenceResult::for_body(db, def); + let ty = infer[self.binding_id]; Type::new(db, def, ty) } @@ -4058,18 +3931,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) } } @@ -4188,7 +4053,39 @@ impl GenericParam { GenericParam::ConstParam(_) => return None, GenericParam::LifetimeParam(it) => generics.lifetime_idx(it.id)?, }; - db.variances_of(parent)?.get(index).copied() + db.variances_of(parent).get(index).map(Into::into) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Variance { + Bivariant, + Covariant, + Contravariant, + Invariant, +} + +impl From<rustc_type_ir::Variance> for Variance { + #[inline] + fn from(value: rustc_type_ir::Variance) -> Self { + match value { + rustc_type_ir::Variance::Covariant => Variance::Covariant, + rustc_type_ir::Variance::Invariant => Variance::Invariant, + rustc_type_ir::Variance::Contravariant => Variance::Contravariant, + rustc_type_ir::Variance::Bivariant => Variance::Bivariant, + } + } +} + +impl fmt::Display for Variance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let description = match self { + Variance::Bivariant => "bivariant", + Variance::Covariant => "covariant", + Variance::Contravariant => "contravariant", + Variance::Invariant => "invariant", + }; + f.pad(description) } } @@ -4227,8 +4124,9 @@ impl TypeParam { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.parent().resolver(db); - let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(db, self.id.into())) - .intern(Interner); + 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) } @@ -4236,10 +4134,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_ns(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() @@ -4248,16 +4149,16 @@ 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.data(Interner) { - GenericArgData::Ty(it) if *it.kind(Interner) != TyKind::Error => { - Some(Type::new_with_resolver_inner(db, &resolver, it.clone())) + match ty { + GenericArg::Ty(it) if !it.is_ty_error() => { + Some(Type::new_with_resolver_inner(db, &resolver, it)) } _ => None, } } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.attrs(GenericParamId::from(self.id).into()).is_unstable() + self.attrs(db).is_unstable() } } @@ -4311,7 +4212,7 @@ impl ConstParam { } pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { - Type::new(db, self.id.parent(), db.const_param_ty(self.id)) + Type::new(db, self.id.parent(), db.const_param_ty_ns(self.id)) } pub fn default( @@ -4320,17 +4221,16 @@ impl ConstParam { display_target: DisplayTarget, ) -> Option<ast::ConstArg> { let arg = generic_arg_from_param(db, self.id.into())?; - known_const_to_ast(arg.constant(Interner)?, db, display_target) + known_const_to_ast(arg.konst()?, db, display_target) } } -fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg> { +fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg<'_>> { let local_idx = hir_ty::param_idx(db, id)?; let defaults = db.generic_defaults(id.parent); - let ty = defaults.get(local_idx)?.clone(); - let full_subst = TyBuilder::placeholder_subst(db, id.parent); - let subst = &full_subst.as_slice(Interner)[..local_idx]; - Some(ty.substitute(Interner, &subst)) + let ty = defaults.get(local_idx)?; + // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. + Some(ty.instantiate_identity()) } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -4402,114 +4302,104 @@ pub struct Impl { 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); + let mut result = Vec::new(); + extend_with_def_map(db, crate_def_map(db, krate.id), &mut result); + return result; - inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() + 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)); + + 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() } + /// **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, _pd: _ }: Type<'db>, + 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 fp = TyFingerprint::for_inherent_impl(&ty); - let fp = match fp { - Some(fp) => fp, - None => return Vec::new(), + 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 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), - ) - }); - - 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), + let mut extend_with_impls = + |impls: &[ImplId]| result.extend(impls.iter().copied().map(Impl::from)); + extend_with_impls(method_resolution::incoherent_inherent_impls(db, simplified_ty)); + if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) { + InherentImpls::for_each_crate_and_block( + db, + module.krate(), + module.containing_block(), + &mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)), ); - } - - if let Some(block) = ty.adt_id(Interner).and_then(|def| def.0.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.containing_block(), |block| { + block.loc(db).module.containing_block() + }) + .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| all.extend(impls.iter().copied().map(Impl::from))); + }; + for krate in module.krate().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.containing_block() + && 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_ns(self.id)?; + let trait_ref = db.impl_trait(self.id)?; let id = trait_ref.skip_binder().def_id; Some(Trait { id: id.0 }) } pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> { - let trait_ref = db.impl_trait_ns(self.id)?.instantiate_identity(); + 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)) } pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); - let substs = TyBuilder::placeholder_subst(db, self.id); - let ty = db.impl_self_ty(self.id).substitute(Interner, &substs); + // 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) } @@ -4569,9 +4459,8 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - env: Arc<TraitEnvironment>, + env: Arc<TraitEnvironment<'db>>, trait_ref: hir_ty::next_solver::TraitRef<'db>, - _pd: PhantomCovariantLifetime<'db>, } impl<'db> TraitRef<'db> { @@ -4583,7 +4472,7 @@ impl<'db> TraitRef<'db> { let env = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - TraitRef { env, trait_ref, _pd: PhantomCovariantLifetime::new() } + TraitRef { env, trait_ref } } pub fn trait_(&self) -> Trait { @@ -4592,94 +4481,181 @@ impl<'db> TraitRef<'db> { pub fn self_ty(&self) -> TypeNs<'_> { let ty = self.trait_ref.self_ty(); - TypeNs { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } + TypeNs { env: self.env.clone(), ty } } /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the /// first argument is the `Self` type. pub fn get_type_argument(&self, idx: usize) -> Option<TypeNs<'db>> { - self.trait_ref.args.as_slice().get(idx).and_then(|arg| arg.ty()).map(|ty| TypeNs { - env: self.env.clone(), - ty, - _pd: PhantomCovariantLifetime::new(), - }) + self.trait_ref + .args + .as_slice() + .get(idx) + .and_then(|arg| arg.ty()) + .map(|ty| TypeNs { env: self.env.clone(), ty }) } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Closure { - id: ClosureId, - subst: Substitution, +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +enum AnyClosureId { + ClosureId(InternedClosureId), + CoroutineClosureId(InternedCoroutineId), } -impl From<Closure> for ClosureId { - fn from(value: Closure) -> Self { - value.id - } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Closure<'db> { + id: AnyClosureId, + subst: GenericArgs<'db>, } -impl Closure { - fn as_ty(self) -> Ty { - TyKind::Closure(self.id, self.subst).intern(Interner) +impl<'db> Closure<'db> { + fn as_ty(&self, db: &'db dyn HirDatabase) -> Ty<'db> { + let interner = DbInterner::new_no_crate(db); + match self.id { + AnyClosureId::ClosureId(id) => Ty::new_closure(interner, id.into(), self.subst), + AnyClosureId::CoroutineClosureId(id) => { + Ty::new_coroutine_closure(interner, id.into(), self.subst) + } + } } pub fn display_with_id(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - self.clone() - .as_ty() + self.as_ty(db) .display(db, display_target) .with_closure_style(ClosureStyle::ClosureWithId) .to_string() } pub fn display_with_impl(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - self.clone() - .as_ty() + self.as_ty(db) .display(db, display_target) .with_closure_style(ClosureStyle::ImplFn) .to_string() } - pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec<ClosureCapture> { - let owner = db.lookup_intern_closure((self.id).into()).0; - let infer = &db.infer(owner); - let info = infer.closure_info(&self.id); + pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec<ClosureCapture<'db>> { + let AnyClosureId::ClosureId(id) = self.id else { + // FIXME: Infer coroutine closures' captures. + return Vec::new(); + }; + let owner = db.lookup_intern_closure(id).0; + let infer = InferenceResult::for_body(db, owner); + let info = infer.closure_info(id); info.0 .iter() .cloned() - .map(|capture| ClosureCapture { owner, closure: self.id, capture }) + .map(|capture| ClosureCapture { owner, closure: id, capture }) .collect() } - pub fn capture_types<'db>(&self, db: &'db dyn HirDatabase) -> Vec<Type<'db>> { - let owner = db.lookup_intern_closure((self.id).into()).0; - let infer = &db.infer(owner); - let (captures, _) = infer.closure_info(&self.id); + pub fn capture_types(&self, db: &'db dyn HirDatabase) -> Vec<Type<'db>> { + let AnyClosureId::ClosureId(id) = self.id else { + // FIXME: Infer coroutine closures' captures. + return Vec::new(); + }; + let owner = db.lookup_intern_closure(id).0; + 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: db.trait_environment_for_body(owner), - ty: capture.ty(db, &self.subst), - _pd: PhantomCovariantLifetime::new(), - }) + .map(|capture| Type { env: env.clone(), ty: capture.ty(db, self.subst) }) .collect() } pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { - let owner = db.lookup_intern_closure((self.id).into()).0; - let infer = &db.infer(owner); - let info = infer.closure_info(&self.id); - info.1 + match self.id { + AnyClosureId::ClosureId(id) => { + let owner = db.lookup_intern_closure(id).0; + let infer = InferenceResult::for_body(db, owner); + let info = infer.closure_info(id); + info.1.into() + } + AnyClosureId::CoroutineClosureId(_id) => { + // FIXME: Infer kind for coroutine closures. + match self.subst.as_coroutine_closure().kind() { + rustc_type_ir::ClosureKind::Fn => FnTrait::AsyncFn, + rustc_type_ir::ClosureKind::FnMut => FnTrait::AsyncFnMut, + rustc_type_ir::ClosureKind::FnOnce => FnTrait::AsyncFnOnce, + } + } + } + } +} + +#[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 { +pub struct ClosureCapture<'db> { owner: DefWithBodyId, - closure: ClosureId, - capture: hir_ty::CapturedItem, + closure: InternedClosureId, + capture: hir_ty::CapturedItem<'db>, } -impl ClosureCapture { +impl<'db> ClosureCapture<'db> { pub fn local(&self) -> Local { Local { parent: self.owner, binding_id: self.capture.local() } } @@ -4792,16 +4768,15 @@ impl CaptureUsageSource { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Type<'db> { - env: Arc<TraitEnvironment>, - ty: Ty, - _pd: PhantomCovariantLifetime<'db>, + env: Arc<TraitEnvironment<'db>>, + ty: Ty<'db>, } impl<'db> Type<'db> { pub(crate) fn new_with_resolver( db: &'db dyn HirDatabase, resolver: &Resolver<'_>, - ty: Ty, + ty: Ty<'db>, ) -> Self { Type::new_with_resolver_inner(db, resolver, ty) } @@ -4809,281 +4784,269 @@ impl<'db> Type<'db> { pub(crate) fn new_with_resolver_inner( db: &'db dyn HirDatabase, resolver: &Resolver<'_>, - ty: Ty, + ty: Ty<'db>, ) -> Self { let environment = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + Type { env: environment, ty } } - pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Self { - Type { env: TraitEnvironment::empty(krate), ty, _pd: PhantomCovariantLifetime::new() } + pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty<'db>) -> Self { + Type { env: TraitEnvironment::empty(krate), ty } } - fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Self { + 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)); - Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + Type { env: environment, ty } } fn from_def(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self { + let interner = DbInterner::new_no_crate(db); let ty = db.ty(def.into()); - let substs = TyBuilder::unknown_subst( - db, - match def.into() { - TyDefId::AdtId(it) => GenericDefId::AdtId(it), - TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), - TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), - }, - ); - Type::new(db, def, ty.substitute(Interner, &substs)) + let def = match def.into() { + TyDefId::AdtId(it) => GenericDefId::AdtId(it), + TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), + TyDefId::BuiltinType(_) => { + return Type::new(db, def, ty.skip_binder()); + } + }; + let args = GenericArgs::error_for_item(interner, def.into()); + Type::new(db, def, ty.instantiate(interner, args)) } - fn from_def_placeholders( - db: &'db dyn HirDatabase, - def: impl Into<TyDefId> + HasResolver, - ) -> Self { + // FIXME: We shouldn't leak `TyKind::Param`s. + fn from_def_params(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self { let ty = db.ty(def.into()); - let substs = TyBuilder::placeholder_subst( - db, - match def.into() { - TyDefId::AdtId(it) => GenericDefId::AdtId(it), - TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), - TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), - }, - ); - Type::new(db, def, ty.substitute(Interner, &substs)) + Type::new(db, def, ty.instantiate_identity()) } fn from_value_def( db: &'db dyn HirDatabase, def: impl Into<ValueTyDefId> + HasResolver, ) -> Self { + let interner = DbInterner::new_no_crate(db); let Some(ty) = db.value_ty(def.into()) else { - return Type::new(db, def, TyKind::Error.intern(Interner)); + return Type::new(db, def, Ty::new_error(interner, ErrorGuaranteed)); }; - let substs = TyBuilder::unknown_subst( - db, - match def.into() { - ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), - ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), - ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), - ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), - ValueTyDefId::EnumVariantId(it) => { - GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) - } - ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()), - }, - ); - Type::new(db, def, ty.substitute(Interner, &substs)) + let def = match def.into() { + ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), + ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), + ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), + ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), + ValueTyDefId::EnumVariantId(it) => { + GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) + } + ValueTyDefId::StaticId(_) => { + return Type::new(db, def, ty.skip_binder()); + } + }; + let args = GenericArgs::error_for_item(interner, def.into()); + Type::new(db, def, ty.instantiate(interner, args)) } pub fn new_slice(ty: Self) -> Self { - Type { env: ty.env, ty: TyBuilder::slice(ty.ty), _pd: PhantomCovariantLifetime::new() } + let interner = DbInterner::conjure(); + Type { env: ty.env, ty: Ty::new_slice(interner, ty.ty) } } pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self { - let tys = tys.iter().map(|it| it.ty.clone()); - Type { - env: TraitEnvironment::empty(krate), - ty: TyBuilder::tuple_with(tys), - _pd: PhantomCovariantLifetime::new(), - } + 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) } } pub fn is_unit(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..)) + self.ty.is_unit() } pub fn is_bool(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool)) + matches!(self.ty.kind(), TyKind::Bool) } pub fn is_str(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Str) + matches!(self.ty.kind(), TyKind::Str) } pub fn is_never(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Never) + matches!(self.ty.kind(), TyKind::Never) } pub fn is_mutable_reference(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) + matches!(self.ty.kind(), TyKind::Ref(.., hir_ty::next_solver::Mutability::Mut)) } pub fn is_reference(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Ref(..)) + matches!(self.ty.kind(), TyKind::Ref(..)) } pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { - return go(db, &self.ty); + 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 { match adt_id { - hir_def::AdtId::StructId(s) => { + AdtId::StructId(s) => { let flags = db.struct_signature(s).flags; flags.contains(StructFlags::IS_PHANTOM_DATA) } - hir_def::AdtId::UnionId(_) => false, - hir_def::AdtId::EnumId(_) => false, + AdtId::UnionId(_) | AdtId::EnumId(_) => false, } } - fn go(db: &dyn HirDatabase, ty: &Ty) -> bool { - match ty.kind(Interner) { - // Reference itself - TyKind::Ref(_, _, _) => true, + struct Visitor<'db> { + interner: DbInterner<'db>, + } - // For non-phantom_data adts we check variants/fields as well as generic parameters - TyKind::Adt(adt_id, substitution) if !is_phantom_data(db, adt_id.0) => { - let _variant_id_to_fields = |id: VariantId| { - let variant_data = &id.fields(db); - if variant_data.fields().is_empty() { - vec![] - } else { - let field_types = db.field_types(id); - variant_data - .fields() - .iter() - .map(|(idx, _)| { - field_types[idx].clone().substitute(Interner, substitution) - }) - .filter(|it| !it.contains_unknown()) - .collect() - } - }; - let variant_id_to_fields = |_: VariantId| vec![]; + impl<'db> TypeVisitor<DbInterner<'db>> for Visitor<'db> { + type Result = ControlFlow<()>; - let variants = match adt_id.0 { - hir_def::AdtId::StructId(id) => { - vec![variant_id_to_fields(id.into())] - } - hir_def::AdtId::EnumId(id) => id - .enum_variants(db) - .variants - .iter() - .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) - .collect(), - hir_def::AdtId::UnionId(id) => { - vec![variant_id_to_fields(id.into())] - } - }; + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + match ty.kind() { + // Reference itself + TyKind::Ref(..) => ControlFlow::Break(()), - variants - .into_iter() - .flat_map(|variant| variant.into_iter()) - .any(|ty| go(db, &ty)) - || substitution - .iter(Interner) - .filter_map(|x| x.ty(Interner)) - .any(|ty| go(db, ty)) - } - // And for `PhantomData<T>`, we check `T`. - TyKind::Adt(_, substitution) - | TyKind::Tuple(_, substitution) - | TyKind::OpaqueType(_, substitution) - | TyKind::AssociatedType(_, substitution) - | TyKind::Alias(AliasTy::Projection(ProjectionTy { substitution, .. })) - | TyKind::FnDef(_, substitution) => { - substitution.iter(Interner).filter_map(|x| x.ty(Interner)).any(|ty| go(db, ty)) - } + // For non-phantom_data adts we check variants/fields as well as generic parameters + TyKind::Adt(adt_def, args) + if !is_phantom_data(self.interner.db(), adt_def.def_id().0) => + { + let _variant_id_to_fields = |id: VariantId| { + let variant_data = &id.fields(self.interner.db()); + if variant_data.fields().is_empty() { + vec![] + } else { + let field_types = self.interner.db().field_types(id); + variant_data + .fields() + .iter() + .map(|(idx, _)| { + field_types[idx].instantiate(self.interner, args) + }) + .filter(|it| !it.references_non_lt_error()) + .collect() + } + }; + let variant_id_to_fields = |_: VariantId| vec![]; - // For `[T]` or `*T` we check `T` - TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, ty), + let variants: Vec<Vec<Ty<'db>>> = match adt_def.def_id().0 { + AdtId::StructId(id) => { + vec![variant_id_to_fields(id.into())] + } + AdtId::EnumId(id) => id + .enum_variants(self.interner.db()) + .variants + .iter() + .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) + .collect(), + AdtId::UnionId(id) => { + vec![variant_id_to_fields(id.into())] + } + }; - // Consider everything else as not reference - _ => false, + variants + .into_iter() + .flat_map(|variant| variant.into_iter()) + .try_for_each(|ty| ty.visit_with(self))?; + args.visit_with(self) + } + // And for `PhantomData<T>`, we check `T`. + _ => ty.super_visit_with(self), + } } } } pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> { - let (ty, _lt, m) = self.ty.as_reference()?; - let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut)); - Some((self.derived(ty.clone()), m)) + let TyKind::Ref(_lt, ty, m) = self.ty.kind() else { return None }; + let m = Mutability::from_mutable(matches!(m, hir_ty::next_solver::Mutability::Mut)); + Some((self.derived(ty), m)) } pub fn add_reference(&self, mutability: Mutability) -> Self { + let interner = DbInterner::conjure(); let ty_mutability = match mutability { - Mutability::Shared => hir_ty::Mutability::Not, - Mutability::Mut => hir_ty::Mutability::Mut, + Mutability::Shared => hir_ty::next_solver::Mutability::Not, + Mutability::Mut => hir_ty::next_solver::Mutability::Mut, }; - self.derived(TyKind::Ref(ty_mutability, error_lifetime(), self.ty.clone()).intern(Interner)) + self.derived(Ty::new_ref(interner, Region::error(interner), self.ty, ty_mutability)) } pub fn is_slice(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Slice(..)) + matches!(self.ty.kind(), TyKind::Slice(..)) } pub fn is_usize(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) + matches!(self.ty.kind(), TyKind::Uint(rustc_type_ir::UintTy::Usize)) } pub fn is_float(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) + matches!(self.ty.kind(), TyKind::Float(_)) } pub fn is_char(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Char)) + matches!(self.ty.kind(), TyKind::Char) } pub fn is_int_or_uint(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) + matches!(self.ty.kind(), TyKind::Int(_) | TyKind::Uint(_)) } pub fn is_scalar(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Scalar(_)) + matches!( + self.ty.kind(), + TyKind::Bool | TyKind::Char | TyKind::Int(_) | TyKind::Uint(_) | TyKind::Float(_) + ) } pub fn is_tuple(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Tuple(..)) + matches!(self.ty.kind(), TyKind::Tuple(..)) } pub fn remove_ref(&self) -> Option<Type<'db>> { - match &self.ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), + match self.ty.kind() { + TyKind::Ref(_, ty, _) => Some(self.derived(ty)), _ => None, } } pub fn as_slice(&self) -> Option<Type<'db>> { - match &self.ty.kind(Interner) { - TyKind::Slice(ty) => Some(self.derived(ty.clone())), + match self.ty.kind() { + TyKind::Slice(ty) => Some(self.derived(ty)), _ => None, } } pub fn strip_references(&self) -> Self { - self.derived(self.ty.strip_references().clone()) + self.derived(self.ty.strip_references()) } + // FIXME: This is the same as `remove_ref()`, remove one of these methods. pub fn strip_reference(&self) -> Self { - self.derived(self.ty.strip_reference().clone()) + self.derived(self.ty.strip_reference()) } pub fn is_unknown(&self) -> bool { - self.ty.is_unknown() + self.ty.is_ty_error() } /// Checks that particular type `ty` implements `std::future::IntoFuture` or /// `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)?; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) { + if !traits::implements_trait_unique(self.ty, db, self.env.clone(), trait_) { return None; } @@ -5094,13 +5057,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))?; @@ -5108,27 +5073,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; }; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, iterator_trait) + traits::implements_trait_unique(self.ty, db, self.env.clone(), 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) - }, - )?; - - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, 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.clone(), trait_) { return None; } @@ -5143,41 +5104,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, }; - let canonical_ty = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, fnonce_trait) + traits::implements_trait_unique(self.ty, db, self.env.clone(), 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 mut it = args.iter().map(|t| t.ty.clone()); - let trait_ref = TyBuilder::trait_ref(db, trait_.id) - .push(self.ty.clone()) - .fill(|x| { - match x { - ParamKind::Type => { - it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner) - } - ParamKind::Const(ty) => { - // FIXME: this code is not covered in tests. - unknown_const_as_generic(ty.clone()) - } - ParamKind::Lifetime => error_lifetime().cast(Interner), - } - }) - .build(); - - let goal = Canonical { - value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)), - binders: CanonicalVarKinds::empty(Interner), - }; - - !db.trait_solve(self.env.krate, self.env.block, goal).no_solution() + 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) } pub fn normalize_trait_assoc_type( @@ -5186,58 +5130,44 @@ impl<'db> Type<'db> { args: &[Type<'db>], alias: TypeAlias, ) -> Option<Type<'db>> { - let mut args = args.iter(); - let trait_id = match alias.id.lookup(db).container { - ItemContainerId::TraitId(id) => id, - _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"), - }; - let parent_subst = TyBuilder::subst_for_def(db, trait_id, None) - .push(self.ty.clone()) - .fill(|it| { - // FIXME: this code is not covered in tests. - match it { - ParamKind::Type => args.next().unwrap().ty.clone().cast(Interner), - ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()), - ParamKind::Lifetime => error_lifetime().cast(Interner), - } - }) - .build(); + let interner = DbInterner::new_with(db, self.env.krate); + let args = generic_args_from_tys( + interner, + alias.id.into(), + std::iter::once(self.ty).chain(args.iter().map(|ty| ty.ty)), + ); // FIXME: We don't handle GATs yet. - let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build(); + let projection = Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy::new(interner, alias.id.into(), args), + ); - let ty = db.normalize_projection(projection, self.env.clone()); - if ty.is_unknown() { None } else { Some(self.derived(ty)) } + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let ty = structurally_normalize_ty(&infcx, projection, self.env.clone()); + 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 callee = match self.ty.kind(Interner) { - TyKind::Closure(id, subst) => Callee::Closure(*id, subst.clone()), - TyKind::Function(_) => Callee::FnPtr, - TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?), - kind => { - // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment - let (ty, kind) = if let TyKind::Ref(_, _, ty) = kind { - (ty, ty.kind(Interner)) - } else { - (&self.ty, kind) - }; - if let TyKind::Closure(closure, subst) = kind { - let sig = ty.callable_sig(db)?; - return Some(Callable { - ty: self.clone(), - sig, - callee: Callee::Closure(*closure, subst.clone()), - is_bound_method: false, - }); - } - let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(ty, self.env.clone(), db)?; + 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), + TyKind::FnPtr(..) => Callee::FnPtr, + TyKind::FnDef(id, _) => Callee::Def(id.0), + // 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)?; return Some(Callable { ty: self.clone(), sig, @@ -5247,32 +5177,37 @@ impl<'db> Type<'db> { } }; - let sig = self.ty.callable_sig(db)?; + let sig = self.ty.callable_sig(interner)?; Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false }) } pub fn is_closure(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Closure { .. }) + matches!(self.ty.kind(), TyKind::Closure { .. }) } - pub fn as_closure(&self) -> Option<Closure> { - match self.ty.kind(Interner) { - TyKind::Closure(id, subst) => Some(Closure { id: *id, subst: subst.clone() }), + pub fn as_closure(&self) -> Option<Closure<'db>> { + match self.ty.kind() { + TyKind::Closure(id, subst) => { + Some(Closure { id: AnyClosureId::ClosureId(id.0), subst }) + } + TyKind::CoroutineClosure(id, subst) => { + Some(Closure { id: AnyClosureId::CoroutineClosureId(id.0), subst }) + } _ => None, } } pub fn is_fn(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. }) + matches!(self.ty.kind(), TyKind::FnDef(..) | TyKind::FnPtr { .. }) } pub fn is_array(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Array(..)) + matches!(self.ty.kind(), TyKind::Array(..)) } pub fn is_packed(&self, db: &'db dyn HirDatabase) -> bool { - let adt_id = match *self.ty.kind(Interner) { - TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, + let adt_id = match self.ty.kind() { + TyKind::Adt(adt_def, ..) => adt_def.def_id().0, _ => return false, }; @@ -5284,61 +5219,28 @@ impl<'db> Type<'db> { } pub fn is_raw_ptr(&self) -> bool { - matches!(self.ty.kind(Interner), TyKind::Raw(..)) + matches!(self.ty.kind(), TyKind::RawPtr(..)) } pub fn remove_raw_ptr(&self) -> Option<Type<'db>> { - if let TyKind::Raw(_, ty) = self.ty.kind(Interner) { - Some(self.derived(ty.clone())) - } else { - None - } + if let TyKind::RawPtr(ty, _) = self.ty.kind() { Some(self.derived(ty)) } else { None } } pub fn contains_unknown(&self) -> bool { - // FIXME: When we get rid of `ConstScalar::Unknown`, we can just look at precomputed - // `TypeFlags` in `TyData`. - return go(&self.ty); - - fn go(ty: &Ty) -> bool { - match ty.kind(Interner) { - TyKind::Error => true, - - TyKind::Adt(_, substs) - | TyKind::AssociatedType(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::OpaqueType(_, substs) - | TyKind::FnDef(_, substs) - | TyKind::Closure(_, substs) => { - substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go) - } - - TyKind::Array(_ty, len) if len.is_unknown() => true, - TyKind::Array(ty, _) - | TyKind::Slice(ty) - | TyKind::Raw(_, ty) - | TyKind::Ref(_, _, ty) => go(ty), - - TyKind::Scalar(_) - | TyKind::Str - | TyKind::Never - | TyKind::Placeholder(_) - | TyKind::BoundVar(_) - | TyKind::InferenceVar(_, _) - | TyKind::Dyn(_) - | TyKind::Function(_) - | TyKind::Alias(_) - | TyKind::Foreign(_) - | TyKind::Coroutine(..) - | TyKind::CoroutineWitness(..) => false, - } - } + self.ty.references_non_lt_error() } pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> { - let (variant_id, substs) = match self.ty.kind(Interner) { - TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs), - TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs), + 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 { + AdtId::StructId(id) => id.into(), + AdtId::UnionId(id) => id.into(), + AdtId::EnumId(_) => return Vec::new(), + }; + (id, substs) + } _ => return Vec::new(), }; @@ -5346,37 +5248,34 @@ impl<'db> Type<'db> { .iter() .map(|(local_id, ty)| { let def = Field { parent: variant_id.into(), id: local_id }; - let ty = ty.clone().substitute(Interner, substs); + let ty = ty.instantiate(interner, substs); (def, self.derived(ty)) }) .collect() } pub fn tuple_fields(&self, _db: &'db dyn HirDatabase) -> Vec<Self> { - if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) { - substs - .iter(Interner) - .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())) - .collect() + if let TyKind::Tuple(substs) = self.ty.kind() { + substs.iter().map(|ty| self.derived(ty)).collect() } else { Vec::new() } } pub fn as_array(&self, db: &'db dyn HirDatabase) -> Option<(Self, usize)> { - if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { - try_const_usize(db, len).map(|it| (self.derived(ty.clone()), it as usize)) + if let TyKind::Array(ty, len) = self.ty.kind() { + try_const_usize(db, len).map(|it| (self.derived(ty), it as usize)) } else { None } } - pub fn fingerprint_for_trait_impl(&self) -> Option<TyFingerprint> { - TyFingerprint::for_trait_impl(&self.ty) - } - - pub(crate) fn canonical(&self) -> Canonical<Ty> { - hir_ty::replace_errors_with_variables(&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 @@ -5388,9 +5287,10 @@ impl<'db> Type<'db> { self.autoderef_(db).map(move |ty| self.derived(ty)) } - fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Ty> { + fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Ty<'db>> { + 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(&self.ty); + let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); autoderef(db, self.env.clone(), canonical) } @@ -5399,11 +5299,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() }); @@ -5413,23 +5312,36 @@ impl<'db> Type<'db> { fn iterate_assoc_items_dyn( &self, db: &'db dyn HirDatabase, - krate: Crate, callback: &mut dyn FnMut(AssocItemId) -> bool, ) { - let def_crates = match method_resolution::def_crates(db, &self.ty, 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(&self.ty) { + 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; + }; + + handle_impls(method_resolution::incoherent_inherent_impls(db, simplified_type)); + + if let Some(module) = method_resolution::simplified_type_module(db, &simplified_type) { + InherentImpls::for_each_crate_and_block( + db, + module.krate(), + module.containing_block(), + &mut |impls| { + handle_impls(impls.for_self_ty(&simplified_type)); + }, + ); } } @@ -5452,15 +5364,13 @@ impl<'db> Type<'db> { /// - "U" /// ``` pub fn type_arguments(&self) -> impl Iterator<Item = Type<'db>> + '_ { - self.ty - .strip_references() - .as_adt() - .map(|(_, substs)| substs) - .or_else(|| self.ty.strip_references().as_tuple()) - .into_iter() - .flat_map(|substs| substs.iter(Interner)) - .filter_map(|arg| arg.ty(Interner).cloned()) - .map(move |ty| self.derived(ty)) + match self.ty.strip_references().kind() { + TyKind::Adt(_, substs) => Either::Left(substs.types().map(move |ty| self.derived(ty))), + TyKind::Tuple(substs) => { + Either::Right(Either::Left(substs.iter().map(move |ty| self.derived(ty)))) + } + _ => Either::Right(Either::Right(std::iter::empty())), + } } /// Iterates its type and const arguments @@ -5490,15 +5400,13 @@ impl<'db> Type<'db> { .strip_references() .as_adt() .into_iter() - .flat_map(|(_, substs)| substs.iter(Interner)) - .filter_map(move |arg| { - // arg can be either a `Ty` or `constant` - if let Some(ty) = arg.ty(Interner) { - Some(format_smolstr!("{}", ty.display(db, display_target))) - } else { - arg.constant(Interner) - .map(|const_| format_smolstr!("{}", const_.display(db, display_target))) + .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_) => { + Some(format_smolstr!("{}", const_.display(db, display_target))) } + GenericArg::Lifetime(_) => None, }) } @@ -5524,26 +5432,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 } @@ -5551,7 +5453,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> { @@ -5559,12 +5460,37 @@ 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()); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let unstable_features = + MethodResolutionUnstableFeatures::from_def_map(resolver.top_level_def_map()); + let environment = resolver + .generic_def() + .map_or_else(|| TraitEnvironment::empty(module.krate()), |d| db.trait_environment(d)); + let ctx = MethodResolutionContext { + infcx: &infcx, + resolver, + env: &environment, + 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 @@ -5574,70 +5500,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(); - // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(&self.ty); - - let krate = scope.krate(); - let environment = scope - .resolver() - .generic_def() - .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); - _ = method_resolution::iterate_method_candidates_dyn( - &canonical.to_nextsolver(DbInterner::new_with( - db, - Some(environment.krate), - environment.block, - )), - db, - environment, - traits_in_scope, - with_local_impls.and_then(|b| b.id.containing_block()).into(), - name, - method_resolution::LookupMode::MethodCall, - &mut Callback(callback), - ); + 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); + + 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 }; + 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 }; + 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))] @@ -5646,27 +5579,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 } @@ -5681,53 +5608,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()) - } + let _p = tracing::info_span!( + "iterate_path_candidates_split_inherent", + traits_in_scope = traits_in_scope.len(), + ?name, + ) + .entered(); - fn on_trait_method( - &mut self, - _adjustments: method_resolution::ReceiverAdjustments, - item: AssocItemId, - _is_visible: bool, - ) -> ControlFlow<()> { - self.0.on_trait_item(item.into()) + 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); + + 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) + } + } + }, + ); + } } - } - - let canonical = hir_ty::replace_errors_with_variables(&self.ty); - - let krate = scope.krate(); - let environment = scope - .resolver() - .generic_def() - .map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d)); - - _ = method_resolution::iterate_path_candidates( - &canonical.to_nextsolver(DbInterner::new_with( - db, - Some(environment.krate), - environment.block, - )), - db, - environment, - traits_in_scope, - with_local_impls.and_then(|b| b.id.containing_block()).into(), - name, - &mut Callback(callback), - ); + }) } pub fn as_adt(&self) -> Option<Adt> { @@ -5759,7 +5701,7 @@ impl<'db> Type<'db> { pub fn env_traits(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Trait> { let _p = tracing::info_span!("env_traits").entered(); self.autoderef_(db) - .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) + .filter(|ty| matches!(ty.kind(), TyKind::Param(_))) .flat_map(|ty| { self.env .traits_in_scope_from_clauses(ty) @@ -5770,136 +5712,66 @@ impl<'db> Type<'db> { pub fn as_impl_traits(&self, db: &'db dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> { self.ty.impl_trait_bounds(db).map(|it| { - it.into_iter().filter_map(|pred| match pred.skip_binders() { - hir_ty::WhereClause::Implemented(trait_ref) => { - Some(Trait::from(trait_ref.hir_trait_id())) - } + it.into_iter().filter_map(|pred| match pred.kind().skip_binder() { + ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)), _ => None, }) }) } pub fn as_associated_type_parent_trait(&self, db: &'db dyn HirDatabase) -> Option<Trait> { - self.ty.associated_type_parent_trait(db).map(Into::into) + let TyKind::Alias(AliasTyKind::Projection, alias) = self.ty.kind() else { return None }; + match alias.def_id.expect_type_alias().loc(db).container { + ItemContainerId::TraitId(id) => Some(Trait { id }), + _ => None, + } } - fn derived(&self, ty: Ty) -> Self { - Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } + fn derived(&self, ty: Ty<'db>) -> Self { + Type { env: self.env.clone(), ty } } - /// Visits every type, including generic arguments, in this type. `cb` is called with type + /// Visits every type, including generic arguments, in this type. `callback` is called with type /// itself first, and then with its generic arguments. - pub fn walk(&self, db: &'db dyn HirDatabase, mut cb: impl FnMut(Type<'db>)) { - fn walk_substs<'db>( + pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { + struct Visitor<'db, F> { db: &'db dyn HirDatabase, - type_: &Type<'db>, - substs: &Substitution, - cb: &mut impl FnMut(Type<'db>), - ) { - for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) { - walk_type(db, &type_.derived(ty.clone()), cb); - } + env: Arc<TraitEnvironment<'db>>, + callback: F, + visited: FxHashSet<Ty<'db>>, } + impl<'db, F> TypeVisitor<DbInterner<'db>> for Visitor<'db, F> + where + F: FnMut(Type<'db>), + { + type Result = (); - fn walk_bounds<'db>( - db: &'db dyn HirDatabase, - type_: &Type<'db>, - bounds: &[QuantifiedWhereClause], - cb: &mut impl FnMut(Type<'db>), - ) { - for pred in bounds { - if let WhereClause::Implemented(trait_ref) = pred.skip_binders() { - cb(type_.clone()); - // skip the self type. it's likely the type we just got the bounds from - if let [self_ty, params @ ..] = trait_ref.substitution.as_slice(Interner) { - for ty in - params.iter().filter(|&ty| ty != self_ty).filter_map(|a| a.ty(Interner)) - { - walk_type(db, &type_.derived(ty.clone()), cb); - } - } - } - } - } - - fn walk_type<'db>( - db: &'db dyn HirDatabase, - type_: &Type<'db>, - cb: &mut impl FnMut(Type<'db>), - ) { - let ty = type_.ty.strip_references(); - match ty.kind(Interner) { - TyKind::Adt(_, substs) => { - cb(type_.derived(ty.clone())); - walk_substs(db, type_, substs, cb); - } - TyKind::AssociatedType(_, substs) - | TyKind::Alias(AliasTy::Projection(hir_ty::ProjectionTy { - substitution: substs, - .. - })) => { - if ty.associated_type_parent_trait(db).is_some() { - cb(type_.derived(ty.clone())); - } - walk_substs(db, type_, substs, cb); - } - TyKind::OpaqueType(_, subst) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - - walk_substs(db, type_, subst, cb); - } - TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - - walk_substs(db, type_, &opaque_ty.substitution, cb); - } - TyKind::Placeholder(_) => { - cb(type_.derived(ty.clone())); - if let Some(bounds) = ty.impl_trait_bounds(db) { - walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); - } - } - TyKind::Dyn(bounds) => { - walk_bounds( - db, - &type_.derived(ty.clone()), - bounds.bounds.skip_binders().interned(), - cb, - ); + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if !self.visited.insert(ty) { + return; } - TyKind::Ref(_, _, ty) - | TyKind::Raw(_, ty) - | TyKind::Array(ty, _) - | TyKind::Slice(ty) => { - walk_type(db, &type_.derived(ty.clone()), cb); - } + (self.callback)(Type { env: self.env.clone(), ty }); - TyKind::FnDef(_, substs) - | TyKind::Tuple(_, substs) - | TyKind::Closure(.., substs) => { - walk_substs(db, type_, substs, cb); - } - TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { - walk_substs(db, type_, &substitution.0, cb); + if let Some(bounds) = ty.impl_trait_bounds(self.db) { + bounds.visit_with(self); } - _ => {} + ty.super_visit_with(self); } } - walk_type(db, self, &mut cb); + let mut visitor = + Visitor { db, env: self.env.clone(), callback, visited: FxHashSet::default() }; + self.ty.visit_with(&mut visitor); } /// Check if type unifies with another type. /// /// 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 tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); + 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) } @@ -5908,61 +5780,61 @@ 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 tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); + 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) } pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { - let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone())); + 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) } - pub fn as_type_param(&self, db: &'db dyn HirDatabase) -> Option<TypeParam> { - match self.ty.kind(Interner) { - TyKind::Placeholder(p) => Some(TypeParam { - id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p).0), - }), + pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option<TypeParam> { + match self.ty.kind() { + TyKind::Param(param) => Some(TypeParam { id: param.id }), _ => None, } } /// Returns unique `GenericParam`s contained in this type. pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet<GenericParam> { - hir_ty::collect_placeholders(&self.ty, db) + hir_ty::collect_params(&self.ty) .into_iter() .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() } pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> { - let interner = DbInterner::new_with(db, None, None); - db.layout_of_ty(self.ty.to_nextsolver(interner), self.env.clone()) + db.layout_of_ty(self.ty, self.env.clone()) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { - db.has_drop_glue(self.ty.clone(), self.env.clone()) + 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()) } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeNs<'db> { - env: Arc<TraitEnvironment>, - ty: hir_ty::next_solver::Ty<'db>, - _pd: PhantomCovariantLifetime<'db>, + env: Arc<TraitEnvironment<'db>>, + ty: Ty<'db>, } impl<'db> TypeNs<'db> { - fn new( - db: &'db dyn HirDatabase, - lexical_env: impl HasResolver, - ty: hir_ty::next_solver::Ty<'db>, - ) -> Self { + 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)); - TypeNs { env: environment, ty, _pd: PhantomCovariantLifetime::new() } + TypeNs { env: environment, ty } + } + + pub fn to_type(&self, _db: &'db dyn HirDatabase) -> Type<'db> { + Type { env: self.env.clone(), ty: self.ty } } // FIXME: Find better API that also handles const generics @@ -5988,6 +5860,10 @@ impl<'db> TypeNs<'db> { let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal); res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes)) } + + pub fn is_bool(&self) -> bool { + matches!(self.ty.kind(), rustc_type_ir::TyKind::Bool) + } } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] @@ -6014,42 +5890,46 @@ impl InlineAsmOperand { #[derive(Debug)] pub struct Callable<'db> { ty: Type<'db>, - sig: CallableSig, - callee: Callee, + sig: PolyFnSig<'db>, + callee: Callee<'db>, /// Whether this is a method that was called with method call syntax. is_bound_method: bool, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] -enum Callee { +enum Callee<'db> { Def(CallableDefId), - Closure(ClosureId, Substitution), + Closure(InternedClosureId, GenericArgs<'db>), + CoroutineClosure(InternedCoroutineId, GenericArgs<'db>), FnPtr, - FnImpl(FnTrait), + FnImpl(traits::FnTrait), } -pub enum CallableKind { +pub enum CallableKind<'db> { Function(Function), TupleStruct(Struct), TupleEnumVariant(Variant), - Closure(Closure), + Closure(Closure<'db>), FnPtr, FnImpl(FnTrait), } impl<'db> Callable<'db> { - pub fn kind(&self) -> CallableKind { + pub fn kind(&self) -> CallableKind<'db> { match self.callee { Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), Callee::Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), Callee::Def(CallableDefId::EnumVariantId(it)) => { CallableKind::TupleEnumVariant(it.into()) } - Callee::Closure(id, ref subst) => { - CallableKind::Closure(Closure { id, subst: subst.clone() }) + Callee::Closure(id, subst) => { + CallableKind::Closure(Closure { id: AnyClosureId::ClosureId(id), subst }) + } + Callee::CoroutineClosure(id, subst) => { + 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()), } } pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> { @@ -6058,25 +5938,31 @@ impl<'db> Callable<'db> { _ => return None, }; let func = Function { id: func }; - Some((func.self_param(db)?, self.ty.derived(self.sig.params()[0].clone()))) + Some(( + func.self_param(db)?, + self.ty.derived(self.sig.skip_binder().inputs_and_output.inputs()[0]), + )) } pub fn n_params(&self) -> usize { - self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } + self.sig.skip_binder().inputs_and_output.inputs().len() + - if self.is_bound_method { 1 } else { 0 } } pub fn params(&self) -> Vec<Param<'db>> { self.sig - .params() + .skip_binder() + .inputs_and_output + .inputs() .iter() .enumerate() .skip(if self.is_bound_method { 1 } else { 0 }) - .map(|(idx, ty)| (idx, self.ty.derived(ty.clone()))) + .map(|(idx, ty)| (idx, self.ty.derived(*ty))) .map(|(idx, ty)| Param { func: self.callee.clone(), idx, ty }) .collect() } pub fn return_type(&self) -> Type<'db> { - self.ty.derived(self.sig.ret().clone()) + self.ty.derived(self.sig.skip_binder().output()) } - pub fn sig(&self) -> &CallableSig { + pub fn sig(&self) -> impl Eq { &self.sig } @@ -6094,7 +5980,7 @@ impl Layout { } pub fn align(&self) -> u64 { - self.0.align.abi.bytes() + self.0.align.bytes() } pub fn niches(&self) -> Option<u128> { @@ -6628,5 +6514,37 @@ fn as_name_opt(name: Option<impl AsName>) -> Name { name.map_or_else(Name::missing, |name| name.as_name()) } +fn generic_args_from_tys<'db>( + interner: DbInterner<'db>, + def_id: SolverDefId, + args: impl IntoIterator<Item = Ty<'db>>, +) -> GenericArgs<'db> { + let mut args = args.into_iter(); + GenericArgs::for_item(interner, def_id, |_, id, _| { + if matches!(id, GenericParamId::TypeParamId(_)) + && let Some(arg) = args.next() + { + arg.into() + } else { + next_solver::GenericArg::error_from_id(interner, id) + } + }) +} + +fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool { + let params = db.generic_params(generic_def); + let defaults = db.generic_defaults(generic_def); + params + .iter_type_or_consts() + .filter(|(_, param)| matches!(param, TypeOrConstParamData::TypeParamData(_))) + .map(|(local_id, _)| TypeOrConstParamId { parent: generic_def, local_id }) + .any(|param| { + let Some(param) = hir_ty::param_idx(db, param) else { + return false; + }; + defaults.get(param).is_none() + }) +} + pub use hir_ty::next_solver; pub use hir_ty::setup_tracing; |