1
Fork 0

Dejargnonize subst

This commit is contained in:
Shoyu Vanilla 2024-02-12 15:39:32 +09:00
parent 084ce5bdb5
commit 3856df059e
128 changed files with 574 additions and 541 deletions

View file

@ -1,4 +1,4 @@
//! This module contains code to substitute new values into a
//! This module contains code to instantiate new values into a
//! `Canonical<'tcx, T>`.
//!
//! For an overview of what canonicalization is and how it fits into
@ -16,17 +16,17 @@ use rustc_middle::ty::{self, TyCtxt};
pub trait CanonicalExt<'tcx, V> {
/// Instantiate the wrapped value, replacing each canonical value
/// with the value given in `var_values`.
fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
where
V: TypeFoldable<TyCtxt<'tcx>>;
/// Allows one to apply a substitute to some subset of
/// 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 substitution `var_values` to this value
/// of `self`). Apply the instantiation `var_values` to this value
/// V, replacing each of the canonical variables.
fn substitute_projected<T>(
fn instantiate_projected<T>(
&self,
tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
@ -37,14 +37,14 @@ pub trait CanonicalExt<'tcx, V> {
}
impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
self.substitute_projected(tcx, var_values, |value| value.clone())
self.instantiate_projected(tcx, var_values, |value| value.clone())
}
fn substitute_projected<T>(
fn instantiate_projected<T>(
&self,
tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
@ -55,14 +55,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
{
assert_eq!(self.variables.len(), var_values.len());
let value = projection_fn(&self.value);
substitute_value(tcx, var_values, value)
instantiate_value(tcx, var_values, value)
}
}
/// Substitute the values from `var_values` into `value`. `var_values`
/// 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 substitute_value<'tcx, T>(
pub(super) fn instantiate_value<'tcx, T>(
tcx: TyCtxt<'tcx>,
var_values: &CanonicalVarValues<'tcx>,
value: T,

View file

@ -30,24 +30,24 @@ use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, List, Ty, TyCtxt};
use rustc_span::Span;
pub use instantiate::CanonicalExt;
pub use rustc_middle::infer::canonical::*;
pub use substitute::CanonicalExt;
mod canonicalizer;
mod instantiate;
pub mod query_response;
mod substitute;
impl<'tcx> InferCtxt<'tcx> {
/// Creates a substitution S for the canonical value with fresh
/// Creates an instantiation S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
/// Returns both the instantiated result *and* the substitution S.
/// Returns both the instantiated result *and* the instantiation S.
///
/// This can be invoked as part of constructing an
/// inference context at the start of a query (see
/// `InferCtxtBuilder::build_with_canonical`). It basically
/// brings the canonical value "into scope" within your new infcx.
///
/// At the end of processing, the substitution S (once
/// At the end of processing, the instantiation S (once
/// canonicalized) then represents the values that you computed
/// for each of the canonical inputs to your query.
pub fn instantiate_canonical_with_fresh_inference_vars<T>(
@ -73,14 +73,14 @@ impl<'tcx> InferCtxt<'tcx> {
let canonical_inference_vars =
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
let result = canonical.substitute(self.tcx, &canonical_inference_vars);
let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
(result, canonical_inference_vars)
}
/// Given the "infos" about the canonical variables from some
/// canonical, creates fresh variables with the same
/// characteristics (see `instantiate_canonical_var` for
/// details). You can then use `substitute` to instantiate the
/// details). You can then use `instantiate` to instantiate the
/// canonical variable with these inference variables.
fn instantiate_canonical_vars(
&self,

View file

@ -7,7 +7,7 @@
//!
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt};
use crate::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
@ -189,18 +189,18 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
let InferOk { value: result_subst, mut obligations } =
self.query_response_substitution(cause, param_env, original_values, query_response)?;
let InferOk { value: result_args, mut obligations } =
self.query_response_instantiation(cause, param_env, original_values, query_response)?;
obligations.extend(self.query_outlives_constraints_into_obligations(
cause,
param_env,
&query_response.value.region_constraints.outlives,
&result_subst,
&result_args,
));
let user_result: R =
query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
Ok(InferOk { value: user_result, obligations })
}
@ -225,11 +225,11 @@ impl<'tcx> InferCtxt<'tcx> {
/// basic operations as `instantiate_query_response_and_region_obligations` but
/// it returns its result differently:
///
/// - It creates a substitution `S` that maps from the original
/// - It creates an instantiation `S` that maps from the original
/// query variables to the values computed in the query
/// result. If any errors arise, they are propagated back as an
/// `Err` result.
/// - In the case of a successful substitution, we will append
/// - In the case of a successful instantiation, we will append
/// `QueryOutlivesConstraint` values onto the
/// `output_query_region_constraints` vector for the solver to
/// use (if an error arises, some values may also be pushed, but
@ -239,7 +239,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// that must be processed. In this case, those subobligations
/// are propagated back in the return value.
/// - Finally, the query result (of type `R`) is propagated back,
/// after applying the substitution `S`.
/// after applying the instantiation `S`.
pub fn instantiate_nll_query_response_and_region_obligations<R>(
&self,
cause: &ObligationCause<'tcx>,
@ -251,8 +251,13 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
let InferOk { value: result_subst, mut obligations } = self
.query_response_substitution_guess(cause, param_env, original_values, query_response)?;
let InferOk { value: result_args, mut obligations } = self
.query_response_instantiation_guess(
cause,
param_env,
original_values,
query_response,
)?;
// Compute `QueryOutlivesConstraint` values that unify each of
// the original values `v_o` that was canonicalized into a
@ -262,7 +267,7 @@ impl<'tcx> InferCtxt<'tcx> {
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| {
v.var_values[BoundVar::new(index)]
});
match (original_value.unpack(), result_value.unpack()) {
@ -321,7 +326,7 @@ impl<'tcx> InferCtxt<'tcx> {
// ...also include the other query region constraints from the query.
output_query_region_constraints.outlives.extend(
query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
let r_c = substitute_value(self.tcx, &result_subst, r_c);
let r_c = instantiate_value(self.tcx, &result_args, r_c);
// Screen out `'a: 'a` cases.
let ty::OutlivesPredicate(k1, r2) = r_c.0;
@ -336,26 +341,26 @@ impl<'tcx> InferCtxt<'tcx> {
.region_constraints
.member_constraints
.iter()
.map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())),
.map(|p_c| instantiate_value(self.tcx, &result_args, p_c.clone())),
);
let user_result: R =
query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone());
query_response.instantiate_projected(self.tcx, &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 a substitution that can be applied
/// computing a query, returns an instantiation that can be applied
/// to the query result to convert the result back into the
/// original namespace.
///
/// The substitution also comes accompanied with subobligations
/// 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_substitution<R>(
fn query_response_instantiation<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -366,11 +371,11 @@ impl<'tcx> InferCtxt<'tcx> {
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
debug!(
"query_response_substitution(original_values={:#?}, query_response={:#?})",
"query_response_instantiation(original_values={:#?}, query_response={:#?})",
original_values, query_response,
);
let mut value = self.query_response_substitution_guess(
let mut value = self.query_response_instantiation_guess(
cause,
param_env,
original_values,
@ -378,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> {
)?;
value.obligations.extend(
self.unify_query_response_substitution_guess(
self.unify_query_response_instantiation_guess(
cause,
param_env,
original_values,
@ -392,7 +397,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
/// Given the original values and the (canonicalized) result from
/// computing a query, returns a **guess** at a substitution that
/// 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
@ -401,7 +406,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// variable instead. Therefore, the result of this method must be
/// properly unified
#[instrument(level = "debug", skip(self, cause, param_env))]
fn query_response_substitution_guess<R>(
fn query_response_instantiation_guess<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -450,7 +455,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let ty::Bound(debruijn, b) = *result_value.kind() {
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
// We only allow a `ty::INNERMOST` index in substitutions.
// We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b.var] = Some(*original_value);
}
@ -460,7 +465,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let ty::ReBound(debruijn, br) = *result_value {
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
// We only allow a `ty::INNERMOST` index in substitutions.
// We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.var] = Some(*original_value);
}
@ -469,7 +474,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
// We only allow a `ty::INNERMOST` index in substitutions.
// We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b] = Some(*original_value);
}
@ -477,10 +482,10 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
// Create a result substitution: if we found a value for a
// 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 result_subst = CanonicalVarValues {
let result_args = CanonicalVarValues {
var_values: self.tcx.mk_args_from_iter(
query_response.variables.iter().enumerate().map(|(index, info)| {
if info.universe() != ty::UniverseIndex::ROOT {
@ -511,8 +516,8 @@ impl<'tcx> InferCtxt<'tcx> {
// Carry all newly resolved opaque types to the caller's scope
for &(a, b) in &query_response.value.opaque_types {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
let a = instantiate_value(self.tcx, &result_args, a);
let b = instantiate_value(self.tcx, &result_args, 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 we may be instantiating
@ -532,7 +537,7 @@ impl<'tcx> InferCtxt<'tcx> {
);
}
Ok(InferOk { value: result_subst, obligations })
Ok(InferOk { value: result_args, obligations })
}
/// Given a "guess" at the values for the canonical variables in
@ -540,13 +545,13 @@ impl<'tcx> InferCtxt<'tcx> {
/// query result. Often, but not always, this is a no-op, because
/// we already found the mapping in the "guessing" step.
///
/// See also: `query_response_substitution_guess`
fn unify_query_response_substitution_guess<R>(
/// See also: [`Self::query_response_instantiation_guess`]
fn unify_query_response_instantiation_guess<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
result_subst: &CanonicalVarValues<'tcx>,
result_args: &CanonicalVarValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
) -> InferResult<'tcx, ()>
where
@ -554,15 +559,15 @@ impl<'tcx> InferCtxt<'tcx> {
{
// A closure that yields the result value for the given
// canonical variable; this is taken from
// `query_response.var_values` after applying the substitution
// `result_subst`.
let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> {
query_response.substitute_projected(self.tcx, result_subst, |v| v.var_values[index])
// `query_response.var_values` after applying the instantiation
// by `result_args`.
let instantiated_query_response = |index: BoundVar| -> GenericArg<'tcx> {
query_response.instantiate_projected(self.tcx, result_args, |v| v.var_values[index])
};
// Unify the original value for each variable with the value
// taken from `query_response` (after applying `result_subst`).
self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response)
// taken from `query_response` (after applying `result_args`).
self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response)
}
/// Converts the region constraints resulting from a query into an
@ -571,11 +576,11 @@ impl<'tcx> InferCtxt<'tcx> {
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
result_subst: &'a CanonicalVarValues<'tcx>,
uninstantiated_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
result_args: &'a CanonicalVarValues<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
unsubstituted_region_constraints.iter().map(move |&constraint| {
let predicate = substitute_value(self.tcx, result_subst, constraint);
uninstantiated_region_constraints.iter().map(move |&constraint| {
let predicate = instantiate_value(self.tcx, result_args, constraint);
self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
})
}

View file

@ -679,7 +679,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
/// invoked with the new infcx, along with the instantiated value
/// `V` and a substitution `S`. This substitution `S` maps from
/// `V` and a instantiation `S`. This instantiation `S` maps from
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
pub fn build_with_canonical<T>(
@ -691,8 +691,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>>,
{
let infcx = self.build();
let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
(infcx, value, subst)
let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
(infcx, value, args)
}
pub fn build(&mut self) -> InferCtxt<'tcx> {
@ -1194,13 +1194,13 @@ impl<'tcx> InferCtxt<'tcx> {
}
GenericParamDefKind::Type { .. } => {
// Create a type inference variable for the given
// type parameter definition. The substitutions are
// type parameter definition. The generic parameters are
// for actual parameters that may be referred to by
// the default of this type parameter, if it exists.
// e.g., `struct Foo<A, B, C = (A, B)>(...);` when
// used in a path such as `Foo::<T, U>::new()` will
// use an inference variable for `C` with `[T, U]`
// as the substitutions for the default, `(T, U)`.
// as the generic parameters for the default, `(T, U)`.
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
self.universe(),
TypeVariableOrigin {
@ -1256,7 +1256,7 @@ impl<'tcx> InferCtxt<'tcx> {
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
}
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping each
/// type/region parameter to a fresh inference variable.
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
@ -1411,7 +1411,7 @@ impl<'tcx> InferCtxt<'tcx> {
T: TypeFoldable<TyCtxt<'tcx>>,
{
if !value.has_infer() {
return value; // Avoid duplicated subst-folding.
return value; // Avoid duplicated type-folding.
}
let mut r = InferenceLiteralEraser { tcx: self.tcx };
value.fold_with(&mut r)
@ -1458,7 +1458,7 @@ impl<'tcx> InferCtxt<'tcx> {
// Instantiates the bound variables in a given binder with fresh inference
// variables in the current universe.
//
// Use this method if you'd like to find some substitution of the binder's
// Use this method if you'd like to find some generic parameters of the binder's
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
// that corresponds to your use case, consider whether or not you should
// use [`InferCtxt::enter_forall`] instead.
@ -1603,10 +1603,10 @@ impl<'tcx> InferCtxt<'tcx> {
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
/// substitutions and environment are used to resolve the constant. Alternatively if the
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
/// generic parameters and environment are used to resolve the constant. Alternatively if the
/// constant has generic parameters in scope the instantiations are used to evaluate the value of
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is still
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
///
@ -1652,7 +1652,7 @@ impl<'tcx> InferCtxt<'tcx> {
let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
// variables, thus we don't need to instantiate back the original values.
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
}

View file

@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// ```
///
/// As indicating in the comments above, each of those references
/// is (in the compiler) basically a substitution (`args`)
/// is (in the compiler) basically generic paramters (`args`)
/// applied to the type of a suitable `def_id` (which identifies
/// `Foo1` or `Foo2`).
///

View file

@ -25,7 +25,7 @@ use crate::infer::region_constraints::VerifyIfEq;
/// * `None` if `some_type` cannot be made equal to `test_ty`,
/// no matter the values of the variables in `exists`.
/// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo
/// any bound existential variables, which will be substituted) for the
/// any bound existential variables, which will be instantiated) for the
/// type under test.
///
/// NB: This function uses a simplistic, syntactic version of type equality.
@ -59,7 +59,7 @@ pub fn extract_verify_if_eq<'tcx>(
}
} else {
// The region does not contain any bound variables, so we don't need
// to do any substitution.
// to do any instantiation.
//
// Example:
//

View file

@ -277,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// ```
///
/// If we were given the `DefId` of `Foo::Bar`, we would return
/// `'a`. You could then apply the substitutions from the
/// `'a`. You could then apply the instantiations from the
/// projection to convert this into your namespace. This also
/// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
/// the trait. In fact, it works by searching for just such a

View file

@ -183,14 +183,14 @@ where
fn relate_item_args(
&mut self,
item_def_id: DefId,
a_subst: ty::GenericArgsRef<'tcx>,
b_subst: ty::GenericArgsRef<'tcx>,
a_arg: ty::GenericArgsRef<'tcx>,
b_arg: ty::GenericArgsRef<'tcx>,
) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
if self.ambient_variance == ty::Variance::Invariant {
// Avoid fetching the variance if we are in an invariant
// context; no need, and it can induce dependency cycles
// (e.g., #41849).
relate::relate_args_invariantly(self, a_subst, b_subst)
relate::relate_args_invariantly(self, a_arg, b_arg)
} else {
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
@ -198,8 +198,8 @@ where
self,
item_def_id,
opt_variances,
a_subst,
b_subst,
a_arg,
b_arg,
false,
)
}

View file

@ -118,7 +118,7 @@ pub enum TypeVariableOriginKind {
AdjustmentType,
/// In type check, when we are type checking a function that
/// returns `-> dyn Foo`, we substitute a type variable for the
/// returns `-> dyn Foo`, we instantiate a type variable with the
/// return type for diagnostic purposes.
DynReturnFn,
LatticeVariable,

View file

@ -285,7 +285,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
let obligations =
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
elaboratable.child_with_derived_cause(
clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
clause
.instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
span,
bound_clause.rebind(data),
index,