//! This module contains code to instantiate new values into a //! `Canonical<'db, T>`. //! //! For an overview of what canonicalization is and how it fits into //! rustc, check out the [chapter in the rustc dev guide][c]. //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use std::{fmt::Debug, iter}; use crate::next_solver::{ BoundConst, BoundRegion, BoundTy, Canonical, CanonicalVarKind, CanonicalVarValues, Clauses, Const, ConstKind, DbInterner, GenericArg, ParamEnv, Predicate, Region, RegionKind, Ty, TyKind, fold::FnMutDelegate, infer::{ InferCtxt, InferOk, InferResult, canonical::{QueryRegionConstraints, QueryResponse, canonicalizer::OriginalQueryValues}, opaque_types::table::OpaqueTypeStorageEntries, traits::{ObligationCause, PredicateObligations}, }, }; use rustc_hash::FxHashMap; use rustc_index::{Idx as _, IndexVec}; use rustc_type_ir::{ BoundVar, BoundVarIndexKind, GenericArgKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, inherent::{GenericArg as _, IntoKind}, }; use tracing::{debug, instrument}; pub trait CanonicalExt<'db, V> { fn instantiate(&self, tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>) -> V where V: TypeFoldable>; fn instantiate_projected( &self, tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>, projection_fn: impl FnOnce(&V) -> T, ) -> T where T: TypeFoldable>; } /// FIXME(-Znext-solver): This or public because it is shared with the /// new trait solver implementation. We should deduplicate canonicalization. impl<'db, V> CanonicalExt<'db, V> for Canonical<'db, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. fn instantiate(&self, tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>) -> V where V: TypeFoldable>, { self.instantiate_projected(tcx, var_values, |value| value.clone()) } /// Allows one to apply a instantiation to some subset of /// `self.value`. Invoke `projection_fn` with `self.value` to get /// a value V that is expressed in terms of the same canonical /// variables bound in `self` (usually this extracts from subset /// of `self`). Apply the instantiation `var_values` to this value /// V, replacing each of the canonical variables. fn instantiate_projected( &self, tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>, projection_fn: impl FnOnce(&V) -> T, ) -> T where T: TypeFoldable>, { assert_eq!(self.variables.len(), var_values.len()); let value = projection_fn(&self.value); instantiate_value(tcx, var_values, value) } } /// Instantiate the values from `var_values` into `value`. `var_values` /// must be values for the set of canonical variables that appear in /// `value`. pub(super) fn instantiate_value<'db, T>( tcx: DbInterner<'db>, var_values: &CanonicalVarValues<'db>, value: T, ) -> T where T: TypeFoldable>, { if var_values.var_values.is_empty() { value } else { let delegate = FnMutDelegate { regions: &mut |br: BoundRegion| match var_values[br.var].kind() { GenericArgKind::Lifetime(l) => l, r => panic!("{br:?} is a region but value is {r:?}"), }, types: &mut |bound_ty: BoundTy| match var_values[bound_ty.var].kind() { GenericArgKind::Type(ty) => ty, r => panic!("{bound_ty:?} is a type but value is {r:?}"), }, consts: &mut |bound_ct: BoundConst| match var_values[bound_ct.var].kind() { GenericArgKind::Const(ct) => ct, c => panic!("{bound_ct:?} is a const but value is {c:?}"), }, }; let value = tcx.replace_escaping_bound_vars_uncached(value, delegate); value.fold_with(&mut CanonicalInstantiator { tcx, var_values: var_values.var_values.as_slice(), cache: Default::default(), }) } } /// Replaces the bound vars in a canonical binder with var values. struct CanonicalInstantiator<'db, 'a> { tcx: DbInterner<'db>, // The values that the bound vars are being instantiated with. var_values: &'a [GenericArg<'db>], // Because we use `BoundVarIndexKind::Canonical`, we can cache // based only on the entire ty, not worrying about a `DebruijnIndex` cache: FxHashMap, Ty<'db>>, } impl<'db, 'a> TypeFolder> for CanonicalInstantiator<'db, 'a> { fn cx(&self) -> DbInterner<'db> { self.tcx } fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { match t.kind() { TyKind::Bound(BoundVarIndexKind::Canonical, bound_ty) => { self.var_values[bound_ty.var.as_usize()].expect_ty() } _ => { if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { t } else if let Some(&t) = self.cache.get(&t) { t } else { let res = t.super_fold_with(self); assert!(self.cache.insert(t, res).is_none()); res } } } } fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { match r.kind() { RegionKind::ReBound(BoundVarIndexKind::Canonical, br) => { self.var_values[br.var.as_usize()].expect_region() } _ => r, } } fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { match ct.kind() { ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => { self.var_values[bound_const.var.as_usize()].expect_const() } _ => ct.super_fold_with(self), } } fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> { if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p } } fn fold_clauses(&mut self, c: Clauses<'db>) -> Clauses<'db> { if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { return c; } // FIXME: We might need cache here for perf like rustc c.super_fold_with(self) } } impl<'db> InferCtxt<'db> { /// A version of `make_canonicalized_query_response` that does /// not pack in obligations, for contexts that want to drop /// pending obligations instead of treating them as an ambiguity (e.g. /// typeck "probing" contexts). /// /// If you DO want to keep track of pending obligations (which /// include all region obligations, so this includes all cases /// that care about regions) with this function, you have to /// do it yourself, by e.g., having them be a part of the answer. pub fn make_query_response_ignoring_pending_obligations( &self, inference_vars: CanonicalVarValues<'db>, answer: T, prev_entries: OpaqueTypeStorageEntries, ) -> Canonical<'db, QueryResponse<'db, T>> where T: TypeFoldable>, { // While we ignore region constraints and pending obligations, // we do return constrained opaque types to avoid unconstrained // inference variables in the response. This is important as we want // to check that opaques in deref steps stay unconstrained. // // This doesn't handle the more general case for non-opaques as // ambiguous `Projection` obligations have same the issue. let opaque_types = self .inner .borrow_mut() .opaque_type_storage .opaque_types_added_since(prev_entries) .map(|(k, v)| (k, v.ty)) .collect(); self.canonicalize_response(QueryResponse { var_values: inference_vars, region_constraints: QueryRegionConstraints::default(), opaque_types, value: answer, }) } /// Given the (canonicalized) result to a canonical query, /// instantiates the result so it can be used, plugging in the /// values from the canonical query. (Note that the result may /// have been ambiguous; you should check the certainty level of /// the query before applying this function.) /// /// To get a good understanding of what is happening here, check /// out the [chapter in the rustc dev guide][c]. /// /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#processing-the-canonicalized-query-result pub fn instantiate_query_response_and_region_obligations( &self, cause: &ObligationCause, param_env: ParamEnv<'db>, original_values: &OriginalQueryValues<'db>, query_response: &Canonical<'db, QueryResponse<'db, R>>, ) -> InferResult<'db, R> where R: TypeFoldable>, { let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; for predicate in &query_response.value.region_constraints.outlives { let predicate = instantiate_value(self.interner, &result_args, *predicate); self.register_outlives_constraint(predicate); } for assumption in &query_response.value.region_constraints.assumptions { let assumption = instantiate_value(self.interner, &result_args, *assumption); self.register_region_assumption(assumption); } let user_result: R = query_response .instantiate_projected(self.interner, &result_args, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } /// Given the original values and the (canonicalized) result from /// computing a query, returns an instantiation that can be applied /// to the query result to convert the result back into the /// original namespace. /// /// The instantiation also comes accompanied with subobligations /// that arose from unification; these might occur if (for /// example) we are doing lazy normalization and the value /// assigned to a type variable is unified with an unnormalized /// projection. fn query_response_instantiation( &self, cause: &ObligationCause, param_env: ParamEnv<'db>, original_values: &OriginalQueryValues<'db>, query_response: &Canonical<'db, QueryResponse<'db, R>>, ) -> InferResult<'db, CanonicalVarValues<'db>> where R: Debug + TypeFoldable>, { debug!( "query_response_instantiation(original_values={:#?}, query_response={:#?})", original_values, query_response, ); let mut value = self.query_response_instantiation_guess( cause, param_env, original_values, query_response, )?; value.obligations.extend( self.unify_query_response_instantiation_guess( cause, param_env, original_values, &value.value, query_response, )? .into_obligations(), ); Ok(value) } /// Given the original values and the (canonicalized) result from /// computing a query, returns a **guess** at an instantiation that /// can be applied to the query result to convert the result back /// into the original namespace. This is called a **guess** /// because it uses a quick heuristic to find the values for each /// canonical variable; if that quick heuristic fails, then we /// will instantiate fresh inference variables for each canonical /// variable instead. Therefore, the result of this method must be /// properly unified #[instrument(level = "debug", skip(self, param_env))] fn query_response_instantiation_guess( &self, cause: &ObligationCause, param_env: ParamEnv<'db>, original_values: &OriginalQueryValues<'db>, query_response: &Canonical<'db, QueryResponse<'db, R>>, ) -> InferResult<'db, CanonicalVarValues<'db>> where R: Debug + TypeFoldable>, { // For each new universe created in the query result that did // not appear in the original query, create a local // superuniverse. let mut universe_map = original_values.universe_map.clone(); let num_universes_in_query = original_values.universe_map.len(); let num_universes_in_response = query_response.max_universe.as_usize() + 1; for _ in num_universes_in_query..num_universes_in_response { universe_map.push(self.create_next_universe()); } assert!(!universe_map.is_empty()); // always have the root universe assert_eq!(universe_map[UniverseIndex::ROOT.as_usize()], UniverseIndex::ROOT); // Every canonical query result includes values for each of // the inputs to the query. Therefore, we begin by unifying // these values with the original inputs that were // canonicalized. let result_values = &query_response.value.var_values; assert_eq!(original_values.var_values.len(), result_values.len()); // Quickly try to find initial values for the canonical // variables in the result in terms of the query. We do this // by iterating down the values that the query gave to each of // the canonical inputs. If we find that one of those values // is directly equal to one of the canonical variables in the // result, then we can type the corresponding value from the // input. See the example above. let mut opt_values: IndexVec>> = IndexVec::from_elem_n(None, query_response.variables.len()); for (original_value, result_value) in iter::zip(&original_values.var_values, result_values) { match result_value.kind() { GenericArgKind::Type(result_value) => { // We disable the instantiation guess for inference variables // and only use it for placeholders. We need to handle the // `sub_root` of type inference variables which would make this // more involved. They are also a lot rarer than region variables. if let TyKind::Bound(index_kind, b) = result_value.kind() && !matches!( query_response.variables.as_slice()[b.var.as_usize()], CanonicalVarKind::Ty { .. } ) { // We only allow a `Canonical` index in generic parameters. assert!(matches!(index_kind, BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Lifetime(result_value) => { if let RegionKind::ReBound(index_kind, b) = result_value.kind() { // We only allow a `Canonical` index in generic parameters. assert!(matches!(index_kind, BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Const(result_value) => { if let ConstKind::Bound(index_kind, b) = result_value.kind() { // We only allow a `Canonical` index in generic parameters. assert!(matches!(index_kind, BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } } } // Create result arguments: if we found a value for a // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. let interner = self.interner; let variables = query_response.variables; let var_values = CanonicalVarValues::instantiate(interner, variables, |var_values, kind| { if kind.universe() != UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all, we have to deal with them for now. self.instantiate_canonical_var(kind, var_values, |u| universe_map[u.as_usize()]) } else if kind.is_existential() { match opt_values[BoundVar::new(var_values.len())] { Some(k) => k, None => self.instantiate_canonical_var(kind, var_values, |u| { universe_map[u.as_usize()] }), } } else { // For placeholders which were already part of the input, we simply map this // universal bound variable back the placeholder of the input. opt_values[BoundVar::new(var_values.len())] .expect("expected placeholder to be unified with itself during response") } }); let mut obligations = PredicateObligations::new(); // Carry all newly resolved opaque types to the caller's scope for &(a, b) in &query_response.value.opaque_types { let a = instantiate_value(self.interner, &var_values, a); let b = instantiate_value(self.interner, &var_values, b); debug!(?a, ?b, "constrain opaque type"); // We use equate here instead of, for example, just registering the // opaque type's hidden value directly, because the hidden type may have been an inference // variable that got constrained to the opaque type itself. In that case we want to equate // the generic args of the opaque with the generic params of its hidden type version. obligations.extend( self.at(cause, param_env) .eq(Ty::new_opaque(self.interner, a.def_id, a.args), b)? .obligations, ); } Ok(InferOk { value: var_values, obligations }) } /// Given a "guess" at the values for the canonical variables in /// the input, try to unify with the *actual* values found in the /// query result. Often, but not always, this is a no-op, because /// we already found the mapping in the "guessing" step. /// /// See also: [`Self::query_response_instantiation_guess`] fn unify_query_response_instantiation_guess( &self, cause: &ObligationCause, param_env: ParamEnv<'db>, original_values: &OriginalQueryValues<'db>, result_args: &CanonicalVarValues<'db>, query_response: &Canonical<'db, QueryResponse<'db, R>>, ) -> InferResult<'db, ()> where R: Debug + TypeFoldable>, { // A closure that yields the result value for the given // canonical variable; this is taken from // `query_response.var_values` after applying the instantiation // by `result_args`. let instantiated_query_response = |index: BoundVar| -> GenericArg<'db> { query_response .instantiate_projected(self.interner, result_args, |v| v.var_values[index]) }; // Unify the original value for each variable with the value // taken from `query_response` (after applying `result_args`). self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response) } /// Given two sets of values for the same set of canonical variables, unify them. /// The second set is produced lazily by supplying indices from the first set. fn unify_canonical_vars( &self, cause: &ObligationCause, param_env: ParamEnv<'db>, variables1: &OriginalQueryValues<'db>, variables2: impl Fn(BoundVar) -> GenericArg<'db>, ) -> InferResult<'db, ()> { let mut obligations = PredicateObligations::new(); for (index, value1) in variables1.var_values.iter().enumerate() { let value2 = variables2(BoundVar::new(index)); match (value1.kind(), value2.kind()) { (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { obligations.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); } (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2)) if re1.is_erased() && re2.is_erased() => { // no action needed } (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(v1, v2); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { let ok = self.at(cause, param_env).eq(v1, v2)?; obligations.extend(ok.into_obligations()); } _ => { panic!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); } } } Ok(InferOk { value: (), obligations }) } }