Skip to content

Rename compute_x methods #140186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 24, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 48 additions & 31 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! Core logic responsible for determining what it means for various type system
//! primitives to be "well formed". Actually checking whether these primitives are
//! well formed is performed elsewhere (e.g. during type checking or item well formedness
//! checking).

use std::iter;

use rustc_hir as hir;
Expand All @@ -15,12 +20,13 @@ use tracing::{debug, instrument, trace};

use crate::infer::InferCtxt;
use crate::traits;

/// Returns the set of obligations needed to make `arg` well-formed.
/// If `arg` contains unresolved inference variables, this may include
/// further WF obligations. However, if `arg` IS an unresolved
/// inference variable, returns `None`, because we are not able to
/// make any progress at all. This is to prevent "livelock" where we
/// say "$0 is WF if $0 is WF".
/// make any progress at all. This is to prevent cycles where we
/// say "?0 is WF if ?0 is WF".
pub fn obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
Expand All @@ -29,14 +35,14 @@ pub fn obligations<'tcx>(
arg: GenericArg<'tcx>,
span: Span,
) -> Option<PredicateObligations<'tcx>> {
// Handle the "livelock" case (see comment above) by bailing out if necessary.
// Handle the "cycle" case (see comment above) by bailing out if necessary.
let arg = match arg.unpack() {
GenericArgKind::Type(ty) => {
match ty.kind() {
ty::Infer(ty::TyVar(_)) => {
let resolved_ty = infcx.shallow_resolve(ty);
if resolved_ty == ty {
// No progress, bail out to prevent "livelock".
// No progress, bail out to prevent cycles.
return None;
} else {
resolved_ty
Expand All @@ -51,7 +57,7 @@ pub fn obligations<'tcx>(
ty::ConstKind::Infer(_) => {
let resolved = infcx.shallow_resolve_const(ct);
if resolved == ct {
// No progress.
// No progress, bail out to prevent cycles.
return None;
} else {
resolved
Expand All @@ -74,7 +80,7 @@ pub fn obligations<'tcx>(
recursion_depth,
item: None,
};
wf.compute(arg);
wf.add_wf_preds_for_generic_arg(arg);
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);

let result = wf.normalize(infcx);
Expand All @@ -97,7 +103,7 @@ pub fn unnormalized_obligations<'tcx>(

// However, if `arg` IS an unresolved inference variable, returns `None`,
// because we are not able to make any progress at all. This is to prevent
// "livelock" where we say "$0 is WF if $0 is WF".
// cycles where we say "?0 is WF if ?0 is WF".
if arg.is_non_region_infer() {
return None;
}
Expand All @@ -115,7 +121,7 @@ pub fn unnormalized_obligations<'tcx>(
recursion_depth: 0,
item: None,
};
wf.compute(arg);
wf.add_wf_preds_for_generic_arg(arg);
Some(wf.out)
}

Expand All @@ -140,7 +146,7 @@ pub fn trait_obligations<'tcx>(
recursion_depth: 0,
item: Some(item),
};
wf.compute_trait_pred(trait_pred, Elaborate::All);
wf.add_wf_preds_for_trait_pred(trait_pred, Elaborate::All);
debug!(obligations = ?wf.out);
wf.normalize(infcx)
}
Expand Down Expand Up @@ -171,30 +177,30 @@ pub fn clause_obligations<'tcx>(
// It's ok to skip the binder here because wf code is prepared for it
match clause.kind().skip_binder() {
ty::ClauseKind::Trait(t) => {
wf.compute_trait_pred(t, Elaborate::None);
wf.add_wf_preds_for_trait_pred(t, Elaborate::None);
}
ty::ClauseKind::HostEffect(..) => {
// Technically the well-formedness of this predicate is implied by
// the corresponding trait predicate it should've been generated beside.
}
ty::ClauseKind::RegionOutlives(..) => {}
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
wf.compute(ty.into());
wf.add_wf_preds_for_generic_arg(ty.into());
}
ty::ClauseKind::Projection(t) => {
wf.compute_alias_term(t.projection_term);
wf.compute(t.term.into_arg());
wf.add_wf_preds_for_alias_term(t.projection_term);
wf.add_wf_preds_for_generic_arg(t.term.into_arg());
}
ty::ClauseKind::ConstArgHasType(ct, ty) => {
wf.compute(ct.into());
wf.compute(ty.into());
wf.add_wf_preds_for_generic_arg(ct.into());
wf.add_wf_preds_for_generic_arg(ty.into());
}
ty::ClauseKind::WellFormed(arg) => {
wf.compute(arg);
wf.add_wf_preds_for_generic_arg(arg);
}

ty::ClauseKind::ConstEvaluatable(ct) => {
wf.compute(ct.into());
wf.add_wf_preds_for_generic_arg(ct.into());
}
}

Expand Down Expand Up @@ -372,14 +378,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}

/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
fn add_wf_preds_for_trait_pred(
&mut self,
trait_pred: ty::TraitPredicate<'tcx>,
elaborate: Elaborate,
) {
let tcx = self.tcx();
let trait_ref = trait_pred.trait_ref;

// Negative trait predicates don't require supertraits to hold, just
// that their args are WF.
if trait_pred.polarity == ty::PredicatePolarity::Negative {
self.compute_negative_trait_pred(trait_ref);
self.add_wf_preds_for_negative_trait_pred(trait_ref);
return;
}

Expand Down Expand Up @@ -445,15 +455,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {

// Compute the obligations that are required for `trait_ref` to be WF,
// given that it is a *negative* trait predicate.
fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
for arg in trait_ref.args {
self.compute(arg);
self.add_wf_preds_for_generic_arg(arg);
}
}

/// Pushes the obligations required for an alias (except inherent) to be WF
/// into `self.out`.
fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
fn add_wf_preds_for_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
// A projection is well-formed if
//
// (a) its predicates hold (*)
Expand All @@ -478,13 +488,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let obligations = self.nominal_obligations(data.def_id, data.args);
self.out.extend(obligations);

self.compute_projection_args(data.args);
self.add_wf_preds_for_projection_args(data.args);
}

/// Pushes the obligations required for an inherent alias to be WF
/// into `self.out`.
// FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
// An inherent projection is well-formed if
//
// (a) its predicates hold (*)
Expand All @@ -511,7 +521,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
data.args.visit_with(self);
}

fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
fn add_wf_preds_for_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
let tcx = self.tcx();
let cause = self.cause(ObligationCauseCode::WellFormed(None));
let param_env = self.param_env;
Expand Down Expand Up @@ -557,7 +567,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {

/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
#[instrument(level = "debug", skip(self))]
fn compute(&mut self, arg: GenericArg<'tcx>) {
fn add_wf_preds_for_generic_arg(&mut self, arg: GenericArg<'tcx>) {
arg.visit_with(self);
debug!(?self.out);
}
Expand Down Expand Up @@ -596,7 +606,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
.collect()
}

fn from_object_ty(
fn add_wf_preds_for_dyn_ty(
&mut self,
ty: Ty<'tcx>,
data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
Expand Down Expand Up @@ -651,6 +661,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
outlives,
));
}

// We don't add any wf predicates corresponding to the trait ref's generic arguments
// which allows code like this to compile:
// ```rust
// trait Trait<T: Sized> {}
// fn foo(_: &dyn Trait<[u32]>) {}
// ```
}
}
}
Expand Down Expand Up @@ -761,7 +778,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
self.out.extend(obligations);
}
ty::Alias(ty::Inherent, data) => {
self.compute_inherent_projection(data);
self.add_wf_preds_for_inherent_projection(data);
return; // Subtree handled by compute_inherent_projection.
}

Expand Down Expand Up @@ -895,7 +912,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
//
// Here, we defer WF checking due to higher-ranked
// regions. This is perhaps not ideal.
self.from_object_ty(t, data, r);
self.add_wf_preds_for_dyn_ty(t, data, r);

// FIXME(#27579) RFC also considers adding trait
// obligations that don't refer to Self and
Expand All @@ -917,11 +934,11 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// 1. Check if they have been resolved, and if so proceed with
// THAT type.
// 2. If not, we've at least simplified things (e.g., we went
// from `Vec<$0>: WF` to `$0: WF`), so we can
// from `Vec?0>: WF` to `?0: WF`), so we can
// register a pending obligation and keep
// moving. (Goal is that an "inductive hypothesis"
// is satisfied to ensure termination.)
// See also the comment on `fn obligations`, describing "livelock"
// See also the comment on `fn obligations`, describing cycle
// prevention, which happens before this can be reached.
ty::Infer(_) => {
let cause = self.cause(ObligationCauseCode::WellFormed(None));
Expand Down
Loading