1
Fork 0

Rollup merge of #104926 - spastorino:calculate_diverging_fallback-cleanups, r=lcnr

Move relationships from FulfillmentContext to Inherited

r? `@lcnr`
This commit is contained in:
Dylan DPC 2023-01-23 11:52:04 +05:30 committed by GitHub
commit 3d4c3125be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 61 additions and 113 deletions

View file

@ -196,8 +196,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> { ) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
debug!("calculate_diverging_fallback({:?})", unsolved_variables); debug!("calculate_diverging_fallback({:?})", unsolved_variables);
let relationships = self.fulfillment_cx.borrow_mut().relationships().clone();
// Construct a coercion graph where an edge `A -> B` indicates // Construct a coercion graph where an edge `A -> B` indicates
// a type variable is that is coerced // a type variable is that is coerced
let coercion_graph = self.create_coercion_graph(); let coercion_graph = self.create_coercion_graph();
@ -281,9 +279,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
roots_reachable_from_non_diverging, roots_reachable_from_non_diverging,
); );
debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations());
debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations()); debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
debug!("relationships: {:#?}", relationships);
// For each diverging variable, figure out whether it can // For each diverging variable, figure out whether it can
// reach a member of N. If so, it falls back to `()`. Else // reach a member of N. If so, it falls back to `()`. Else
@ -297,16 +293,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
.depth_first_search(root_vid) .depth_first_search(root_vid)
.any(|n| roots_reachable_from_non_diverging.visited(n)); .any(|n| roots_reachable_from_non_diverging.visited(n));
let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; let mut found_infer_var_info = ty::InferVarInfo { self_in_trait: false, output: false };
for (vid, rel) in relationships.iter() { for (vid, info) in self.inh.infer_var_info.borrow().iter() {
if self.root_var(*vid) == root_vid { if self.infcx.root_var(*vid) == root_vid {
relationship.self_in_trait |= rel.self_in_trait; found_infer_var_info.self_in_trait |= info.self_in_trait;
relationship.output |= rel.output; found_infer_var_info.output |= info.output;
} }
} }
if relationship.self_in_trait && relationship.output { if found_infer_var_info.self_in_trait && found_infer_var_info.output {
// This case falls back to () to ensure that the code pattern in // This case falls back to () to ensure that the code pattern in
// tests/ui/never_type/fallback-closure-ret.rs continues to // tests/ui/never_type/fallback-closure-ret.rs continues to
// compile when never_type_fallback is enabled. // compile when never_type_fallback is enabled.

View file

@ -1,6 +1,6 @@
use super::callee::DeferredCallResolution; use super::callee::DeferredCallResolution;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap; use rustc_hir::HirIdMap;
@ -10,7 +10,8 @@ use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap; use rustc_span::def_id::LocalDefIdMap;
use rustc_span::{self, Span}; use rustc_span::{self, Span};
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _};
use std::cell::RefCell; use std::cell::RefCell;
use std::ops::Deref; use std::ops::Deref;
@ -63,6 +64,8 @@ pub struct Inherited<'tcx> {
/// we record that type variable here. This is later used to inform /// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details. /// fallback. See the `fallback` module for details.
pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>, pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
pub(super) infer_var_info: RefCell<FxHashMap<ty::TyVid, ty::InferVarInfo>>,
} }
impl<'tcx> Deref for Inherited<'tcx> { impl<'tcx> Deref for Inherited<'tcx> {
@ -128,6 +131,7 @@ impl<'tcx> Inherited<'tcx> {
deferred_generator_interiors: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()), diverging_type_vars: RefCell::new(Default::default()),
body_id, body_id,
infer_var_info: RefCell::new(Default::default()),
} }
} }
@ -136,6 +140,9 @@ impl<'tcx> Inherited<'tcx> {
if obligation.has_escaping_bound_vars() { if obligation.has_escaping_bound_vars() {
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
} }
self.update_infer_var_info(&obligation);
self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
} }
@ -152,4 +159,43 @@ impl<'tcx> Inherited<'tcx> {
self.register_predicates(infer_ok.obligations); self.register_predicates(infer_ok.obligations);
infer_ok.value infer_ok.value
} }
pub fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) {
let infer_var_info = &mut self.infer_var_info.borrow_mut();
// (*) binder skipped
if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
&& self.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
{
let new_self_ty = self.tcx.types.unit;
// Then construct a new obligation with Self = () added
// to the ParamEnv, and see if it holds.
let o = obligation.with(self.tcx,
obligation
.predicate
.kind()
.rebind(
// (*) binder moved here
ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(self.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() {
infer_var_info.entry(ty).or_default().self_in_trait = true;
}
}
if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
{
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("infer_var_info: {:?}.output = true", vid);
infer_var_info.entry(vid).or_default().output = true;
}
}
}
} }

View file

@ -1,6 +1,5 @@
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::Obligation; use crate::traits::Obligation;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_middle::ty::{self, ToPredicate, Ty};
@ -42,8 +41,6 @@ pub trait TraitEngine<'tcx>: 'tcx {
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
} }
pub trait TraitEngineExt<'tcx> { pub trait TraitEngineExt<'tcx> {

View file

@ -2619,7 +2619,7 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
} }
#[derive(Debug, Default, Copy, Clone)] #[derive(Debug, Default, Copy, Clone)]
pub struct FoundRelationships { pub struct InferVarInfo {
/// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
/// obligation, where: /// obligation, where:
/// ///

View file

@ -1,6 +1,5 @@
use std::mem; use std::mem;
use rustc_data_structures::fx::FxHashMap;
use rustc_infer::{ use rustc_infer::{
infer::InferCtxt, infer::InferCtxt,
traits::{ traits::{
@ -8,7 +7,6 @@ use rustc_infer::{
SelectionError, TraitEngine, SelectionError, TraitEngine,
}, },
}; };
use rustc_middle::ty;
use super::{search_graph, Certainty, EvalCtxt}; use super::{search_graph, Certainty, EvalCtxt};
@ -102,8 +100,4 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.clone() self.obligations.clone()
} }
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
unimplemented!("Should be moved out of `TraitEngine`")
}
} }

View file

@ -7,24 +7,18 @@ use crate::traits::{
ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation, ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
SelectionError, TraitEngine, SelectionError, TraitEngine,
}; };
use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{self, TypeVisitable}; use rustc_middle::ty::TypeVisitable;
pub struct FulfillmentContext<'tcx> { pub struct FulfillmentContext<'tcx> {
obligations: FxIndexSet<PredicateObligation<'tcx>>, obligations: FxIndexSet<PredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
usable_in_snapshot: bool, usable_in_snapshot: bool,
} }
impl FulfillmentContext<'_> { impl FulfillmentContext<'_> {
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
FulfillmentContext { FulfillmentContext { obligations: FxIndexSet::default(), usable_in_snapshot: false }
obligations: FxIndexSet::default(),
relationships: FxHashMap::default(),
usable_in_snapshot: false,
}
} }
pub(crate) fn new_in_snapshot() -> Self { pub(crate) fn new_in_snapshot() -> Self {
@ -43,8 +37,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
} }
let obligation = infcx.resolve_vars_if_possible(obligation); let obligation = infcx.resolve_vars_if_possible(obligation);
super::relationships::update(self, infcx, &obligation);
self.obligations.insert(obligation); self.obligations.insert(obligation);
} }
@ -154,8 +146,4 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.iter().cloned().collect() self.obligations.iter().cloned().collect()
} }
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
} }

View file

@ -1,5 +1,4 @@
use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@ -54,8 +53,6 @@ pub struct FulfillmentContext<'tcx> {
// fulfillment context. // fulfillment context.
predicates: ObligationForest<PendingPredicateObligation<'tcx>>, predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
// Is it OK to register obligations into this infcx inside // Is it OK to register obligations into this infcx inside
// an infcx snapshot? // an infcx snapshot?
// //
@ -85,19 +82,11 @@ static_assert_size!(PendingPredicateObligation<'_>, 72);
impl<'a, 'tcx> FulfillmentContext<'tcx> { impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context. /// Creates a new fulfillment context.
pub(super) fn new() -> FulfillmentContext<'tcx> { pub(super) fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext { FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: false }
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
usable_in_snapshot: false,
}
} }
pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> { pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> {
FulfillmentContext { FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: true }
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
usable_in_snapshot: true,
}
} }
/// Attempts to select obligations using `selcx`. /// Attempts to select obligations using `selcx`.
@ -139,8 +128,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
super::relationships::update(self, infcx, &obligation);
self.predicates self.predicates
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
} }
@ -164,10 +151,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone()) self.predicates.map_pending_obligations(|o| o.obligation.clone())
} }
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
} }
struct FulfillProcessor<'a, 'tcx> { struct FulfillProcessor<'a, 'tcx> {

View file

@ -14,7 +14,6 @@ mod object_safety;
pub mod outlives_bounds; pub mod outlives_bounds;
mod project; mod project;
pub mod query; pub mod query;
pub(crate) mod relationships;
mod select; mod select;
mod specialize; mod specialize;
mod structural_match; mod structural_match;

View file

@ -1,48 +0,0 @@
use crate::infer::InferCtxt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::PredicateObligation;
use rustc_infer::traits::TraitEngine;
use rustc_middle::ty;
pub(crate) fn update<'tcx, T>(
engine: &mut T,
infcx: &InferCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>,
) where
T: TraitEngine<'tcx>,
{
// (*) binder skipped
if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = infcx.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| infcx.root_var(t))
&& infcx.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
{
let new_self_ty = infcx.tcx.types.unit;
// Then construct a new obligation with Self = () added
// to the ParamEnv, and see if it holds.
let o = obligation.with(infcx.tcx,
obligation
.predicate
.kind()
.rebind(
// (*) binder moved here
ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() {
engine.relationships().entry(ty).or_default().self_in_trait = true;
}
}
if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
{
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true;
}
}
}

View file

@ -1,12 +1,5 @@
// compile-flags: -Ztrait-solver=next // compile-flags: -Ztrait-solver=next
// known-bug: unknown // check-pass
// failure-status: 101
// dont-check-compiler-stderr
// This test will fail until we fix `FulfillmentCtxt::relationships`. That's
// because we create a type variable for closure upvar types, which is not
// constrained until after we try to do fallback on diverging type variables.
// Thus, we will call that function, which is unimplemented.
fn require_fn(_: impl Fn() -> i32) {} fn require_fn(_: impl Fn() -> i32) {}