Auto merge of #127438 - compiler-errors:compute-outlives-visitor, r=lcnr
Make `push_outlives_components` into a `TypeVisitor`
This involves removing the `visited: &mut SsoHashSet<GenericArg<'tcx>>` that is being passed around the `VerifyBoundCx`. The fact that we were using it when decomposing different type tests seems sketchy, so I don't think, though it may technically result in us registering more redundant outlives components 🤷
I did end up deleting some of the comments that referred back to RFC 1214 during this refactor. I can add them back if you think they were useful.
r? lcnr
This commit is contained in:
commit
59a4f02f83
3 changed files with 150 additions and 270 deletions
|
@ -471,7 +471,7 @@ where
|
||||||
// projection outlive; in some cases, this may add insufficient
|
// projection outlive; in some cases, this may add insufficient
|
||||||
// edges into the inference graph, leading to inference failures
|
// edges into the inference graph, leading to inference failures
|
||||||
// even though a satisfactory solution exists.
|
// even though a satisfactory solution exists.
|
||||||
let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default());
|
let verify_bound = self.verify_bound.alias_bound(alias_ty);
|
||||||
debug!("alias_must_outlive: pushing {:?}", verify_bound);
|
debug!("alias_must_outlive: pushing {:?}", verify_bound);
|
||||||
self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
|
self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::infer::outlives::env::RegionBoundPairs;
|
use crate::infer::outlives::env::RegionBoundPairs;
|
||||||
use crate::infer::region_constraints::VerifyIfEq;
|
use crate::infer::region_constraints::VerifyIfEq;
|
||||||
use crate::infer::{GenericKind, VerifyBound};
|
use crate::infer::{GenericKind, VerifyBound};
|
||||||
use rustc_data_structures::sso::SsoHashSet;
|
|
||||||
use rustc_middle::ty::GenericArg;
|
|
||||||
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
|
||||||
use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
|
use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
|
||||||
|
|
||||||
|
@ -99,12 +97,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
|
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, visited))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
pub fn alias_bound(
|
pub fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
|
||||||
&self,
|
|
||||||
alias_ty: ty::AliasTy<'tcx>,
|
|
||||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
|
||||||
) -> VerifyBound<'tcx> {
|
|
||||||
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
|
||||||
|
|
||||||
// Search the env for where clauses like `P: 'a`.
|
// Search the env for where clauses like `P: 'a`.
|
||||||
|
@ -130,21 +124,17 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
// see the extensive comment in projection_must_outlive
|
// see the extensive comment in projection_must_outlive
|
||||||
let recursive_bound = {
|
let recursive_bound = {
|
||||||
let mut components = smallvec![];
|
let mut components = smallvec![];
|
||||||
compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components, visited);
|
compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components);
|
||||||
self.bound_from_components(&components, visited)
|
self.bound_from_components(&components)
|
||||||
};
|
};
|
||||||
|
|
||||||
VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
|
VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bound_from_components(
|
fn bound_from_components(&self, components: &[Component<TyCtxt<'tcx>>]) -> VerifyBound<'tcx> {
|
||||||
&self,
|
|
||||||
components: &[Component<TyCtxt<'tcx>>],
|
|
||||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
|
||||||
) -> VerifyBound<'tcx> {
|
|
||||||
let mut bounds = components
|
let mut bounds = components
|
||||||
.iter()
|
.iter()
|
||||||
.map(|component| self.bound_from_single_component(component, visited))
|
.map(|component| self.bound_from_single_component(component))
|
||||||
// Remove bounds that must hold, since they are not interesting.
|
// Remove bounds that must hold, since they are not interesting.
|
||||||
.filter(|bound| !bound.must_hold());
|
.filter(|bound| !bound.must_hold());
|
||||||
|
|
||||||
|
@ -159,7 +149,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
fn bound_from_single_component(
|
fn bound_from_single_component(
|
||||||
&self,
|
&self,
|
||||||
component: &Component<TyCtxt<'tcx>>,
|
component: &Component<TyCtxt<'tcx>>,
|
||||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
|
||||||
) -> VerifyBound<'tcx> {
|
) -> VerifyBound<'tcx> {
|
||||||
match *component {
|
match *component {
|
||||||
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
||||||
|
@ -167,10 +156,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
Component::Placeholder(placeholder_ty) => {
|
Component::Placeholder(placeholder_ty) => {
|
||||||
self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty))
|
self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty))
|
||||||
}
|
}
|
||||||
Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
|
Component::Alias(alias_ty) => self.alias_bound(alias_ty),
|
||||||
Component::EscapingAlias(ref components) => {
|
Component::EscapingAlias(ref components) => self.bound_from_components(components),
|
||||||
self.bound_from_components(components, visited)
|
|
||||||
}
|
|
||||||
Component::UnresolvedInferenceVariable(v) => {
|
Component::UnresolvedInferenceVariable(v) => {
|
||||||
// Ignore this, we presume it will yield an error later, since
|
// Ignore this, we presume it will yield an error later, since
|
||||||
// if a type variable is not resolved by this point it never
|
// if a type variable is not resolved by this point it never
|
||||||
|
|
|
@ -3,11 +3,10 @@
|
||||||
//! RFC for reference.
|
//! RFC for reference.
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use crate::data_structures::SsoHashSet;
|
use crate::data_structures::SsoHashSet;
|
||||||
use crate::inherent::*;
|
use crate::inherent::*;
|
||||||
use crate::visit::TypeVisitableExt as _;
|
use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor};
|
||||||
use crate::{self as ty, Interner};
|
use crate::{self as ty, Interner};
|
||||||
|
|
||||||
#[derive(derivative::Derivative)]
|
#[derive(derivative::Derivative)]
|
||||||
|
@ -55,41 +54,22 @@ pub enum Component<I: Interner> {
|
||||||
/// Push onto `out` all the things that must outlive `'a` for the condition
|
/// Push onto `out` all the things that must outlive `'a` for the condition
|
||||||
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
|
/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
|
||||||
pub fn push_outlives_components<I: Interner>(
|
pub fn push_outlives_components<I: Interner>(
|
||||||
tcx: I,
|
|
||||||
ty0: I::Ty,
|
|
||||||
out: &mut SmallVec<[Component<I>; 4]>,
|
|
||||||
) {
|
|
||||||
let mut visited = SsoHashSet::new();
|
|
||||||
compute_components_for_ty(tcx, ty0, out, &mut visited);
|
|
||||||
debug!("components({:?}) = {:?}", ty0, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_components_for_arg<I: Interner>(
|
|
||||||
tcx: I,
|
|
||||||
arg: I::GenericArg,
|
|
||||||
out: &mut SmallVec<[Component<I>; 4]>,
|
|
||||||
visited: &mut SsoHashSet<I::GenericArg>,
|
|
||||||
) {
|
|
||||||
match arg.kind() {
|
|
||||||
ty::GenericArgKind::Type(ty) => {
|
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
|
||||||
}
|
|
||||||
ty::GenericArgKind::Lifetime(lt) => {
|
|
||||||
compute_components_for_lt(lt, out);
|
|
||||||
}
|
|
||||||
ty::GenericArgKind::Const(ct) => {
|
|
||||||
compute_components_for_const(tcx, ct, out, visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_components_for_ty<I: Interner>(
|
|
||||||
tcx: I,
|
tcx: I,
|
||||||
ty: I::Ty,
|
ty: I::Ty,
|
||||||
out: &mut SmallVec<[Component<I>; 4]>,
|
out: &mut SmallVec<[Component<I>; 4]>,
|
||||||
visited: &mut SsoHashSet<I::GenericArg>,
|
|
||||||
) {
|
) {
|
||||||
if !visited.insert(ty.into()) {
|
ty.visit_with(&mut OutlivesCollector { tcx, out, visited: Default::default() });
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OutlivesCollector<'a, I: Interner> {
|
||||||
|
tcx: I,
|
||||||
|
out: &'a mut SmallVec<[Component<I>; 4]>,
|
||||||
|
visited: SsoHashSet<I::Ty>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
|
||||||
|
fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
|
||||||
|
if !self.visited.insert(ty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Descend through the types, looking for the various "base"
|
// Descend through the types, looking for the various "base"
|
||||||
|
@ -108,35 +88,24 @@ fn compute_components_for_ty<I: Interner>(
|
||||||
// for further background and discussion.
|
// for further background and discussion.
|
||||||
for child in args.iter() {
|
for child in args.iter() {
|
||||||
match child.kind() {
|
match child.kind() {
|
||||||
ty::GenericArgKind::Type(ty) => {
|
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
|
||||||
}
|
|
||||||
ty::GenericArgKind::Lifetime(_) => {}
|
ty::GenericArgKind::Lifetime(_) => {}
|
||||||
ty::GenericArgKind::Const(ct) => {
|
ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => {
|
||||||
compute_components_for_const(tcx, ct, out, visited);
|
child.visit_with(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Pat(element, _) | ty::Array(element, _) => {
|
|
||||||
compute_components_for_ty(tcx, element, out, visited);
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Closure(_, args) => {
|
ty::Closure(_, args) => {
|
||||||
let tupled_ty = args.as_closure().tupled_upvars_ty();
|
args.as_closure().tupled_upvars_ty().visit_with(self);
|
||||||
compute_components_for_ty(tcx, tupled_ty, out, visited);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::CoroutineClosure(_, args) => {
|
ty::CoroutineClosure(_, args) => {
|
||||||
let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty();
|
args.as_coroutine_closure().tupled_upvars_ty().visit_with(self);
|
||||||
compute_components_for_ty(tcx, tupled_ty, out, visited);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Coroutine(_, args) => {
|
ty::Coroutine(_, args) => {
|
||||||
// Same as the closure case
|
args.as_coroutine().tupled_upvars_ty().visit_with(self);
|
||||||
let tupled_ty = args.as_coroutine().tupled_upvars_ty();
|
|
||||||
compute_components_for_ty(tcx, tupled_ty, out, visited);
|
|
||||||
|
|
||||||
// We ignore regions in the coroutine interior as we don't
|
// We ignore regions in the coroutine interior as we don't
|
||||||
// want these to affect region inference
|
// want these to affect region inference
|
||||||
|
@ -144,16 +113,16 @@ fn compute_components_for_ty<I: Interner>(
|
||||||
|
|
||||||
// All regions are bound inside a witness, and we don't emit
|
// All regions are bound inside a witness, and we don't emit
|
||||||
// higher-ranked outlives components currently.
|
// higher-ranked outlives components currently.
|
||||||
ty::CoroutineWitness(..) => {},
|
ty::CoroutineWitness(..) => {}
|
||||||
|
|
||||||
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
|
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
|
||||||
// is implied by the environment is done in regionck.
|
// is implied by the environment is done in regionck.
|
||||||
ty::Param(p) => {
|
ty::Param(p) => {
|
||||||
out.push(Component::Param(p));
|
self.out.push(Component::Param(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Placeholder(p) => {
|
ty::Placeholder(p) => {
|
||||||
out.push(Component::Placeholder(p));
|
self.out.push(Component::Placeholder(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For projections, we prefer to generate an obligation like
|
// For projections, we prefer to generate an obligation like
|
||||||
|
@ -172,15 +141,14 @@ fn compute_components_for_ty<I: Interner>(
|
||||||
// the rules OutlivesProjectionEnv,
|
// the rules OutlivesProjectionEnv,
|
||||||
// OutlivesProjectionTraitDef, and
|
// OutlivesProjectionTraitDef, and
|
||||||
// OutlivesProjectionComponents to regionck.
|
// OutlivesProjectionComponents to regionck.
|
||||||
out.push(Component::Alias(alias_ty));
|
self.out.push(Component::Alias(alias_ty));
|
||||||
} else {
|
} else {
|
||||||
// fallback case: hard code
|
// fallback case: hard code
|
||||||
// OutlivesProjectionComponents. Continue walking
|
// OutlivesProjectionComponents. Continue walking
|
||||||
// through and constrain Pi.
|
// through and constrain Pi.
|
||||||
let mut subcomponents = smallvec![];
|
let mut subcomponents = smallvec![];
|
||||||
let mut subvisited = SsoHashSet::new();
|
compute_alias_components_recursive(self.tcx, ty, &mut subcomponents);
|
||||||
compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited);
|
self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
|
||||||
out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,84 +156,47 @@ fn compute_components_for_ty<I: Interner>(
|
||||||
// So, if we encounter an inference variable, just record
|
// So, if we encounter an inference variable, just record
|
||||||
// the unresolved variable as a component.
|
// the unresolved variable as a component.
|
||||||
ty::Infer(infer_ty) => {
|
ty::Infer(infer_ty) => {
|
||||||
out.push(Component::UnresolvedInferenceVariable(infer_ty));
|
self.out.push(Component::UnresolvedInferenceVariable(infer_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most types do not introduce any region binders, nor
|
// Most types do not introduce any region binders, nor
|
||||||
// involve any other subtle cases, and so the WF relation
|
// involve any other subtle cases, and so the WF relation
|
||||||
// simply constraints any regions referenced directly by
|
// simply constraints any regions referenced directly by
|
||||||
// the type and then visits the types that are lexically
|
// the type and then visits the types that are lexically
|
||||||
// contained within. (The comments refer to relevant rules
|
// contained within.
|
||||||
// from RFC1214.)
|
ty::Bool
|
||||||
|
| ty::Char
|
||||||
ty::Bool | // OutlivesScalar
|
| ty::Int(_)
|
||||||
ty::Char | // OutlivesScalar
|
| ty::Uint(_)
|
||||||
ty::Int(..) | // OutlivesScalar
|
| ty::Float(_)
|
||||||
ty::Uint(..) | // OutlivesScalar
|
| ty::Str
|
||||||
ty::Float(..) | // OutlivesScalar
|
| ty::Never
|
||||||
ty::Never | // OutlivesScalar
|
| ty::Error(_) => {
|
||||||
ty::Foreign(..) | // OutlivesNominalType
|
// Trivial
|
||||||
ty::Str | // OutlivesScalar (ish)
|
|
||||||
ty::Bound(..) |
|
|
||||||
ty::Error(_) => {
|
|
||||||
// Trivial.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutlivesNominalType
|
ty::Bound(_, _) => {
|
||||||
ty::Adt(_, args) => {
|
// FIXME: Bound vars matter here!
|
||||||
for arg in args.iter() {
|
|
||||||
compute_components_for_arg(tcx, arg, out, visited);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutlivesNominalType
|
ty::Adt(_, _)
|
||||||
ty::Slice(ty) |
|
| ty::Foreign(_)
|
||||||
ty::RawPtr(ty, _) => {
|
| ty::Array(_, _)
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
| ty::Pat(_, _)
|
||||||
}
|
| ty::Slice(_)
|
||||||
ty::Tuple(tys) => {
|
| ty::RawPtr(_, _)
|
||||||
for ty in tys.iter() {
|
| ty::Ref(_, _, _)
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
| ty::FnPtr(_)
|
||||||
}
|
| ty::Dynamic(_, _, _)
|
||||||
}
|
| ty::Tuple(_) => {
|
||||||
|
ty.super_visit_with(self);
|
||||||
// OutlivesReference
|
|
||||||
ty::Ref(lt, ty, _) => {
|
|
||||||
compute_components_for_lt(lt, out);
|
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Dynamic(preds, lt, _) => {
|
|
||||||
compute_components_for_lt(lt, out);
|
|
||||||
for pred in preds.iter() {
|
|
||||||
match pred.skip_binder() {
|
|
||||||
ty::ExistentialPredicate::Trait(tr) => {
|
|
||||||
for arg in tr.args.iter() {
|
|
||||||
compute_components_for_arg(tcx, arg, out, visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::ExistentialPredicate::Projection(proj) => {
|
|
||||||
for arg in proj.args.iter() {
|
|
||||||
compute_components_for_arg(tcx, arg, out, visited);
|
|
||||||
}
|
|
||||||
match proj.term.kind() {
|
|
||||||
ty::TermKind::Ty(ty) => {
|
|
||||||
compute_components_for_ty(tcx, ty, out, visited)
|
|
||||||
}
|
|
||||||
ty::TermKind::Const(ct) => {
|
|
||||||
compute_components_for_const(tcx, ct, out, visited)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::ExistentialPredicate::AutoTrait(..) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::FnPtr(sig) => {
|
fn visit_region(&mut self, lt: I::Region) -> Self::Result {
|
||||||
for ty in sig.skip_binder().inputs_and_output.iter() {
|
if !lt.is_bound() {
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
self.out.push(Component::Region(lt));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,7 +209,6 @@ pub fn compute_alias_components_recursive<I: Interner>(
|
||||||
tcx: I,
|
tcx: I,
|
||||||
alias_ty: I::Ty,
|
alias_ty: I::Ty,
|
||||||
out: &mut SmallVec<[Component<I>; 4]>,
|
out: &mut SmallVec<[Component<I>; 4]>,
|
||||||
visited: &mut SsoHashSet<I::GenericArg>,
|
|
||||||
) {
|
) {
|
||||||
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
|
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
|
||||||
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
|
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
|
||||||
|
@ -287,49 +217,12 @@ pub fn compute_alias_components_recursive<I: Interner>(
|
||||||
let opt_variances =
|
let opt_variances =
|
||||||
if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None };
|
if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None };
|
||||||
|
|
||||||
|
let mut visitor = OutlivesCollector { tcx, out, visited: Default::default() };
|
||||||
|
|
||||||
for (index, child) in alias_ty.args.iter().enumerate() {
|
for (index, child) in alias_ty.args.iter().enumerate() {
|
||||||
if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) {
|
if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
compute_components_for_arg(tcx, child, out, visited);
|
child.visit_with(&mut visitor);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_components_for_lt<I: Interner>(lt: I::Region, out: &mut SmallVec<[Component<I>; 4]>) {
|
|
||||||
if !lt.is_bound() {
|
|
||||||
out.push(Component::Region(lt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_components_for_const<I: Interner>(
|
|
||||||
tcx: I,
|
|
||||||
ct: I::Const,
|
|
||||||
out: &mut SmallVec<[Component<I>; 4]>,
|
|
||||||
visited: &mut SsoHashSet<I::GenericArg>,
|
|
||||||
) {
|
|
||||||
if !visited.insert(ct.into()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
match ct.kind() {
|
|
||||||
ty::ConstKind::Param(_)
|
|
||||||
| ty::ConstKind::Bound(_, _)
|
|
||||||
| ty::ConstKind::Infer(_)
|
|
||||||
| ty::ConstKind::Placeholder(_)
|
|
||||||
| ty::ConstKind::Error(_) => {
|
|
||||||
// Trivial
|
|
||||||
}
|
|
||||||
ty::ConstKind::Expr(e) => {
|
|
||||||
for arg in e.args().iter() {
|
|
||||||
compute_components_for_arg(tcx, arg, out, visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::ConstKind::Value(ty, _) => {
|
|
||||||
compute_components_for_ty(tcx, ty, out, visited);
|
|
||||||
}
|
|
||||||
ty::ConstKind::Unevaluated(uv) => {
|
|
||||||
for arg in uv.args.iter() {
|
|
||||||
compute_components_for_arg(tcx, arg, out, visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue