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

@ -336,12 +336,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
let mut emitted_bad_param_err = None;
// If we have an method return type bound, then we need to substitute
// If we have an method return type bound, then we need to instantiate
// the method's early bound params with suitable late-bound params.
let mut num_bound_vars = candidate.bound_vars().len();
let args =
candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| {
let subst = match param.kind {
let arg = match param.kind {
ty::GenericParamDefKind::Lifetime => ty::Region::new_bound(
tcx,
ty::INNERMOST,
@ -379,7 +379,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
};
num_bound_vars += 1;
subst
arg
});
// Next, we need to check that the return-type notation is being used on
@ -402,12 +402,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
// Finally, move the fn return type's bound vars over to account for the early bound
// params (and trait ref's late bound params). This logic is very similar to
// `Predicate::subst_supertrait`, and it's no coincidence why.
// `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
// and it's no coincidence why.
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
let subst_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
let bound_vars = tcx.late_bound_vars(binding.hir_id);
ty::Binder::bind_with_vars(subst_output, bound_vars)
ty::Binder::bind_with_vars(instantiation_output, bound_vars)
} else {
// Append the generic arguments of the associated type to the `trait_ref`.
candidate.map_bound(|trait_ref| {

View file

@ -1,6 +1,6 @@
use super::IsMethodCall;
use crate::astconv::{
errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound,
errors::prohibit_assoc_ty_binding, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound,
GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
};
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
@ -177,9 +177,9 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
has_self: bool,
self_ty: Option<Ty<'tcx>>,
arg_count: &GenericArgCountResult,
ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
ctx: &mut impl CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>,
) -> GenericArgsRef<'tcx> {
// Collect the segments of the path; we need to substitute arguments
// Collect the segments of the path; we need to instantiate arguments
// for parameters throughout the entire path (wherever there are
// generic parameters).
let mut parent_defs = tcx.generics_of(def_id);
@ -191,7 +191,7 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
}
// We manually build up the generic arguments, rather than using convenience
// methods in `subst.rs`, so that we can iterate over the arguments and
// methods in `rustc_middle/src/ty/generic_args.rs`, so that we can iterate over the arguments and
// parameters in lock-step linearly, instead of trying to match each pair.
let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
// Iterate over each segment of the path.

View file

@ -214,7 +214,7 @@ pub struct GenericArgCountResult {
pub correct: Result<(), GenericArgCountMismatch>,
}
pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> {
pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> {
fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool);
fn provided_kind(
@ -366,8 +366,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if generics.has_self {
if generics.parent.is_some() {
// The parent is a trait so it should have at least one subst
// for the `Self` type.
// The parent is a trait so it should have at least one
// generic parameter for the `Self` type.
assert!(!parent_args.is_empty())
} else {
// This item (presumably a trait) needs a self-type.
@ -402,7 +402,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return (tcx.mk_args(parent_args), arg_count);
}
struct SubstsForAstPathCtxt<'a, 'tcx> {
struct InstantiationsForAstPathCtxt<'a, 'tcx> {
astconv: &'a (dyn AstConv<'tcx> + 'a),
def_id: DefId,
generic_args: &'a GenericArgs<'tcx>,
@ -411,7 +411,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
infer_args: bool,
}
impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
for InstantiationsForAstPathCtxt<'a, 'tcx>
{
fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) {
if did == self.def_id {
(Some(self.generic_args), self.infer_args)
@ -556,7 +558,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
let mut args_ctx = SubstsForAstPathCtxt {
let mut args_ctx = InstantiationsForAstPathCtxt {
astconv: self,
def_id,
span,
@ -2412,8 +2414,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let self_ty = self.tcx().type_of(parent).instantiate_identity();
let generic_self_ty = ty::GenericArg::from(self_ty);
let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
sig.instantiate(self.tcx(), substs)
let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty));
sig.instantiate(self.tcx(), args)
} else {
sig.instantiate_identity()
};

View file

@ -175,7 +175,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// A `Self` within the original bound will be instantiated with a
// `trait_object_dummy_self`, so check for that.
let references_self = match pred.skip_binder().term.unpack() {
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),

View file

@ -1030,7 +1030,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
match t.kind() {
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
ty::Adt(def, subst) => {
ty::Adt(def, args) => {
if !def.did().is_local() {
let non_exhaustive = def.is_variant_list_non_exhaustive()
|| def
@ -1042,13 +1042,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return ControlFlow::Break((
def.descr(),
def.did(),
subst,
args,
non_exhaustive,
));
}
}
def.all_fields()
.map(|field| field.ty(tcx, subst))
.map(|field| field.ty(tcx, args))
.try_for_each(|t| check_non_exhaustive(tcx, t))
}
_ => ControlFlow::Continue(()),

View file

@ -125,9 +125,9 @@ fn check_method_is_structurally_compatible<'tcx>(
/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo
/// ```
///
/// We now want to extract and substitute the type of the *trait*
/// We now want to extract and instantiate the type of the *trait*
/// method and compare it. To do so, we must create a compound
/// substitution by combining `trait_to_impl_args` and
/// instantiation by combining `trait_to_impl_args` and
/// `impl_to_placeholder_args`, and also adding a mapping for the method
/// type parameters. We extend the mapping to also include
/// the method parameters.
@ -146,11 +146,11 @@ fn check_method_is_structurally_compatible<'tcx>(
/// vs `'b`). However, the normal subtyping rules on fn types handle
/// this kind of equivalency just fine.
///
/// We now use these substitutions to ensure that all declared bounds are
/// satisfied by the implementation's method.
/// We now use these generic parameters to ensure that all declared bounds
/// are satisfied by the implementation's method.
///
/// We do this by creating a parameter environment which contains a
/// substitution corresponding to `impl_to_placeholder_args`. We then build
/// generic parameter corresponding to `impl_to_placeholder_args`. We then build
/// `trait_to_placeholder_args` and use it to convert the predicates contained
/// in the `trait_m` generics to the placeholder form.
///
@ -454,7 +454,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during substitution later.
// just so we don't ICE during instantiation later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
let trait_to_impl_args = impl_trait_ref.args;
@ -543,7 +543,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// }
// ```
// .. to compile. However, since we use both the normalized and unnormalized
// inputs and outputs from the substituted trait signature, we will end up
// inputs and outputs from the instantiated trait signature, we will end up
// seeing the hidden type of an RPIT in the signature itself. Naively, this
// means that we will use the hidden type to imply the hidden type's own
// well-formedness.
@ -699,7 +699,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
// region args that are synthesized during AST lowering. These are args
// that are appended to the parent args (trait and trait method). However,
// we're trying to infer the unsubstituted type value of the RPITIT inside
// we're trying to infer the uninstantiated type value of the RPITIT inside
// the *impl*, so we can later use the impl's method args to normalize
// an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
//
@ -711,7 +711,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// guarantee that the indices from the trait args and impl args line up.
// So to fix this, we subtract the number of trait args and add the number of
// impl args to *renumber* these early-bound regions to their corresponding
// indices in the impl's substitutions list.
// indices in the impl's generic parameters list.
//
// Also, we only need to account for a difference in trait and impl args,
// since we previously enforce that the trait method and impl method have the

View file

@ -124,14 +124,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
// Take the param-env of the adt and substitute the args that show up in
// Take the param-env of the adt and instantiate the args that show up in
// the implementation's self type. This gives us the assumptions that the
// self ty of the implementation is allowed to know just from it being a
// well-formed adt, since that's all we're allowed to assume while proving
// the Drop implementation is not specialized.
//
// We don't need to normalize this param-env or anything, since we're only
// substituting it with free params, so no additional param-env normalization
// instantiating it with free params, so no additional param-env normalization
// can occur on top of what has been done in the param_env query itself.
let param_env =
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);

View file

@ -56,7 +56,7 @@ type variable is an instance of a type parameter. That is,
given a generic function `fn foo<T>(t: T)`, while checking the
function `foo`, the type `ty_param(0)` refers to the type `T`, which
is treated in abstract. However, when `foo()` is called, `T` will be
substituted for a fresh type variable `N`. This variable will
instantiated with a fresh type variable `N`. This variable will
eventually be resolved to some concrete type (which might itself be
a type parameter).

View file

@ -618,7 +618,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
// The bounds we that we would require from `to_check`
let mut bounds = FxHashSet::default();
let (regions, types) = GATSubstCollector::visit(gat_def_id.to_def_id(), to_check);
let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check);
// If both regions and types are empty, then this GAT isn't in the
// set of types we are checking, and we shouldn't try to do clause analysis
@ -787,34 +787,34 @@ fn test_region_obligations<'tcx>(
/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
/// the two vectors, `regions` and `types` (depending on their kind). For each
/// parameter `Pi` also track the index `i`.
struct GATSubstCollector<'tcx> {
struct GATArgsCollector<'tcx> {
gat: DefId,
// Which region appears and which parameter index its substituted for
// Which region appears and which parameter index its instantiated with
regions: FxHashSet<(ty::Region<'tcx>, usize)>,
// Which params appears and which parameter index its substituted for
// Which params appears and which parameter index its instantiated with
types: FxHashSet<(Ty<'tcx>, usize)>,
}
impl<'tcx> GATSubstCollector<'tcx> {
impl<'tcx> GATArgsCollector<'tcx> {
fn visit<T: TypeFoldable<TyCtxt<'tcx>>>(
gat: DefId,
t: T,
) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
let mut visitor =
GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
t.visit_with(&mut visitor);
(visitor.regions, visitor.types)
}
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATSubstCollector<'tcx> {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
type BreakTy = !;
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
ty::Alias(ty::Projection, p) if p.def_id == self.gat => {
for (idx, subst) in p.args.iter().enumerate() {
match subst.unpack() {
for (idx, arg) in p.args.iter().enumerate() {
match arg.unpack() {
GenericArgKind::Lifetime(lt) if !lt.is_bound() => {
self.regions.insert((lt, idx));
}
@ -1407,14 +1407,14 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
}
// Check that trait predicates are WF when params are substituted by their defaults.
// Check that trait predicates are WF when params are instantiated with their defaults.
// We don't want to overly constrain the predicates that may be written but we want to
// catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
// Therefore we check if a predicate which contains a single type param
// with a concrete default is WF with that default substituted.
// with a concrete default is WF with that default instantiated.
// For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
//
// First we build the defaulted substitution.
// First we build the defaulted generic parameters.
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
match param.kind {
GenericParamDefKind::Lifetime => {
@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let default_ty = tcx.type_of(param.def_id).instantiate_identity();
// ... and it's not a dependent default, ...
if !default_ty.has_param() {
// ... then substitute it with the default.
// ... then instantiate it with the default.
return default_ty.into();
}
}
@ -1441,7 +1441,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
// ... and it's not a dependent default, ...
if !default_ct.has_param() {
// ... then substitute it with the default.
// ... then instantiate it with the default.
return default_ct.into();
}
}
@ -1451,7 +1451,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
});
// Now we build the substituted predicates.
// Now we build the instantiated predicates.
let default_obligations = predicates
.predicates
.iter()
@ -1483,23 +1483,25 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count).is_break();
let substituted_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args);
let instantiated_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
if instantiated_pred.has_non_region_param()
|| param_count.params.len() > 1
|| has_region
{
None
} else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
} else if predicates.predicates.iter().any(|&(p, _)| p == instantiated_pred) {
// Avoid duplication of predicates that contain no parameters, for example.
None
} else {
Some((substituted_pred, sp))
Some((instantiated_pred, sp))
}
})
.map(|(pred, sp)| {
// Convert each of those into an obligation. So if you have
// something like `struct Foo<T: Copy = String>`, we would
// take that predicate `T: Copy`, substitute to `String: Copy`
// take that predicate `T: Copy`, instantiated with `String: Copy`
// (actually that happens in the previous `flat_map` call),
// and then try to prove it (in this case, we'll fail).
//

View file

@ -396,7 +396,7 @@ pub fn coerce_unsized_info<'tcx>(
//
// To check if this impl is legal, we would walk down
// the fields of `Foo` and consider their types with
// both substitutes. We are looking to find that
// both generic parameters. We are looking to find that
// exactly one (non-phantom) field has changed its
// type, which we will expect to be the pointer that
// is becoming fat (we could probably generalize this

View file

@ -71,7 +71,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, args: [N#0])`.
//
// This causes ICEs (#86580) when building the args for Foo in `fn foo() -> Foo { .. }` as
// we substitute the defaults with the partially built args when we build the args. Subst'ing
// we instantiate the defaults with the partially built args when we build the args. Instantiating
// the `N#0` on the unevaluated const indexes into the empty args we're in the process of building.
//
// We fix this by having this function return the parent's generics ourselves and truncating the

View file

@ -1786,7 +1786,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(data) => {
// The order here needs to match what we would get from `subst_supertrait`
// The order here needs to match what we would get from
// `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
let pred_bound_vars = bound_predicate.bound_vars();
let mut all_bound_vars = bound_vars.clone();
all_bound_vars.extend(pred_bound_vars.iter());

View file

@ -119,7 +119,7 @@ pub fn identify_constrained_generic_params<'tcx>(
/// * `<U as Iterator>::Item = T` -- a desugared ProjectionPredicate
///
/// When we, for example, try to go over the trait-reference
/// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
/// `IntoIter<u32> as Trait`, we instantiate the impl parameters with fresh
/// variables and match them with the impl trait-ref, so we know that
/// `$U = IntoIter<u32>`.
///

View file

@ -372,8 +372,8 @@ pub struct ManualImplementation {
}
#[derive(Diagnostic)]
#[diag(hir_analysis_substs_on_overridden_impl)]
pub struct SubstsOnOverriddenImpl {
#[diag(hir_analysis_generic_args_on_overridden_impl)]
pub struct GenericArgsOnOverriddenImpl {
#[primary_span]
pub span: Span,
}

View file

@ -34,8 +34,8 @@
//! impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }
//! ```
//!
//! We get that the subst for `impl2` are `[T, std::vec::IntoIter<T>]`. `T` is
//! constrained to be `<I as Iterator>::Item`, so we check only
//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
//! `T` is constrained to be `<I as Iterator>::Item`, so we check only
//! `std::vec::IntoIter<T>` for repeated parameters, which it doesn't have. The
//! predicates of `impl1` are only `T: Sized`, which is also a predicate of
//! `impl2`. So this specialization is sound.
@ -65,7 +65,7 @@
//! cause use after frees with purely safe code in the same way as specializing
//! on traits with methods can.
use crate::errors::SubstsOnOverriddenImpl;
use crate::errors::GenericArgsOnOverriddenImpl;
use crate::{constrained_generic_params as cgp, errors};
use rustc_data_structures::fx::FxHashSet;
@ -179,8 +179,8 @@ fn check_constness(
}
/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
/// substitutions `(S1, S2)` that equate their trait references. The returned
/// types are expressed in terms of the generics of `impl1`.
/// generic parameters `(S1, S2)` that equate their trait references.
/// The returned types are expressed in terms of the generics of `impl1`.
///
/// Example
///
@ -228,13 +228,13 @@ fn get_impl_args(
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
let span = tcx.def_span(impl1_def_id);
let guar = tcx.dcx().emit_err(SubstsOnOverriddenImpl { span });
let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
return Err(guar);
};
Ok((impl1_args, impl2_args))
}
/// Returns a list of all of the unconstrained subst of the given impl.
/// Returns a list of all of the unconstrained generic parameters of the given impl.
///
/// For example given the impl:
///

View file

@ -229,7 +229,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
/// Here, we should fetch the explicit predicates, which
/// will give us `U: 'static` and `U: Outer`. The latter we
/// can ignore, but we will want to process `U: 'static`,
/// applying the substitution as above.
/// applying the instantiation as above.
fn check_explicit_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@ -316,7 +316,7 @@ fn check_explicit_predicates<'tcx>(
/// Here, when processing the type of field `outer`, we would request the
/// set of implicit predicates computed for `Inner` thus far. This will
/// initially come back empty, but in next round we will get `U: 'b`.
/// We then apply the substitution `['b => 'a, U => T]` and thus get the
/// We then apply the instantiation `['b => 'a, U => T]` and thus get the
/// requirement that `T: 'a` holds for `Outer`.
fn check_inferred_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
@ -334,7 +334,7 @@ fn check_inferred_predicates<'tcx>(
for (&predicate, &span) in predicates.as_ref().skip_binder() {
// `predicate` is `U: 'b` in the example above.
// So apply the substitution to get `T: 'a`.
// So apply the instantiation to get `T: 'a`.
let ty::OutlivesPredicate(arg, region) =
predicates.rebind(predicate).instantiate(tcx, args);
insert_outlives_predicate(tcx, arg, region, span, required_predicates);

View file

@ -172,16 +172,16 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
trait_ref: ty::TraitRef { def_id: _, args, .. },
polarity: _,
}) => {
for subst in &args[1..] {
subst.visit_with(&mut collector);
for arg in &args[1..] {
arg.visit_with(&mut collector);
}
}
ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_ty: ty::AliasTy { args, .. },
term,
}) => {
for subst in &args[1..] {
subst.visit_with(&mut collector);
for arg in &args[1..] {
arg.visit_with(&mut collector);
}
term.visit_with(&mut collector);
}