From 34f773f5964d92d5dcaa67cd403ac1b3e19e73b2 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 22 Sep 2025 17:38:31 -0400 Subject: [PATCH] Use ParamEnv in TraitEnvironment --- crates/hir-ty/src/autoderef.rs | 2 +- crates/hir-ty/src/chalk_ext.rs | 14 ++- crates/hir-ty/src/db.rs | 4 +- crates/hir-ty/src/display.rs | 5 +- crates/hir-ty/src/drop.rs | 7 +- crates/hir-ty/src/infer/closure.rs | 6 +- crates/hir-ty/src/infer/coerce.rs | 20 ++-- crates/hir-ty/src/infer/expr.rs | 5 +- crates/hir-ty/src/infer/unify.rs | 18 ++-- crates/hir-ty/src/lower.rs | 111 ++------------------- crates/hir-ty/src/lower_nextsolver.rs | 130 +++++++++++++++++++++++-- crates/hir-ty/src/method_resolution.rs | 21 +++- crates/hir-ty/src/tests/regression.rs | 2 +- crates/hir-ty/src/traits.rs | 18 +--- crates/hir/src/lib.rs | 11 ++- crates/ide-completion/src/tests.rs | 8 +- crates/ide/src/view_memory_layout.rs | 4 +- 17 files changed, 216 insertions(+), 170 deletions(-) diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index 4c79c800fc..21a86d3e43 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -298,7 +298,7 @@ fn structurally_normalize_ty<'db>( ) -> Option<(Ty<'db>, PredicateObligations<'db>)> { let mut ocx = ObligationCtxt::new(&table.infer_ctxt); let Ok(normalized_ty) = - ocx.structurally_normalize_ty(&ObligationCause::misc(), table.param_env, ty) + ocx.structurally_normalize_ty(&ObligationCause::misc(), table.trait_env.env, ty) else { // We shouldn't have errors here in the old solver, except for // evaluate/fulfill mismatches, but that's not a reason for an ICE. diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index 1faf9f66dc..6956a0a123 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -15,8 +15,13 @@ use crate::{ AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, ToChalk, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, - WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, + WhereClause, + db::HirDatabase, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, + generics::generics, + next_solver::{DbInterner, mapping::NextSolverToChalk}, + to_chalk_trait_id, + utils::ClosureSubst, }; pub trait TyExt { @@ -372,7 +377,10 @@ impl TyExt for Ty { let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); let env = db.trait_environment_for_body(owner); let goal = Canonical { - value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), + value: InEnvironment::new( + &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), + trait_ref.cast(Interner), + ), binders: CanonicalVarKinds::empty(Interner), }; !db.trait_solve(crate_id, None, goal).no_solution() diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 24e6171351..44f48069ab 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -182,12 +182,12 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; - #[salsa::invoke(crate::lower::trait_environment_for_body_query)] + #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> Arc>; - #[salsa::invoke(crate::lower::trait_environment_query)] + #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)] fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 02f3eb39a4..dc42304e1c 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -792,10 +792,7 @@ fn render_const_scalar_ns( let trait_env = TraitEnvironment::empty(f.krate()); let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis); - let ty = infcx - .at(&ObligationCause::new(), trait_env.env.to_nextsolver(interner)) - .deeply_normalize(ty) - .unwrap_or(ty); + let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, trait_env) } diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index 88a7d15d8e..413f70532a 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -7,6 +7,8 @@ use hir_def::signatures::StructFlags; use stdx::never; use triomphe::Arc; +use crate::next_solver::DbInterner; +use crate::next_solver::mapping::NextSolverToChalk; use crate::{ AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment, Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase, @@ -188,7 +190,10 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc>) -> bool }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build(); let goal = Canonical { - value: InEnvironment::new(&env.env, trait_ref.cast(Interner)), + value: InEnvironment::new( + &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), + trait_ref.cast(Interner), + ), binders: CanonicalVarKinds::empty(Interner), }; db.trait_solve(env.krate, env.block, goal).certain() diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 1d5d8dd13e..4a57b2f375 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -318,7 +318,7 @@ impl<'db> InferenceContext<'db> { _ = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.param_env) + .at(&ObligationCause::new(), self.table.trait_env.env) .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); @@ -703,7 +703,7 @@ impl<'db> InferenceContext<'db> { let cause = ObligationCause::new(); let InferOk { value: (), obligations } = table .infer_ctxt - .at(&cause, table.param_env) + .at(&cause, table.trait_env.env) .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?; all_obligations.extend(obligations); } @@ -711,7 +711,7 @@ impl<'db> InferenceContext<'db> { let supplied_output_ty = supplied_sig.output(); let cause = ObligationCause::new(); let InferOk { value: (), obligations } = - table.infer_ctxt.at(&cause, table.param_env).eq( + table.infer_ctxt.at(&cause, table.trait_env.env).eq( DefineOpaqueTypes::Yes, expected_sigs.liberated_sig.output(), supplied_output_ty, diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index 42948ccb93..219b519e46 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -144,7 +144,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { fn unify_raw(&mut self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|this| { - let at = this.infer_ctxt().at(&this.cause, this.table.param_env); + let at = this.infer_ctxt().at(&this.cause, this.table.trait_env.env); let res = if this.use_lub { at.lub(b, a) @@ -330,7 +330,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { obligations.push(Obligation::new( self.interner(), self.cause.clone(), - self.table.param_env, + self.table.trait_env.env, Binder::dummy(PredicateKind::Coerce(CoercePredicate { a: source_ty, b: target_ty, @@ -718,7 +718,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new( self.interner(), cause, - self.table.param_env, + self.table.trait_env.env, TraitRef::new( self.interner(), coerce_unsized_did.into(), @@ -1114,8 +1114,12 @@ impl<'db> InferenceContext<'db> { match self.table.commit_if_ok(|table| { // We need to eagerly handle nested obligations due to lazy norm. let mut ocx = ObligationCtxt::new(&table.infer_ctxt); - let value = - ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?; + let value = ocx.lub( + &ObligationCause::new(), + table.trait_env.env, + prev_ty, + new_ty, + )?; if ocx.select_where_possible().is_empty() { Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { @@ -1158,7 +1162,7 @@ impl<'db> InferenceContext<'db> { let sig = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.param_env) + .at(&ObligationCause::new(), self.table.trait_env.env) .lub(a_sig, b_sig) .map(|ok| self.table.register_infer_ok(ok))?; @@ -1248,7 +1252,7 @@ impl<'db> InferenceContext<'db> { .commit_if_ok(|table| { table .infer_ctxt - .at(&ObligationCause::new(), table.param_env) + .at(&ObligationCause::new(), table.trait_env.env) .lub(prev_ty, new_ty) }) .unwrap_err()) @@ -1498,7 +1502,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { assert!(expression_ty.is_unit(), "if let hack without unit type"); icx.table .infer_ctxt - .at(cause, icx.table.param_env) + .at(cause, icx.table.trait_env.env) .eq( // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs DefineOpaqueTypes::Yes, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index c5a51dfc4c..b4a332f1da 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -1662,7 +1662,6 @@ impl<'db> InferenceContext<'db> { }); self.resolver.reset_to_guard(g); if let Some(prev_env) = prev_env { - self.table.param_env = prev_env.env.to_nextsolver(self.table.interner); self.table.trait_env = prev_env; } @@ -2132,7 +2131,7 @@ impl<'db> InferenceContext<'db> { let origin = ObligationCause::new(); ocx.sup( &origin, - self.table.param_env, + self.table.trait_env.env, expected_output.to_nextsolver(interner), formal_output, )?; @@ -2239,7 +2238,7 @@ impl<'db> InferenceContext<'db> { let formal_ty_error = this .table .infer_ctxt - .at(&ObligationCause::new(), this.table.param_env) + .at(&ObligationCause::new(), this.table.trait_env.env) .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty); // If neither check failed, the types are compatible diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 1204fb06d2..6df9cbaa29 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -29,8 +29,8 @@ use crate::{ db::HirDatabase, fold_generic_args, fold_tys_and_consts, next_solver::{ - self, ClauseKind, DbInterner, ErrorGuaranteed, ParamEnv, Predicate, PredicateKind, - SolverDefIds, Term, TraitRef, + self, ClauseKind, DbInterner, ErrorGuaranteed, Predicate, PredicateKind, SolverDefIds, + Term, TraitRef, fulfill::FulfillmentCtxt, infer::{ DbInternerInferExt, InferCtxt, InferOk, @@ -213,7 +213,6 @@ pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, pub(crate) interner: DbInterner<'db>, pub(crate) trait_env: Arc>, - pub(crate) param_env: ParamEnv<'db>, pub(crate) tait_coercion_table: Option>, pub(crate) infer_ctxt: InferCtxt<'db>, diverging_tys: FxHashSet, @@ -235,7 +234,6 @@ impl<'db> InferenceTable<'db> { InferenceTable { db, interner, - param_env: trait_env.env.to_nextsolver(interner), trait_env, tait_coercion_table: None, fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt), @@ -426,7 +424,7 @@ impl<'db> InferenceTable<'db> { { let ty = self.resolve_vars_with_obligations(ty); self.infer_ctxt - .at(&ObligationCause::new(), self.param_env) + .at(&ObligationCause::new(), self.trait_env.env) .deeply_normalize(ty.clone()) .unwrap_or(ty) } @@ -741,7 +739,7 @@ impl<'db> InferenceTable<'db> { ) -> InferResult<'db, ()> { let variance = rustc_type_ir::Variance::Invariant; let span = crate::next_solver::Span::dummy(); - match self.infer_ctxt.relate(self.param_env, lhs, variance, rhs, span) { + match self.infer_ctxt.relate(self.trait_env.env, lhs, variance, rhs, span) { Ok(goals) => Ok(crate::infer::InferOk { goals, value: () }), Err(_) => Err(TypeError), } @@ -798,7 +796,7 @@ impl<'db> InferenceTable<'db> { fn structurally_normalize_term(&mut self, term: Term<'db>) -> Term<'db> { self.infer_ctxt - .at(&ObligationCause::new(), self.param_env) + .at(&ObligationCause::new(), self.trait_env.env) .structurally_normalize_term(term, &mut self.fulfillment_cx) .unwrap_or(term) } @@ -818,7 +816,7 @@ impl<'db> InferenceTable<'db> { // in a reentrant borrow, causing an ICE. let result = self .infer_ctxt - .at(&ObligationCause::misc(), self.param_env) + .at(&ObligationCause::misc(), self.trait_env.env) .structurally_normalize_ty(ty, &mut self.fulfillment_cx); match result { Ok(normalized_ty) => normalized_ty, @@ -874,14 +872,14 @@ impl<'db> InferenceTable<'db> { /// choice (during e.g. method resolution or deref). #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult { - let goal = next_solver::Goal { param_env: self.param_env, predicate }; + let goal = next_solver::Goal { param_env: self.trait_env.env, predicate }; let canonicalized = self.canonicalize(goal); next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = next_solver::Goal { param_env: self.param_env, predicate }; + let goal = next_solver::Goal { param_env: self.trait_env.env, predicate }; self.register_obligation_in_env(goal) } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index eeec9d0454..20f421dbbc 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -24,9 +24,9 @@ use chalk_ir::{ use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, - Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, + GenericDefId, GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, + StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, @@ -46,11 +46,10 @@ use stdx::{impl_from, never}; use triomphe::{Arc, ThinArc}; use crate::{ - AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DomainGoal, DynTy, FnAbi, - FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, - LifetimeData, LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses, - Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, - all_super_traits, + AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, + FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, + LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, + TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, all_super_traits, consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, db::HirDatabase, error_lifetime, @@ -1086,102 +1085,6 @@ pub(crate) fn generic_predicates_for_param_cycle_result( GenericPredicates(None) } -pub(crate) fn trait_environment_for_body_query( - db: &dyn HirDatabase, - def: DefWithBodyId, -) -> Arc> { - let Some(def) = def.as_generic_def_id(db) else { - let krate = def.module(db).krate(); - return TraitEnvironment::empty(krate); - }; - db.trait_environment(def) -} - -pub(crate) fn trait_environment_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> Arc> { - let generics = generics(db, def); - if generics.has_no_predicates() && generics.is_empty() { - return TraitEnvironment::empty(def.krate(db)); - } - - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_type_param_mode(ParamLoweringMode::Placeholder); - let mut traits_in_scope = Vec::new(); - let mut clauses = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - for pred in ctx.lower_where_predicate(pred, false) { - if let WhereClause::Implemented(tr) = pred.skip_binders() { - traits_in_scope - .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); - } - let program_clause: Binders = - pred.map(|pred| pred.into_from_env_goal(Interner).cast(Interner)); - clauses.push(program_clause); - } - } - } - - if let Some(trait_id) = def.assoc_trait_container(db) { - // add `Self: Trait` to the environment in trait - // function default implementations (and speculative code - // inside consts or type aliases) - cov_mark::hit!(trait_self_implements_self); - let substs = TyBuilder::placeholder_subst(db, trait_id); - let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; - let pred = WhereClause::Implemented(trait_ref); - clauses.push(Binders::empty( - Interner, - pred.cast::(Interner).into_from_env_goal(Interner), - )); - } - - let subst = generics.placeholder_subst(db); - if !subst.is_empty(Interner) { - let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_clauses) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - clauses.extend(implicitly_sized_clauses.map(|pred| { - Binders::empty( - Interner, - pred.into_from_env_goal(Interner).cast::(Interner), - ) - })); - }; - } - - let clauses = chalk_ir::ProgramClauses::from_iter( - Interner, - clauses.into_iter().map(|g| { - chalk_ir::ProgramClause::new( - Interner, - chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication { - consequence: g, - conditions: chalk_ir::Goals::empty(Interner), - constraints: chalk_ir::Constraints::empty(Interner), - priority: chalk_ir::ClausePriority::High, - })), - ) - }), - ); - let env = chalk_ir::Environment { clauses }; - - TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenericPredicates(Option]>>); diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs index 6ecf8874c4..1ca56feb09 100644 --- a/crates/hir-ty/src/lower_nextsolver.rs +++ b/crates/hir-ty/src/lower_nextsolver.rs @@ -19,9 +19,9 @@ use base_db::Crate; use either::Either; use hir_def::item_tree::FieldsShape; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId, - GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId, - TypeOrConstParamId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, + GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, + StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId, expr_store::{ ExpressionStore, path::{GenericArg, Path}, @@ -57,7 +57,7 @@ use triomphe::Arc; use crate::ValueTyDefId; use crate::{ - FnAbi, ImplTraitId, Interner, ParamKind, TyDefId, TyLoweringDiagnostic, + FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic}, db::HirDatabase, @@ -66,8 +66,10 @@ use crate::{ next_solver::{ AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind, BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder, - EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, - TraitPredicate, TraitRef, Ty, Tys, abi::Safety, mapping::ChalkToNextSolver, + EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region, + SolverDefId, TraitPredicate, TraitRef, Ty, Tys, + abi::Safety, + mapping::{ChalkToNextSolver, convert_ty_for_result}, }, }; @@ -1375,6 +1377,122 @@ impl<'db> ops::Deref for GenericPredicates<'db> { } } +pub(crate) fn trait_environment_for_body_query( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> Arc> { + let Some(def) = def.as_generic_def_id(db) else { + let krate = def.module(db).krate(); + return TraitEnvironment::empty(krate); + }; + db.trait_environment(def) +} + +pub(crate) fn trait_environment_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> Arc> { + let generics = generics(db, def); + if generics.has_no_predicates() && generics.is_empty() { + return TraitEnvironment::empty(def.krate(db)); + } + + let interner = DbInterner::new_with(db, Some(def.krate(db)), None); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + let mut traits_in_scope = Vec::new(); + let mut clauses = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { + if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { + traits_in_scope + .push((convert_ty_for_result(interner, tr.self_ty()), tr.def_id().0)); + } + clauses.push(pred); + } + } + } + + if let Some(trait_id) = def.assoc_trait_container(db) { + // add `Self: Trait` to the environment in trait + // function default implementations (and speculative code + // inside consts or type aliases) + cov_mark::hit!(trait_self_implements_self); + let trait_ref = TraitRef::identity(ctx.interner, trait_id.into()); + let clause = Clause(Predicate::new( + ctx.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( + TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive }, + ))), + )); + clauses.push(clause); + } + + let explicitly_unsized_tys = ctx.unsized_types; + + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); + if let Some(sized_trait) = sized_trait { + let (mut generics, mut def_id) = + (crate::next_solver::generics::generics(db, def.into()), def); + loop { + let self_idx = trait_self_param_idx(db, def_id); + for (idx, p) in generics.own_params.iter().enumerate() { + if let Some(self_idx) = self_idx + && p.index() as usize == self_idx + { + continue; + } + let GenericParamId::TypeParamId(param_id) = p.id else { + continue; + }; + let idx = idx as u32 + generics.parent_count as u32; + let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone()); + if explicitly_unsized_tys.contains(¶m_ty) { + continue; + } + let trait_ref = TraitRef::new_from_args( + ctx.interner, + sized_trait.into(), + GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]), + ); + let clause = Clause(Predicate::new( + ctx.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + clauses.push(clause); + } + + if let Some(g) = generics.parent { + generics = crate::next_solver::generics::generics(db, g.into()); + def_id = g; + } else { + break; + } + } + } + + let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses); + let clauses = Clauses::new_from_iter(ctx.interner, clauses); + let env = ParamEnv { clauses }; + + TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) +} + #[derive(Copy, Clone, Debug)] pub(crate) enum PredicateFilter { SelfTrait, diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index db74ca2587..fd28159b49 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -31,7 +31,7 @@ use crate::{ infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, lang_items::is_box, next_solver::{ - self, SolverDefId, + self, DbInterner, SolverDefId, infer::{ DefineOpaqueTypes, traits::{ObligationCause, PredicateObligation}, @@ -1755,7 +1755,10 @@ fn is_valid_trait_method_candidate( }; let res = table .infer_ctxt - .at(&next_solver::infer::traits::ObligationCause::dummy(), table.param_env) + .at( + &next_solver::infer::traits::ObligationCause::dummy(), + table.trait_env.env, + ) .relate( DefineOpaqueTypes::No, expected_receiver.to_nextsolver(table.interner), @@ -1845,7 +1848,12 @@ fn is_valid_impl_fn_candidate( let mut ctxt = ObligationCtxt::new(&table.infer_ctxt); ctxt.register_obligations(predicates.into_iter().map(|p| { - PredicateObligation::new(table.interner, ObligationCause::new(), table.param_env, p.0) + PredicateObligation::new( + table.interner, + ObligationCause::new(), + table.trait_env.env, + p.0, + ) })); if ctxt.select_where_possible().is_empty() { @@ -1893,7 +1901,10 @@ fn generic_implements_goal<'db>( let binders = CanonicalVarKinds::from_iter(Interner, kinds); let obligation = trait_ref.cast(Interner); - let value = InEnvironment::new(&env.env, obligation); + let value = InEnvironment::new( + &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)), + obligation, + ); Canonical { binders, value } } @@ -1910,7 +1921,7 @@ fn generic_implements_goal_ns<'db>( let trait_ref = rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args) .with_replaced_self_ty(table.infer_ctxt.interner, self_ty); - let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.param_env, trait_ref); + let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.trait_env.env, trait_ref); table.canonicalize(goal) } diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 2ba1e2341b..a6215ef8fe 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -632,7 +632,7 @@ fn issue_4053_diesel_where_clauses() { 488..522 '{ ... }': as BoxedDsl>::Output 498..502 'self': SelectStatement 498..508 'self.order': O - 498..515 'self.o...into()': dyn QueryFragment + '? + 498..515 'self.o...into()': dyn QueryFragment + 'static "#]], ); } diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index d6a86c1397..8ac152341e 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -25,7 +25,7 @@ use crate::{ db::HirDatabase, infer::unify::InferenceTable, next_solver::{ - DbInterner, GenericArg, Predicate, SolverContext, Span, + DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span, infer::{DbInternerInferExt, InferCtxt}, mapping::{ChalkToNextSolver, convert_canonical_args_for_result}, util::mini_canonicalize, @@ -44,8 +44,7 @@ pub struct TraitEnvironment<'db> { pub block: Option, // FIXME make this a BTreeMap traits_from_clauses: Box<[(Ty, TraitId)]>, - pub env: chalk_ir::Environment, - _db: std::marker::PhantomData<&'db ()>, + pub env: ParamEnv<'db>, } impl<'db> TraitEnvironment<'db> { @@ -54,8 +53,7 @@ impl<'db> TraitEnvironment<'db> { krate, block: None, traits_from_clauses: Box::default(), - env: chalk_ir::Environment::new(Interner), - _db: std::marker::PhantomData, + env: ParamEnv::empty(), }) } @@ -63,15 +61,9 @@ impl<'db> TraitEnvironment<'db> { krate: Crate, block: Option, traits_from_clauses: Box<[(Ty, TraitId)]>, - env: chalk_ir::Environment, + env: ParamEnv<'db>, ) -> Arc { - Arc::new(TraitEnvironment { - krate, - block, - traits_from_clauses, - env, - _db: std::marker::PhantomData, - }) + Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env }) } // pub fn with_block(self: &mut Arc, block: BlockId) { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index eaae15835d..862067e591 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -88,7 +88,7 @@ use hir_ty::{ next_solver::{ ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, - mapping::{ChalkToNextSolver, convert_ty_for_result}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, primitive::UintTy, traits::FnTrait, @@ -5171,7 +5171,14 @@ impl<'db> Type<'db> { .build(); let goal = Canonical { - value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)), + value: hir_ty::InEnvironment::new( + &self.env.env.to_chalk(DbInterner::new_with( + db, + Some(self.env.krate), + self.env.block, + )), + trait_ref.cast(Interner), + ), binders: CanonicalVarKinds::empty(Interner), }; diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 809a26bf5d..b20b570c2b 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -26,6 +26,7 @@ mod visibility; use base_db::{SourceDatabase, salsa}; use expect_test::Expect; +use hir::db::HirDatabase; use hir::{PrefixKind, setup_tracing}; use ide_db::{ FilePosition, RootDatabase, SnippetCap, @@ -306,8 +307,11 @@ pub(crate) fn get_all_items( trigger_character: Option, ) -> Vec { let (db, position) = position(code); - let res = salsa::attach(&db, || crate::completions(&db, &config, position, trigger_character)) - .map_or_else(Vec::default, Into::into); + let res = salsa::attach(&db, || { + HirDatabase::zalsa_register_downcaster(&db); + crate::completions(&db, &config, position, trigger_character) + }) + .map_or_else(Vec::default, Into::into); // validate res.iter().for_each(|it| { let sr = it.source_range; diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index 5457d57b39..04537f908f 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -100,8 +100,8 @@ pub(crate) fn view_memory_layout( Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), Definition::Field(it) => salsa::attach(db, || it.ty(db).to_type(db)), - Definition::Const(it) => it.ty(db), - Definition::Static(it) => it.ty(db), + Definition::Const(it) => salsa::attach(db, || it.ty(db)), + Definition::Static(it) => salsa::attach(db, || it.ty(db)), _ => return None, };