diff options
| author | csmoe <35686186+csmoe@users.noreply.github.com> | 2018-03-11 10:29:22 +0800 |
|---|---|---|
| committer | csmoe <35686186+csmoe@users.noreply.github.com> | 2018-03-23 09:21:29 +0800 |
| commit | 20703b3d091658ddc58eb5b04ef6a14d04e5b40f (patch) | |
| tree | 99bdcbe609bedcb051532ad6928d9dee856ddf51 /src | |
| parent | 52f7e8836cc2e6c0edfaf402ee40ca724a8c0989 (diff) | |
| download | rust-20703b3d091658ddc58eb5b04ef6a14d04e5b40f.tar.gz rust-20703b3d091658ddc58eb5b04ef6a14d04e5b40f.zip | |
introduce trait engine mod
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/infer/mod.rs | 2 | ||||
| -rw-r--r-- | src/librustc/traits/engine.rs | 69 | ||||
| -rw-r--r-- | src/librustc/traits/fulfill.rs | 149 | ||||
| -rw-r--r-- | src/librustc/traits/mod.rs | 3 | ||||
| -rw-r--r-- | src/librustc/traits/trans/mod.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/dropck.rs | 4 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 9 | ||||
| -rw-r--r-- | src/librustc_typeck/coherence/builtin.rs | 4 | ||||
| -rw-r--r-- | src/librustc_typeck/lib.rs | 4 |
9 files changed, 160 insertions, 86 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fe919775da0..eb693ea3c6a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -27,7 +27,7 @@ use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; -use traits::{self, ObligationCause, PredicateObligations}; +use traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::BTreeMap; diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs new file mode 100644 index 00000000000..17cd7d8d9c7 --- /dev/null +++ b/src/librustc/traits/engine.rs @@ -0,0 +1,69 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::InferCtxt; +use ty::{self, Ty, TyCtxt}; +use hir::def_id::DefId; + +use super::{FulfillmentContext, FulfillmentError}; +use super::{ObligationCause, PredicateObligation, PendingPredicateObligation}; + +pub trait TraitEngine<'tcx> { + /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `<SomeType as SomeTrait>::X == $0`. When the + /// inference engine runs, it will attempt to find an impl of + /// `SomeTrait` or a where clause that lets us unify `$0` with + /// something concrete. If this fails, we'll unify `$0` with + /// `projection_ty` again. + fn normalize_projection_type<'a, 'gcx>( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + ) -> Ty<'tcx>; + + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). + fn register_bound<'a, 'gcx>( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + cause: ObligationCause<'tcx>, + ); + + fn register_predicate_obligation<'a, 'gcx>( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligation: PredicateObligation<'tcx>, + ); + + fn select_all_or_error<'a, 'gcx>( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>>; + + fn select_where_possible<'a, 'gcx>( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>>; + + fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>>; +} + +impl<'tcx> dyn TraitEngine<'tcx> { + pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> { + Box::new(FulfillmentContext::new()) + } +} diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 150a2ead9e9..3e4c4b2cae0 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -21,6 +21,7 @@ use middle::const_val::{ConstEvalErr, ErrKind}; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; +use super::engine::TraitEngine; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation, Obligation}; use super::project; @@ -84,7 +85,60 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { register_region_obligations: false } } + + pub fn register_predicate_obligations<I>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: I) + where I: IntoIterator<Item = PredicateObligation<'tcx>> + { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } + + /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it + /// only attempts to select obligations that haven't been seen before. + fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>) + -> Result<(),Vec<FulfillmentError<'tcx>>> { + debug!("select(obligation-forest-size={})", self.predicates.len()); + + let mut errors = Vec::new(); + + loop { + debug!("select: starting another iteration"); + + // Process pending obligations. + let outcome = self.predicates.process_obligations(&mut FulfillProcessor { + selcx, + register_region_obligations: self.register_region_obligations + }); + debug!("select: outcome={:?}", outcome); + + // FIXME: if we kept the original cache key, we could mark projection + // obligations as complete for the projection cache here. + + errors.extend( + outcome.errors.into_iter() + .map(|e| to_fulfillment_error(e))); + + // If nothing new was added, no need to keep looping. + if outcome.stalled { + break; + } + } + + debug!("select({} predicates remaining, {} errors) done", + self.predicates.len(), errors.len()); + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } +} + +impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by /// creating a fresh type variable `$0` as well as a projection /// predicate `<SomeType as SomeTrait>::X == $0`. When the @@ -92,12 +146,12 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { /// `SomeTrait` or a where clause that lets us unify `$0` with /// something concrete. If this fails, we'll unify `$0` with /// `projection_ty` again. - pub fn normalize_projection_type(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>) - -> Ty<'tcx> + fn normalize_projection_type<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>) + -> Ty<'tcx> { debug!("normalize_projection_type(projection_ty={:?})", projection_ty); @@ -125,12 +179,12 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { /// Requires that `ty` must implement the trait with `def_id` in /// the given environment. This trait must not have any type /// parameters (except for `Self`). - pub fn register_bound(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - cause: ObligationCause<'tcx>) + fn register_bound<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + cause: ObligationCause<'tcx>) { let trait_ref = ty::TraitRef { def_id, @@ -144,9 +198,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } - pub fn register_predicate_obligation(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligation: PredicateObligation<'tcx>) + fn register_predicate_obligation<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligation: PredicateObligation<'tcx>) { // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. @@ -162,19 +216,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } - pub fn register_predicate_obligations<I>(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligations: I) - where I: IntoIterator<Item = PredicateObligation<'tcx>> - { - for obligation in obligations { - self.register_predicate_obligation(infcx, obligation); - } - } - - pub fn select_all_or_error(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<(),Vec<FulfillmentError<'tcx>>> + fn select_all_or_error<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>) + -> Result<(),Vec<FulfillmentError<'tcx>>> { self.select_where_possible(infcx)?; @@ -190,58 +234,17 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } } - pub fn select_where_possible(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<(),Vec<FulfillmentError<'tcx>>> + fn select_where_possible<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>) + -> Result<(),Vec<FulfillmentError<'tcx>>> { let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx) } - pub fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> { + fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> { self.predicates.pending_obligations() } - - /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it - /// only attempts to select obligations that haven't been seen before. - fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>) - -> Result<(),Vec<FulfillmentError<'tcx>>> { - debug!("select(obligation-forest-size={})", self.predicates.len()); - - let mut errors = Vec::new(); - - loop { - debug!("select: starting another iteration"); - - // Process pending obligations. - let outcome = self.predicates.process_obligations(&mut FulfillProcessor { - selcx, - register_region_obligations: self.register_region_obligations - }); - debug!("select: outcome={:?}", outcome); - - // FIXME: if we kept the original cache key, we could mark projection - // obligations as complete for the projection cache here. - - errors.extend( - outcome.errors.into_iter() - .map(|e| to_fulfillment_error(e))); - - // If nothing new was added, no need to keep looping. - if outcome.stalled { - break; - } - } - - debug!("select({} predicates remaining, {} errors) done", - self.predicates.len(), errors.len()); - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } } struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a0ba88f7d55..64b939dddc9 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -34,7 +34,7 @@ use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult}; -pub use self::fulfill::FulfillmentContext; +pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::project::MismatchedProjectionTypes; pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type}; pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal, Normalized}; @@ -54,6 +54,7 @@ pub use self::util::transitive_bounds; mod coherence; pub mod error_reporting; +mod engine; mod fulfill; mod project; mod object_safety; diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index cc8b74e0ee2..ba39d796147 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -18,7 +18,7 @@ use std::marker::PhantomData; use syntax_pos::DUMMY_SP; use infer::InferCtxt; use syntax_pos::Span; -use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable}; +use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable}; use ty::{self, Ty, TyCtxt}; use ty::subst::{Subst, Substs}; use ty::fold::TypeFoldable; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 596381d7ea6..3a13e2fe294 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -16,7 +16,7 @@ use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::middle::region; use rustc::ty::subst::{Subst, Substs, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::traits::{self, ObligationCause}; +use rustc::traits::{self, ObligationCause, TraitEngine}; use util::common::ErrorReported; use syntax::ast; @@ -84,7 +84,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( tcx.infer_ctxt().enter(|ref infcx| { let impl_param_env = tcx.param_env(self_type_did); let tcx = infcx.tcx; - let mut fulfillment_cx = traits::FulfillmentContext::new(); + let mut fulfillment_cx = TraitEngine::new(); let named_type = tcx.type_of(self_type_did); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 69879bbe85d..3ecdb4e5cec 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,8 @@ use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{GlobalId}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; +use rustc::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc::traits::engine::TraitEngine; use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; @@ -195,7 +196,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { locals: RefCell<NodeMap<Ty<'tcx>>>, - fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>, + fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>, // When we process a call like `c()` where `c` is a closure type, // 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> { maybe_tables: infcx.in_progress_tables, }, infcx, - fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), + fulfillment_cx: RefCell::new(TraitEngine::new()), locals: RefCell::new(NodeMap()), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), @@ -2893,7 +2894,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // out unconstrained or ambiguous, as we're // just trying to get hints here. self.save_and_restore_in_snapshot_flag(|_| { - let mut fulfill = FulfillmentContext::new(); + let mut fulfill = TraitEngine::new(); for obligation in ok.obligations { fulfill.register_predicate_obligation(self, obligation); } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 9493c36fe95..9700aa6bc54 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -15,7 +15,7 @@ use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::middle::region; use rustc::middle::lang_items::UnsizeTraitLangItem; -use rustc::traits::{self, ObligationCause}; +use rustc::traits::{self, TraitEngine, ObligationCause}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::TypeFoldable; use rustc::ty::adjustment::CoerceUnsizedInfo; @@ -372,7 +372,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let mut fulfill_cx = traits::FulfillmentContext::new(); + let mut fulfill_cx = TraitEngine::new(); // Register an obligation for `A: Trait<B>`. let cause = traits::ObligationCause::misc(span, impl_node_id); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9f98932f24b..7f61ecb83db 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -111,7 +111,7 @@ use rustc::infer::InferOk; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode}; +use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode, TraitEngine}; use session::{CompileIncomplete, config}; use util::common::time; @@ -160,7 +160,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> bool { tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(); - let mut fulfill_cx = FulfillmentContext::new(); + let mut fulfill_cx = TraitEngine::new(); match infcx.at(&cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); |
