Skip to content

Commit 20703b3

Browse files
committed
introduce trait engine mod
1 parent 52f7e88 commit 20703b3

File tree

9 files changed

+160
-86
lines changed

9 files changed

+160
-86
lines changed

src/librustc/infer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use ty::{self, Ty, TyCtxt};
2727
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
2828
use ty::fold::TypeFoldable;
2929
use ty::relate::RelateResult;
30-
use traits::{self, ObligationCause, PredicateObligations};
30+
use traits::{self, ObligationCause, PredicateObligations, TraitEngine};
3131
use rustc_data_structures::unify as ut;
3232
use std::cell::{Cell, RefCell, Ref, RefMut};
3333
use std::collections::BTreeMap;

src/librustc/traits/engine.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use infer::InferCtxt;
12+
use ty::{self, Ty, TyCtxt};
13+
use hir::def_id::DefId;
14+
15+
use super::{FulfillmentContext, FulfillmentError};
16+
use super::{ObligationCause, PredicateObligation, PendingPredicateObligation};
17+
18+
pub trait TraitEngine<'tcx> {
19+
/// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
20+
/// creating a fresh type variable `$0` as well as a projection
21+
/// predicate `<SomeType as SomeTrait>::X == $0`. When the
22+
/// inference engine runs, it will attempt to find an impl of
23+
/// `SomeTrait` or a where clause that lets us unify `$0` with
24+
/// something concrete. If this fails, we'll unify `$0` with
25+
/// `projection_ty` again.
26+
fn normalize_projection_type<'a, 'gcx>(
27+
&mut self,
28+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
29+
param_env: ty::ParamEnv<'tcx>,
30+
projection_ty: ty::ProjectionTy<'tcx>,
31+
cause: ObligationCause<'tcx>,
32+
) -> Ty<'tcx>;
33+
34+
/// Requires that `ty` must implement the trait with `def_id` in
35+
/// the given environment. This trait must not have any type
36+
/// parameters (except for `Self`).
37+
fn register_bound<'a, 'gcx>(
38+
&mut self,
39+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
40+
param_env: ty::ParamEnv<'tcx>,
41+
ty: Ty<'tcx>,
42+
def_id: DefId,
43+
cause: ObligationCause<'tcx>,
44+
);
45+
46+
fn register_predicate_obligation<'a, 'gcx>(
47+
&mut self,
48+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
49+
obligation: PredicateObligation<'tcx>,
50+
);
51+
52+
fn select_all_or_error<'a, 'gcx>(
53+
&mut self,
54+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
55+
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
56+
57+
fn select_where_possible<'a, 'gcx>(
58+
&mut self,
59+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
60+
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
61+
62+
fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
63+
}
64+
65+
impl<'tcx> dyn TraitEngine<'tcx> {
66+
pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
67+
Box::new(FulfillmentContext::new())
68+
}
69+
}

src/librustc/traits/fulfill.rs

Lines changed: 76 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use middle::const_val::{ConstEvalErr, ErrKind};
2121
use super::CodeAmbiguity;
2222
use super::CodeProjectionError;
2323
use super::CodeSelectionError;
24+
use super::engine::TraitEngine;
2425
use super::{FulfillmentError, FulfillmentErrorCode};
2526
use super::{ObligationCause, PredicateObligation, Obligation};
2627
use super::project;
@@ -84,20 +85,73 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
8485
register_region_obligations: false
8586
}
8687
}
88+
89+
pub fn register_predicate_obligations<I>(&mut self,
90+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
91+
obligations: I)
92+
where I: IntoIterator<Item = PredicateObligation<'tcx>>
93+
{
94+
for obligation in obligations {
95+
self.register_predicate_obligation(infcx, obligation);
96+
}
97+
}
98+
99+
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
100+
/// only attempts to select obligations that haven't been seen before.
101+
fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
102+
-> Result<(),Vec<FulfillmentError<'tcx>>> {
103+
debug!("select(obligation-forest-size={})", self.predicates.len());
104+
105+
let mut errors = Vec::new();
106+
107+
loop {
108+
debug!("select: starting another iteration");
109+
110+
// Process pending obligations.
111+
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
112+
selcx,
113+
register_region_obligations: self.register_region_obligations
114+
});
115+
debug!("select: outcome={:?}", outcome);
116+
117+
// FIXME: if we kept the original cache key, we could mark projection
118+
// obligations as complete for the projection cache here.
119+
120+
errors.extend(
121+
outcome.errors.into_iter()
122+
.map(|e| to_fulfillment_error(e)));
123+
124+
// If nothing new was added, no need to keep looping.
125+
if outcome.stalled {
126+
break;
127+
}
128+
}
129+
130+
debug!("select({} predicates remaining, {} errors) done",
131+
self.predicates.len(), errors.len());
87132

133+
if errors.is_empty() {
134+
Ok(())
135+
} else {
136+
Err(errors)
137+
}
138+
}
139+
}
140+
141+
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
88142
/// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
89143
/// creating a fresh type variable `$0` as well as a projection
90144
/// predicate `<SomeType as SomeTrait>::X == $0`. When the
91145
/// inference engine runs, it will attempt to find an impl of
92146
/// `SomeTrait` or a where clause that lets us unify `$0` with
93147
/// something concrete. If this fails, we'll unify `$0` with
94148
/// `projection_ty` again.
95-
pub fn normalize_projection_type(&mut self,
96-
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
97-
param_env: ty::ParamEnv<'tcx>,
98-
projection_ty: ty::ProjectionTy<'tcx>,
99-
cause: ObligationCause<'tcx>)
100-
-> Ty<'tcx>
149+
fn normalize_projection_type<'a, 'gcx>(&mut self,
150+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
151+
param_env: ty::ParamEnv<'tcx>,
152+
projection_ty: ty::ProjectionTy<'tcx>,
153+
cause: ObligationCause<'tcx>)
154+
-> Ty<'tcx>
101155
{
102156
debug!("normalize_projection_type(projection_ty={:?})",
103157
projection_ty);
@@ -125,12 +179,12 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
125179
/// Requires that `ty` must implement the trait with `def_id` in
126180
/// the given environment. This trait must not have any type
127181
/// parameters (except for `Self`).
128-
pub fn register_bound(&mut self,
129-
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
130-
param_env: ty::ParamEnv<'tcx>,
131-
ty: Ty<'tcx>,
132-
def_id: DefId,
133-
cause: ObligationCause<'tcx>)
182+
fn register_bound<'a, 'gcx>(&mut self,
183+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
184+
param_env: ty::ParamEnv<'tcx>,
185+
ty: Ty<'tcx>,
186+
def_id: DefId,
187+
cause: ObligationCause<'tcx>)
134188
{
135189
let trait_ref = ty::TraitRef {
136190
def_id,
@@ -144,9 +198,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
144198
});
145199
}
146200

147-
pub fn register_predicate_obligation(&mut self,
148-
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
149-
obligation: PredicateObligation<'tcx>)
201+
fn register_predicate_obligation<'a, 'gcx>(&mut self,
202+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
203+
obligation: PredicateObligation<'tcx>)
150204
{
151205
// this helps to reduce duplicate errors, as well as making
152206
// debug output much nicer to read and so on.
@@ -162,19 +216,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
162216
});
163217
}
164218

165-
pub fn register_predicate_obligations<I>(&mut self,
166-
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
167-
obligations: I)
168-
where I: IntoIterator<Item = PredicateObligation<'tcx>>
169-
{
170-
for obligation in obligations {
171-
self.register_predicate_obligation(infcx, obligation);
172-
}
173-
}
174-
175-
pub fn select_all_or_error(&mut self,
176-
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
177-
-> Result<(),Vec<FulfillmentError<'tcx>>>
219+
fn select_all_or_error<'a, 'gcx>(&mut self,
220+
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
221+
-> Result<(),Vec<FulfillmentError<'tcx>>>
178222
{
179223
self.select_where_possible(infcx)?;
180224

@@ -190,58 +234,17 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
190234
}
191235
}
192236

193-
pub fn select_where_possible(&mut self,
194-
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
195-
-> Result<(),Vec<FulfillmentError<'tcx>>>
237+
fn select_where_possible<'a, 'gcx>(&mut self,
238+
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
239+
-> Result<(),Vec<FulfillmentError<'tcx>>>
196240
{
197241
let mut selcx = SelectionContext::new(infcx);
198242
self.select(&mut selcx)
199243
}
200244

201-
pub fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> {
245+
fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> {
202246
self.predicates.pending_obligations()
203247
}
204-
205-
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
206-
/// only attempts to select obligations that haven't been seen before.
207-
fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
208-
-> Result<(),Vec<FulfillmentError<'tcx>>> {
209-
debug!("select(obligation-forest-size={})", self.predicates.len());
210-
211-
let mut errors = Vec::new();
212-
213-
loop {
214-
debug!("select: starting another iteration");
215-
216-
// Process pending obligations.
217-
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
218-
selcx,
219-
register_region_obligations: self.register_region_obligations
220-
});
221-
debug!("select: outcome={:?}", outcome);
222-
223-
// FIXME: if we kept the original cache key, we could mark projection
224-
// obligations as complete for the projection cache here.
225-
226-
errors.extend(
227-
outcome.errors.into_iter()
228-
.map(|e| to_fulfillment_error(e)));
229-
230-
// If nothing new was added, no need to keep looping.
231-
if outcome.stalled {
232-
break;
233-
}
234-
}
235-
236-
debug!("select({} predicates remaining, {} errors) done",
237-
self.predicates.len(), errors.len());
238-
239-
if errors.is_empty() {
240-
Ok(())
241-
} else {
242-
Err(errors)
243-
}
244-
}
245248
}
246249

247250
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {

src/librustc/traits/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use syntax::ast;
3434
use syntax_pos::{Span, DUMMY_SP};
3535

3636
pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult};
37-
pub use self::fulfill::FulfillmentContext;
37+
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
3838
pub use self::project::MismatchedProjectionTypes;
3939
pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type};
4040
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal, Normalized};
@@ -54,6 +54,7 @@ pub use self::util::transitive_bounds;
5454

5555
mod coherence;
5656
pub mod error_reporting;
57+
mod engine;
5758
mod fulfill;
5859
mod project;
5960
mod object_safety;

src/librustc/traits/trans/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::marker::PhantomData;
1818
use syntax_pos::DUMMY_SP;
1919
use infer::InferCtxt;
2020
use syntax_pos::Span;
21-
use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable};
21+
use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable};
2222
use ty::{self, Ty, TyCtxt};
2323
use ty::subst::{Subst, Substs};
2424
use ty::fold::TypeFoldable;

src/librustc_typeck/check/dropck.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc::infer::outlives::env::OutlivesEnvironment;
1616
use rustc::middle::region;
1717
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
1818
use rustc::ty::{self, Ty, TyCtxt};
19-
use rustc::traits::{self, ObligationCause};
19+
use rustc::traits::{self, ObligationCause, TraitEngine};
2020
use util::common::ErrorReported;
2121

2222
use syntax::ast;
@@ -84,7 +84,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
8484
tcx.infer_ctxt().enter(|ref infcx| {
8585
let impl_param_env = tcx.param_env(self_type_did);
8686
let tcx = infcx.tcx;
87-
let mut fulfillment_cx = traits::FulfillmentContext::new();
87+
let mut fulfillment_cx = TraitEngine::new();
8888

8989
let named_type = tcx.type_of(self_type_did);
9090

src/librustc_typeck/check/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ use rustc::infer::type_variable::{TypeVariableOrigin};
9595
use rustc::middle::region;
9696
use rustc::mir::interpret::{GlobalId};
9797
use rustc::ty::subst::{Kind, Subst, Substs};
98-
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
98+
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
99+
use rustc::traits::engine::TraitEngine;
99100
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
100101
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
101102
use rustc::ty::fold::TypeFoldable;
@@ -195,7 +196,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
195196

196197
locals: RefCell<NodeMap<Ty<'tcx>>>,
197198

198-
fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
199+
fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
199200

200201
// When we process a call like `c()` where `c` is a closure type,
201202
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
@@ -634,7 +635,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
634635
maybe_tables: infcx.in_progress_tables,
635636
},
636637
infcx,
637-
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
638+
fulfillment_cx: RefCell::new(TraitEngine::new()),
638639
locals: RefCell::new(NodeMap()),
639640
deferred_call_resolutions: RefCell::new(DefIdMap()),
640641
deferred_cast_checks: RefCell::new(Vec::new()),
@@ -2893,7 +2894,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
28932894
// out unconstrained or ambiguous, as we're
28942895
// just trying to get hints here.
28952896
self.save_and_restore_in_snapshot_flag(|_| {
2896-
let mut fulfill = FulfillmentContext::new();
2897+
let mut fulfill = TraitEngine::new();
28972898
for obligation in ok.obligations {
28982899
fulfill.register_predicate_obligation(self, obligation);
28992900
}

src/librustc_typeck/coherence/builtin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::infer::outlives::env::OutlivesEnvironment;
1515
use rustc::middle::region;
1616
use rustc::middle::lang_items::UnsizeTraitLangItem;
1717

18-
use rustc::traits::{self, ObligationCause};
18+
use rustc::traits::{self, TraitEngine, ObligationCause};
1919
use rustc::ty::{self, Ty, TyCtxt};
2020
use rustc::ty::TypeFoldable;
2121
use rustc::ty::adjustment::CoerceUnsizedInfo;
@@ -372,7 +372,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
372372
}
373373
};
374374

375-
let mut fulfill_cx = traits::FulfillmentContext::new();
375+
let mut fulfill_cx = TraitEngine::new();
376376

377377
// Register an obligation for `A: Trait<B>`.
378378
let cause = traits::ObligationCause::misc(span, impl_node_id);

0 commit comments

Comments
 (0)