Skip to content

Commit 9c9424d

Browse files
committed
Auto merge of #49202 - csmoe:trait_engine, r=nikomatsakis
Introduce trait engine address #48895 step 1: introduce trait engine
2 parents 3efe61c + 39712e5 commit 9c9424d

File tree

13 files changed

+196
-118
lines changed

13 files changed

+196
-118
lines changed

Diff for: src/librustc/infer/outlives/bounds.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use infer::InferCtxt;
1212
use syntax::ast;
1313
use syntax::codemap::Span;
14-
use traits::FulfillmentContext;
14+
use traits::{FulfillmentContext, TraitEngine};
1515
use ty::{self, Ty, TypeFoldable};
1616
use ty::outlives::Component;
1717
use ty::wf;

Diff for: src/librustc/traits/engine.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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, PendingPredicateObligation, PredicateObligation};
17+
18+
pub trait TraitEngine<'tcx>: 'tcx {
19+
fn normalize_projection_type<'a, 'gcx>(
20+
&mut self,
21+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
22+
param_env: ty::ParamEnv<'tcx>,
23+
projection_ty: ty::ProjectionTy<'tcx>,
24+
cause: ObligationCause<'tcx>,
25+
) -> Ty<'tcx>;
26+
27+
fn register_bound<'a, 'gcx>(
28+
&mut self,
29+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
30+
param_env: ty::ParamEnv<'tcx>,
31+
ty: Ty<'tcx>,
32+
def_id: DefId,
33+
cause: ObligationCause<'tcx>,
34+
);
35+
36+
fn register_predicate_obligation<'a, 'gcx>(
37+
&mut self,
38+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
39+
obligation: PredicateObligation<'tcx>,
40+
);
41+
42+
fn select_all_or_error<'a, 'gcx>(
43+
&mut self,
44+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
45+
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
46+
47+
fn select_where_possible<'a, 'gcx>(
48+
&mut self,
49+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
50+
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
51+
52+
fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>;
53+
}
54+
55+
impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> {
56+
pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> {
57+
Box::new(FulfillmentContext::new())
58+
}
59+
60+
pub fn register_predicate_obligations<I>(
61+
&mut self,
62+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
63+
obligations: I,
64+
) where
65+
I: IntoIterator<Item = PredicateObligation<'tcx>>,
66+
{
67+
for obligation in obligations {
68+
self.register_predicate_obligation(infcx, obligation);
69+
}
70+
}
71+
}

Diff for: src/librustc/traits/fulfill.rs

+76-73
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;
@@ -85,19 +86,72 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
8586
}
8687
}
8788

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());
132+
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> {

Diff for: src/librustc/traits/mod.rs

+3-1
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};
@@ -45,6 +45,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
4545
pub use self::select::IntercrateAmbiguityCause;
4646
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
4747
pub use self::specialize::{SpecializesCache, find_associated_item};
48+
pub use self::engine::TraitEngine;
4849
pub use self::util::elaborate_predicates;
4950
pub use self::util::supertraits;
5051
pub use self::util::Supertraits;
@@ -54,6 +55,7 @@ pub use self::util::transitive_bounds;
5455

5556
mod coherence;
5657
pub mod error_reporting;
58+
mod engine;
5759
mod fulfill;
5860
mod project;
5961
mod object_safety;

Diff for: src/librustc/traits/specialize/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2626
use hir::def_id::DefId;
2727
use infer::{InferCtxt, InferOk};
2828
use ty::subst::{Subst, Substs};
29-
use traits::{self, ObligationCause};
29+
use traits::{self, ObligationCause, TraitEngine};
3030
use traits::select::IntercrateAmbiguityCause;
3131
use ty::{self, TyCtxt, TypeFoldable};
3232
use syntax_pos::DUMMY_SP;

Diff for: src/librustc/traits/trans/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ 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,
22+
TraitEngine, Vtable};
2223
use ty::{self, Ty, TyCtxt};
2324
use ty::subst::{Subst, Substs};
2425
use ty::fold::TypeFoldable;

Diff for: src/librustc_mir/borrow_check/nll/type_check/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use dataflow::move_paths::MoveData;
2020
use rustc::hir::def_id::DefId;
2121
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
2222
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
23-
use rustc::traits::{self, Normalized, FulfillmentContext};
23+
use rustc::traits::{self, Normalized, TraitEngine};
2424
use rustc::traits::query::NoSolution;
2525
use rustc::ty::error::TypeError;
2626
use rustc::ty::fold::TypeFoldable;
@@ -662,7 +662,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
662662
where
663663
OP: FnOnce(&mut Self) -> InferResult<'tcx, R>,
664664
{
665-
let mut fulfill_cx = FulfillmentContext::new();
665+
let mut fulfill_cx = TraitEngine::new(self.infcx.tcx);
666666
let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?;
667667
fulfill_cx.register_predicate_obligations(self.infcx, obligations);
668668
if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) {

Diff for: src/librustc_mir/transform/qualify_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_data_structures::fx::FxHashSet;
2121
use rustc::hir;
2222
use rustc::hir::def_id::DefId;
2323
use rustc::middle::const_val::ConstVal;
24-
use rustc::traits;
24+
use rustc::traits::{self, TraitEngine};
2525
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
2626
use rustc::ty::cast::CastTy;
2727
use rustc::ty::maps::Providers;

Diff for: src/librustc_traits/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc::infer::InferCtxt;
1212
use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints,
1313
QueryResult};
1414
use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
15-
use rustc::traits::FulfillmentContext;
15+
use rustc::traits::{FulfillmentContext, TraitEngine};
1616
use rustc::traits::query::NoSolution;
1717
use rustc::ty;
1818
use std::fmt::Debug;

Diff for: src/librustc_typeck/check/dropck.rs

+2-2
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::{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(tcx);
8888

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

0 commit comments

Comments
 (0)