Skip to content

Commit 4b56fd9

Browse files
committed
try to avoid FnCtxt during wf
1 parent 29d0390 commit 4b56fd9

15 files changed

+468
-445
lines changed

compiler/rustc_trait_selection/src/traits/engine.rs

+95-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
use rustc_middle::ty::TyCtxt;
1+
use std::cell::RefCell;
22

33
use super::TraitEngine;
44
use super::{ChalkFulfillmentContext, FulfillmentContext};
5+
use crate::infer::InferCtxtExt;
6+
use rustc_hir::def_id::DefId;
7+
use rustc_infer::infer::{InferCtxt, InferOk};
8+
use rustc_infer::traits::{
9+
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
10+
};
11+
use rustc_middle::ty::error::TypeError;
12+
use rustc_middle::ty::ToPredicate;
13+
use rustc_middle::ty::TypeFoldable;
14+
use rustc_middle::ty::{self, Ty, TyCtxt};
515

616
pub trait TraitEngineExt<'tcx> {
717
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
@@ -16,3 +26,87 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
1626
}
1727
}
1828
}
29+
30+
/// Used if you want to have pleasant experience when dealing
31+
/// with obligations outside of hir or mir typeck.
32+
pub struct ObligationCtxt<'a, 'tcx> {
33+
pub infcx: &'a InferCtxt<'a, 'tcx>,
34+
engine: RefCell<Box<dyn TraitEngine<'tcx>>>,
35+
}
36+
37+
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
38+
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
39+
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
40+
}
41+
42+
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
43+
self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
44+
}
45+
46+
pub fn register_obligations(
47+
&self,
48+
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
49+
) {
50+
// Can't use `register_predicate_obligations` because the iterator
51+
// may also use this `ObligationCtxt`.
52+
for obligation in obligations {
53+
self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation)
54+
}
55+
}
56+
57+
pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
58+
let InferOk { value, obligations } = infer_ok;
59+
self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations);
60+
value
61+
}
62+
63+
/// Requires that `ty` must implement the trait with `def_id` in
64+
/// the given environment. This trait must not have any type
65+
/// parameters (except for `Self`).
66+
pub fn register_bound(
67+
&self,
68+
cause: ObligationCause<'tcx>,
69+
param_env: ty::ParamEnv<'tcx>,
70+
ty: Ty<'tcx>,
71+
def_id: DefId,
72+
) {
73+
let tcx = self.infcx.tcx;
74+
let trait_ref = ty::TraitRef { def_id, substs: tcx.mk_substs_trait(ty, &[]) };
75+
self.register_obligation(Obligation {
76+
cause,
77+
recursion_depth: 0,
78+
param_env,
79+
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
80+
});
81+
}
82+
83+
pub fn normalize<T: TypeFoldable<'tcx>>(
84+
&self,
85+
cause: ObligationCause<'tcx>,
86+
param_env: ty::ParamEnv<'tcx>,
87+
value: T,
88+
) -> T {
89+
let infer_ok = self.infcx.partially_normalize_associated_types_in(cause, param_env, value);
90+
self.register_infer_ok_obligations(infer_ok)
91+
}
92+
93+
pub fn equate_types(
94+
&self,
95+
cause: &ObligationCause<'tcx>,
96+
param_env: ty::ParamEnv<'tcx>,
97+
expected: Ty<'tcx>,
98+
actual: Ty<'tcx>,
99+
) -> Result<(), TypeError<'tcx>> {
100+
match self.infcx.at(cause, param_env).eq(expected, actual) {
101+
Ok(InferOk { obligations, value: () }) => {
102+
self.register_obligations(obligations);
103+
Ok(())
104+
}
105+
Err(e) => Err(e),
106+
}
107+
}
108+
109+
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
110+
self.engine.borrow_mut().select_all_or_error(self.infcx)
111+
}
112+
}

compiler/rustc_trait_selection/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub use self::SelectionError::*;
4747

4848
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
4949
pub use self::coherence::{OrphanCheckErr, OverlapResult};
50-
pub use self::engine::TraitEngineExt;
50+
pub use self::engine::{ObligationCtxt, TraitEngineExt};
5151
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
5252
pub use self::object_safety::astconv_object_safety_violations;
5353
pub use self::object_safety::is_vtable_safe_method;

compiler/rustc_typeck/src/check/check.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
use crate::check::wfcheck::for_item;
2-
31
use super::coercion::CoerceMany;
42
use super::compare_method::check_type_bounds;
53
use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
64
use super::*;
7-
85
use rustc_attr as attr;
96
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
107
use rustc_hir as hir;
@@ -29,8 +26,8 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE
2926
use rustc_span::symbol::sym;
3027
use rustc_span::{self, Span};
3128
use rustc_target::spec::abi::Abi;
32-
use rustc_trait_selection::traits;
3329
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
30+
use rustc_trait_selection::traits::{self, ObligationCtxt};
3431
use rustc_ty_utils::representability::{self, Representability};
3532

3633
use std::iter;
@@ -733,14 +730,13 @@ fn check_opaque_meets_bounds<'tcx>(
733730
let param_env = tcx.param_env(defining_use_anchor);
734731

735732
tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
736-
let inh = Inherited::new(infcx, def_id);
737-
let infcx = &inh.infcx;
733+
let ocx = ObligationCtxt::new(&infcx);
738734
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
739735

740736
let misc_cause = traits::ObligationCause::misc(span, hir_id);
741737

742738
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
743-
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
739+
Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
744740
Err(ty_err) => {
745741
tcx.sess.delay_span_bug(
746742
span,
@@ -754,11 +750,11 @@ fn check_opaque_meets_bounds<'tcx>(
754750
// hidden type is well formed even without those bounds.
755751
let predicate =
756752
ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
757-
inh.register_predicate(Obligation::new(misc_cause, param_env, predicate));
753+
ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
758754

759755
// Check that all obligations are satisfied by the implementation's
760756
// version.
761-
let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
757+
let errors = ocx.select_all_or_error();
762758
if !errors.is_empty() {
763759
infcx.report_fulfillment_errors(&errors, None, false);
764760
}
@@ -940,9 +936,10 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
940936
DefKind::GlobalAsm => {
941937
let it = tcx.hir().item(id);
942938
let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) };
943-
for_item(tcx, it).with_fcx(|fcx| {
939+
Inherited::build(tcx, it.def_id).enter(|inh| {
940+
let fcx = FnCtxt::new(&inh, tcx.param_env(it.def_id), id.hir_id());
944941
fcx.check_asm(asm, it.hir_id());
945-
Default::default()
942+
fcx.select_all_obligations_or_error();
946943
})
947944
}
948945
_ => {}

0 commit comments

Comments
 (0)