From 6916b0f8c20a29eb37e067cc0b49059b0f4fac5d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 1 May 2026 12:57:23 +0300 Subject: [PATCH 1/2] Make `trait_environment()` take `GenericDefId` and not `ExpressionStoreOwnedId` A `ParamEnv` is fundamentally associated with generic arguments and not with a body. It feels wrong to attach it to `ExpressionStoreOwnedId`. There is one exception: a defaulted trait method with RPITIT has a different ParamEnv inside its body than for its callers, since inside the body the RPITIT is interpreted as an RPIT equating the internal assoc type. We don't yet handle RPITIT, but even when we'll do I don't feel it's justifies treating *any* body as different. --- crates/hir-ty/src/consteval.rs | 27 ++++++++----------- crates/hir-ty/src/db.rs | 2 +- crates/hir-ty/src/diagnostics/expr.rs | 2 +- crates/hir-ty/src/display.rs | 8 ++---- crates/hir-ty/src/infer.rs | 2 +- crates/hir-ty/src/layout/tests.rs | 16 +++++------ crates/hir-ty/src/lib.rs | 2 +- crates/hir-ty/src/lower.rs | 7 +---- crates/hir-ty/src/mir/borrowck.rs | 2 +- crates/hir-ty/src/mir/eval.rs | 2 +- crates/hir-ty/src/mir/eval/tests.rs | 4 +-- crates/hir-ty/src/mir/lower.rs | 4 +-- crates/hir-ty/src/opaques.rs | 7 +++-- crates/hir-ty/src/specialization.rs | 9 ++----- crates/hir/src/lib.rs | 11 +++++--- crates/hir/src/source_analyzer.rs | 19 ++++++++----- .../rust-analyzer/src/cli/analysis_stats.rs | 2 +- 17 files changed, 56 insertions(+), 70 deletions(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index fb52813c52ff..2c43feeb3b1a 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -5,7 +5,7 @@ mod tests; use base_db::Crate; use hir_def::{ - ConstId, EnumVariantId, ExpressionStoreOwnerId, GenericDefId, HasModule, StaticId, + ConstId, EnumVariantId, ExpressionStoreOwnerId, HasModule, StaticId, attrs::AttrFlags, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{Expr, ExprId, Literal}, @@ -422,8 +422,11 @@ pub(crate) fn const_eval_discriminant_variant( let mir_body = db.monomorphized_mir_body( def.into(), GenericArgs::empty(interner).store(), - ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } - .store(), + ParamEnvAndCrate { + param_env: db.trait_environment(def.generic_def(db)), + krate: def.krate(db), + } + .store(), )?; let c = interpret_mir(db, mir_body, false, None)?.0?; let c = if is_signed { allocation_as_isize(c) } else { allocation_as_usize(c) as i128 }; @@ -459,12 +462,8 @@ pub(crate) fn const_eval<'db>( let body = db.monomorphized_mir_body( def.into(), subst, - ParamEnvAndCrate { - param_env: db - .trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(def))), - krate: def.krate(db), - } - .store(), + ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } + .store(), )?; let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; Ok(c.store()) @@ -503,7 +502,7 @@ pub(crate) fn anon_const_eval<'db>( def.into(), subst, ParamEnvAndCrate { - param_env: db.trait_environment(def.loc(db).owner), + param_env: db.trait_environment(def.loc(db).owner.generic_def(db)), krate: def.krate(db), } .store(), @@ -541,12 +540,8 @@ pub(crate) fn const_eval_static<'db>( let body = db.monomorphized_mir_body( def.into(), GenericArgs::empty(interner).store(), - ParamEnvAndCrate { - param_env: db - .trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(def))), - krate: def.krate(db), - } - .store(), + ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } + .store(), )?; let c = interpret_mir(db, body, false, None)?.0?; Ok(c.store()) diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index c24a5b943db0..511ab856107f 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -247,7 +247,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::trait_environment)] #[salsa::transparent] - fn trait_environment<'db>(&'db self, def: ExpressionStoreOwnerId) -> ParamEnv<'db>; + fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics)] #[salsa::transparent] diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 760ebd27e057..be4de11ceb36 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -83,7 +83,7 @@ impl<'db> BodyValidationDiagnostic<'db> { let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); let infer = InferenceResult::of(db, owner); let body = Body::of(db, owner); - let env = db.trait_environment(owner.into()); + let env = db.trait_environment(owner.generic_def(db)); let interner = DbInterner::new_with(db, owner.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into())); diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 0acf6e63d782..8edb178cd74f 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -968,9 +968,7 @@ fn render_const_scalar_inner<'db>( s.fields(f.db), f, field_types, - f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( - def, - ))), + f.db.trait_environment(def.into()), &layout, args, b, @@ -996,9 +994,7 @@ fn render_const_scalar_inner<'db>( var_id.fields(f.db), f, field_types, - f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( - def, - ))), + f.db.trait_environment(def.into()), var_layout, args, b, diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 86a4f613b318..c217afc1c49c 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -1318,7 +1318,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { resolver: Resolver<'db>, allow_using_generic_params: bool, ) -> Self { - let trait_env = db.trait_environment(store_owner); + let trait_env = db.trait_environment(generic_def); let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), store_owner); let types = crate::next_solver::default_types(db); InferenceContext { diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 482945f5f0aa..d66d5e1c9666 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -1,7 +1,7 @@ use base_db::target::TargetData; use either::Either; use hir_def::{ - DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, HasModule, + DefWithBodyId, HasModule, expr_store::Body, signatures::{ EnumSignature, FunctionSignature, StructSignature, TypeAliasSignature, UnionSignature, @@ -92,13 +92,10 @@ fn eval_goal( ), Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity().skip_norm_wip(), }; - let param_env = db.trait_environment( - match adt_or_type_alias_id { - Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), - Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), - } - .into(), - ); + let param_env = db.trait_environment(match adt_or_type_alias_id { + Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), + Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), + }); let krate = match adt_or_type_alias_id { Either::Left(it) => it.krate(&db), Either::Right(it) => it.krate(&db), @@ -145,8 +142,7 @@ fn eval_expr( .0; let infer = InferenceResult::of(&db, DefWithBodyId::from(function_id)); let goal_ty = infer.type_of_binding[b].clone(); - let param_env = - db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(function_id))); + let param_env = db.trait_environment(function_id.into()); let krate = function_id.krate(&db); db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate }.store()) }) diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 1900a41f7f17..f612bdc26697 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -385,7 +385,7 @@ pub fn associated_type_shorthand_candidates( let mut dedup_map = FxHashSet::default(); let param_ty = Ty::new_param(interner, param, type_or_const_param_idx(db, param.into())); // We use the ParamEnv and not the predicates because the ParamEnv elaborates bounds. - let param_env = db.trait_environment(ExpressionStoreOwnerId::from(def)); + let param_env = db.trait_environment(def); for clause in param_env.clauses { let ClauseKind::Trait(trait_clause) = clause.kind().skip_binder() else { continue }; if trait_clause.self_ty() != param_ty { diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 8beaa481b528..df83b2abb870 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -2240,12 +2240,7 @@ pub(crate) fn param_env_from_predicates<'db>( ParamEnv { clauses } } -pub(crate) fn trait_environment<'db>( - db: &'db dyn HirDatabase, - def: ExpressionStoreOwnerId, -) -> ParamEnv<'db> { - let def = def.generic_def(db); - +pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> { return ParamEnv { clauses: trait_environment_query(db, def).as_ref() }; #[salsa::tracked(returns(ref))] diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index 940bc572595e..bc158ac884e9 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -141,7 +141,7 @@ pub fn borrowck_query( let _p = tracing::info_span!("borrowck_query").entered(); let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); - let env = db.trait_environment(def.expression_store_owner(db)); + let env = db.trait_environment(def.generic_def(db)); // This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`. let typing_mode = TypingMode::borrowck(interner, def.into()); let res = all_mir_bodies( diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index a8879521eba6..961218f3ef6a 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -685,7 +685,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { db, random_state: oorandom::Rand64::new(0), param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate { - param_env: db.trait_environment(owner.expression_store_owner(db)), + param_env: db.trait_environment(owner.generic_def(db)), krate: crate_id, }), crate_id, diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index 6bf966c3ef1d..0e94a5b92dd1 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -1,4 +1,4 @@ -use hir_def::{GenericDefId, HasModule, signatures::FunctionSignature}; +use hir_def::{HasModule, signatures::FunctionSignature}; use hir_expand::EditionedFileId; use span::Edition; use syntax::{TextRange, TextSize}; @@ -41,7 +41,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), func_id.into(), GenericArgs::empty(interner).store(), crate::ParamEnvAndCrate { - param_env: db.trait_environment(GenericDefId::from(func_id).into()), + param_env: db.trait_environment(func_id.into()), krate: func_id.krate(db), } .store(), diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 025aff9307e1..68612c2ce2fe 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -314,8 +314,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { closures: vec![], }; let store_owner = owner.expression_store_owner(db); - let resolver = store_owner.resolver(db); - let env = db.trait_environment(store_owner); + let resolver = owner.resolver(db); + let env = db.trait_environment(owner.generic_def(db)); let interner = DbInterner::new_with(db, resolver.krate()); // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body? let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs index 79d2fa0c2d1c..dfd1fd96c656 100644 --- a/crates/hir-ty/src/opaques.rs +++ b/crates/hir-ty/src/opaques.rs @@ -1,8 +1,8 @@ //! Handling of opaque types, detection of defining scope and hidden type. use hir_def::{ - AssocItemId, AssocItemLoc, DefWithBodyId, ExpressionStoreOwnerId, FunctionId, GenericDefId, - HasModule, ItemContainerId, TypeAliasId, signatures::ImplSignature, + AssocItemId, AssocItemLoc, DefWithBodyId, FunctionId, HasModule, ItemContainerId, TypeAliasId, + signatures::ImplSignature, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -129,8 +129,7 @@ pub(crate) fn tait_hidden_types( let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let mut ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); - let param_env = - db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(type_alias))); + let param_env = db.trait_environment(type_alias.into()); let defining_bodies = tait_defining_bodies(db, loc); diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs index 467b598447d6..2d206fe38002 100644 --- a/crates/hir-ty/src/specialization.rs +++ b/crates/hir-ty/src/specialization.rs @@ -1,9 +1,6 @@ //! Impl specialization related things -use hir_def::{ - ExpressionStoreOwnerId, GenericDefId, HasModule, ImplId, signatures::ImplSignature, - unstable_features::UnstableFeatures, -}; +use hir_def::{HasModule, ImplId, signatures::ImplSignature, unstable_features::UnstableFeatures}; use tracing::debug; use crate::{ @@ -48,9 +45,7 @@ fn specializes_query( specializing_impl_def_id: ImplId, parent_impl_def_id: ImplId, ) -> bool { - let trait_env = db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( - specializing_impl_def_id, - ))); + let trait_env = db.trait_environment(specializing_impl_def_id.into()); let interner = DbInterner::new_with(db, specializing_impl_def_id.krate(db)); let specializing_impl_signature = ImplSignature::of(db, specializing_impl_def_id); diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9f94243062b3..1629f8019185 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2927,7 +2927,7 @@ impl Function { id.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { - param_env: db.trait_environment(GenericDefId::from(id).into()), + param_env: db.trait_environment(id.into()), krate: id.module(db).krate(db), } .store(), @@ -7454,7 +7454,7 @@ fn param_env_from_resolver<'db>( ParamEnvAndCrate { param_env: resolver.generic_def().map_or_else( || ParamEnv::empty(DbInterner::new_no_crate(db)), - |generic_def| db.trait_environment(generic_def.into()), + |generic_def| db.trait_environment(generic_def), ), krate: resolver.krate(), } @@ -7464,14 +7464,17 @@ fn param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment(id.into().into()), krate: id.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } } fn body_param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } + ParamEnvAndCrate { + param_env: db.trait_environment(id.into().generic_def(db)), + krate: id.krate(db), + } } // FIXME: We probably don't want to expose this. diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index ba62cc11c3c0..3afa98365e18 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -332,10 +332,17 @@ impl<'db> SourceAnalyzer<'db> { fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { self.param_and(self.body_or_sig.as_ref().map_or_else( || ParamEnv::empty(DbInterner::new_no_crate(db)), - |body_or_sig| match *body_or_sig { - BodyOrSig::Body { def, .. } => db.trait_environment(def.into()), - BodyOrSig::VariantFields { def, .. } => db.trait_environment(def.into()), - BodyOrSig::Sig { def, .. } => db.trait_environment(def.into()), + |body_or_sig| { + let def = match *body_or_sig { + BodyOrSig::Body { def, .. } => def.generic_def(db), + BodyOrSig::VariantFields { def, .. } => match def { + VariantId::EnumVariantId(def) => def.loc(db).parent.into(), + VariantId::StructId(def) => def.into(), + VariantId::UnionId(def) => def.into(), + }, + BodyOrSig::Sig { def, .. } => def, + }; + db.trait_environment(def) }, )) } @@ -1590,7 +1597,7 @@ impl<'db> SourceAnalyzer<'db> { func: FunctionId, substs: GenericArgs<'db>, ) -> (Function, GenericArgs<'db>) { - let owner = match self.resolver.expression_store_owner() { + let owner = match self.resolver.generic_def() { Some(it) => it, None => return (func.into(), substs), }; @@ -1610,7 +1617,7 @@ impl<'db> SourceAnalyzer<'db> { const_id: ConstId, subs: GenericArgs<'db>, ) -> (ConstId, GenericArgs<'db>) { - let owner = match self.resolver.expression_store_owner() { + let owner = match self.resolver.generic_def() { Some(it) => it, None => return (const_id, subs), }; diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 61e0b1e611cf..ec5503fe39f5 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -415,7 +415,7 @@ impl flags::AnalysisStats { hir_def::AdtId::from(a), GenericArgs::empty(interner).store(), hir_ty::ParamEnvAndCrate { - param_env: db.trait_environment(GenericDefId::from(a).into()), + param_env: db.trait_environment(a.into()), krate: a.krate(db).into(), } .store(), From 5495bcb5341ef080d61dfbd59d632b4fb188de1e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 3 May 2026 04:54:23 +0300 Subject: [PATCH 2/2] Refactor handling of generic params in `hir::Type` The essence of the new handling is that `hir::Type` now remembers its owner (and not `ParamEnv`; we could remember both but that is unnecessary) and refuse (panics) to work with types not from the same owner. It would be best if we could enforce this statically, but unfortunately we can't. --- crates/hir-ty/src/traits.rs | 6 +- crates/hir/src/attrs.rs | 15 +- crates/hir/src/diagnostics.rs | 59 +- crates/hir/src/display.rs | 12 +- crates/hir/src/lib.rs | 1353 ++++++++--------- crates/hir/src/semantics.rs | 10 +- crates/hir/src/source_analyzer.rs | 120 +- crates/hir/src/term_search/expr.rs | 17 +- crates/hir/src/term_search/tactics.rs | 87 +- .../src/handlers/add_missing_match_arms.rs | 29 +- .../ide-assists/src/handlers/auto_import.rs | 2 +- .../src/handlers/expand_rest_pattern.rs | 8 +- .../handlers/generate_from_impl_for_enum.rs | 7 +- .../generate_single_field_struct_from.rs | 7 +- .../src/handlers/replace_method_eager_lazy.rs | 13 +- .../src/handlers/wrap_return_type.rs | 4 +- crates/ide-completion/src/completions.rs | 6 +- crates/ide-completion/src/completions/expr.rs | 3 + .../ide-completion/src/completions/record.rs | 12 +- crates/ide-completion/src/context.rs | 7 + crates/ide-completion/src/context/analysis.rs | 16 +- crates/ide-completion/src/render.rs | 63 +- crates/ide-completion/src/render/function.rs | 7 +- crates/ide-completion/src/render/literal.rs | 2 +- crates/ide-completion/src/render/pattern.rs | 7 +- crates/ide-completion/src/render/variant.rs | 2 +- crates/ide-completion/src/tests/expression.rs | 4 +- crates/ide-completion/src/tests/predicate.rs | 4 +- crates/ide-completion/src/tests/type_pos.rs | 14 +- .../ide-db/src/syntax_helpers/suggest_name.rs | 4 +- .../src/handlers/type_mismatch.rs | 4 +- crates/ide/src/goto_type_definition.rs | 2 +- crates/ide/src/hover.rs | 4 +- crates/ide/src/hover/render.rs | 16 +- crates/ide/src/rename.rs | 4 +- crates/ide/src/signature_help.rs | 2 +- crates/ide/src/view_memory_layout.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 6 +- 38 files changed, 948 insertions(+), 992 deletions(-) diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 9582f2ceba83..f6b5adfb6fff 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -121,7 +121,7 @@ pub fn implements_trait_unique<'db>( env: ParamEnvAndCrate<'db>, trait_: TraitId, ) -> bool { - implements_trait_unique_impl(db, env, trait_, &mut |infcx| { + implements_trait_unique_with_infcx(db, env, trait_, &mut |infcx| { infcx.fill_rest_fresh_args(Span::Dummy, trait_.into(), [ty.into()]) }) } @@ -133,10 +133,10 @@ pub fn implements_trait_unique_with_args<'db>( trait_: TraitId, args: GenericArgs<'db>, ) -> bool { - implements_trait_unique_impl(db, env, trait_, &mut |_| args) + implements_trait_unique_with_infcx(db, env, trait_, &mut |_| args) } -fn implements_trait_unique_impl<'db>( +pub fn implements_trait_unique_with_infcx<'db>( db: &'db dyn HirDatabase, env: ParamEnvAndCrate<'db>, trait_: TraitId, diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index f9cf05e73a10..9a61885ccb70 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -26,8 +26,8 @@ use stdx::never; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, EnumVariant, - ExternCrateDecl, Field, Function, GenericParam, HasCrate, Impl, LangItem, LifetimeParam, Macro, - Module, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, + ExternCrateDecl, Field, Function, GenericParam, Impl, LangItem, LifetimeParam, Macro, Module, + ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, }; #[derive(Debug, Clone, Copy)] @@ -487,27 +487,28 @@ fn resolve_impl_trait_item<'db>( ns: Option, ) -> Option { let krate = ty.krate(db); - let environment = crate::param_env_from_resolver(db, &resolver); + let param_env = ty.param_env(db); let traits_in_scope = resolver.traits_in_scope(db); // `ty.iterate_path_candidates()` require a scope, which is not available when resolving // attributes here. Use path resolution directly instead. // // FIXME: resolve type aliases (which are not yielded by iterate_path_candidates) - let interner = DbInterner::new_with(db, environment.krate); + let interner = DbInterner::new_with(db, param_env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let features = resolver.top_level_def_map().features(); let ctx = MethodResolutionContext { infcx: &infcx, resolver: &resolver, - param_env: environment.param_env, + param_env: param_env.param_env, traits_in_scope: &traits_in_scope, - edition: krate.edition(db), + edition: krate.data(db).edition, features, call_span: hir_ty::Span::Dummy, receiver_span: hir_ty::Span::Dummy, }; - let resolution = ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty.ty); + let resolution = + ctx.probe_for_name(method_resolution::Mode::Path, name.clone(), ty.ty.skip_binder()); let resolution = match resolution { Ok(resolution) => resolution.item, Err(MethodError::PrivateMatch(resolution)) => resolution.item, diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index a399df827666..1809aa6c2710 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -16,12 +16,11 @@ use hir_def::{ use hir_expand::{HirFileId, InFile, mod_path::ModPath, name::Name}; use hir_ty::{ CastError, ExplicitDropMethodUseKind, InferenceDiagnostic, InferenceTyDiagnosticSource, - ParamEnvAndCrate, PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic, - TyLoweringDiagnosticKind, + PathGenericsSource, PathLoweringDiagnostic, TyLoweringDiagnostic, TyLoweringDiagnosticKind, db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, display::{DisplayTarget, HirDisplay}, - next_solver::DbInterner, + next_solver::{DbInterner, EarlyBinder}, solver_errors::SolverDiagnosticKind, }; use stdx::{impl_from, never}; @@ -32,7 +31,7 @@ use syntax::{ }; use triomphe::Arc; -use crate::{AssocItem, Field, Function, GenericDef, Local, Trait, Type, Variant}; +use crate::{AssocItem, Field, Function, GenericDef, Local, Trait, Type, TypeOwnerId, Variant}; pub use hir_def::VariantId; pub use hir_ty::{ @@ -772,7 +771,7 @@ impl<'db> AnyDiagnostic<'db> { d: &'db InferenceDiagnostic, source_map: &hir_def::expr_store::BodySourceMap, sig_map: &hir_def::expr_store::ExpressionStoreSourceMap, - env: ParamEnvAndCrate<'db>, + type_owner: TypeOwnerId, ) -> Option> { let expr_syntax = |expr| { source_map @@ -796,6 +795,7 @@ impl<'db> AnyDiagnostic<'db> { ExprOrPatId::ExprId(expr) => expr_syntax(expr), ExprOrPatId::PatId(pat) => pat_syntax(pat), }; + let new_ty = |ty| Type { owner: type_owner, ty: EarlyBinder::bind(ty) }; let span_syntax = |span| match span { hir_ty::Span::ExprId(idx) => expr_syntax(idx).map(|it| it.upcast()), hir_ty::Span::PatId(idx) => pat_syntax(idx).map(|it| it.upcast()), @@ -825,7 +825,11 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::ExpectedArrayOrSlicePat { pat, found } => { let pat = pat_syntax(*pat)?.map(Into::into); - ExpectedArrayOrSlicePat { pat, found: Type::new(db, def, found.as_ref()) }.into() + ExpectedArrayOrSlicePat { + pat, + found: Type { owner: type_owner, ty: EarlyBinder::bind(found.as_ref()) }, + } + .into() } &InferenceDiagnostic::InvalidRangePatType { pat } => { let pat = pat_syntax(pat)?.map(Into::into); @@ -855,8 +859,7 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::ExpectedFunction { call_expr, found } => { let call_expr = expr_syntax(*call_expr)?; - ExpectedFunction { call: call_expr, found: Type::new(db, def, found.as_ref()) } - .into() + ExpectedFunction { call: call_expr, found: new_ty(found.as_ref()) }.into() } InferenceDiagnostic::UnresolvedField { expr, @@ -868,7 +871,7 @@ impl<'db> AnyDiagnostic<'db> { UnresolvedField { expr, name: name.clone(), - receiver: Type::new(db, def, receiver.as_ref()), + receiver: new_ty(receiver.as_ref()), method_with_same_name_exists: *method_with_same_name_exists, } .into() @@ -884,10 +887,10 @@ impl<'db> AnyDiagnostic<'db> { UnresolvedMethodCall { expr, name: name.clone(), - receiver: Type::new(db, def, receiver.as_ref()), + receiver: new_ty(receiver.as_ref()), field_with_same_name: field_with_same_name .as_ref() - .map(|ty| Type::new(db, def, ty.as_ref())), + .map(|ty| new_ty(ty.as_ref())), assoc_func_with_same_name: assoc_func_with_same_name.map(Into::into), } .into() @@ -924,7 +927,7 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::TypedHole { expr, expected } => { let expr = expr_syntax(*expr)?; - TypedHole { expr, expected: Type::new(db, def, expected.as_ref()) }.into() + TypedHole { expr, expected: new_ty(expected.as_ref()) }.into() } &InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => { let InFile { file_id, value } = pat_syntax(pat)?; @@ -935,17 +938,17 @@ impl<'db> AnyDiagnostic<'db> { } InferenceDiagnostic::CastToUnsized { expr, cast_ty } => { let expr = expr_syntax(*expr)?; - CastToUnsized { expr, cast_ty: Type::new(db, def, cast_ty.as_ref()) }.into() + CastToUnsized { expr, cast_ty: new_ty(cast_ty.as_ref()) }.into() } InferenceDiagnostic::InvalidCast { expr, error, expr_ty, cast_ty } => { let expr = expr_syntax(*expr)?; - let expr_ty = Type::new(db, def, expr_ty.as_ref()); - let cast_ty = Type::new(db, def, cast_ty.as_ref()); + let expr_ty = new_ty(expr_ty.as_ref()); + let cast_ty = new_ty(cast_ty.as_ref()); InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() } InferenceDiagnostic::CannotBeDereferenced { expr, found } => { let expr = expr_syntax(*expr)?; - CannotBeDereferenced { expr, found: Type::new(db, def, found.as_ref()) }.into() + CannotBeDereferenced { expr, found: new_ty(found.as_ref()) }.into() } InferenceDiagnostic::TyDiagnostic { source, diag } => { let source_map = match source { @@ -1020,10 +1023,7 @@ impl<'db> AnyDiagnostic<'db> { &InferenceDiagnostic::TypeMustBeKnown { at_point, ref top_term } => { let at_point = span_syntax(at_point)?; let top_term = top_term.as_ref().map(|top_term| match top_term.as_ref().kind() { - rustc_type_ir::GenericArgKind::Type(ty) => Either::Left(Type { - ty, - env: crate::body_param_env_from_has_crate(db, def), - }), + rustc_type_ir::GenericArgKind::Type(ty) => Either::Left(new_ty(ty)), // FIXME: Printing the const to string is definitely not the correct thing to do here. rustc_type_ir::GenericArgKind::Const(konst) => Either::Right( konst.display(db, DisplayTarget::from_crate(db, def.krate(db))).to_string(), @@ -1042,14 +1042,14 @@ impl<'db> AnyDiagnostic<'db> { let expr_or_pat = expr_or_pat_syntax(*node)?; TypeMismatch { expr_or_pat, - expected: Type { env, ty: expected.as_ref() }, - actual: Type { env, ty: found.as_ref() }, + expected: Type { owner: type_owner, ty: EarlyBinder::bind(expected.as_ref()) }, + actual: Type { owner: type_owner, ty: EarlyBinder::bind(found.as_ref()) }, } .into() } InferenceDiagnostic::SolverDiagnostic(d) => { let span = span_syntax(d.span)?; - Self::solver_diagnostic(db, &d.kind, span, env)? + Self::solver_diagnostic(db, &d.kind, span, type_owner)? } InferenceDiagnostic::ExplicitDropMethodUse { kind } => { let expr_or_path = match kind { @@ -1077,16 +1077,21 @@ impl<'db> AnyDiagnostic<'db> { db: &'db dyn HirDatabase, d: &'db SolverDiagnosticKind, span: SpanSyntax, - env: ParamEnvAndCrate<'db>, + type_owner: TypeOwnerId, ) -> Option> { let interner = DbInterner::new_no_crate(db); Some(match d { SolverDiagnosticKind::TraitUnimplemented { trait_predicate, root_trait_predicate } => { - let trait_predicate = - crate::TraitPredicate { inner: trait_predicate.get(interner), env }; + let trait_predicate = crate::TraitPredicate { + inner: trait_predicate.get(interner), + owner: type_owner, + }; let root_trait_predicate = root_trait_predicate.as_ref().map(|root_trait_predicate| { - crate::TraitPredicate { inner: root_trait_predicate.get(interner), env } + crate::TraitPredicate { + inner: root_trait_predicate.get(interner), + owner: type_owner, + } }); UnimplementedTrait { span, trait_predicate, root_trait_predicate }.into() } diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index c3af5fa7cef8..ed18482bf380 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -33,7 +33,7 @@ use crate::{ Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, EnumVariant, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitPredicate, - TraitRef, TupleField, Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, + TraitRef, TupleField, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, }; fn write_builtin_derive_impl_method<'db>( @@ -552,13 +552,7 @@ impl<'db> HirDisplay<'db> for EnumVariant { impl<'db> HirDisplay<'db> for Type<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - self.ty.hir_fmt(f) - } -} - -impl<'db> HirDisplay<'db> for TypeNs<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - self.ty.hir_fmt(f) + self.ty.skip_binder().hir_fmt(f) } } @@ -598,7 +592,7 @@ impl<'db> HirDisplay<'db> for TypeParam { let params = GenericParams::of(f.db, self.id.parent()); let param_data = ¶ms[self.id.local_id()]; let krate = self.id.parent().krate(f.db).id; - let ty = self.ty(f.db).ty; + let ty = self.ty(f.db).ty.skip_binder(); let predicates = GenericPredicates::query_all(f.db, self.id.parent()); let predicates = predicates .iter_identity() diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1629f8019185..223d142f93cb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -39,7 +39,8 @@ mod display; pub use hir_def::ModuleId; use std::{ - fmt, + borrow::Borrow, + fmt, iter, mem::discriminant, ops::{ControlFlow, Not}, }; @@ -93,19 +94,17 @@ use hir_ty::{ method_resolution::{self, InherentImpls, MethodResolutionContext}, mir::interpret_mir, next_solver::{ - AliasTy, AnyImplId, ClauseKind, ConstKind, DbInterner, EarlyBinder, EarlyParamRegion, - ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Region, - RegionKind, SolverDefId, Ty, TyKind, TypingMode, + AliasTy, AnyImplId, ClauseKind, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, + GenericArgs, ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, traits::{self, is_inherent_impl_coherent, structurally_normalize_ty}, }; use itertools::Itertools; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use rustc_type_ir::{ - AliasTyKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitor, fast_reject, - inherent::{GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _}, + AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, fast_reject, + inherent::{AdtDef as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _}, }; use span::{AstIdNode, Edition, FileId}; use stdx::{format_to, impl_from, never}; @@ -183,6 +182,7 @@ pub use { mir::{MirEvalError, MirLowerError}, next_solver::abi::Safety, next_solver::{clear_tls_solver_cache, collect_ty_garbage}, + setup_tracing, }, // FIXME: These are needed for import assets, properly encapsulate them. hir_ty::{method_resolution::TraitImpls, next_solver::SimplifiedType}, @@ -198,6 +198,7 @@ use { name::AsName, span_map::{ExpansionSpanMap, RealSpanMap, SpanMap}, }, + hir_ty::next_solver, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -945,7 +946,7 @@ impl Module { if !missing.is_empty() { let env = ParamEnvAndCrate { - param_env: db.trait_environment(GenericDefId::from(impl_id).into()), + param_env: db.trait_environment(GenericDefId::from(impl_id)), krate: self.id.krate(db), }; let self_ty = db.impl_self_ty(impl_id).instantiate_identity().skip_norm_wip(); @@ -1333,24 +1334,6 @@ pub struct Field { pub(crate) id: LocalFieldId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InstantiatedField<'db> { - pub(crate) inner: Field, - pub(crate) args: GenericArgs<'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 interner = DbInterner::new_no_crate(db); - - let var_id = self.inner.parent.into(); - let field = db.field_types(var_id)[self.inner.id].get(); - let ty = field.instantiate(interner, self.args).skip_norm_wip(); - TypeNs::new(db, var_id, ty) - } -} - #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct TupleField { pub owner: InferBodyId, @@ -1371,7 +1354,7 @@ impl TupleField { .get(self.index as usize) .copied() .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)); - Type { env: body_param_env_from_has_crate(db, self.owner.expression_store_owner(db)), ty } + Type::new_body(db, self.owner.expression_store_owner(db), ty) } } @@ -1421,46 +1404,14 @@ impl Field { /// 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 ty = db.field_types(var_id)[self.id].get().skip_binder(); - TypeNs::new(db, var_id, ty) - } - - // FIXME: Find better API to also handle const generics - pub fn ty_with_args<'db>( - &self, - db: &'db dyn HirDatabase, - generics: impl Iterator>, - ) -> Type<'db> { + pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let var_id = self.parent.into(); - let def_id: AdtId = match self.parent { - Variant::Struct(it) => it.id.into(), - Variant::Union(it) => it.id.into(), - Variant::EnumVariant(it) => it.parent_enum(db).id.into(), - }; - 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].get().instantiate(interner, args).skip_norm_wip(); - Type::new(db, var_id, ty) + let ty = db.field_types(var_id)[self.id].get().instantiate_identity().skip_norm_wip(); + Type::new(var_id.adt_id(db).into(), ty) } pub fn layout<'db>(&self, db: &'db dyn HirDatabase) -> Result, LayoutError> { - db.layout_of_ty( - self.ty(db).ty.store(), - param_env_from_has_crate( - db, - match hir_def::VariantId::from(self.parent) { - hir_def::VariantId::EnumVariantId(id) => { - GenericDefId::AdtId(id.lookup(db).parent.into()) - } - hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), - hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()), - }, - ) - .store(), - ) - .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) + self.ty(db).layout(db) } pub fn parent_def(&self, _db: &dyn HirDatabase) -> Variant { @@ -1505,10 +1456,6 @@ impl Struct { Type::from_def(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<'_> { Type::from_value_def(db, self.id) } @@ -1532,11 +1479,6 @@ impl Struct { pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } - - pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedStruct<'db> { - let args = infer_ctxt.fresh_args_for_item(hir_ty::Span::Dummy, self.id.into()); - InstantiatedStruct { inner: self, args } - } } impl HasVisibility for Struct { @@ -1547,34 +1489,6 @@ impl HasVisibility for Struct { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InstantiatedStruct<'db> { - pub(crate) inner: Struct, - pub(crate) args: GenericArgs<'db>, -} - -impl<'db> InstantiatedStruct<'db> { - pub fn fields(self, db: &dyn HirDatabase) -> Vec> { - self.inner - .id - .fields(db) - .fields() - .iter() - .map(|(id, _)| InstantiatedField { - inner: Field { parent: self.inner.into(), id }, - args: self.args, - }) - .collect() - } - - pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { - let interner = DbInterner::new_no_crate(db); - - let ty = db.ty(self.inner.id.into()); - TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args).skip_norm_wip()) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Union { pub(crate) id: UnionId, @@ -1593,10 +1507,6 @@ impl Union { Type::from_def(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<'_> { Type::from_value_def(db, self.id) } @@ -1660,17 +1570,11 @@ impl Enum { Type::from_def(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 krate = self.id.lookup(db).container.krate(db); - let interner = DbInterner::new_with(db, krate); - Type::new_for_crate( - db, - krate, + let interner = DbInterner::new_no_crate(db); + Type::no_params( + Type::builtin_type_crate(db), match EnumSignature::variant_body_type(db, self.id) { layout::IntegerType::Pointer(sign) => match sign { true => Ty::new_int(interner, rustc_type_ir::IntTy::Isize), @@ -1724,27 +1628,6 @@ impl HasVisibility for Enum { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InstantiatedEnum<'db> { - pub(crate) inner: Enum, - pub(crate) args: GenericArgs<'db>, -} - -impl<'db> InstantiatedEnum<'db> { - pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { - let interner = DbInterner::new_no_crate(db); - - let ty = db.ty(self.inner.id.into()); - TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args).skip_norm_wip()) - } -} - -impl From<&EnumVariant> for DefWithBodyId { - fn from(&v: &EnumVariant) -> Self { - DefWithBodyId::VariantId(v.into()) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariant { pub(crate) id: EnumVariantId, @@ -1811,40 +1694,6 @@ impl EnumVariant { pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE) } - - pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> InstantiatedVariant<'db> { - let args = infer_ctxt.fresh_args_for_item( - hir_ty::Span::Dummy, - self.parent_enum(infer_ctxt.interner.db()).id.into(), - ); - InstantiatedVariant { inner: self, args } - } -} - -// FIXME: Rename to `EnumVariant` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InstantiatedVariant<'db> { - pub(crate) inner: EnumVariant, - pub(crate) args: GenericArgs<'db>, -} - -impl<'db> InstantiatedVariant<'db> { - pub fn parent_enum(self, db: &dyn HirDatabase) -> InstantiatedEnum<'db> { - InstantiatedEnum { inner: self.inner.id.lookup(db).parent.into(), args: self.args } - } - - pub fn fields(self, db: &dyn HirDatabase) -> Vec> { - self.inner - .id - .fields(db) - .fields() - .iter() - .map(|(id, _)| InstantiatedField { - inner: Field { parent: self.inner.into(), id }, - args: self.args, - }) - .collect() - } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -1893,23 +1742,6 @@ impl Adt { Type::from_def(db, id) } - /// Turns this ADT into a type with the given type parameters. This isn't - /// the greatest API, FIXME find a better one. - pub fn ty_with_args<'db>( - self, - db: &'db dyn HirDatabase, - args: impl IntoIterator>, - ) -> Type<'db> { - let id = AdtId::from(self); - 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) - } - pub fn module(self, db: &dyn HirDatabase) -> Module { match self { Adt::Struct(s) => s.module(db), @@ -2017,8 +1849,7 @@ impl AnonConst { pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { let loc = self.id.loc(db); - let env = body_param_env_from_has_crate(db, loc.owner); - Type { env, ty: loc.ty.get().instantiate_identity().skip_norm_wip() } + Type { owner: self.id.into(), ty: loc.ty.get() } } pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { @@ -2128,7 +1959,7 @@ impl DefWithBody { }, DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), - DefWithBody::EnumVariant(it) => it.into(), + DefWithBody::EnumVariant(it) => it.id.into(), }) } @@ -2168,8 +1999,6 @@ impl DefWithBody { let Ok(id) = self.try_into() else { return; }; - let krate = self.module(db).id.krate(db); - let env = body_param_env_from_has_crate(db, id); let (body, source_map) = Body::with_source_map(db, id); let sig_source_map = match self { @@ -2192,6 +2021,7 @@ impl DefWithBody { expr_store_diagnostics(db, acc, source_map); let infer = InferenceResult::of(db, id); + let type_owner = id.generic_def(db).into(); for d in infer.diagnostics() { acc.extend(AnyDiagnostic::inference_diagnostic( db, @@ -2199,7 +2029,7 @@ impl DefWithBody { d, source_map, sig_source_map, - env, + type_owner, )); } @@ -2269,7 +2099,7 @@ impl DefWithBody { }; acc.push( MovedOutOfRef { - ty: Type::new_for_crate(db, krate, moof.ty.as_ref()), + ty: Type { owner: type_owner, ty: EarlyBinder::bind(moof.ty.as_ref()) }, span, } .into(), @@ -2369,9 +2199,9 @@ impl DefWithBody { ) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { let infer = InferenceResult::of(db, def_id); - let resolver = def_id.resolver(db); + let def_id = def_id.generic_def(db); - infer.expression_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) + infer.expression_types().map(move |(_, ty)| Type::new(def_id, ty)) }) } @@ -2379,9 +2209,9 @@ impl DefWithBody { pub fn pattern_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { let infer = InferenceResult::of(db, def_id); - let resolver = def_id.resolver(db); + let def_id = def_id.generic_def(db); - infer.pattern_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) + infer.pattern_types().map(move |(_, ty)| Type::new(def_id, ty)) }) } @@ -2389,9 +2219,9 @@ impl DefWithBody { pub fn binding_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { let infer = InferenceResult::of(db, def_id); - let resolver = def_id.resolver(db); + let def_id = def_id.generic_def(db); - infer.binding_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) + infer.binding_types().map(move |(_, ty)| Type::new(def_id, ty)) }) } } @@ -2475,12 +2305,9 @@ impl Function { AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { // Get the type for the trait function, as we can't get the type for the impl function // because it has not `CallableDefId`. - let krate = impl_.module(db).krate(db); - let interner = DbInterner::new_with(db, krate); - let param_env = hir_ty::builtin_derive::param_env(interner, impl_); - let env = ParamEnvAndCrate { param_env, krate }; + // FIXME: This does not account for replacing `Self`. Do we really need that? let Some(trait_method) = method.trait_method(db, impl_) else { - return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) }; + return Type::unknown(); }; Function::from(trait_method).ty(db) } @@ -2490,160 +2317,36 @@ impl Function { pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { match self.id { AnyFunctionId::FunctionId(id) => { - let resolver = id.resolver(db); let interner = DbInterner::new_no_crate(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let callable_sig = db.callable_item_signature(id.into()).instantiate_identity().skip_norm_wip(); let ty = Ty::new_fn_ptr(interner, callable_sig); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::new(id.into(), ty) } AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { - struct ParamsShifter<'db> { - interner: DbInterner<'db>, - shift_by: i32, - } - - impl<'db> TypeFolder> for ParamsShifter<'db> { - fn cx(&self) -> DbInterner<'db> { - self.interner - } - - fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> { - if let TyKind::Param(param) = ty.kind() { - Ty::new_param( - self.interner, - param.id, - param.index.checked_add_signed(self.shift_by).unwrap(), - ) - } else { - ty.super_fold_with(self) - } - } - - fn fold_const( - &mut self, - ct: hir_ty::next_solver::Const<'db>, - ) -> hir_ty::next_solver::Const<'db> { - if let ConstKind::Param(param) = ct.kind() { - hir_ty::next_solver::Const::new_param( - self.interner, - ParamConst { - id: param.id, - index: param.index.checked_add_signed(self.shift_by).unwrap(), - }, - ) - } else { - ct.super_fold_with(self) - } - } - - fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { - if let RegionKind::ReEarlyParam(param) = r.kind() { - Region::new_early_param( - self.interner, - EarlyParamRegion { - id: param.id, - index: param.index.checked_add_signed(self.shift_by).unwrap(), - }, - ) - } else { - r - } - } - } - // Get the type for the trait function, as we can't get the type for the impl function // because it has not `CallableDefId`. - let krate = impl_.module(db).krate(db); - let interner = DbInterner::new_with(db, krate); - let param_env = hir_ty::builtin_derive::param_env(interner, impl_); - let env = ParamEnvAndCrate { param_env, krate }; + // FIXME: This does not account for replacing `Self`. Do we really need that? let Some(trait_method) = method.trait_method(db, impl_) else { - return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) }; + return Type::unknown(); }; - // The procedure works as follows: the method may have additional generic parameters (e.g. `Hash::hash()`), - // and we want them to be params of the impl method as well. So we start with the trait method identity - // args and extract from them the trait method own args. In parallel, we retrieve the impl trait ref. - // Now we can put our args as [...impl_trait_ref.args, ...trait_method_own_args], but we have one problem: - // the args in `trait_method_own_args` use indices appropriate for the trait method, which are not necessarily - // good for the impl method. So we shift them by `impl_generics_len - trait_generics_len`, which is essentially - // `impl_generics_len - impl_trait_ref.args.len()`. - let trait_method_fn_ptr = Ty::new_fn_ptr( - interner, - db.callable_item_signature(trait_method.into()) - .instantiate_identity() - .skip_norm_wip(), - ); - let impl_trait_ref = hir_ty::builtin_derive::impl_trait(interner, impl_) - .instantiate_identity() - .skip_norm_wip(); - let trait_method_args = - GenericArgs::identity_for_item(interner, trait_method.into()); - let trait_method_own_args = GenericArgs::new_from_iter( - interner, - trait_method_args.iter().skip(impl_trait_ref.args.len()), - ); - let impl_params_count = hir_ty::builtin_derive::generic_params_count(db, impl_); - let shift_args_by = impl_params_count as i32 - impl_trait_ref.args.len() as i32; - let shifted_trait_method_own_args = trait_method_own_args - .fold_with(&mut ParamsShifter { interner, shift_by: shift_args_by }); - let impl_method_args = GenericArgs::new_from_iter( - interner, - impl_trait_ref.args.iter().chain(shifted_trait_method_own_args), - ); - let impl_method_fn_ptr = EarlyBinder::bind(trait_method_fn_ptr) - .instantiate(interner, impl_method_args) - .skip_norm_wip(); - Type { env, ty: impl_method_fn_ptr } + Function::from(trait_method).fn_ptr_type(db) } } } - fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (ParamEnvAndCrate<'db>, PolyFnSig<'db>) { + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, PolyFnSig<'db>) { let fn_ptr = self.fn_ptr_type(db); - let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.kind() else { + let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.skip_binder().kind() else { unreachable!(); }; - (fn_ptr.env, sig_tys.with(hdr)) + (fn_ptr.owner, sig_tys.with(hdr)) } - // FIXME: Find a better API to express all combinations here, perhaps we should have `PreInstantiationType`? - /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> { - let (env, sig) = self.fn_sig(db); - Type { env, ty: sig.skip_binder().output() } - } - - // FIXME: Find better API to also handle const generics - pub fn ret_type_with_args<'db>( - self, - db: &'db dyn HirDatabase, - generics: impl Iterator>, - ) -> Type<'db> { - let ret_type = self.ret_type(db); - let interner = DbInterner::new_no_crate(db); - let args = self.adapt_generic_args(interner, generics); - ret_type.derived(EarlyBinder::bind(ret_type.ty).instantiate(interner, args).skip_norm_wip()) - } - - fn adapt_generic_args<'db>( - self, - interner: DbInterner<'db>, - generics: impl Iterator>, - ) -> GenericArgs<'db> { - let generics = generics.map(|ty| ty.ty); - match self.id { - AnyFunctionId::FunctionId(id) => generic_args_from_tys(interner, id.into(), generics), - AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => { - let impl_args = GenericArgs::identity_for_item(interner, impl_.into()); - GenericArgs::new_from_iter( - interner, - impl_args.iter().chain(generics.map(Into::into)), - ) - } - } + let (owner, sig) = self.fn_sig(db); + Type { owner, ty: EarlyBinder::bind(sig.skip_binder().output()) } } pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option> { @@ -2653,15 +2356,13 @@ impl Function { if !self.is_async(db) { return None; } - let resolver = id.resolver(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let ret_ty = db.callable_item_signature(id.into()).instantiate_identity().skip_binder().output(); for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() { if let ClauseKind::Projection(projection) = pred.kind().skip_binder() && let Some(output_ty) = projection.term.as_type() { - return Type::new_with_resolver_inner(db, &resolver, output_ty).into(); + return Some(Type::new(id.into(), output_ty)); } } None @@ -2687,7 +2388,7 @@ impl Function { } pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { - let (env, sig) = self.fn_sig(db); + let (owner, sig) = self.fn_sig(db); let func = match self.id { AnyFunctionId::FunctionId(id) => Callee::Def(CallableDefId::FunctionId(id)), AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => { @@ -2698,7 +2399,11 @@ impl Function { .inputs() .iter() .enumerate() - .map(|(idx, &ty)| Param { func: func.clone(), ty: Type { env, ty }, idx }) + .map(|(idx, &ty)| Param { + func: func.clone(), + ty: Type { owner, ty: EarlyBinder::bind(ty) }, + idx, + }) .collect() } @@ -2724,28 +2429,6 @@ impl Function { params } - // FIXME: Find better API to also handle const generics - pub fn params_without_self_with_args<'db>( - self, - db: &'db dyn HirDatabase, - generics: impl Iterator>, - ) -> Vec> { - let interner = DbInterner::new_no_crate(db); - let args = self.adapt_generic_args(interner, generics); - let params = self.params_without_self(db); - params - .into_iter() - .map(|param| Param { - func: param.func, - idx: param.idx, - ty: Type { - env: param.ty.env, - ty: EarlyBinder::bind(param.ty.ty).instantiate(interner, args).skip_norm_wip(), - }, - }) - .collect() - } - pub fn is_const(self, db: &dyn HirDatabase) -> bool { match self.id { AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_const(), @@ -3099,20 +2782,8 @@ impl SelfParam { } pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { - let (env, sig) = self.func.fn_sig(db); - Type { env, ty: sig.skip_binder().inputs()[0] } - } - - // FIXME: Find better API to also handle const generics - pub fn ty_with_args<'db>( - &self, - db: &'db dyn HirDatabase, - generics: impl Iterator>, - ) -> Type<'db> { - let interner = DbInterner::new_no_crate(db); - let args = self.func.adapt_generic_args(interner, generics); - let Type { env, ty } = self.ty(db); - Type { env, ty: EarlyBinder::bind(ty).instantiate(interner, args).skip_norm_wip() } + let (owner, sig) = self.func.fn_sig(db); + Type { owner, ty: EarlyBinder::bind(sig.skip_binder().inputs()[0]) } } } @@ -3444,10 +3115,6 @@ impl TypeAlias { Type::from_def(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 { TypeAliasSignature::of(db, self.id).name.clone() } @@ -3496,10 +3163,13 @@ impl BuiltinType { } } + pub fn bool() -> BuiltinType { + BuiltinType { inner: hir_def::builtin_type::BuiltinType::Bool } + } + pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { - let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| all_crates(db)[0]); let interner = DbInterner::new_no_crate(db); - Type::new_for_crate(db, core, Ty::from_builtin_type(interner, self.inner)) + Type::no_params(Type::builtin_type_crate(db), Ty::from_builtin_type(interner, self.inner)) } pub fn name(self) -> Name { @@ -4292,23 +3962,19 @@ impl GenericDef { // We cannot call this `Substitution` unfortunately... #[derive(Debug)] pub struct GenericSubstitution<'db> { + owner: TypeOwnerId, def: GenericDefId, subst: GenericArgs<'db>, - env: ParamEnvAndCrate<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, env: ParamEnvAndCrate<'db>) -> Self { - Self { def, subst, env } + fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Self { + Self { owner, def, subst } } - fn new_from_fn( - def: Function, - subst: GenericArgs<'db>, - env: ParamEnvAndCrate<'db>, - ) -> Option { + fn new_from_fn(def: Function, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Option { match def.id { - AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, env)), + AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, owner)), AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, } } @@ -4355,7 +4021,12 @@ impl<'db> GenericSubstitution<'db> { .zip(type_params); container_params .chain(self_params) - .filter_map(|(ty, name)| Some((name?.symbol().clone(), Type { ty, env: self.env }))) + .filter_map(|(ty, name)| { + Some(( + name?.symbol().clone(), + Type { ty: EarlyBinder::bind(ty), owner: self.owner }, + )) + }) .collect() } } @@ -4468,7 +4139,7 @@ impl Local { let def = self.parent; let infer = InferenceResult::of(db, self.parent_infer); let ty = infer.binding_ty(self.binding_id); - Type::new(db, def, ty) + Type::new_body(db, def, ty) } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` @@ -4768,18 +4439,17 @@ impl TypeParam { } pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { - let resolver = self.id.parent().resolver(db); let interner = DbInterner::new_no_crate(db); let index = hir_ty::type_or_const_param_idx(db, self.id.into()); let ty = Ty::new_param(interner, self.id, index); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::new(self.id.parent(), ty) } /// FIXME: this only lists trait bounds from the item defining the type /// 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 { - let self_ty = self.ty(db).ty; + let self_ty = self.ty(db).ty.instantiate_identity().skip_norm_wip(); GenericPredicates::query_explicit(db, self.id.parent()) .iter_identity() .filter_map(|pred| match &pred.kind().skip_binder() { @@ -4793,10 +4463,9 @@ impl TypeParam { pub fn default(self, db: &dyn HirDatabase) -> Option> { let ty = generic_arg_from_param(db, self.id.into())?; - let resolver = self.id.parent().resolver(db); match ty.kind() { rustc_type_ir::GenericArgKind::Type(it) if !it.is_ty_error() => { - Some(Type::new_with_resolver_inner(db, &resolver, it)) + Some(Type::new(self.id.parent(), it)) } _ => None, } @@ -4857,7 +4526,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(self.id.parent(), db.const_param_ty(self.id)) } pub fn default(self, db: &dyn HirDatabase, display_target: DisplayTarget) -> Option { @@ -4979,21 +4648,26 @@ impl Impl { /// blanket impls, and only does a shallow type constructor check. In fact, this should've probably been on `Adt` /// etc., and not on `Type`. If you would want to create a precise list of all impls applying to a type, /// you would need to include blanket impls, and try to prove to predicates for each candidate. - pub fn all_for_type<'db>(db: &'db dyn HirDatabase, Type { ty, env }: Type<'db>) -> Vec { + pub fn all_for_type<'db>(db: &'db dyn HirDatabase, ty: Type<'db>) -> Vec { 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 { + let Some(simplified_ty) = fast_reject::simplify_type( + interner, + ty.ty.skip_binder(), + fast_reject::TreatParams::AsRigid, + ) else { return Vec::new(); }; let mut extend_with_impls = |impls: Either<&[ImplId], &[BuiltinDeriveImplId]>| match impls { Either::Left(impls) => result.extend(impls.iter().copied().map(Impl::from)), Either::Right(impls) => result.extend(impls.iter().copied().map(Impl::from)), }; - method_resolution::with_incoherent_inherent_impls(db, env.krate, &simplified_ty, |impls| { - extend_with_impls(Either::Left(impls)) - }); + method_resolution::with_incoherent_inherent_impls( + db, + ty.krate(db), + &simplified_ty, + |impls| extend_with_impls(Either::Left(impls)), + ); if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) { InherentImpls::for_each_crate_and_block( db, @@ -5001,7 +4675,7 @@ impl Impl { module.block(db), &mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))), ); - std::iter::successors(module.block(db), |block| block.loc(db).module.block(db)) + iter::successors(module.block(db), |block| block.loc(db).module.block(db)) .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls)); for &krate in &*all_crates(db) { @@ -5056,21 +4730,16 @@ impl Impl { match self.id { AnyImplId::ImplId(id) => { let trait_ref = db.impl_trait(id)?.instantiate_identity().skip_norm_wip(); - let resolver = id.resolver(db); - Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) + Some(TraitRef::new(id.into(), trait_ref)) } AnyImplId::BuiltinDeriveImplId(id) => { let loc = id.loc(db); let krate = loc.module(db).krate(db); let interner = DbInterner::new_with(db, krate); - let env = ParamEnvAndCrate { - param_env: hir_ty::builtin_derive::param_env(interner, id), - krate, - }; let trait_ref = hir_ty::builtin_derive::impl_trait(interner, id) .instantiate_identity() .skip_norm_wip(); - Some(TraitRef { env, trait_ref }) + Some(TraitRef { owner: TypeOwnerId::BuiltinDeriveImplId(id), trait_ref }) } } } @@ -5078,24 +4747,16 @@ impl Impl { pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { match self.id { AnyImplId::ImplId(id) => { - let resolver = id.resolver(db); - // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. let ty = db.impl_self_ty(id).instantiate_identity().skip_norm_wip(); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::new(id.into(), ty) } AnyImplId::BuiltinDeriveImplId(id) => { let loc = id.loc(db); let krate = loc.module(db).krate(db); let interner = DbInterner::new_with(db, krate); - let env = ParamEnvAndCrate { - param_env: hir_ty::builtin_derive::param_env(interner, id), - krate, - }; - let ty = hir_ty::builtin_derive::impl_trait(interner, id) - .instantiate_identity() - .skip_norm_wip() - .self_ty(); - Type { env, ty } + let ty = + hir_ty::builtin_derive::impl_trait(interner, id).map_bound(|it| it.self_ty()); + Type { owner: TypeOwnerId::BuiltinDeriveImplId(id), ty } } } } @@ -5157,38 +4818,33 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - env: ParamEnvAndCrate<'db>, + owner: TypeOwnerId, trait_ref: hir_ty::next_solver::TraitRef<'db>, } impl<'db> TraitRef<'db> { - pub(crate) fn new_with_resolver( - db: &'db dyn HirDatabase, - resolver: &Resolver<'_>, - trait_ref: hir_ty::next_solver::TraitRef<'db>, - ) -> Self { - let env = param_env_from_resolver(db, resolver); - TraitRef { env, trait_ref } + fn new(owner: GenericDefId, trait_ref: hir_ty::next_solver::TraitRef<'db>) -> Self { + Self { owner: TypeOwnerId::GenericDefId(owner), trait_ref } } pub fn trait_(&self) -> Trait { Trait { id: self.trait_ref.def_id.0 } } - pub fn self_ty(&self) -> TypeNs<'_> { + pub fn self_ty(&self) -> Type<'_> { let ty = self.trait_ref.self_ty(); - TypeNs { env: self.env, ty } + Type { owner: self.owner, ty: EarlyBinder::bind(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> { + pub fn get_type_argument(&self, idx: usize) -> Option> { self.trait_ref .args .as_slice() .get(idx) .and_then(|arg| arg.ty()) - .map(|ty| TypeNs { env: self.env, ty }) + .map(|ty| Type { owner: self.owner, ty: EarlyBinder::bind(ty) }) } } @@ -5200,6 +4856,7 @@ enum AnyClosureId { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Closure<'db> { + owner: TypeOwnerId, id: AnyClosureId, subst: GenericArgs<'db>, } @@ -5237,12 +4894,11 @@ impl<'db> Closure<'db> { let InternedClosure { owner: infer_owner, expr: closure, .. } = closure; let infer = InferenceResult::of(db, infer_owner); let owner = infer_owner.expression_store_owner(db); - let param_env = body_param_env_from_has_crate(db, owner); infer.closures_data[&closure] .min_captures .values() .flatten() - .map(|capture| ClosureCapture { owner, infer_owner, closure, capture, param_env }) + .map(|capture| ClosureCapture { owner, infer_owner, closure, capture }) .collect() } @@ -5333,7 +4989,6 @@ pub struct ClosureCapture<'db> { infer_owner: InferBodyId, closure: ExprId, capture: &'db hir_ty::closure_analysis::CapturedPlace, - param_env: ParamEnvAndCrate<'db>, } impl<'db> ClosureCapture<'db> { @@ -5441,14 +5096,14 @@ impl<'db> ClosureCapture<'db> { result } - pub fn ty(&self, _db: &'db dyn HirDatabase) -> Type<'db> { - Type { env: self.param_env, ty: self.capture.place.ty() } + pub fn ty(&self, db: &'db dyn HirDatabase) -> Type<'db> { + Type::new_body(db, self.owner, self.capture.place.ty()) } /// The type that is stored in the closure, which is different from [`Self::ty()`], representing /// the place's type, when the capture is by ref. pub fn captured_ty(&self, db: &'db dyn HirDatabase) -> Type<'db> { - Type { env: self.param_env, ty: self.capture.captured_ty(db) } + Type::new_body(db, self.owner, self.capture.captured_ty(db)) } } @@ -5524,74 +5179,143 @@ impl CaptureUsageSource { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +enum TypeOwnerId { + GenericDefId(GenericDefId), + BuiltinDeriveImplId(BuiltinDeriveImplId), + AnonConstId(AnonConstId), + // FIXME: What do when we unify two different crates? Currently we just randomly keep one. + NoParams(base_db::Crate), +} +impl_from!(GenericDefId, BuiltinDeriveImplId, AnonConstId for TypeOwnerId); + +impl TypeOwnerId { + fn unify(self, other: Self) -> Option { + match (self, other) { + (TypeOwnerId::NoParams(_), owner) => Some(owner), + (owner, TypeOwnerId::NoParams(_)) => Some(owner), + (_, _) => { + if self == other { + Some(self) + } else { + None + } + } + } + } + + #[track_caller] + fn must_unify(self, other: Self) -> Self { + self.unify(other).expect("failed to unify type owners") + } + + fn can_rebase_into( + self, + db: &dyn HirDatabase, + rebase_into: Self, + self_ty: EarlyBinder<'_, Ty<'_>>, + ) -> bool { + if self == rebase_into || !self_ty.skip_binder().has_param() { + return true; + } + let self_def = match self { + TypeOwnerId::GenericDefId(def) => def, + TypeOwnerId::BuiltinDeriveImplId(_) | TypeOwnerId::AnonConstId(_) => return false, + TypeOwnerId::NoParams(_) => return true, + }; + let self_def = match self_def { + GenericDefId::ImplId(def) => ItemContainerId::ImplId(def), + GenericDefId::TraitId(def) => ItemContainerId::TraitId(def), + GenericDefId::AdtId(_) + | GenericDefId::ConstId(_) + | GenericDefId::FunctionId(_) + | GenericDefId::StaticId(_) + | GenericDefId::TypeAliasId(_) => return false, + }; + let rebase_into_def = match rebase_into { + TypeOwnerId::GenericDefId(def) => def, + TypeOwnerId::BuiltinDeriveImplId(_) + | TypeOwnerId::AnonConstId(_) + | TypeOwnerId::NoParams(_) => return false, + }; + let rebase_into_parent = match rebase_into_def { + GenericDefId::ConstId(def) => def.loc(db).container, + GenericDefId::FunctionId(def) => def.loc(db).container, + GenericDefId::TypeAliasId(def) => def.loc(db).container, + GenericDefId::AdtId(_) + | GenericDefId::ImplId(_) + | GenericDefId::StaticId(_) + | GenericDefId::TraitId(_) => return false, + }; + self_def == rebase_into_parent + } +} + +/// Note: A [`Type`] remembers its origin. Trying to do anything (except comparing) +/// with types of different origins will cause errors or panics. Instead, use the `instantiate` methods. +#[derive(Clone, Debug)] pub struct Type<'db> { - env: ParamEnvAndCrate<'db>, - ty: Ty<'db>, + owner: TypeOwnerId, + ty: EarlyBinder<'db, Ty<'db>>, } -impl<'db> Type<'db> { - pub(crate) fn new_with_resolver( - db: &'db dyn HirDatabase, - resolver: &Resolver<'_>, - ty: Ty<'db>, - ) -> Self { - Type::new_with_resolver_inner(db, resolver, ty) +impl<'db> std::hash::Hash for Type<'db> { + fn hash(&self, state: &mut H) { + // Do not hash the owner as different owners can compare the same. + // self.owner.hash(state); + self.ty.hash(state); } +} - pub(crate) fn new_with_resolver_inner( - db: &'db dyn HirDatabase, - resolver: &Resolver<'_>, - ty: Ty<'db>, - ) -> Self { - let environment = param_env_from_resolver(db, resolver); - Type { env: environment, ty } +impl<'db> PartialEq for Type<'db> { + fn eq(&self, other: &Self) -> bool { + if self.ty != other.ty { + return false; + } + hir_ty::with_attached_db(|db| { + self.owner.can_rebase_into(db, other.owner, self.ty) + || other.owner.can_rebase_into(db, self.owner, other.ty) + }) } +} - pub(crate) fn new_for_crate( - db: &'db dyn HirDatabase, - krate: base_db::Crate, - ty: Ty<'db>, - ) -> Self { - let interner = DbInterner::new_with(db, krate); - Type { env: ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate }, ty } +impl<'db> Eq for Type<'db> {} + +impl<'db> Type<'db> { + fn new(owner: GenericDefId, ty: Ty<'db>) -> Self { + Type { owner: TypeOwnerId::GenericDefId(owner), ty: EarlyBinder::bind(ty) } } - fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self { - let resolver = lexical_env.resolver(db); - let environment = param_env_from_resolver(db, &resolver); - Type { env: environment, ty } + fn new_body(db: &dyn HirDatabase, owner: ExpressionStoreOwnerId, ty: Ty<'db>) -> Self { + Self::new(owner.generic_def(db), ty) } - fn from_def(db: &'db dyn HirDatabase, def: impl Into + HasResolver) -> Self { - let interner = DbInterner::new_no_crate(db); - let ty = db.ty(def.into()); - 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).skip_norm_wip()) + fn no_params(krate: base_db::Crate, ty: Ty<'db>) -> Self { + Type { owner: TypeOwnerId::NoParams(krate), ty: EarlyBinder::bind(ty) } } - // FIXME: We shouldn't leak `TyKind::Param`s. - fn from_def_params(db: &'db dyn HirDatabase, def: impl Into + HasResolver) -> Self { - let ty = db.ty(def.into()); - Type::new(db, def, ty.instantiate_identity().skip_norm_wip()) + fn builtin_type_crate(db: &'db dyn HirDatabase) -> base_db::Crate { + // It doesn't really matter. + all_crates(db)[0] } - fn from_value_def( - db: &'db dyn HirDatabase, - def: impl Into + HasResolver, - ) -> Self { - let interner = DbInterner::new_no_crate(db); - let Some(ty) = db.value_ty(def.into()) else { - return Type::new(db, def, Ty::new_error(interner, ErrorGuaranteed)); + fn from_def(db: &'db dyn HirDatabase, def: impl Into) -> Self { + let def = def.into(); + let ty = db.ty(def); + let owner = match def { + TyDefId::AdtId(it) => TypeOwnerId::GenericDefId(GenericDefId::AdtId(it)), + TyDefId::TypeAliasId(it) => TypeOwnerId::GenericDefId(GenericDefId::TypeAliasId(it)), + TyDefId::BuiltinType(_) => TypeOwnerId::NoParams(Self::builtin_type_crate(db)), + }; + Type { owner, ty } + } + + fn from_value_def(db: &'db dyn HirDatabase, def: impl Into) -> Self { + let def = def.into(); + let Some(ty) = db.value_ty(def) else { + return Type::unknown(); }; - let def = match def.into() { + let def = match def { ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), @@ -5599,55 +5323,192 @@ impl<'db> Type<'db> { ValueTyDefId::EnumVariantId(it) => { GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) } - ValueTyDefId::StaticId(_) => { - return Type::new(db, def, ty.skip_binder()); + ValueTyDefId::StaticId(it) => { + return Type::no_params(hir_def::HasModule::krate(&it, db), ty.skip_binder()); + } + }; + Type::new(def, ty.instantiate_identity().skip_norm_wip()) + } + + /// Replace any generic parameters with error types. + pub fn instantiate_with_errors(&self) -> Self { + let interner = DbInterner::conjure(); + let krate = self.krate(interner.db()); + let args = match self.owner { + TypeOwnerId::GenericDefId(def) => GenericArgs::error_for_item(interner, def.into()), + TypeOwnerId::BuiltinDeriveImplId(def) => { + GenericArgs::error_for_item(interner, def.into()) } + TypeOwnerId::AnonConstId(def) => GenericArgs::error_for_item(interner, def.into()), + TypeOwnerId::NoParams(_) => GenericArgs::empty(interner), }; - let args = GenericArgs::error_for_item(interner, def.into()); - Type::new(db, def, ty.instantiate(interner, args).skip_norm_wip()) + Type::no_params(krate, self.ty.instantiate(interner, args).skip_norm_wip()) + } + + // FIXME: Find some way with const params, maybe even lifetimes? + pub fn instantiate(&self, args: impl IntoIterator>>) -> Type<'db> { + let interner = DbInterner::conjure(); + let (args, owner) = match self.owner { + TypeOwnerId::GenericDefId(def) => generic_args_from_tys(interner, def.into(), args), + TypeOwnerId::BuiltinDeriveImplId(def) => { + generic_args_from_tys(interner, def.into(), args) + } + TypeOwnerId::AnonConstId(def) => generic_args_from_tys(interner, def.into(), args), + TypeOwnerId::NoParams(krate) => { + (GenericArgs::empty(interner), TypeOwnerId::NoParams(krate)) + } + }; + Type { owner, ty: EarlyBinder::bind(self.ty.instantiate(interner, args).skip_norm_wip()) } + } + + /// Instantiates multiple types with infer vars, keeping the same infer vars for the same owners. + fn instantiate_many_with_infer( + tys: impl IntoIterator>>, + infcx: &InferCtxt<'db>, + ) -> impl Iterator> { + let mut var_for_param = FxHashMap::default(); + tys.into_iter().map(move |ty| { + let ty = ty.borrow(); + let owner = match ty.owner { + TypeOwnerId::GenericDefId(def) => def.into(), + TypeOwnerId::BuiltinDeriveImplId(def) => def.into(), + TypeOwnerId::AnonConstId(def) => def.into(), + TypeOwnerId::NoParams(_) => return ty.ty.skip_binder(), + }; + let args = GenericArgs::for_item(infcx.interner, owner, |_, param, _| { + *var_for_param + .entry(param) + .or_insert_with(|| infcx.var_for_def(param, hir_ty::Span::Dummy)) + }); + + ty.ty.instantiate(infcx.interner, args).skip_norm_wip() + }) + } + + /// Tries to put this type as-is in the context of `rebase_into`. This will return `Some(_)` if: + /// + /// - The type does not reference generic parameters, or + /// - `rebase_into` is in the context of a child of our context (for example, a function in an impl). + pub fn try_rebase_into( + &self, + db: &'db dyn HirDatabase, + rebase_into: &Type<'db>, + ) -> Option { + if self.owner.can_rebase_into(db, rebase_into.owner, self.ty) { + Some(Type { owner: rebase_into.owner, ty: self.ty }) + } else { + None + } + } + + /// If `self` can be rebased into `rebase_into`, returns that. Otherwise, instantiates `self` with errors + /// and returns that. + pub fn rebase_into_or_error( + &self, + db: &'db dyn HirDatabase, + rebase_into: &Type<'db>, + ) -> Type<'db> { + self.try_rebase_into(db, rebase_into).unwrap_or_else(|| self.instantiate_with_errors()) + } + + pub fn try_rebase_into_owner( + &self, + db: &'db dyn HirDatabase, + new_owner: GenericDef, + ) -> Option { + let new_owner = new_owner.id()?.into(); + if self.owner.can_rebase_into(db, new_owner, self.ty) { + Some(Type { owner: new_owner, ty: self.ty }) + } else { + None + } + } + + pub fn rebase_into_owner_or_error( + &self, + db: &'db dyn HirDatabase, + new_owner: GenericDef, + ) -> Self { + self.try_rebase_into_owner(db, new_owner).unwrap_or_else(|| self.instantiate_with_errors()) + } + + pub fn unknown() -> Self { + let interner = DbInterner::conjure(); + Type::no_params( + Self::builtin_type_crate(interner.db()), + Ty::new_error(interner, ErrorGuaranteed), + ) } pub fn new_slice(db: &'db dyn HirDatabase, ty: Self) -> Self { let interner = DbInterner::new_no_crate(db); - Type { env: ty.env, ty: Ty::new_slice(interner, ty.ty) } + Type { owner: ty.owner, ty: ty.ty.map_bound(|ty| Ty::new_slice(interner, ty)) } } - pub fn new_tuple(db: &'db dyn HirDatabase, krate: base_db::Crate, tys: &[Self]) -> Self { - let tys = tys.iter().map(|it| it.ty); - let interner = DbInterner::new_with(db, krate); - Type { - env: ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate }, - ty: Ty::new_tup_from_iter(interner, tys), - } + pub fn new_tuple( + db: &'db dyn HirDatabase, + tys: impl IntoIterator>>, + ) -> Self { + let interner = DbInterner::new_no_crate(db); + let mut owner = None::; + let ty = EarlyBinder::bind(Ty::new_tup_from_iter( + interner, + tys.into_iter().map(|ty| { + let ty = ty.borrow(); + + match &mut owner { + Some(owner) => *owner = owner.must_unify(ty.owner), + None => owner = Some(ty.owner), + } + + ty.ty.skip_binder() + }), + )); + let owner = + owner.unwrap_or_else(|| TypeOwnerId::NoParams(Self::builtin_type_crate(interner.db()))); + Type { owner, ty } + } + + pub fn new_unit() -> Self { + let interner = DbInterner::conjure(); + Type::no_params(Self::builtin_type_crate(interner.db()), Ty::new_unit(interner)) } pub fn is_unit(&self) -> bool { - self.ty.is_unit() + self.ty.skip_binder().is_unit() } pub fn is_bool(&self) -> bool { - matches!(self.ty.kind(), TyKind::Bool) + matches!(self.ty.skip_binder().kind(), TyKind::Bool) } pub fn is_str(&self) -> bool { - matches!(self.ty.kind(), TyKind::Str) + matches!(self.ty.skip_binder().kind(), TyKind::Str) } pub fn is_never(&self) -> bool { - matches!(self.ty.kind(), TyKind::Never) + matches!(self.ty.skip_binder().kind(), TyKind::Never) } pub fn is_mutable_reference(&self) -> bool { - matches!(self.ty.kind(), TyKind::Ref(.., hir_ty::next_solver::Mutability::Mut)) + matches!( + self.ty.skip_binder().kind(), + TyKind::Ref(.., hir_ty::next_solver::Mutability::Mut) + ) } pub fn is_reference(&self) -> bool { - matches!(self.ty.kind(), TyKind::Ref(..)) + matches!(self.ty.skip_binder().kind(), TyKind::Ref(..)) } pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { let interner = DbInterner::new_no_crate(db); - return self.ty.visit_with(&mut Visitor { interner }).is_break(); + return self + .ty + .instantiate_identity() + .skip_norm_wip() + .visit_with(&mut Visitor { interner }) + .is_break(); fn is_phantom_data(db: &dyn HirDatabase, adt_id: AdtId) -> bool { match adt_id { @@ -5725,89 +5586,129 @@ impl<'db> Type<'db> { } pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> { - let TyKind::Ref(_lt, ty, m) = self.ty.kind() else { return None }; + let TyKind::Ref(_lt, ty, m) = self.ty.skip_binder().kind() else { return None }; let m = Mutability::from_mutable(matches!(m, hir_ty::next_solver::Mutability::Mut)); Some((self.derived(ty), m)) } + pub fn as_reference_inner(&self) -> Option> { + self.as_reference().map(|(inner, _)| inner) + } + pub fn add_reference(&self, db: &'db dyn HirDatabase, mutability: Mutability) -> Self { let interner = DbInterner::new_no_crate(db); let ty_mutability = match mutability { Mutability::Shared => hir_ty::next_solver::Mutability::Not, Mutability::Mut => hir_ty::next_solver::Mutability::Mut, }; - self.derived(Ty::new_ref(interner, Region::error(interner), self.ty, ty_mutability)) + self.derived(Ty::new_ref( + interner, + Region::error(interner), + self.ty.skip_binder(), + ty_mutability, + )) } pub fn is_slice(&self) -> bool { - matches!(self.ty.kind(), TyKind::Slice(..)) + matches!(self.ty.skip_binder().kind(), TyKind::Slice(..)) } pub fn is_usize(&self) -> bool { - matches!(self.ty.kind(), TyKind::Uint(rustc_type_ir::UintTy::Usize)) + matches!(self.ty.skip_binder().kind(), TyKind::Uint(rustc_type_ir::UintTy::Usize)) } pub fn is_float(&self) -> bool { - matches!(self.ty.kind(), TyKind::Float(_)) + matches!(self.ty.skip_binder().kind(), TyKind::Float(_)) } pub fn is_char(&self) -> bool { - matches!(self.ty.kind(), TyKind::Char) + matches!(self.ty.skip_binder().kind(), TyKind::Char) } pub fn is_int_or_uint(&self) -> bool { - matches!(self.ty.kind(), TyKind::Int(_) | TyKind::Uint(_)) + matches!(self.ty.skip_binder().kind(), TyKind::Int(_) | TyKind::Uint(_)) } pub fn is_scalar(&self) -> bool { matches!( - self.ty.kind(), + self.ty.skip_binder().kind(), TyKind::Bool | TyKind::Char | TyKind::Int(_) | TyKind::Uint(_) | TyKind::Float(_) ) } pub fn is_tuple(&self) -> bool { - matches!(self.ty.kind(), TyKind::Tuple(..)) - } - - pub fn remove_ref(&self) -> Option> { - match self.ty.kind() { - TyKind::Ref(_, ty, _) => Some(self.derived(ty)), - _ => None, - } + matches!(self.ty.skip_binder().kind(), TyKind::Tuple(..)) } pub fn as_slice(&self) -> Option> { - match self.ty.kind() { + match self.ty.skip_binder().kind() { TyKind::Slice(ty) => Some(self.derived(ty)), _ => None, } } pub fn strip_references(&self) -> Self { - self.derived(self.ty.strip_references()) + self.derived(self.ty.skip_binder().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()) + self.derived(self.ty.skip_binder().strip_reference()) } pub fn is_unknown(&self) -> bool { - self.ty.is_ty_error() + self.ty.skip_binder().is_ty_error() + } + + fn krate(&self, db: &'db dyn HirDatabase) -> base_db::Crate { + match self.owner { + TypeOwnerId::GenericDefId(def) => hir_def::HasModule::krate(&def, db), + TypeOwnerId::BuiltinDeriveImplId(def) => { + hir_def::HasModule::krate(&def.loc(db).adt, db) + } + TypeOwnerId::AnonConstId(def) => hir_def::HasModule::krate(&def, db), + TypeOwnerId::NoParams(krate) => krate, + } + } + + fn param_env(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { + let interner = DbInterner::new_no_crate(db); + let krate = self.krate(db); + match self.owner { + TypeOwnerId::GenericDefId(def) => { + ParamEnvAndCrate { param_env: db.trait_environment(def), krate } + } + TypeOwnerId::BuiltinDeriveImplId(def) => ParamEnvAndCrate { + param_env: hir_ty::builtin_derive::param_env(interner, def), + krate, + }, + TypeOwnerId::AnonConstId(def) => ParamEnvAndCrate { + param_env: db.trait_environment(def.loc(db).owner.generic_def(db)), + krate, + }, + TypeOwnerId::NoParams(_) => { + ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate } + } + } } /// 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> { - let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let env = self.param_env(db); + let lang_items = hir_def::lang_item::lang_items(db, env.krate); let (trait_, output_assoc_type) = lang_items .IntoFuture .zip(lang_items.IntoFutureOutput) .or(lang_items.Future.zip(lang_items.FutureOutput))?; - if !traits::implements_trait_unique(self.ty, db, self.env, trait_) { + if !traits::implements_trait_unique( + self.ty.instantiate_identity().skip_norm_wip(), + db, + env, + trait_, + ) { return None; } @@ -5816,32 +5717,46 @@ impl<'db> Type<'db> { /// This does **not** resolve `IntoFuture`, only `Future`. pub fn future_output(self, db: &'db dyn HirDatabase) -> Option> { - let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let krate = self.krate(db); + let lang_items = hir_def::lang_item::lang_items(db, 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> { - let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let krate = self.krate(db); + let lang_items = hir_def::lang_item::lang_items(db, krate); let iterator_item = lang_items.IteratorItem?; self.normalize_trait_assoc_type(db, &[], iterator_item.into()) } pub fn impls_iterator(self, db: &'db dyn HirDatabase) -> bool { - let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let env = self.param_env(db); + let lang_items = hir_def::lang_item::lang_items(db, env.krate); let Some(iterator_trait) = lang_items.Iterator else { return false; }; - traits::implements_trait_unique(self.ty, db, self.env, iterator_trait) + traits::implements_trait_unique( + self.ty.instantiate_identity().skip_norm_wip(), + db, + env, + iterator_trait, + ) } /// Resolves the projection `::IntoIter` and returns the resulting type pub fn into_iterator_iter(self, db: &'db dyn HirDatabase) -> Option> { - let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let env = self.param_env(db); + let lang_items = hir_def::lang_item::lang_items(db, env.krate); let trait_ = lang_items.IntoIterator?; - if !traits::implements_trait_unique(self.ty, db, self.env, trait_) { + if !traits::implements_trait_unique( + self.ty.instantiate_identity().skip_norm_wip(), + db, + env, + trait_, + ) { return None; } @@ -5854,24 +5769,63 @@ 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 lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let env = self.param_env(db); + let lang_items = hir_def::lang_item::lang_items(db, env.krate); let fnonce_trait = match lang_items.FnOnce { Some(it) => it, None => return false, }; - traits::implements_trait_unique(self.ty, db, self.env, fnonce_trait) + traits::implements_trait_unique( + self.ty.instantiate_identity().skip_norm_wip(), + db, + env, + fnonce_trait, + ) } // FIXME: Find better API that also handles const generics pub fn impls_trait(&self, db: &'db dyn HirDatabase, trait_: Trait, args: &[Type<'db>]) -> bool { + let env = self.param_env(db); 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, trait_.id, args) + let (args, _owner) = + generic_args_from_tys(interner, trait_.id.into(), iter::once(self).chain(args)); + traits::implements_trait_unique_with_args(db, env, trait_.id, args) + } + + /// Unlike [`Type::impls_trait()`], which checks whether the type always implements the trait, + /// this check whether there are any generic args substitution for `args`` that will cause the + /// trait to be implemented. + /// + /// For example, suppose we're there's `struct Foo` and we're checking `Foo: Trait`. + /// `impls_trait()` will return true only if there is `impl Trait for Foo`, while this + /// method will also return true if there is only `impl Trait for Foo`. + /// + /// Note that you can of course instantiate `Foo` with `` and then the checks will + /// be the same, but this check for *any* substitution. + /// + /// Unlike almost anything that takes more than one type, you *can* pass types from different origins + /// to this function. + pub fn has_any_impl( + &self, + db: &'db dyn HirDatabase, + trait_: Trait, + args: &[Type<'db>], + ) -> bool { + let interner = DbInterner::new_no_crate(db); + let env = ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate: self.krate(db) }; + traits::implements_trait_unique_with_infcx(db, env, trait_.id, &mut |infcx| { + let mut args = Self::instantiate_many_with_infer(iter::once(self).chain(args), infcx); + GenericArgs::for_item(infcx.interner, trait_.id.into(), |_, param, _| { + if let GenericParamId::TypeParamId(_) = param + && let Some(arg) = args.next() + { + arg.into() + } else { + infcx.var_for_def(param, hir_ty::Span::Dummy) + } + }) + }) } pub fn normalize_trait_assoc_type( @@ -5880,12 +5834,10 @@ impl<'db> Type<'db> { args: &[Type<'db>], alias: TypeAlias, ) -> Option> { - 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)), - ); + let env = self.param_env(db); + let interner = DbInterner::new_with(db, env.krate); + let (args, owner) = + generic_args_from_tys(interner, alias.id.into(), iter::once(self).chain(args)); // FIXME: We don't handle GATs yet. let projection = Ty::new_alias( interner, @@ -5897,12 +5849,13 @@ impl<'db> Type<'db> { ); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = structurally_normalize_ty(&infcx, projection, self.env.param_env); - if ty.is_ty_error() { None } else { Some(self.derived(ty)) } + let ty = structurally_normalize_ty(&infcx, projection, env.param_env); + if ty.is_ty_error() { None } else { Some(Type { owner, ty: EarlyBinder::bind(ty) }) } } pub fn is_copy(&self, db: &'db dyn HirDatabase) -> bool { - let lang_items = hir_def::lang_item::lang_items(db, self.env.krate); + let env = self.param_env(db); + let lang_items = hir_def::lang_item::lang_items(db, env.krate); let Some(copy_trait) = lang_items.Copy else { return false; }; @@ -5911,7 +5864,7 @@ impl<'db> Type<'db> { pub fn as_callable(&self, db: &'db dyn HirDatabase) -> Option> { let interner = DbInterner::new_no_crate(db); - let callee = match self.ty.kind() { + let callee = match self.ty.skip_binder().kind() { TyKind::Closure(id, subst) => Callee::Closure(id.0, subst), TyKind::CoroutineClosure(id, subst) => Callee::CoroutineClosure(id.0, subst), TyKind::FnPtr(..) => Callee::FnPtr, @@ -5919,7 +5872,9 @@ impl<'db> Type<'db> { // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db), _ => { - let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(self.ty, self.env, db)?; + let env = self.param_env(db); + let (fn_trait, sig) = + hir_ty::callable_sig_from_fn_trait(self.ty.skip_binder(), env, db)?; return Some(Callable { ty: self.clone(), sig, @@ -5929,74 +5884,77 @@ impl<'db> Type<'db> { } }; - let sig = self.ty.callable_sig(interner)?; + let sig = self.ty.skip_binder().callable_sig(interner)?; Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false }) } pub fn is_closure(&self) -> bool { - matches!(self.ty.kind(), TyKind::Closure { .. }) + matches!(self.ty.skip_binder().kind(), TyKind::Closure { .. }) } pub fn as_closure(&self) -> Option> { - match self.ty.kind() { + match self.ty.skip_binder().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 }) + Some(Closure { id: AnyClosureId::ClosureId(id.0), subst, owner: self.owner }) } + TyKind::CoroutineClosure(id, subst) => Some(Closure { + id: AnyClosureId::CoroutineClosureId(id.0), + subst, + owner: self.owner, + }), _ => None, } } pub fn is_fn(&self) -> bool { - matches!(self.ty.kind(), TyKind::FnDef(..) | TyKind::FnPtr { .. }) + matches!(self.ty.skip_binder().kind(), TyKind::FnDef(..) | TyKind::FnPtr { .. }) } pub fn is_array(&self) -> bool { - matches!(self.ty.kind(), TyKind::Array(..)) + matches!(self.ty.skip_binder().kind(), TyKind::Array(..)) } - pub fn is_packed(&self, db: &'db dyn HirDatabase) -> bool { - let adt_id = match self.ty.kind() { - TyKind::Adt(adt_def, ..) => adt_def.def_id(), - _ => return false, - }; - - let adt = adt_id.into(); - match adt { - Adt::Struct(s) => s.repr(db).unwrap_or_default().pack.is_some(), + pub fn is_packed(&self, _db: &'db dyn HirDatabase) -> bool { + match self.ty.skip_binder().kind() { + TyKind::Adt(adt_def, ..) => adt_def.is_packed(), _ => false, } } pub fn is_raw_ptr(&self) -> bool { - matches!(self.ty.kind(), TyKind::RawPtr(..)) + matches!(self.ty.skip_binder().kind(), TyKind::RawPtr(..)) } pub fn is_mutable_raw_ptr(&self) -> bool { // Used outside of rust-analyzer (e.g. by `ra_ap_hir` consumers). - matches!(self.ty.kind(), TyKind::RawPtr(.., hir_ty::next_solver::Mutability::Mut)) + matches!( + self.ty.skip_binder().kind(), + TyKind::RawPtr(.., hir_ty::next_solver::Mutability::Mut) + ) } pub fn as_raw_ptr(&self) -> Option<(Type<'db>, Mutability)> { // Used outside of rust-analyzer (e.g. by `ra_ap_hir` consumers). - let TyKind::RawPtr(ty, m) = self.ty.kind() else { return None }; + let TyKind::RawPtr(ty, m) = self.ty.skip_binder().kind() else { return None }; let m = Mutability::from_mutable(matches!(m, hir_ty::next_solver::Mutability::Mut)); Some((self.derived(ty), m)) } pub fn remove_raw_ptr(&self) -> Option> { - if let TyKind::RawPtr(ty, _) = self.ty.kind() { Some(self.derived(ty)) } else { None } + if let TyKind::RawPtr(ty, _) = self.ty.skip_binder().kind() { + Some(self.derived(ty)) + } else { + None + } } pub fn contains_unknown(&self) -> bool { - self.ty.references_non_lt_error() + self.ty.skip_binder().references_non_lt_error() } pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> { let interner = DbInterner::new_no_crate(db); - let (variant_id, substs) = match self.ty.kind() { + let (variant_id, substs) = match self.ty.skip_binder().kind() { TyKind::Adt(adt_def, substs) => { let id = match adt_def.def_id() { AdtId::StructId(id) => id.into(), @@ -6019,7 +5977,7 @@ impl<'db> Type<'db> { } pub fn tuple_fields(&self, _db: &'db dyn HirDatabase) -> Vec { - if let TyKind::Tuple(substs) = self.ty.kind() { + if let TyKind::Tuple(substs) = self.ty.skip_binder().kind() { substs.iter().map(|ty| self.derived(ty)).collect() } else { Vec::new() @@ -6027,17 +5985,18 @@ impl<'db> Type<'db> { } pub fn as_array(&self, db: &'db dyn HirDatabase) -> Option<(Self, usize)> { - if let TyKind::Array(ty, len) = self.ty.kind() { + if let TyKind::Array(ty, len) = self.ty.skip_binder().kind() { try_const_usize(db, len).map(|it| (self.derived(ty), it as usize)) } else { None } } + // FIXME: We should probably remove this. pub fn fingerprint_for_trait_impl(&self, db: &'db dyn HirDatabase) -> Option { fast_reject::simplify_type( DbInterner::new_no_crate(db), - self.ty, + self.ty.skip_binder(), fast_reject::TreatParams::AsRigid, ) } @@ -6053,9 +6012,10 @@ impl<'db> Type<'db> { fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator> { let interner = DbInterner::new_no_crate(db); + let env = self.param_env(db); // There should be no inference vars in types passed here - let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty); - autoderef(db, self.env, canonical) + let canonical = hir_ty::replace_errors_with_variables(interner, &self.ty.skip_binder()); + autoderef(db, env, canonical) } // This would be nicer if it just returned an iterator, but that runs into @@ -6087,17 +6047,20 @@ impl<'db> Type<'db> { } } }; + let krate = self.krate(db); let interner = DbInterner::new_no_crate(db); - let Some(simplified_type) = - fast_reject::simplify_type(interner, self.ty, fast_reject::TreatParams::AsRigid) - else { + let Some(simplified_type) = fast_reject::simplify_type( + interner, + self.ty.skip_binder(), + fast_reject::TreatParams::AsRigid, + ) else { return; }; method_resolution::with_incoherent_inherent_impls( db, - self.env.krate, + krate, &simplified_type, &mut handle_impls, ); @@ -6133,12 +6096,12 @@ impl<'db> Type<'db> { /// - "U" /// ``` pub fn type_arguments(&self) -> impl Iterator> + '_ { - match self.ty.strip_references().kind() { + match self.ty.skip_binder().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())), + _ => Either::Right(Either::Right(iter::empty())), } } @@ -6166,6 +6129,7 @@ impl<'db> Type<'db> { display_target: DisplayTarget, ) -> impl Iterator + 'a { self.ty + .skip_binder() .strip_references() .as_adt() .into_iter() @@ -6256,7 +6220,7 @@ impl<'db> Type<'db> { }; let infcx = interner.infer_ctxt().build(typing_mode); let features = resolver.top_level_def_map().features(); - let environment = param_env_from_resolver(db, resolver); + let environment = self.param_env(db); let ctx = MethodResolutionContext { infcx: &infcx, resolver, @@ -6291,7 +6255,8 @@ impl<'db> Type<'db> { 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 canonical = + hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty.skip_binder()); let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical); match name { @@ -6399,7 +6364,8 @@ impl<'db> Type<'db> { 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 canonical = + hir_ty::replace_errors_with_variables(ctx.infcx.interner, &self.ty.skip_binder()); let (self_ty, _) = ctx.infcx.instantiate_canonical(hir_ty::Span::Dummy, &canonical); match name { @@ -6448,23 +6414,23 @@ impl<'db> Type<'db> { } pub fn as_adt(&self) -> Option { - let (adt, _subst) = self.ty.as_adt()?; + let (adt, _subst) = self.ty.skip_binder().as_adt()?; Some(adt.into()) } /// Holes in the args can come from lifetime/const params. pub fn as_adt_with_args(&self) -> Option<(Adt, Vec>>)> { - let (adt, args) = self.ty.as_adt()?; + let (adt, args) = self.ty.skip_binder().as_adt()?; let args = args.iter().map(|arg| Some(self.derived(arg.ty()?))).collect(); Some((adt.into(), args)) } pub fn as_builtin(&self) -> Option { - self.ty.as_builtin().map(|inner| BuiltinType { inner }) + self.ty.skip_binder().as_builtin().map(|inner| BuiltinType { inner }) } pub fn as_dyn_trait(&self) -> Option { - self.ty.dyn_trait().map(Into::into) + self.ty.skip_binder().dyn_trait().map(Into::into) } /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type, @@ -6483,11 +6449,11 @@ impl<'db> Type<'db> { pub fn env_traits(&self, db: &'db dyn HirDatabase) -> impl Iterator { let _p = tracing::info_span!("env_traits").entered(); + let env = self.param_env(db); self.autoderef_(db) .filter(|ty| matches!(ty.kind(), TyKind::Param(_))) - .flat_map(|ty| { - self.env - .param_env + .flat_map(move |ty| { + env.param_env .clauses() .iter() .filter_map(move |pred| match pred.kind().skip_binder() { @@ -6501,7 +6467,7 @@ impl<'db> Type<'db> { } pub fn as_impl_traits(&self, db: &'db dyn HirDatabase) -> Option> { - self.ty.impl_trait_bounds(db).map(|it| { + self.ty.skip_binder().impl_trait_bounds(db).map(|it| { it.into_iter().filter_map(|pred| match pred.kind().skip_binder() { ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)), _ => None, @@ -6511,7 +6477,7 @@ impl<'db> Type<'db> { pub fn as_associated_type_parent_trait(&self, db: &'db dyn HirDatabase) -> Option { let TyKind::Alias(AliasTy { kind: AliasTyKind::Projection { def_id }, .. }) = - self.ty.kind() + self.ty.skip_binder().kind() else { return None; }; @@ -6522,7 +6488,7 @@ impl<'db> Type<'db> { } fn derived(&self, ty: Ty<'db>) -> Self { - Type { env: self.env, ty } + Type { owner: self.owner, ty: EarlyBinder::bind(ty) } } /// Visits every type, including generic arguments, in this type. `callback` is called with type @@ -6530,7 +6496,7 @@ impl<'db> Type<'db> { pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { struct Visitor<'db, F> { db: &'db dyn HirDatabase, - env: ParamEnvAndCrate<'db>, + owner: TypeOwnerId, callback: F, visited: FxHashSet>, } @@ -6545,7 +6511,7 @@ impl<'db> Type<'db> { return; } - (self.callback)(Type { env: self.env, ty }); + (self.callback)(Type { owner: self.owner, ty: EarlyBinder::bind(ty) }); if let Some(bounds) = ty.impl_trait_bounds(self.db) { bounds.visit_with(self); @@ -6555,17 +6521,23 @@ impl<'db> Type<'db> { } } - let mut visitor = Visitor { db, env: self.env, callback, visited: FxHashSet::default() }; - self.ty.visit_with(&mut visitor); + let mut visitor = + Visitor { db, owner: self.owner, callback, visited: FxHashSet::default() }; + self.ty.skip_binder().visit_with(&mut visitor); } /// Check if type unifies with another type. /// /// Note that we consider placeholder types to unify with everything. /// For example `Option` and `Option` unify although there is unresolved goal `T = U`. pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { + self.owner.must_unify(other.owner); + let env = self.param_env(db); 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, &tys) + let tys = hir_ty::replace_errors_with_variables( + interner, + &(self.ty.skip_binder(), other.ty.skip_binder()), + ); + hir_ty::could_unify(db, env, &tys) } /// Check if type unifies with another type eagerly making sure there are no unresolved goals. @@ -6573,19 +6545,29 @@ 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` and `Option` 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 { + self.owner.must_unify(other.owner); + let env = self.param_env(db); 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, &tys) + let tys = hir_ty::replace_errors_with_variables( + interner, + &(self.ty.skip_binder(), other.ty.skip_binder()), + ); + hir_ty::could_unify_deeply(db, env, &tys) } pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { + self.owner.must_unify(to.owner); + let env = self.param_env(db); 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, &tys) + let tys = hir_ty::replace_errors_with_variables( + interner, + &(self.ty.skip_binder(), to.ty.skip_binder()), + ); + hir_ty::could_coerce(db, env, &tys) } pub fn as_type_param(&self, _db: &'db dyn HirDatabase) -> Option { - match self.ty.kind() { + match self.ty.skip_binder().kind() { TyKind::Param(param) => Some(TypeParam { id: param.id }), _ => None, } @@ -6593,60 +6575,23 @@ impl<'db> Type<'db> { /// Returns unique `GenericParam`s contained in this type. pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet { - hir_ty::collect_params(&self.ty) + hir_ty::collect_params(&self.ty.skip_binder()) .into_iter() .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() } pub fn layout(&self, db: &'db dyn HirDatabase) -> Result, LayoutError> { - db.layout_of_ty(self.ty.store(), self.env.store()) - .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) + let env = self.param_env(db); + db.layout_of_ty(self.ty.skip_binder().store(), env.store()) + .map(|layout| Layout(layout, db.target_data_layout(env.krate).unwrap())) } pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { - let interner = DbInterner::new_with(db, self.env.krate); + let env = self.param_env(db); + let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.param_env) - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TypeNs<'db> { - env: ParamEnvAndCrate<'db>, - ty: Ty<'db>, -} - -impl<'db> TypeNs<'db> { - fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty<'db>) -> Self { - let resolver = lexical_env.resolver(db); - let environment = param_env_from_resolver(db, &resolver); - TypeNs { env: environment, ty } - } - - pub fn to_type(&self, _db: &'db dyn HirDatabase) -> Type<'db> { - Type { env: self.env, ty: self.ty } - } - - // FIXME: Find better API that also handles const generics - pub fn impls_trait(&self, infcx: InferCtxt<'db>, trait_: Trait, args: &[TypeNs<'db>]) -> bool { - let args = GenericArgs::new_from_iter( - infcx.interner, - [self.ty].into_iter().chain(args.iter().map(|t| t.ty)).map(GenericArg::from), - ); - let trait_ref = - hir_ty::next_solver::TraitRef::new_from_args(infcx.interner, trait_.id.into(), args); - let obligation = hir_ty::next_solver::infer::traits::Obligation::new( - infcx.interner, - hir_ty::next_solver::infer::traits::ObligationCause::dummy(), - self.env.param_env, - trait_ref, - ); - infcx.predicate_must_hold_modulo_regions(&obligation) - } - - pub fn is_bool(&self) -> bool { - matches!(self.ty.kind(), rustc_type_ir::TyKind::Bool) + hir_ty::drop::has_drop_glue(&infcx, self.ty.skip_binder(), env.param_env) } } @@ -6711,12 +6656,16 @@ impl<'db> Callable<'db> { Callee::Def(CallableDefId::EnumVariantId(it)) => { CallableKind::TupleEnumVariant(it.into()) } - 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::Closure(id, subst) => CallableKind::Closure(Closure { + id: AnyClosureId::ClosureId(id), + subst, + owner: self.ty.owner, + }), + Callee::CoroutineClosure(id, subst) => CallableKind::Closure(Closure { + id: AnyClosureId::CoroutineClosureId(id), + subst, + owner: self.ty.owner, + }), Callee::FnPtr => CallableKind::FnPtr, Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_.into()), } @@ -6857,7 +6806,7 @@ impl<'db> Layout<'db> { reverse_index .into_iter() .flatten() - .chain(std::iter::once((0, self.0.size.bytes()))) + .chain(iter::once((0, self.0.size.bytes()))) .tuple_windows() .filter_map(|((i, start), (_, end))| { let size = field_size(i)?; @@ -7015,7 +6964,7 @@ pub enum PredicatePolarity { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitPredicate<'db> { inner: hir_ty::next_solver::TraitPredicate<'db>, - env: ParamEnvAndCrate<'db>, + owner: TypeOwnerId, } impl<'db> TraitPredicate<'db> { @@ -7027,7 +6976,7 @@ impl<'db> TraitPredicate<'db> { } pub fn trait_ref(&self) -> TraitRef<'db> { - TraitRef { env: self.env, trait_ref: self.inner.trait_ref } + TraitRef { owner: self.owner, trait_ref: self.inner.trait_ref } } } @@ -7097,8 +7046,8 @@ impl HasCrate for TypeAlias { } impl HasCrate for Type<'_> { - fn krate(&self, _db: &dyn HirDatabase) -> Crate { - self.env.krate.into() + fn krate(&self, db: &dyn HirDatabase) -> Crate { + self.krate(db).into() } } @@ -7417,21 +7366,33 @@ fn as_name_opt(name: Option) -> Name { name.map_or_else(Name::missing, |name| name.as_name()) } +#[track_caller] fn generic_args_from_tys<'db>( interner: DbInterner<'db>, def_id: SolverDefId, - args: impl IntoIterator>, -) -> GenericArgs<'db> { + args: impl IntoIterator>>, +) -> (GenericArgs<'db>, TypeOwnerId) { + let mut owner = None::; let mut args = args.into_iter(); - GenericArgs::for_item(interner, def_id, |_, id, _| { + let args = GenericArgs::for_item(interner, def_id, |_, id, _| { if matches!(id, GenericParamId::TypeParamId(_)) && let Some(arg) = args.next() { - arg.into() + let arg = arg.borrow(); + + match &mut owner { + Some(owner) => *owner = owner.must_unify(arg.owner), + None => owner = Some(arg.owner), + } + + arg.ty.skip_binder().into() } else { next_solver::GenericArg::error_from_id(interner, id) } - }) + }); + let owner = + owner.unwrap_or_else(|| TypeOwnerId::NoParams(Type::builtin_type_crate(interner.db()))); + (args, owner) } fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool { @@ -7447,19 +7408,6 @@ fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) }) } -fn param_env_from_resolver<'db>( - db: &'db dyn HirDatabase, - resolver: &Resolver<'_>, -) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { - param_env: resolver.generic_def().map_or_else( - || ParamEnv::empty(DbInterner::new_no_crate(db)), - |generic_def| db.trait_environment(generic_def), - ), - krate: resolver.krate(), - } -} - fn param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, id: impl hir_def::HasModule + Into + Copy, @@ -7467,16 +7415,6 @@ fn param_env_from_has_crate<'db>( ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } } -fn body_param_env_from_has_crate<'db>( - db: &'db dyn HirDatabase, - id: impl hir_def::HasModule + Into + Copy, -) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { - param_env: db.trait_environment(id.into().generic_def(db)), - krate: id.krate(db), - } -} - // FIXME: We probably don't want to expose this. pub trait MacroCallIdExt { fn loc(self, db: &dyn HirDatabase) -> &hir_expand::MacroCallLoc; @@ -7525,6 +7463,3 @@ pub fn struct_tail_raw<'db>( } ty } - -pub use hir_ty::next_solver; -pub use hir_ty::setup_tracing; diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d0202c1054c5..b2dc35700b7b 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1740,11 +1740,7 @@ impl<'db> SemanticsImpl<'db> { analyzer.expr_adjustments(expr).map(|it| { it.iter() .map(|adjust| { - let target = Type::new_with_resolver( - self.db, - &analyzer.resolver, - adjust.target.as_ref(), - ); + let target = analyzer.ty(adjust.target.as_ref()); let kind = match adjust.kind { hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { @@ -1835,10 +1831,10 @@ impl<'db> SemanticsImpl<'db> { let substs = hir_ty::next_solver::GenericArgs::for_item(interner, trait_.id.into(), |_, id, _| { assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type"); - subst.next().expect("too few subst").ty.into() + subst.next().expect("too few subst").ty.skip_binder().into() }); assert!(subst.next().is_none(), "too many subst"); - Some(match self.db.lookup_impl_method(env.env, func, substs).0 { + Some(match self.db.lookup_impl_method(env.param_env(self.db), func, substs).0 { Either::Left(it) => it.into(), Either::Right((impl_, method)) => { Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 3afa98365e18..f24ec420b5df 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -41,8 +41,8 @@ use hir_ty::{ lang_items::lang_items_for_bin_op, method_resolution::{self, CandidateId}, next_solver::{ - AliasTy, DbInterner, DefaultAny, ErrorGuaranteed, GenericArgs, ParamEnv, Region, Ty, - TyKind, TypingMode, infer::DbInternerInferExt, + AliasTy, DbInterner, DefaultAny, EarlyBinder, ErrorGuaranteed, GenericArgs, ParamEnv, + Region, Ty, TyKind, TypingMode, infer::DbInternerInferExt, }, traits::structurally_normalize_ty, }; @@ -63,7 +63,7 @@ use syntax::{ use crate::{ Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, - SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, + SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, TypeOwnerId, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -75,6 +75,7 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option>, + pub(crate) type_owner: TypeOwnerId, pub(crate) infer_body: Option, } @@ -148,6 +149,7 @@ impl<'db> SourceAnalyzer<'db> { resolver, body_or_sig: Some(BodyOrSig::Body { def, body, source_map, infer }), file_id, + type_owner: def.generic_def(db).into(), infer_body: Some(def.into()), } } @@ -212,6 +214,7 @@ impl<'db> SourceAnalyzer<'db> { resolver, body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }), file_id, + type_owner: def.into(), infer_body, } } @@ -261,6 +264,7 @@ impl<'db> SourceAnalyzer<'db> { infer, }), file_id, + type_owner: GenericDefId::from(def.adt_id(db)).into(), infer_body, } } @@ -269,7 +273,16 @@ impl<'db> SourceAnalyzer<'db> { resolver: Resolver<'db>, node: InFile<&SyntaxNode>, ) -> SourceAnalyzer<'db> { - SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id, infer_body: None } + SourceAnalyzer { + type_owner: resolver + .generic_def() + .map(Into::into) + .unwrap_or_else(|| TypeOwnerId::NoParams(resolver.krate())), + resolver, + body_or_sig: None, + file_id: node.file_id, + infer_body: None, + } } fn owner(&self) -> Option { @@ -288,6 +301,10 @@ impl<'db> SourceAnalyzer<'db> { }) } + pub(crate) fn ty(&self, ty: Ty<'db>) -> Type<'db> { + Type { owner: self.type_owner, ty: EarlyBinder::bind(ty) } + } + pub(crate) fn def( &self, ) -> Option<( @@ -426,12 +443,12 @@ impl<'db> SourceAnalyzer<'db> { } } - Some(Type::new_with_resolver(db, &self.resolver, ty)) + Some(self.ty(ty)) } pub(crate) fn type_of_expr( &self, - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, expr: &ast::Expr, ) -> Option<(Type<'db>, Option>)> { let expr_id = self.expr_id(expr.clone())?; @@ -441,13 +458,13 @@ impl<'db> SourceAnalyzer<'db> { .and_then(|expr_id| infer.expr_adjustment(expr_id)) .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.as_ref())); let ty = infer.expr_or_pat_ty(expr_id); - let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty); + let mk_ty = |ty: Ty<'db>| self.ty(ty); Some((mk_ty(ty), coerced.map(mk_ty))) } pub(crate) fn type_of_pat( &self, - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, pat: &ast::Pat, ) -> Option<(Type<'db>, Option>)> { let expr_or_pat_id = self.pat_id(pat)?; @@ -464,25 +481,25 @@ impl<'db> SourceAnalyzer<'db> { }; let ty = infer.expr_or_pat_ty(expr_or_pat_id); - let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty); + let mk_ty = |ty: Ty<'db>| self.ty(ty); Some((mk_ty(ty), coerced.map(mk_ty))) } pub(crate) fn type_of_binding_in_pat( &self, - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, pat: &ast::IdentPat, ) -> Option> { let binding_id = self.binding_id_of_pat(pat)?; let infer = self.infer()?; let ty = infer.binding_ty(binding_id); - let mk_ty = |ty: Ty<'db>| Type::new_with_resolver(db, &self.resolver, ty); + let mk_ty = |ty: Ty<'db>| self.ty(ty); Some(mk_ty(ty)) } pub(crate) fn type_of_self( &self, - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, _param: &ast::SelfParam, ) -> Option> { let binding = match self.body_or_sig.as_ref()? { @@ -490,7 +507,7 @@ impl<'db> SourceAnalyzer<'db> { BodyOrSig::Body { body, .. } => body.self_param()?, }; let ty = self.infer()?.binding_ty(binding); - Some(Type::new_with_resolver(db, &self.resolver, ty)) + Some(self.ty(ty)) } pub(crate) fn binding_mode_of_pat( @@ -512,7 +529,7 @@ impl<'db> SourceAnalyzer<'db> { } pub(crate) fn pattern_adjustments( &self, - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, pat: &ast::Pat, ) -> Option; 1]>> { let pat_id = self.pat_id(pat)?; @@ -521,7 +538,7 @@ impl<'db> SourceAnalyzer<'db> { infer .pat_adjustment(pat_id.as_pat()?)? .iter() - .map(|adjust| Type::new_with_resolver(db, &self.resolver, adjust.source.as_ref())) + .map(|adjust| self.ty(adjust.source.as_ref())) .collect(), ) } @@ -535,7 +552,7 @@ impl<'db> SourceAnalyzer<'db> { let (func, args) = self.infer()?.method_resolution(expr_id)?; let interner = DbInterner::new_no_crate(db); let ty = db.value_ty(func.into())?.instantiate(interner, args).skip_norm_wip(); - let ty = Type::new_with_resolver(db, &self.resolver, ty); + let ty = self.ty(ty); let mut res = ty.as_callable(db)?; res.is_bound_method = true; Some(res) @@ -565,7 +582,7 @@ impl<'db> SourceAnalyzer<'db> { self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs); Some(( Either::Left(fn_), - GenericSubstitution::new_from_fn(fn_, subst, self.trait_environment(db)), + GenericSubstitution::new_from_fn(fn_, subst, self.type_owner), )) } None => { @@ -600,12 +617,12 @@ impl<'db> SourceAnalyzer<'db> { &self, field_expr: ExprId, infer: &InferenceResult, - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, ) -> Option> { let body = self.store()?; if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] { let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?; - return Some(GenericSubstitution::new(adt.into(), subst, self.trait_environment(db))); + return Some(GenericSubstitution::new(adt.into(), subst, self.type_owner)); } None } @@ -636,10 +653,7 @@ impl<'db> SourceAnalyzer<'db> { }, None => inference_result.method_resolution(expr_id).map(|(f, substs)| { let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs); - ( - Either::Right(f), - GenericSubstitution::new_from_fn(f, subst, self.trait_environment(db)), - ) + (Either::Right(f), GenericSubstitution::new_from_fn(f, subst, self.type_owner)) }), } } @@ -729,7 +743,7 @@ impl<'db> SourceAnalyzer<'db> { .map(Trait::from); if let Some(into_future_trait) = into_future_trait { - let type_ = Type::new_with_resolver(db, &self.resolver, ty); + let type_ = self.ty(ty); if type_.impls_trait(db, into_future_trait, &[]) { let items = into_future_trait.items(db); let into_future_type = items.into_iter().find_map(|item| match item { @@ -741,7 +755,7 @@ impl<'db> SourceAnalyzer<'db> { _ => None, })?; let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?; - ty = future_trait.ty; + ty = future_trait.ty.skip_binder(); } } @@ -890,8 +904,8 @@ impl<'db> SourceAnalyzer<'db> { Some(( field.into(), local, - Type::new_with_resolver(db, &self.resolver, field_ty), - GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)), + self.ty(field_ty), + GenericSubstitution::new(adt.into(), subst, self.type_owner), )) } @@ -914,8 +928,8 @@ impl<'db> SourceAnalyzer<'db> { .skip_norm_wip(); Some(( field.into(), - Type::new_with_resolver(db, &self.resolver, field_ty), - GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)), + self.ty(field_ty), + GenericSubstitution::new(adt.into(), subst, self.type_owner), )) } @@ -970,15 +984,15 @@ impl<'db> SourceAnalyzer<'db> { let container = offset_of_expr.ty()?; let container = self.type_of_type(db, &container)?; - let trait_env = container.env; + let env = self.trait_environment(db); - let interner = DbInterner::new_with(db, trait_env.krate); + let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); - let mut container = Either::Right(container.ty); + let mut container = Either::Right(container.ty.skip_binder()); for field_name in offset_of_expr.fields() { if let Either::Right(container) = &mut container { - *container = structurally_normalize_ty(&infcx, *container, trait_env.param_env); + *container = structurally_normalize_ty(&infcx, *container, env.param_env); } let handle_variants = |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| { @@ -1025,7 +1039,10 @@ impl<'db> SourceAnalyzer<'db> { }; if field_name.syntax().text_range() == name_ref.syntax().text_range() { - return Some((field_def, GenericSubstitution::new(generic_def, subst, trait_env))); + return Some(( + field_def, + GenericSubstitution::new(generic_def, subst, self.type_owner), + )); } } never!("the `NameRef` is a child of the `OffsetOfExpr`, we should've visited it"); @@ -1053,7 +1070,7 @@ impl<'db> SourceAnalyzer<'db> { let subst = GenericSubstitution::new( f_in_trait.into(), subs, - self.trait_environment(db), + self.type_owner, ); (AssocItem::Function(f_in_trait.into()), Some(subst)) } @@ -1066,14 +1083,14 @@ impl<'db> SourceAnalyzer<'db> { let subst = GenericSubstitution::new_from_fn( fn_, subst, - self.trait_environment(db), + self.type_owner, ); (AssocItem::Function(fn_), subst) } else { let subst = GenericSubstitution::new( f_in_trait.into(), subs, - self.trait_environment(db), + self.type_owner, ); (AssocItem::Function(f_in_trait.into()), Some(subst)) } @@ -1083,11 +1100,8 @@ impl<'db> SourceAnalyzer<'db> { CandidateId::ConstId(const_id) => { let (konst, subst) = self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs); - let subst = GenericSubstitution::new( - konst.into(), - subst, - self.trait_environment(db), - ); + let subst = + GenericSubstitution::new(konst.into(), subst, self.type_owner); (AssocItem::Const(konst.into()), Some(subst)) } }; @@ -1111,20 +1125,13 @@ impl<'db> SourceAnalyzer<'db> { CandidateId::ConstId(const_id) => { let (konst, subst) = self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs); - let subst = GenericSubstitution::new( - konst.into(), - subst, - self.trait_environment(db), - ); + let subst = + GenericSubstitution::new(konst.into(), subst, self.type_owner); (AssocItemId::from(konst), subst) } CandidateId::FunctionId(function_id) => ( function_id.into(), - GenericSubstitution::new( - function_id.into(), - subs, - self.trait_environment(db), - ), + GenericSubstitution::new(function_id.into(), subs, self.type_owner), ), }; return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst))); @@ -1328,12 +1335,11 @@ impl<'db> SourceAnalyzer<'db> { } else { return None; }; - let env = self.trait_environment(db); let (subst, expected_resolution) = match ty.kind() { TyKind::Adt(adt_def, subst) => { let adt_id = adt_def.def_id(); ( - GenericSubstitution::new(adt_id.into(), subst, env), + GenericSubstitution::new(adt_id.into(), subst, self.type_owner), PathResolution::Def(ModuleDef::Adt(adt_id.into())), ) } @@ -1344,7 +1350,7 @@ impl<'db> SourceAnalyzer<'db> { }) => { let assoc_id = def_id.0; ( - GenericSubstitution::new(assoc_id.into(), args, env), + GenericSubstitution::new(assoc_id.into(), args, self.type_owner), PathResolution::Def(ModuleDef::TypeAlias(assoc_id.into())), ) } @@ -1355,7 +1361,7 @@ impl<'db> SourceAnalyzer<'db> { CallableDefId::EnumVariantId(_) => return None, }; ( - GenericSubstitution::new(generic_def_id, subst, env), + GenericSubstitution::new(generic_def_id, subst, self.type_owner), PathResolution::Def(ModuleDefId::from(fn_id.0).into()), ) } @@ -1474,7 +1480,7 @@ impl<'db> SourceAnalyzer<'db> { .map(|local_id| { let field = FieldId { parent: variant, local_id }; let ty = field_types[local_id].get().instantiate(interner, substs).skip_norm_wip(); - (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty)) + (field.into(), self.ty(ty)) }) .collect() } diff --git a/crates/hir/src/term_search/expr.rs b/crates/hir/src/term_search/expr.rs index e3d0121e4912..a824c8bdca5d 100644 --- a/crates/hir/src/term_search/expr.rs +++ b/crates/hir/src/term_search/expr.rs @@ -310,21 +310,18 @@ impl<'db> Expr<'db> { Expr::Local(it) => it.ty(db), Expr::ConstParam(it) => it.ty(db), Expr::FamousType { ty, .. } => ty.clone(), - Expr::Function { func, generics, .. } => { - func.ret_type_with_args(db, generics.iter().cloned()) - } - Expr::Method { func, generics, target, .. } => func.ret_type_with_args( - db, - target.ty(db).type_arguments().chain(generics.iter().cloned()), - ), + Expr::Function { func, generics, .. } => func.ret_type(db).instantiate(generics), + Expr::Method { func, generics, target, .. } => func + .ret_type(db) + .instantiate(target.ty(db).type_arguments().chain(generics.iter().cloned())), Expr::Variant { variant, generics, .. } => { - Adt::from(variant.parent_enum(db)).ty_with_args(db, generics.iter().cloned()) + Adt::from(variant.parent_enum(db)).ty(db).instantiate(generics) } Expr::Struct { strukt, generics, .. } => { - Adt::from(*strukt).ty_with_args(db, generics.iter().cloned()) + Adt::from(*strukt).ty(db).instantiate(generics) } Expr::Tuple { ty, .. } => ty.clone(), - Expr::Field { expr, field } => field.ty_with_args(db, expr.ty(db).type_arguments()), + Expr::Field { expr, field } => field.ty(db).instantiate(expr.ty(db).type_arguments()), Expr::Reference(it) => it.ty(db), Expr::Many(ty) => ty.clone(), } diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs index 67b6fd64c1e6..2b7f7da3bf0d 100644 --- a/crates/hir/src/term_search/tactics.rs +++ b/crates/hir/src/term_search/tactics.rs @@ -10,18 +10,13 @@ use std::iter; -use hir_ty::{ - db::HirDatabase, - mir::BorrowKind, - next_solver::{DbInterner, Ty}, -}; +use hir_ty::{db::HirDatabase, mir::BorrowKind}; use itertools::Itertools; use rustc_hash::FxHashSet; -use rustc_type_ir::inherent::Ty as _; use crate::{ - Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef, - Type, TypeParam, term_search::Expr, + Adt, AssocItem, BuiltinType, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, + ModuleDef, ScopeDef, Type, TypeParam, term_search::Expr, }; use super::{LookupTable, NewTypesKey, TermSearchCtx}; @@ -87,7 +82,7 @@ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( return None; } - ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr) + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(expr) }) } @@ -137,7 +132,7 @@ pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>( lookup.insert(ty.clone(), std::iter::once(expr.clone())); - ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr) + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(expr) }) } @@ -202,7 +197,9 @@ pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( // Early exit if some param cannot be filled from lookup let param_exprs: Vec>> = fields .into_iter() - .map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned()))) + .map(|field| { + lookup.find(db, &field.ty(db).instantiate(generics.iter().cloned())) + }) .collect::>()?; // Note that we need special case for 0 param constructors because of multi cartesian @@ -252,7 +249,7 @@ pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( .fields(db) .into_iter() .map(|field| { - lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())) + lookup.find(db, &field.ty(db).instantiate(generics.iter().cloned())) }) .collect::>()?; @@ -285,7 +282,9 @@ pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( } Adt::Union(_) => None, }) - .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) + .filter_map(|(ty, exprs)| { + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(exprs) + }) .flatten() } @@ -364,7 +363,7 @@ pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( }) .collect::>()?; - let ret_ty = it.ret_type_with_args(db, generics.iter().cloned()); + let ret_ty = it.ret_type(db).instantiate(generics.iter().cloned()); // Filter out private and unsafe functions if !it.is_visible_from(db, module) || it.is_unsafe_to_call( @@ -381,10 +380,10 @@ pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( // Early exit if some param cannot be filled from lookup let param_exprs: Vec>> = it - .params_without_self_with_args(db, generics.iter().cloned()) + .params_without_self(db) .into_iter() .map(|field| { - let ty = field.ty(); + let ty = &field.ty().instantiate(&generics); match ty.is_mutable_reference() { true => None, false => lookup.find_autoref(db, ty), @@ -418,7 +417,9 @@ pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( _ => None, }) .flatten() - .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) + .filter_map(|(ty, exprs)| { + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(exprs) + }) .flatten() } @@ -493,7 +494,7 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( return None; } - let ret_ty = it.ret_type_with_args(db, ty.type_arguments()); + let ret_ty = it.ret_type(db).instantiate(ty.type_arguments()); // Filter out functions that return references if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr() { @@ -501,12 +502,12 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( } // Ignore functions that do not change the type - if ty.could_unify_with_deeply(db, &ret_ty) { + if ty.instantiate_with_errors().could_unify_with_deeply(db, &ret_ty) { return None; } let self_ty = - it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments()); + it.self_param(db).expect("No self param").ty(db).instantiate(ty.type_arguments()); // Ignore functions that have different self type if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) { @@ -517,9 +518,9 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( // Early exit if some param cannot be filled from lookup let param_exprs: Vec>> = it - .params_without_self_with_args(db, ty.type_arguments()) + .params_without_self(db) .into_iter() - .map(|field| lookup.find_autoref(db, field.ty())) + .map(|field| lookup.find_autoref(db, &field.ty().instantiate(ty.type_arguments()))) .collect::>()?; let generics: Vec<_> = ty.type_arguments().collect(); @@ -540,7 +541,9 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( Some((ret_ty, fn_exprs)) }) - .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) + .filter_map(|(ty, exprs)| { + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(exprs) + }) .flatten() } @@ -581,7 +584,9 @@ pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>( Some((filed_ty, exprs)) }) }) - .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) + .filter_map(|(ty, exprs)| { + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(exprs) + }) .flatten() } @@ -604,20 +609,18 @@ pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; - let module = ctx.scope.module(); - let interner = DbInterner::new_no_crate(db); - let bool_ty = Ty::new_bool(interner); - let unit_ty = Ty::new_unit(interner); + let bool_ty = BuiltinType::bool().ty(db); + let unit_ty = Type::new_unit(); [ - Expr::FamousType { ty: Type::new(db, module.id, bool_ty), value: "true" }, - Expr::FamousType { ty: Type::new(db, module.id, bool_ty), value: "false" }, - Expr::FamousType { ty: Type::new(db, module.id, unit_ty), value: "()" }, + Expr::FamousType { ty: bool_ty.clone(), value: "true" }, + Expr::FamousType { ty: bool_ty, value: "false" }, + Expr::FamousType { ty: unit_ty, value: "()" }, ] .into_iter() .inspect(|exprs| { lookup.insert(exprs.ty(db), std::iter::once(exprs.clone())); }) - .filter(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal)) + .filter(|expr| expr.ty(db).instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal)) } /// # Impl static method (without self type) tactic @@ -691,7 +694,7 @@ pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( return None; } - let ret_ty = it.ret_type_with_args(db, ty.type_arguments()); + let ret_ty = it.ret_type(db).instantiate(ty.type_arguments()); // Filter out functions that return references if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr() { @@ -700,9 +703,9 @@ pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( // Early exit if some param cannot be filled from lookup let param_exprs: Vec>> = it - .params_without_self_with_args(db, ty.type_arguments()) + .params_without_self(db) .into_iter() - .map(|field| lookup.find_autoref(db, field.ty())) + .map(|field| lookup.find_autoref(db, &field.ty().instantiate(ty.type_arguments()))) .collect::>()?; // Note that we need special case for 0 param constructors because of multi cartesian @@ -722,7 +725,9 @@ pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( Some((ret_ty, fn_exprs)) }) - .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) + .filter_map(|(ty, exprs)| { + ty.instantiate_with_errors().could_unify_with_deeply(db, &ctx.goal).then_some(exprs) + }) .flatten() } @@ -745,7 +750,6 @@ pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; - let module = ctx.scope.module(); lookup .types_wishlist() @@ -774,7 +778,7 @@ pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( .filter(|_| should_continue()) .map(|params| { let tys: Vec> = params.iter().map(|it| it.ty(db)).collect(); - let tuple_ty = Type::new_tuple(db, module.krate(db).into(), &tys); + let tuple_ty = Type::new_tuple(db, &tys); let expr = Expr::Tuple { ty: tuple_ty.clone(), params }; lookup.insert(tuple_ty, iter::once(expr.clone())); @@ -785,5 +789,10 @@ pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( Some(exprs) }) .flatten() - .filter_map(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal).then_some(expr)) + .filter_map(|expr| { + expr.ty(db) + .instantiate_with_errors() + .could_unify_with_deeply(db, &ctx.goal) + .then_some(expr) + }) } diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 667a1d7813c5..632fe0d72cfa 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -80,16 +80,25 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_, let module = scope.module(); let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(scope.krate())); let self_ty = if ctx.config.prefer_self_ty { - scope.expression_store_owner().and_then(|def| { - match def { - hir::ExpressionStoreOwner::Body(def_with_body) => { - def_with_body.as_assoc_item(ctx.db()) + scope + .expression_store_owner() + .and_then(|def| { + match def { + hir::ExpressionStoreOwner::Body(def_with_body) => { + def_with_body.as_assoc_item(ctx.db()) + } + hir::ExpressionStoreOwner::Signature(def) => def.as_assoc_item(ctx.db()), + hir::ExpressionStoreOwner::VariantFields(_) => None, + }? + .implementing_ty(ctx.db()) + }) + .map(|self_ty| { + if let Some(owner) = scope.generic_def() { + self_ty.try_rebase_into_owner(ctx.db(), owner).unwrap() + } else { + self_ty } - hir::ExpressionStoreOwner::Signature(def) => def.as_assoc_item(ctx.db()), - hir::ExpressionStoreOwner::VariantFields(_) => None, - }? - .implementing_ty(ctx.db()) - }) + }) } else { None }; @@ -613,7 +622,7 @@ fn build_pat( hir::StructKind::Tuple => { let mut name_generator = suggest_name::NameGenerator::default(); let pats = fields.into_iter().map(|f| { - let name = name_generator.for_type(&f.ty(db).to_type(db), db, edition); + let name = name_generator.for_type(&f.ty(db), db, edition); match name { Some(name) => make.ident_pat(false, false, make.name(&name)).into(), None => make.wildcard_pat().into(), diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index ac0bae7cd9b1..a2ca251c5a65 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -293,7 +293,7 @@ pub(crate) fn relevance_score( if let Some(ty) = ty { if ty == *expected { score = 100000; - } else if ty.could_unify_with(ctx.db(), expected) { + } else if ty.could_unify_with(ctx.db(), &expected.instantiate_with_errors()) { score = 10000; } } diff --git a/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/crates/ide-assists/src/handlers/expand_rest_pattern.rs index 4aa11b4e03c8..8ae322c02003 100644 --- a/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -137,13 +137,7 @@ fn expand_tuple_struct_rest_pattern( pat.fields() .take(prefix_count) .chain(fields[prefix_count..fields.len() - suffix_count].iter().map(|f| { - gen_unnamed_pat( - ctx, - make, - &mut name_gen, - &f.ty(ctx.db()).to_type(ctx.sema.db), - f.index(), - ) + gen_unnamed_pat(ctx, make, &mut name_gen, &f.ty(ctx.db()), f.index()) })) .chain(pat.fields().skip(prefix_count + 1)), ); diff --git a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index 52df6182ac56..1617016172d0 100644 --- a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -1,4 +1,3 @@ -use hir::next_solver::{DbInterner, TypingMode}; use ide_db::{RootDatabase, famous_defs::FamousDefs}; use syntax::ast::{self, AstNode, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory}; use syntax::syntax_editor::Position; @@ -159,16 +158,12 @@ fn existing_from_impl( let variant = sema.to_def(variant)?; let krate = variant.module(db).krate(db); let from_trait = FamousDefs(sema, krate).core_convert_From()?; - let interner = DbInterner::new_with(db, krate.base()); - use hir::next_solver::infer::DbInternerInferExt; - let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); - let variant = variant.instantiate_infer(&infcx); let enum_ = variant.parent_enum(sema.db); let field_ty = variant.fields(sema.db).first()?.ty(sema.db); let enum_ty = enum_.ty(sema.db); tracing::debug!(?enum_, ?field_ty, ?enum_ty); - enum_ty.impls_trait(infcx, from_trait, &[field_ty]).then_some(()) + enum_ty.has_any_impl(db, from_trait, &[field_ty]).then_some(()) } #[cfg(test)] diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index 4348dfa212c7..d5629e2e7e07 100644 --- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -1,4 +1,3 @@ -use hir::next_solver::{DbInterner, TypingMode}; use hir::{HasCrate, ModuleDef, Semantics}; use ide_db::use_trivial_constructor::use_trivial_constructor_with_factory; use ide_db::{ @@ -233,15 +232,11 @@ fn from_impl_exists( let strukt = sema.to_def(strukt)?; let krate = strukt.krate(db); let from_trait = FamousDefs(sema, krate).core_convert_From()?; - let interner = DbInterner::new_with(db, krate.base()); - use hir::next_solver::infer::DbInternerInferExt; - let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); - let strukt = strukt.instantiate_infer(&infcx); let field_ty = strukt.fields(db).get(main_field_i)?.ty(db); let struct_ty = strukt.ty(db); tracing::debug!(?strukt, ?field_ty, ?struct_ty); - struct_ty.impls_trait(infcx, from_trait, &[field_ty]).then_some(()) + struct_ty.has_any_impl(db, from_trait, &[field_ty]).then_some(()) } #[cfg(test)] diff --git a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs index 22b8861e5f54..17ee8597c102 100644 --- a/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs +++ b/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs @@ -67,11 +67,14 @@ pub(crate) fn replace_with_lazy_method( let editor = builder.make_editor(call.syntax()); let add_param = match &*method_name_lazy { "and_then" => true, - "or_else" | "unwrap_or_else" => { - FamousDefs(&ctx.sema, scope.krate()).core_result_Result().is_some_and( - |result| result.ty(ctx.db()).could_unify_with(ctx.db(), &receiver_ty), - ) - } + "or_else" | "unwrap_or_else" => FamousDefs(&ctx.sema, scope.krate()) + .core_result_Result() + .is_some_and(|result| { + result + .ty(ctx.db()) + .instantiate_with_errors() + .could_unify_with(ctx.db(), &receiver_ty) + }), _ => false, }; let closured = into_closure(&last_arg, add_param, editor.make()); diff --git a/crates/ide-assists/src/handlers/wrap_return_type.rs b/crates/ide-assists/src/handlers/wrap_return_type.rs index f9c103aab8f1..032cc28858c2 100644 --- a/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -92,7 +92,7 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_, '_>) - }; let semantic_ty = ty_constructor .map(|ty_constructor| { - hir::Adt::from(ty_constructor).ty_with_args(ctx.db(), [ty.clone()]) + hir::Adt::from(ty_constructor).ty(ctx.db()).instantiate([ty.clone()]) }) .unwrap_or_else(|| ty.clone()); (ast_ty, semantic_ty) @@ -256,7 +256,7 @@ fn wrapper_alias<'db>( ); let new_ty = - hir::Adt::from(enum_ty).ty_with_args(ctx.db(), [semantic_ret_type.clone()]); + hir::Adt::from(enum_ty).ty(ctx.db()).instantiate([semantic_ret_type.clone()]); Some((make.ty_path(path), new_ty)) }) diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index f3190bbbc82e..20048ea97b2c 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -199,10 +199,10 @@ impl Completions { item.add_to(self, ctx.db); } - pub(crate) fn add_expr( + pub(crate) fn add_expr<'db>( &mut self, - ctx: &CompletionContext<'_, '_>, - expr: &hir::term_search::Expr<'_>, + ctx: &CompletionContext<'_, 'db>, + expr: &hir::term_search::Expr<'db>, ) { if let Some(item) = render_expr(ctx, expr) { item.add_to(self, ctx.db) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index a2a4cbac2161..506662ca7237 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -182,6 +182,9 @@ pub(crate) fn complete_expr_path( } _ => return, }; + // Note: this is not *required* here, we do it to also find methods that require + // the type to be instantiated with specific types. + let ty = ty.instantiate_with_errors(); if let Some(hir::Adt::Enum(e)) = ty.as_adt() { cov_mark::hit!(completes_variant_through_alias); diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs index 1238a91dad87..48a51690271b 100644 --- a/crates/ide-completion/src/completions/record.rs +++ b/crates/ide-completion/src/completions/record.rs @@ -28,11 +28,7 @@ pub(crate) fn complete_record_pattern_fields( record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some(); match were_fields_specified { - false => un - .fields(ctx.db) - .into_iter() - .map(|f| (f, f.ty(ctx.db).to_type(ctx.db))) - .collect(), + false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), true => return, } } @@ -60,11 +56,7 @@ pub(crate) fn complete_record_expr_fields( record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some(); match were_fields_specified { - false => un - .fields(ctx.db) - .into_iter() - .map(|f| (f, f.ty(ctx.db).to_type(ctx.db))) - .collect(), + false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(), true => return, } } diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index f7fced3f062e..1579ad2477ce 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -729,6 +729,13 @@ impl<'db> CompletionContext<'_, 'db> { vec![] } } + + pub(crate) fn rebase_ty(&self, ty: &hir::Type<'db>) -> hir::Type<'db> { + self.scope + .generic_def() + .and_then(|def| ty.try_rebase_into_owner(self.db, def)) + .unwrap_or_else(|| ty.instantiate_with_errors()) + } } // CompletionContext construction diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 6be981361929..b213b34311d0 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -648,6 +648,16 @@ fn expected_type_and_name<'db>( _ => ty, }; + let mut generic_def = None; + let mut rebase_ty = { + let node = node.clone(); + move |ty: hir::Type<'db>| { + let def = *generic_def + .get_or_insert_with(|| sema.scope(&node).and_then(|scope| scope.generic_def())); + def.and_then(|def| ty.try_rebase_into_owner(sema.db, def)) + .unwrap_or_else(|| ty.instantiate_with_errors()) + } + }; let (ty, name) = loop { break match_ast! { match node { @@ -797,20 +807,20 @@ fn expected_type_and_name<'db>( _ => None, }); let nr = it.fields().take_while(|it| it.syntax().text_range().end() <= token.text_range().start()).count(); - let ty = fields.and_then(|fields| Some(fields.get(nr)?.ty(sema.db).to_type(sema.db))); + let ty = fields.and_then(|fields| Some(rebase_ty(fields.get(nr)?.ty(sema.db)))); (ty, None) }, ast::Fn(it) => { cov_mark::hit!(expected_type_fn_ret_with_leading_char); cov_mark::hit!(expected_type_fn_ret_without_leading_char); let def = sema.to_def(&it); - (def.map(|def| def.ret_type(sema.db)), None) + (def.map(|def| rebase_ty(def.ret_type(sema.db))), None) }, ast::ReturnExpr(it) => { let fn_ = sema.ancestors_with_macros(it.syntax().clone()) .find_map(Either::::cast); let ty = fn_.and_then(|f| match f { - Either::Left(f) => Some(sema.to_def(&f)?.ret_type(sema.db)), + Either::Left(f) => Some(rebase_ty(sema.to_def(&f)?.ret_type(sema.db))), Either::Right(f) => { let ty = sema.type_of_expr(&f.into())?.original.as_callable(sema.db)?; Some(ty.return_type()) diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index e2bfb7909e66..dc121bd5b2d2 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -71,7 +71,7 @@ impl<'a, 'db> RenderContext<'a, 'db> { self.completion.config.snippet_cap } - fn db(&self) -> &'a RootDatabase { + fn db(&self) -> &'db RootDatabase { self.completion.db } @@ -294,9 +294,9 @@ pub(crate) fn render_resolution_with_import_pat( Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution)) } -pub(crate) fn render_expr( - ctx: &CompletionContext<'_, '_>, - expr: &hir::term_search::Expr<'_>, +pub(crate) fn render_expr<'db>( + ctx: &CompletionContext<'_, 'db>, + expr: &hir::term_search::Expr<'db>, ) -> Option { let mut i = 1; let mut snippet_formatter = |ty: &hir::Type<'_>| { @@ -341,7 +341,7 @@ pub(crate) fn render_expr( "Autogenerated expression by term search", ))); item.set_relevance(crate::CompletionRelevance { - type_match: compute_type_match(ctx, &expr.ty(ctx.db)), + type_match: compute_type_match(ctx, &ctx.rebase_ty(&expr.ty(ctx.db))), ..Default::default() }); for trait_ in expr.traits_used(ctx.db) { @@ -405,8 +405,8 @@ fn render_resolution_pat( } } -fn render_resolution_path( - ctx: RenderContext<'_, '_>, +fn render_resolution_path<'db>( + ctx: RenderContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, import_to_add: Option, @@ -480,11 +480,12 @@ fn render_resolution_path( } adds_ret_type_arrow(completion, path_ctx, &mut item, insert_text.into()); - let mut set_item_relevance = |ty: Type<'_>| { + let mut set_item_relevance = |ty: Type<'db>| { if !ty.is_unknown() { item.detail(ty.display(db, krate).to_string()); } + let ty = completion.rebase_ty(&ty); item.set_relevance(CompletionRelevance { type_match: compute_type_match(completion, &ty), exact_name_match: compute_exact_name_match(completion, &name), @@ -688,8 +689,8 @@ fn compute_type_match( // &mut ty -> &ty if completion_ty.is_mutable_reference() - && let Some(expected_type) = expected_type.remove_ref() - && let Some(completion_ty) = completion_ty.remove_ref() + && let Some((expected_type, _)) = expected_type.as_reference() + && let Some((completion_ty, _)) = completion_ty.as_reference() { return match_types(ctx, &expected_type, &completion_ty); } @@ -718,12 +719,12 @@ fn compute_ref_match( completion_ty: &hir::Type<'_>, ) -> Option { let expected_type = ctx.expected_type.as_ref()?; - let expected_without_ref = expected_type.remove_ref(); - let completion_without_ref = completion_ty.remove_ref(); + let expected_without_ref = expected_type.as_reference(); + let completion_without_ref = completion_ty.as_reference(); if expected_type.could_unify_with(ctx.db, completion_ty) { return None; } - if let Some(expected_without_ref) = &expected_without_ref + if let Some((expected_without_ref, _)) = &expected_without_ref && (completion_without_ref.is_none() || completion_ty.could_unify_with(ctx.db, expected_without_ref)) && completion_ty @@ -739,7 +740,7 @@ fn compute_ref_match( return Some(CompletionItemRefMode::Reference(mutability)); } - if let Some(completion_without_ref) = completion_without_ref + if let Some((completion_without_ref, _)) = completion_without_ref && completion_without_ref == *expected_type && completion_without_ref.is_copy(ctx.db) { @@ -952,9 +953,9 @@ fn main() { } "#, expect![[r#" - st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type_could_unify] - ex dep::test_mod_b::Struct { } [type_could_unify] - st Struct Struct [type_could_unify+requires_import] + st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type] + ex dep::test_mod_b::Struct { } [type] + st Struct Struct [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Struct) [] @@ -992,7 +993,7 @@ fn main() { } "#, expect![[r#" - un Union Union [type_could_unify+requires_import] + un Union Union [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Union) [] @@ -1028,9 +1029,9 @@ fn main() { } "#, expect![[r#" - ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type_could_unify] - ex dep::test_mod_b::Enum::variant [type_could_unify] - en Enum Enum [type_could_unify+requires_import] + ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type] + ex dep::test_mod_b::Enum::variant [type] + en Enum Enum [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Enum) [] @@ -1066,8 +1067,8 @@ fn main() { } "#, expect![[r#" - ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type_could_unify] - ex dep::test_mod_b::Enum::Variant [type_could_unify] + ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type] + ex dep::test_mod_b::Enum::Variant [type] md dep:: [] fn main() fn() [] fn test(…) fn(Enum) [] @@ -1130,7 +1131,7 @@ fn main() { } "#, expect![[r#" - ct CONST i32 [type_could_unify+requires_import] + ct CONST i32 [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(i32) [] @@ -1162,7 +1163,7 @@ fn main() { } "#, expect![[r#" - sc STATIC i32 [type_could_unify+requires_import] + sc STATIC i32 [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(i32) [] @@ -2947,7 +2948,7 @@ fn main() { st &mut S(…) [type] lc ssss S [local] lc &mut ssss [type+local] - st S S<{unknown}> [] + st S S [] fn foo(…) fn(&mut S) [] fn main() fn() [] "#]], @@ -2970,7 +2971,7 @@ fn main() { expect![[r#" ex ssss.0 [type_could_unify] lc ssss S<{unknown}> [local] - st S S<{unknown}> [] + st S S [] md core:: [] fn foo(…) fn(&u32) [] fn main() fn() [] @@ -3718,9 +3719,9 @@ fn foo() { lc foo Foo [type+local] ex Foo::B [type] ex foo [type] - en Foo Foo<{unknown}> [type_could_unify] + en Foo Foo [type_could_unify] + fn baz() fn() -> Foo [type_could_unify] fn bar() fn() -> Foo [] - fn baz() fn() -> Foo [] fn foo() fn() [] "#]], ); @@ -3750,6 +3751,7 @@ fn main() { &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)], expect![[r#" sn not !expr [snippet] + me not() fn(self) -> ::Output [type_could_unify+requires_import] sn box Box::new(expr) [] sn call function(expr) [] sn const const {} [] @@ -3763,7 +3765,6 @@ fn main() { sn return return expr [] sn unsafe unsafe {} [] sn while while expr {} [] - me not() fn(self) -> ::Output [requires_import] "#]], ); } @@ -3814,7 +3815,7 @@ enum Foo { en Foo Foo [] st Other Other [] sp Self Foo [] - st Vec<…> Vec<{unknown}> [] + st Vec<…> Vec [] "#]], ); } diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 97d5a25f493d..fe592ab9e99f 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -76,7 +76,7 @@ fn render( completion.edition, ); - let ret_type = func.ret_type(db); + let ret_type = ctx.completion.rebase_ty(&func.ret_type(db)); let assoc_item = func.as_assoc_item(db); let trait_info = @@ -107,6 +107,7 @@ fn render( let function = assoc_item .and_then(|assoc_item| assoc_item.implementing_ty(db)) + .map(|self_type| ctx.completion.rebase_ty(&self_type)) .map(|self_type| compute_return_type_match(db, &ctx, self_type, &ret_type)) .map(|return_type| CompletionRelevanceFn { has_params: has_self_param || func.num_params(db) > 0, @@ -118,7 +119,7 @@ fn render( type_match: if has_call_parens || complete_call_parens.is_some() { compute_type_match(completion, &ret_type) } else { - compute_type_match(completion, &func.ty(db)) + compute_type_match(completion, &ctx.completion.rebase_ty(&func.ty(db))) }, exact_name_match: compute_exact_name_match(completion, &call), function, @@ -287,7 +288,7 @@ pub(super) fn add_call_parens<'b>( } fn ref_of_param(ctx: &CompletionContext<'_, '_>, arg: &str, ty: &hir::Type<'_>) -> &'static str { - if let Some(derefed_ty) = ty.remove_ref() { + if let Some(derefed_ty) = ty.as_reference_inner() { for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) { if name.as_str() == arg { return if local.ty(ctx.db) == derefed_ty { diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs index 9e0cec62e641..943ff5821969 100644 --- a/crates/ide-completion/src/render/literal.rs +++ b/crates/ide-completion/src/render/literal.rs @@ -127,7 +127,7 @@ fn render( item.set_documentation(thing.docs(db)).set_deprecated(thing.is_deprecated(&ctx)); - let ty = thing.ty(db); + let ty = ctx.completion.rebase_ty(&thing.ty(db)); item.set_relevance(CompletionRelevance { type_match: compute_type_match(ctx.completion, &ty), // function is a misnomer here, this is more about constructor information diff --git a/crates/ide-completion/src/render/pattern.rs b/crates/ide-completion/src/render/pattern.rs index 392ecbc302ae..7e70aa13d422 100644 --- a/crates/ide-completion/src/render/pattern.rs +++ b/crates/ide-completion/src/render/pattern.rs @@ -103,17 +103,18 @@ pub(crate) fn render_variant_pat( )) } -fn build_completion( - ctx: RenderContext<'_, '_>, +fn build_completion<'db>( + ctx: RenderContext<'_, 'db>, label: SmolStr, lookup: SmolStr, pat: String, def: impl HasDocs, - adt_ty: hir::Type<'_>, + adt_ty: hir::Type<'db>, // Missing in context of match statement completions is_variant_missing: bool, ) -> CompletionItem { let mut relevance = ctx.completion_relevance(); + let adt_ty = ctx.completion.rebase_ty(&adt_ty); if is_variant_missing { relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty); diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs index f86af6cdcb7d..8d1b88596982 100644 --- a/crates/ide-completion/src/render/variant.rs +++ b/crates/ide-completion/src/render/variant.rs @@ -32,7 +32,7 @@ pub(crate) fn render_record_lit( if let Some(local) = ctx.locals.get(&field_name) && local .ty(ctx.db) - .could_unify_with_deeply(ctx.db, &field.ty(ctx.db).to_type(ctx.db)) + .could_unify_with_deeply(ctx.db, &ctx.rebase_ty(&field.ty(ctx.db))) { f(&format_args!("{}{tab}", field_name.display(ctx.db, ctx.edition))) } else { diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index c26c4c2ff846..82c1b5f60bf3 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -3119,8 +3119,8 @@ fn bar() { } "#, expect![[r#" - en Option Option<{unknown}> - en Result Result<{unknown}, {unknown}> + en Option Option + en Result Result fn bar() fn() lc i i32 ma const_format_args!(…) macro_rules! const_format_args diff --git a/crates/ide-completion/src/tests/predicate.rs b/crates/ide-completion/src/tests/predicate.rs index 9826a8ed7b33..3f3a6f4cf574 100644 --- a/crates/ide-completion/src/tests/predicate.rs +++ b/crates/ide-completion/src/tests/predicate.rs @@ -14,7 +14,7 @@ struct Foo<'lt, T, const C: usize> where $0 {} en Enum Enum ma makro!(…) macro_rules! makro md module:: - st Foo<…> Foo<'_, {unknown}, _> + st Foo<…> Foo<'lt, T, C> st Record Record st Tuple Tuple st Unit Unit @@ -91,7 +91,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {} en Enum Enum ma makro!(…) macro_rules! makro md module:: - st Foo<…> Foo<'_, {unknown}, _> + st Foo<…> Foo<'lt, T, C> st Record Record st Tuple Tuple st Unit Unit diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs index 24080334ae9b..ad058901c047 100644 --- a/crates/ide-completion/src/tests/type_pos.rs +++ b/crates/ide-completion/src/tests/type_pos.rs @@ -15,8 +15,8 @@ struct Foo<'lt, T, const C: usize> { en Enum Enum ma makro!(…) macro_rules! makro md module:: - sp Self Foo<'_, {unknown}, _> - st Foo<…> Foo<'_, {unknown}, _> + sp Self Foo<'lt, T, C> + st Foo<…> Foo<'lt, T, C> st Record Record st Tuple Tuple st Unit Unit @@ -44,8 +44,8 @@ struct Foo<'lt, T, const C: usize>(f$0); en Enum Enum ma makro!(…) macro_rules! makro md module:: - sp Self Foo<'_, {unknown}, _> - st Foo<…> Foo<'_, {unknown}, _> + sp Self Foo<'lt, T, C> + st Foo<…> Foo<'lt, T, C> st Record Record st Tuple Tuple st Unit Unit @@ -409,7 +409,7 @@ const FOO: $0 = Foo(2); en Enum Enum ma makro!(…) macro_rules! makro md module:: - st Foo<…> Foo<{unknown}> + st Foo<…> Foo st Record Record st Tuple Tuple st Unit Unit @@ -438,7 +438,7 @@ static FOO: $0 = Foo(2); en Enum Enum ma makro!(…) macro_rules! makro md module:: - st Foo<…> Foo<{unknown}> + st Foo<…> Foo st Record Record st Tuple Tuple st Unit Unit @@ -629,7 +629,7 @@ fn foo<'lt, T, const C: usize>() { en Enum Enum ma makro!(…) macro_rules! makro md module:: - st Foo<…> Foo<{unknown}> + st Foo<…> Foo st Record Record st Tuple Tuple st Unit Unit diff --git a/crates/ide-db/src/syntax_helpers/suggest_name.rs b/crates/ide-db/src/syntax_helpers/suggest_name.rs index 76fea5c2623c..15920595a827 100644 --- a/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -412,7 +412,7 @@ fn from_type( edition: Edition, ) -> Option { let ty = sema.type_of_expr(expr)?.adjusted(); - let ty = ty.remove_ref().unwrap_or(ty); + let ty = ty.strip_reference(); name_of_type(&ty, sema.db, edition) } @@ -445,7 +445,7 @@ fn name_of_type<'db>( return None; } name - } else if let Some(inner_ty) = ty.remove_ref() { + } else if let Some((inner_ty, _)) = ty.as_reference() { return name_of_type(&inner_ty, db, edition); } else if let Some(inner_ty) = ty.as_slice() { return Some(sequence_name(Some(&inner_ty), db, edition)); diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 08791fecbedb..678e45e145dc 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -127,7 +127,7 @@ fn add_missing_ok_or_some( let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" }; let wrapped_actual_ty = - expected_adt.ty_with_args(ctx.sema.db, std::iter::once(d.actual.clone())); + expected_adt.ty(ctx.sema.db).instantiate(std::iter::once(d.actual.clone())); if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) { return None; @@ -225,7 +225,7 @@ fn remove_unnecessary_wrapper( return None; } - let inner_type = variant.fields(db).first()?.ty_with_args(db, d.actual.type_arguments()); + let inner_type = variant.fields(db).first()?.ty(db).instantiate(d.actual.type_arguments()); if !d.expected.could_unify_with(db, &inner_type) { return None; } diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index ae208fe1b561..ffd144a827e3 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -88,7 +88,7 @@ pub(crate) fn goto_type_definition( ast::Pat(it) => sema.type_of_pat(&it)?.original, ast::SelfParam(it) => sema.type_of_self(&it)?, ast::Type(it) => sema.resolve_type(&it)?, - ast::RecordField(it) => sema.to_def(&it)?.ty(db).to_type(db), + ast::RecordField(it) => sema.to_def(&it)?.ty(db), // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise ast::NameRef(it) => { if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index df1fcecc991f..c3a8e0362fee 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -469,7 +469,7 @@ pub(crate) fn hover_for_definition( Definition::Local(it) => Some(it.ty(db)), Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), - Definition::Field(field) => Some(field.ty(db).to_type(db)), + Definition::Field(field) => Some(field.ty(db)), Definition::TupleField(it) => Some(it.ty(db)), Definition::Function(it) => Some(it.ty(db)), Definition::Adt(it) => Some(it.ty(db)), @@ -630,7 +630,7 @@ fn goto_type_action_for_def( let ty = match def { Definition::Local(it) => Some(it.ty(db)), - Definition::Field(field) => Some(field.ty(db).to_type(db)), + Definition::Field(field) => Some(field.ty(db)), Definition::TupleField(field) => Some(field.ty(db)), Definition::Const(it) => Some(it.ty(db)), Definition::Static(it) => Some(it.ty(db)), diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index e08bbc5c21b6..da4f185d7564 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -664,14 +664,14 @@ pub(super) fn definition( } let drop_info = match def { Definition::Field(field) => { - DropInfo { drop_glue: field.ty(db).to_type(db).drop_glue(db), has_dtor: None } + DropInfo { drop_glue: field.ty(db).drop_glue(db), has_dtor: None } } Definition::Adt(Adt::Struct(strukt)) => { - let struct_drop_glue = strukt.ty_params(db).drop_glue(db); + let struct_drop_glue = strukt.ty(db).drop_glue(db); let mut fields_drop_glue = strukt .fields(db) .iter() - .map(|field| field.ty(db).to_type(db).drop_glue(db)) + .map(|field| field.ty(db).drop_glue(db)) .max() .unwrap_or(DropGlue::None); let has_dtor = match (fields_drop_glue, struct_drop_glue) { @@ -688,10 +688,10 @@ pub(super) fn definition( // Unions cannot have fields with drop glue. Definition::Adt(Adt::Union(union)) => DropInfo { drop_glue: DropGlue::None, - has_dtor: Some(union.ty_params(db).drop_glue(db) != DropGlue::None), + has_dtor: Some(union.ty(db).drop_glue(db) != DropGlue::None), }, Definition::Adt(Adt::Enum(enum_)) => { - let enum_drop_glue = enum_.ty_params(db).drop_glue(db); + let enum_drop_glue = enum_.ty(db).drop_glue(db); let fields_drop_glue = enum_ .variants(db) .iter() @@ -699,7 +699,7 @@ pub(super) fn definition( variant .fields(db) .iter() - .map(|field| field.ty(db).to_type(db).drop_glue(db)) + .map(|field| field.ty(db).drop_glue(db)) .max() .unwrap_or(DropGlue::None) }) @@ -714,13 +714,13 @@ pub(super) fn definition( let fields_drop_glue = variant .fields(db) .iter() - .map(|field| field.ty(db).to_type(db).drop_glue(db)) + .map(|field| field.ty(db).drop_glue(db)) .max() .unwrap_or(DropGlue::None); DropInfo { drop_glue: fields_drop_glue, has_dtor: None } } Definition::TypeAlias(type_alias) => { - DropInfo { drop_glue: type_alias.ty_params(db).drop_glue(db), has_dtor: None } + DropInfo { drop_glue: type_alias.ty(db).drop_glue(db), has_dtor: None } } Definition::Local(local) => { DropInfo { drop_glue: local.ty(db).drop_glue(db), has_dtor: None } diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index b664187932ef..e220cbdce8d3 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -522,11 +522,11 @@ fn rename_to_self( }; let first_param_ty = first_param.ty(); let impl_ty = impl_.self_ty(sema.db); - let (ty, self_param) = if impl_ty.remove_ref().is_some() { + let (ty, self_param) = if impl_ty.is_reference() { // if the impl is a ref to the type we can just match the `&T` with self directly (first_param_ty.clone(), "self") } else { - first_param_ty.remove_ref().map_or((first_param_ty.clone(), "self"), |ty| { + first_param_ty.as_reference_inner().map_or((first_param_ty.clone(), "self"), |ty| { (ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" }) }) }; diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 7854a14187b3..0022c1148a14 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -535,7 +535,7 @@ fn signature_help_for_tuple_struct_pat( pat.syntax(), token, pat.fields(), - fields.into_iter().map(|it| it.ty(db).to_type(db)), + fields.into_iter().map(|it| it.ty(db)), display_target, )) } diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index 1b9df9722b07..03bde6f3e545 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -98,7 +98,7 @@ pub(crate) fn view_memory_layout( Definition::BuiltinType(it) => it.ty(db), Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), - Definition::Field(it) => it.ty(db).to_type(db), + Definition::Field(it) => it.ty(db), Definition::Const(it) => it.ty(db), Definition::Static(it) => it.ty(db), _ => return None, diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index ec5503fe39f5..1a036c3b9919 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -14,14 +14,16 @@ use hir::{ Adt, AssocItem, Crate, DefWithBody, FindPathConfig, GenericDef, HasCrate, HasSource, HirDisplay, ModuleDef, Name, Variant, crate_lang_items, db::{DefDatabase, ExpandDatabase, HirDatabase}, - next_solver::{DbInterner, GenericArgs}, }; use hir_def::{ DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, expr_store::{Body, BodySourceMap, ExpressionStore}, hir::{ExprId, PatId, generics::GenericParams}, }; -use hir_ty::InferenceResult; +use hir_ty::{ + InferenceResult, + next_solver::{DbInterner, GenericArgs}, +}; use ide::{ Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RaFixtureConfig, RootDatabase,