Skip to content

Move relationships from FulfillmentContext to Inherited #104926

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
Show file tree
Hide file tree
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
16 changes: 6 additions & 10 deletions compiler/rustc_hir_typeck/src/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
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
// a type variable is that is coerced
let coercion_graph = self.create_coercion_graph();
Expand Down Expand Up @@ -281,9 +279,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
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!("relationships: {:#?}", relationships);

// For each diverging variable, figure out whether it can
// reach a member of N. If so, it falls back to `()`. Else
Expand All @@ -297,16 +293,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
.depth_first_search(root_vid)
.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() {
if self.root_var(*vid) == root_vid {
relationship.self_in_trait |= rel.self_in_trait;
relationship.output |= rel.output;
for (vid, info) in self.inh.infer_var_info.borrow().iter() {
if self.infcx.root_var(*vid) == root_vid {
found_infer_var_info.self_in_trait |= info.self_in_trait;
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
// tests/ui/never_type/fallback-closure-ret.rs continues to
// compile when never_type_fallback is enabled.
Expand Down
50 changes: 48 additions & 2 deletions compiler/rustc_hir_typeck/src/inherited.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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::def_id::LocalDefId;
use rustc_hir::HirIdMap;
Expand All @@ -10,7 +10,8 @@ use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
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::ops::Deref;
Expand Down Expand Up @@ -63,6 +64,8 @@ pub struct Inherited<'tcx> {
/// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details.
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> {
Expand Down Expand Up @@ -128,6 +131,7 @@ impl<'tcx> Inherited<'tcx> {
deferred_generator_interiors: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()),
body_id,
infer_var_info: RefCell::new(Default::default()),
}
}

Expand All @@ -136,6 +140,9 @@ impl<'tcx> Inherited<'tcx> {
if obligation.has_escaping_bound_vars() {
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);
}

Expand All @@ -152,4 +159,43 @@ impl<'tcx> Inherited<'tcx> {
self.register_predicates(infer_ok.obligations);
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;
}
}
}
}
3 changes: 0 additions & 3 deletions compiler/rustc_infer/src/traits/engine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ToPredicate, Ty};

Expand Down Expand Up @@ -42,8 +41,6 @@ pub trait TraitEngine<'tcx>: 'tcx {
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;

fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;

fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
}

pub trait TraitEngineExt<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2619,7 +2619,7 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
}

#[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`
/// obligation, where:
///
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use std::mem;

use rustc_data_structures::fx::FxHashMap;
use rustc_infer::{
infer::InferCtxt,
traits::{
query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
SelectionError, TraitEngine,
},
};
use rustc_middle::ty;

use super::{search_graph, Certainty, EvalCtxt};

Expand Down Expand Up @@ -102,8 +100,4 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.clone()
}

fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
unimplemented!("Should be moved out of `TraitEngine`")
}
}
18 changes: 3 additions & 15 deletions compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,18 @@ use crate::traits::{
ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
SelectionError, TraitEngine,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::ty::{self, TypeVisitable};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::TypeVisitable;

pub struct FulfillmentContext<'tcx> {
obligations: FxIndexSet<PredicateObligation<'tcx>>,

relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,

usable_in_snapshot: bool,
}

impl FulfillmentContext<'_> {
pub(super) fn new() -> Self {
FulfillmentContext {
obligations: FxIndexSet::default(),
relationships: FxHashMap::default(),
usable_in_snapshot: false,
}
FulfillmentContext { obligations: FxIndexSet::default(), usable_in_snapshot: false }
}

pub(crate) fn new_in_snapshot() -> Self {
Expand All @@ -43,8 +37,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
}
let obligation = infcx.resolve_vars_if_possible(obligation);

super::relationships::update(self, infcx, &obligation);

self.obligations.insert(obligation);
}

Expand Down Expand Up @@ -154,8 +146,4 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.iter().cloned().collect()
}

fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
}
21 changes: 2 additions & 19 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
Expand Down Expand Up @@ -54,8 +53,6 @@ pub struct FulfillmentContext<'tcx> {
// fulfillment context.
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,

relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,

// Is it OK to register obligations into this infcx inside
// an infcx snapshot?
//
Expand Down Expand Up @@ -85,19 +82,11 @@ static_assert_size!(PendingPredicateObligation<'_>, 72);
impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
pub(super) fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
usable_in_snapshot: false,
}
FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: false }
}

pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
usable_in_snapshot: true,
}
FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: true }
}

/// Attempts to select obligations using `selcx`.
Expand Down Expand Up @@ -139,8 +128,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {

assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);

super::relationships::update(self, infcx, &obligation);

self.predicates
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
Expand All @@ -164,10 +151,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
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> {
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ mod object_safety;
pub mod outlives_bounds;
mod project;
pub mod query;
pub(crate) mod relationships;
mod select;
mod specialize;
mod structural_match;
Expand Down
48 changes: 0 additions & 48 deletions compiler/rustc_trait_selection/src/traits/relationships.rs

This file was deleted.

9 changes: 1 addition & 8 deletions tests/ui/traits/new-solver/fn-trait-closure.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
// compile-flags: -Ztrait-solver=next
// known-bug: unknown
// 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.
// check-pass

fn require_fn(_: impl Fn() -> i32) {}

Expand Down