Rollup merge of #73055 - lcnr:skol-no-more, r=matthewjasper
remove leftover mentions of `skol` and `int` from the compiler This PR mostly changes `skol` -> `placeholder` and all cases where `int` is used as a type to `i32`.
This commit is contained in:
commit
b015b28359
@ -63,14 +63,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
/// placeholder region. This is the first step of checking subtyping
|
||||
/// when higher-ranked things are involved.
|
||||
///
|
||||
/// **Important:** you must call this function from within a snapshot.
|
||||
/// Moreover, before committing the snapshot, you must eventually call
|
||||
/// either `plug_leaks` or `pop_placeholders` to remove the placeholder
|
||||
/// regions. If you rollback the snapshot (or are using a probe), then
|
||||
/// the pop occurs as part of the rollback, so an explicit call is not
|
||||
/// needed (but is also permitted).
|
||||
///
|
||||
/// For more information about how placeholders and HRTBs work, see
|
||||
/// **Important:** You have to be careful to not leak these placeholders,
|
||||
/// for more information about how placeholders and HRTBs work, see
|
||||
/// the [rustc dev guide].
|
||||
///
|
||||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
|
||||
|
@ -128,7 +128,7 @@ fn fixed_point<'a>(
|
||||
verifys[i].origin.span(),
|
||||
"we never add verifications while doing higher-ranked things",
|
||||
),
|
||||
&Purged | &AddCombination(..) | &AddVar(..) => {}
|
||||
&AddCombination(..) | &AddVar(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,14 +289,6 @@ pub(crate) enum UndoLog<'tcx> {
|
||||
|
||||
/// We added a GLB/LUB "combination variable".
|
||||
AddCombination(CombineMapType, TwoRegions<'tcx>),
|
||||
|
||||
/// During skolemization, we sometimes purge entries from the undo
|
||||
/// log in a kind of minisnapshot (unlike other snapshots, this
|
||||
/// purging actually takes place *on success*). In that case, we
|
||||
/// replace the corresponding entry with `Noop` so as to avoid the
|
||||
/// need to do a bunch of swapping. (We can't use `swap_remove` as
|
||||
/// the order of the vector is important.)
|
||||
Purged,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
@ -357,9 +349,6 @@ pub(crate) fn with_log<'a>(
|
||||
|
||||
fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
|
||||
match undo_entry {
|
||||
Purged => {
|
||||
// nothing to do here
|
||||
}
|
||||
AddVar(vid) => {
|
||||
self.var_infos.pop().unwrap();
|
||||
assert_eq!(self.var_infos.len(), vid.index() as usize);
|
||||
@ -488,62 +477,6 @@ pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
|
||||
self.var_infos[vid].origin
|
||||
}
|
||||
|
||||
/// Removes all the edges to/from the placeholder regions that are
|
||||
/// in `skols`. This is used after a higher-ranked operation
|
||||
/// completes to remove all trace of the placeholder regions
|
||||
/// created in that time.
|
||||
pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) {
|
||||
debug!("pop_placeholders(placeholders={:?})", placeholders);
|
||||
|
||||
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
|
||||
|
||||
let constraints_to_kill: Vec<usize> = self
|
||||
.undo_log
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.filter(|&(_, undo_entry)| match undo_entry {
|
||||
super::UndoLog::RegionConstraintCollector(undo_entry) => {
|
||||
kill_constraint(placeholders, undo_entry)
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.map(|(index, _)| index)
|
||||
.collect();
|
||||
|
||||
for index in constraints_to_kill {
|
||||
let undo_entry = match &mut self.undo_log[index] {
|
||||
super::UndoLog::RegionConstraintCollector(undo_entry) => {
|
||||
mem::replace(undo_entry, Purged)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.rollback_undo_entry(undo_entry);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fn kill_constraint<'tcx>(
|
||||
placeholders: &FxHashSet<ty::Region<'tcx>>,
|
||||
undo_entry: &UndoLog<'tcx>,
|
||||
) -> bool {
|
||||
match undo_entry {
|
||||
&AddConstraint(Constraint::VarSubVar(..)) => false,
|
||||
&AddConstraint(Constraint::RegSubVar(a, _)) => placeholders.contains(&a),
|
||||
&AddConstraint(Constraint::VarSubReg(_, b)) => placeholders.contains(&b),
|
||||
&AddConstraint(Constraint::RegSubReg(a, b)) => {
|
||||
placeholders.contains(&a) || placeholders.contains(&b)
|
||||
}
|
||||
&AddGiven(..) => false,
|
||||
&AddVerify(_) => false,
|
||||
&AddCombination(_, ref two_regions) => {
|
||||
placeholders.contains(&two_regions.a) || placeholders.contains(&two_regions.b)
|
||||
}
|
||||
&AddVar(..) | &Purged => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
|
||||
// cannot add constraints once regions are resolved
|
||||
debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
|
||||
|
@ -198,10 +198,6 @@ fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
|
||||
assert!(self.logs.len() >= snapshot.undo_len);
|
||||
assert!(self.num_open_snapshots > 0);
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> {
|
||||
self.logs.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
|
||||
|
@ -29,10 +29,10 @@
|
||||
|
||||
pub use rustc_middle::traits::*;
|
||||
|
||||
/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
|
||||
/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
|
||||
/// which the "impl_source" must be found. The process of finding a "impl_source" is
|
||||
/// called "resolving" the `Obligation`. This process consists of
|
||||
/// either identifying an `impl` (e.g., `impl Eq for int`) that
|
||||
/// either identifying an `impl` (e.g., `impl Eq for i32`) that
|
||||
/// satisfies the obligation, or else finding a bound that is in
|
||||
/// scope. The eventual result is usually a `Selection` (defined below).
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -63,11 +63,11 @@ fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
|
||||
// We have to be careful here because we want
|
||||
//
|
||||
// for<'a> Foo<&'a int>
|
||||
// for<'a> Foo<&'a i32>
|
||||
//
|
||||
// and
|
||||
//
|
||||
// for<'b> Foo<&'b int>
|
||||
// for<'b> Foo<&'b i32>
|
||||
//
|
||||
// to be considered equivalent. So normalize all late-bound
|
||||
// regions before we throw things into the underlying set.
|
||||
|
@ -393,23 +393,25 @@ pub enum SelectionError<'tcx> {
|
||||
/// ```
|
||||
/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
|
||||
/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2
|
||||
/// impl Clone for int { ... } // Impl_3
|
||||
/// impl Clone for i32 { ... } // Impl_3
|
||||
///
|
||||
/// fn foo<T:Clone>(concrete: Option<Box<int>>,
|
||||
/// param: T,
|
||||
/// mixed: Option<T>) {
|
||||
/// fn foo<T: Clone>(concrete: Option<Box<i32>>, param: T, mixed: Option<T>) {
|
||||
/// // Case A: Vtable points at a specific impl. Only possible when
|
||||
/// // type is concretely known. If the impl itself has bounded
|
||||
/// // type parameters, Vtable will carry resolutions for those as well:
|
||||
/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
|
||||
///
|
||||
/// // Case A: ImplSource points at a specific impl. Only possible when
|
||||
/// // type is concretely known. If the impl itself has bounded
|
||||
/// // type parameters, ImplSource will carry resolutions for those as well:
|
||||
/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
|
||||
/// // Case A: ImplSource points at a specific impl. Only possible when
|
||||
/// // type is concretely known. If the impl itself has bounded
|
||||
/// // type parameters, ImplSource will carry resolutions for those as well:
|
||||
/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
|
||||
///
|
||||
/// // Case B: ImplSource must be provided by caller. This applies when
|
||||
/// // type is a type parameter.
|
||||
/// param.clone(); // ImplSourceParam
|
||||
/// // Case B: ImplSource must be provided by caller. This applies when
|
||||
/// // type is a type parameter.
|
||||
/// param.clone(); // ImplSourceParam
|
||||
///
|
||||
/// // Case C: A mix of cases A and B.
|
||||
/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam])
|
||||
/// // Case C: A mix of cases A and B.
|
||||
/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam])
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
@ -599,12 +599,12 @@ fn const_for_param(
|
||||
///
|
||||
/// ```
|
||||
/// type Func<A> = fn(A);
|
||||
/// type MetaFunc = for<'a> fn(Func<&'a int>)
|
||||
/// type MetaFunc = for<'a> fn(Func<&'a i32>)
|
||||
/// ```
|
||||
///
|
||||
/// The type `MetaFunc`, when fully expanded, will be
|
||||
///
|
||||
/// for<'a> fn(fn(&'a int))
|
||||
/// for<'a> fn(fn(&'a i32))
|
||||
/// ^~ ^~ ^~~
|
||||
/// | | |
|
||||
/// | | DebruijnIndex of 2
|
||||
@ -613,7 +613,7 @@ fn const_for_param(
|
||||
/// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
|
||||
/// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
|
||||
/// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
|
||||
/// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a
|
||||
/// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
|
||||
/// De Bruijn index of 1. It's only during the substitution that we can see we must increase the
|
||||
/// depth by 1 to account for the binder that we passed through.
|
||||
///
|
||||
@ -621,18 +621,18 @@ fn const_for_param(
|
||||
///
|
||||
/// ```
|
||||
/// type FuncTuple<A> = (A,fn(A));
|
||||
/// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
|
||||
/// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>)
|
||||
/// ```
|
||||
///
|
||||
/// Here the final type will be:
|
||||
///
|
||||
/// for<'a> fn((&'a int, fn(&'a int)))
|
||||
/// for<'a> fn((&'a i32, fn(&'a i32)))
|
||||
/// ^~~ ^~~
|
||||
/// | |
|
||||
/// DebruijnIndex of 1 |
|
||||
/// DebruijnIndex of 2
|
||||
///
|
||||
/// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
|
||||
/// As indicated in the diagram, here the same type `&'a i32` is substituted once, but in the
|
||||
/// first case we do not increase the De Bruijn index and in the second case we do. The reason
|
||||
/// is that only in the second case have we passed through a fn binder.
|
||||
fn shift_vars_through_binders<T: TypeFoldable<'tcx>>(&self, val: T) -> T {
|
||||
|
@ -22,13 +22,13 @@ pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> {
|
||||
/// Skips the subtree corresponding to the last type
|
||||
/// returned by `next()`.
|
||||
///
|
||||
/// Example: Imagine you are walking `Foo<Bar<int>, usize>`.
|
||||
/// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
|
||||
///
|
||||
/// ```
|
||||
/// let mut iter: TypeWalker = ...;
|
||||
/// iter.next(); // yields Foo
|
||||
/// iter.next(); // yields Bar<int>
|
||||
/// iter.skip_current_subtree(); // skips int
|
||||
/// iter.next(); // yields Bar<i32>
|
||||
/// iter.skip_current_subtree(); // skips i32
|
||||
/// iter.next(); // yields usize
|
||||
/// ```
|
||||
pub fn skip_current_subtree(&mut self) {
|
||||
|
@ -361,7 +361,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// handle normalization within binders because
|
||||
// otherwise we wind up a need to normalize when doing
|
||||
// trait matching (since you can have a trait
|
||||
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
||||
// obligation like `for<'a> T::B: Fn(&'a i32)`), but
|
||||
// we can't normalize with bound regions in scope. So
|
||||
// far now we just ignore binders but only normalize
|
||||
// if all bound regions are gone (and then we still
|
||||
|
@ -145,7 +145,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// handle normalization within binders because
|
||||
// otherwise we wind up a need to normalize when doing
|
||||
// trait matching (since you can have a trait
|
||||
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
||||
// obligation like `for<'a> T::B: Fn(&'a i32)`), but
|
||||
// we can't normalize with bound regions in scope. So
|
||||
// far now we just ignore binders but only normalize
|
||||
// if all bound regions are gone (and then we still
|
||||
|
@ -553,14 +553,14 @@ fn confirm_closure_candidate(
|
||||
///
|
||||
/// Here is an example. Imagine we have a closure expression
|
||||
/// and we desugared it so that the type of the expression is
|
||||
/// `Closure`, and `Closure` expects an int as argument. Then it
|
||||
/// `Closure`, and `Closure` expects `i32` as argument. Then it
|
||||
/// is "as if" the compiler generated this impl:
|
||||
///
|
||||
/// impl Fn(int) for Closure { ... }
|
||||
/// impl Fn(i32) for Closure { ... }
|
||||
///
|
||||
/// Now imagine our obligation is `Fn(usize) for Closure`. So far
|
||||
/// Now imagine our obligation is `Closure: Fn(usize)`. So far
|
||||
/// we have matched the self type `Closure`. At this point we'll
|
||||
/// compare the `int` to `usize` and generate an error.
|
||||
/// compare the `i32` to `usize` and generate an error.
|
||||
///
|
||||
/// Note that this checking occurs *after* the impl has selected,
|
||||
/// because these output type parameters should not affect the
|
||||
|
@ -1754,27 +1754,26 @@ fn collect_predicates_for_types(
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
// Because the types were potentially derived from
|
||||
// higher-ranked obligations they may reference late-bound
|
||||
// regions. For example, `for<'a> Foo<&'a int> : Copy` would
|
||||
// yield a type like `for<'a> &'a int`. In general, we
|
||||
// regions. For example, `for<'a> Foo<&'a i32> : Copy` would
|
||||
// yield a type like `for<'a> &'a i32`. In general, we
|
||||
// maintain the invariant that we never manipulate bound
|
||||
// regions, so we have to process these bound regions somehow.
|
||||
//
|
||||
// The strategy is to:
|
||||
//
|
||||
// 1. Instantiate those regions to placeholder regions (e.g.,
|
||||
// `for<'a> &'a int` becomes `&0 int`.
|
||||
// 2. Produce something like `&'0 int : Copy`
|
||||
// 3. Re-bind the regions back to `for<'a> &'a int : Copy`
|
||||
// `for<'a> &'a i32` becomes `&0 i32`.
|
||||
// 2. Produce something like `&'0 i32 : Copy`
|
||||
// 3. Re-bind the regions back to `for<'a> &'a i32 : Copy`
|
||||
|
||||
types
|
||||
.skip_binder()
|
||||
.skip_binder() // binder moved -\
|
||||
.iter()
|
||||
.flat_map(|ty| {
|
||||
// binder moved -\
|
||||
let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
|
||||
|
||||
self.infcx.commit_unconditionally(|_| {
|
||||
let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
|
||||
let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
|
||||
let Normalized { value: normalized_ty, mut obligations } =
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
@ -1782,10 +1781,10 @@ fn collect_predicates_for_types(
|
||||
param_env,
|
||||
cause.clone(),
|
||||
recursion_depth,
|
||||
&skol_ty,
|
||||
&placeholder_ty,
|
||||
)
|
||||
});
|
||||
let skol_obligation = predicate_for_trait_def(
|
||||
let placeholder_obligation = predicate_for_trait_def(
|
||||
self.tcx(),
|
||||
param_env,
|
||||
cause.clone(),
|
||||
@ -1794,7 +1793,7 @@ fn collect_predicates_for_types(
|
||||
normalized_ty,
|
||||
&[],
|
||||
);
|
||||
obligations.push(skol_obligation);
|
||||
obligations.push(placeholder_obligation);
|
||||
obligations
|
||||
})
|
||||
})
|
||||
@ -1844,9 +1843,9 @@ fn match_impl(
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let (skol_obligation, placeholder_map) =
|
||||
let (placeholder_obligation, placeholder_map) =
|
||||
self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let skol_obligation_trait_ref = skol_obligation.trait_ref;
|
||||
let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
|
||||
|
||||
let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
|
||||
|
||||
@ -1865,14 +1864,14 @@ fn match_impl(
|
||||
|
||||
debug!(
|
||||
"match_impl(impl_def_id={:?}, obligation={:?}, \
|
||||
impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
|
||||
impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref
|
||||
impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})",
|
||||
impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref
|
||||
);
|
||||
|
||||
let InferOk { obligations, .. } = self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(skol_obligation_trait_ref, impl_trait_ref)
|
||||
.eq(placeholder_obligation_trait_ref, impl_trait_ref)
|
||||
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
|
||||
nested_obligations.extend(obligations);
|
||||
|
||||
|
@ -130,7 +130,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
|
||||
|
||||
// We determine whether there's a subset relationship by:
|
||||
//
|
||||
// - skolemizing impl1,
|
||||
// - replacing bound vars with placeholders in impl1,
|
||||
// - assuming the where clauses for impl1,
|
||||
// - instantiating impl2 with fresh inference variables,
|
||||
// - unifying,
|
||||
|
@ -1394,13 +1394,13 @@ fn add_predicates_for_ast_type_binding(
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait: SuperTrait<int> { }
|
||||
// trait SubTrait: SuperTrait<i32> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B: SubTrait<T = foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref. These are not well-formed.
|
||||
|
@ -91,14 +91,14 @@ fn compare_predicate_entailment<'tcx>(
|
||||
|
||||
// This code is best explained by example. Consider a trait:
|
||||
//
|
||||
// trait Trait<'t,T> {
|
||||
// fn method<'a,M>(t: &'t T, m: &'a M) -> Self;
|
||||
// trait Trait<'t, T> {
|
||||
// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
|
||||
// }
|
||||
//
|
||||
// And an impl:
|
||||
//
|
||||
// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
|
||||
// fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo;
|
||||
// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
|
||||
// }
|
||||
//
|
||||
// We wish to decide if those two method types are compatible.
|
||||
@ -116,9 +116,9 @@ fn compare_predicate_entailment<'tcx>(
|
||||
// regions (Note: but only early-bound regions, i.e., those
|
||||
// declared on the impl or used in type parameter bounds).
|
||||
//
|
||||
// impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
|
||||
// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
|
||||
//
|
||||
// Now we can apply skol_substs to the type of the impl method
|
||||
// Now we can apply placeholder_substs to the type of the impl method
|
||||
// to yield a new function type in terms of our fresh, placeholder
|
||||
// types:
|
||||
//
|
||||
@ -127,11 +127,11 @@ fn compare_predicate_entailment<'tcx>(
|
||||
// We now want to extract and substitute the type of the *trait*
|
||||
// method and compare it. To do so, we must create a compound
|
||||
// substitution by combining trait_to_impl_substs and
|
||||
// impl_to_skol_substs, and also adding a mapping for the method
|
||||
// impl_to_placeholder_substs, and also adding a mapping for the method
|
||||
// type parameters. We extend the mapping to also include
|
||||
// the method parameters.
|
||||
//
|
||||
// trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 }
|
||||
// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
|
||||
//
|
||||
// Applying this to the trait method type yields:
|
||||
//
|
||||
@ -145,20 +145,20 @@ fn compare_predicate_entailment<'tcx>(
|
||||
// satisfied by the implementation's method.
|
||||
//
|
||||
// We do this by creating a parameter environment which contains a
|
||||
// substitution corresponding to impl_to_skol_substs. We then build
|
||||
// trait_to_skol_substs and use it to convert the predicates contained
|
||||
// substitution corresponding to impl_to_placeholder_substs. We then build
|
||||
// trait_to_placeholder_substs and use it to convert the predicates contained
|
||||
// in the trait_m.generics to the placeholder form.
|
||||
//
|
||||
// Finally we register each of these predicates as an obligation in
|
||||
// a fresh FulfillmentCtxt, and invoke select_all_or_error.
|
||||
|
||||
// Create mapping from impl to placeholder.
|
||||
let impl_to_skol_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
|
||||
let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
|
||||
|
||||
// Create mapping from trait to placeholder.
|
||||
let trait_to_skol_substs =
|
||||
impl_to_skol_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
|
||||
debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs);
|
||||
let trait_to_placeholder_substs =
|
||||
impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
|
||||
debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
|
||||
|
||||
let impl_m_generics = tcx.generics_of(impl_m.def_id);
|
||||
let trait_m_generics = tcx.generics_of(trait_m.def_id);
|
||||
@ -194,7 +194,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||
// if all constraints hold.
|
||||
hybrid_preds
|
||||
.predicates
|
||||
.extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
|
||||
.extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
|
||||
|
||||
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
|
||||
// The key step here is to update the caller_bounds's predicates to be
|
||||
@ -220,7 +220,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
|
||||
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs);
|
||||
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
|
||||
let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
|
||||
impl_m_span,
|
||||
infer::HigherRankedType,
|
||||
@ -261,7 +261,7 @@ fn compare_predicate_entailment<'tcx>(
|
||||
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
|
||||
|
||||
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id));
|
||||
let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
|
||||
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
|
||||
let trait_sig =
|
||||
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig);
|
||||
let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
|
||||
|
@ -1468,7 +1468,7 @@ fn consider_probe(
|
||||
///
|
||||
/// ```
|
||||
/// trait Foo { ... }
|
||||
/// impl Foo for Vec<int> { ... }
|
||||
/// impl Foo for Vec<i32> { ... }
|
||||
/// impl Foo for Vec<usize> { ... }
|
||||
/// ```
|
||||
///
|
||||
|
@ -212,7 +212,7 @@ fn check_pat(
|
||||
// errors in some cases, such as this one:
|
||||
//
|
||||
// ```
|
||||
// fn foo<'x>(x: &'x int) {
|
||||
// fn foo<'x>(x: &'x i32) {
|
||||
// let a = 1;
|
||||
// let mut z = x;
|
||||
// z = &a;
|
||||
@ -220,7 +220,7 @@ fn check_pat(
|
||||
// ```
|
||||
//
|
||||
// The reason we might get an error is that `z` might be
|
||||
// assigned a type like `&'x int`, and then we would have
|
||||
// assigned a type like `&'x i32`, and then we would have
|
||||
// a problem when we try to assign `&a` to `z`, because
|
||||
// the lifetime of `&a` (i.e., the enclosing block) is
|
||||
// shorter than `'x`.
|
||||
@ -229,11 +229,11 @@ fn check_pat(
|
||||
// expected type here is whatever type the user wrote, not
|
||||
// the initializer's type. In this case the user wrote
|
||||
// nothing, so we are going to create a type variable `Z`.
|
||||
// Then we will assign the type of the initializer (`&'x
|
||||
// int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
|
||||
// will instantiate `Z` as a type `&'0 int` where `'0` is
|
||||
// a fresh region variable, with the constraint that `'x :
|
||||
// '0`. So basically we're all set.
|
||||
// Then we will assign the type of the initializer (`&'x i32`)
|
||||
// as a subtype of `Z`: `&'x i32 <: Z`. And hence we
|
||||
// will instantiate `Z` as a type `&'0 i32` where `'0` is
|
||||
// a fresh region variable, with the constraint that `'x : '0`.
|
||||
// So basically we're all set.
|
||||
//
|
||||
// Note that there are two tests to check that this remains true
|
||||
// (`regions-reassign-{match,let}-bound-pointer.rs`).
|
||||
|
Loading…
Reference in New Issue
Block a user