From 20703b3d091658ddc58eb5b04ef6a14d04e5b40f Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sun, 11 Mar 2018 10:29:22 +0800 Subject: [PATCH 1/7] introduce trait engine mod --- src/librustc/infer/mod.rs | 2 +- src/librustc/traits/engine.rs | 69 +++++++++++ src/librustc/traits/fulfill.rs | 149 ++++++++++++----------- src/librustc/traits/mod.rs | 3 +- src/librustc/traits/trans/mod.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/mod.rs | 9 +- src/librustc_typeck/coherence/builtin.rs | 4 +- src/librustc_typeck/lib.rs | 4 +- 9 files changed, 160 insertions(+), 86 deletions(-) create mode 100644 src/librustc/traits/engine.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fe919775da0b4..eb693ea3c6a53 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 0000000000000..17cd7d8d9c7ce --- /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 or the MIT license +// , 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 `::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `::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>>; + + fn select_where_possible<'a, 'gcx>( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + ) -> Result<(), Vec>>; + + fn pending_obligations(&self) -> Vec>; +} + +impl<'tcx> dyn TraitEngine<'tcx> { + pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { + Box::new(FulfillmentContext::new()) + } +} diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 150a2ead9e96d..3e4c4b2cae05b 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(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: I) + where I: IntoIterator> + { + 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>> { + 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 `::X` by /// creating a fresh type variable `$0` as well as a projection /// predicate `::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(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligations: I) - where I: IntoIterator> - { - 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>> + fn select_all_or_error<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>) + -> Result<(),Vec>> { 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>> + fn select_where_possible<'a, 'gcx>(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>) + -> Result<(),Vec>> { let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx) } - pub fn pending_obligations(&self) -> Vec> { + fn pending_obligations(&self) -> Vec> { 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>> { - 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 a0ba88f7d559a..64b939dddc98d 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 cc8b74e0ee23a..ba39d79614709 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 596381d7ea676..3a13e2fe2944d 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 69879bbe85d6e..3ecdb4e5cece7 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>>, - fulfillment_cx: RefCell>, + fulfillment_cx: RefCell>>, // 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 9493c36fe95a5..9700aa6bc54a0 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`. let cause = traits::ObligationCause::misc(span, impl_node_id); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9f98932f24b52..7f61ecb83dbbc 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); From 0c4062a94d337a7482ebf1dbdc1ffa49f0a73b57 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sun, 11 Mar 2018 14:01:01 +0000 Subject: [PATCH 2/7] import trait engine to typeck --- src/librustc/infer/mod.rs | 2 +- src/librustc/infer/outlives/bounds.rs | 2 +- src/librustc/traits/engine.rs | 29 ++++++++++--------- src/librustc/traits/fulfill.rs | 6 ++-- src/librustc/traits/mod.rs | 1 + src/librustc/traits/specialize/mod.rs | 2 +- src/librustc/traits/trans/mod.rs | 3 +- .../borrow_check/nll/type_check/mod.rs | 4 +-- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_traits/util.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 +-- src/librustc_typeck/check/mod.rs | 9 +++--- src/librustc_typeck/coherence/builtin.rs | 2 +- src/librustc_typeck/lib.rs | 5 ++-- 14 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index eb693ea3c6a53..fe919775da0b4 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, TraitEngine}; +use traits::{self, ObligationCause, PredicateObligations}; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::BTreeMap; diff --git a/src/librustc/infer/outlives/bounds.rs b/src/librustc/infer/outlives/bounds.rs index 8bb3f4158ff5b..4bc64acc76306 100644 --- a/src/librustc/infer/outlives/bounds.rs +++ b/src/librustc/infer/outlives/bounds.rs @@ -11,7 +11,7 @@ use infer::InferCtxt; use syntax::ast; use syntax::codemap::Span; -use traits::FulfillmentContext; +use traits::{FulfillmentContext, TraitEngine}; use ty::{self, Ty, TypeFoldable}; use ty::outlives::Component; use ty::wf; diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 17cd7d8d9c7ce..317fe2cc2739d 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -16,13 +16,6 @@ use super::{FulfillmentContext, FulfillmentError}; use super::{ObligationCause, PredicateObligation, PendingPredicateObligation}; pub trait TraitEngine<'tcx> { - /// "Normalize" a projection type `::X` by - /// creating a fresh type variable `$0` as well as a projection - /// predicate `::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>, @@ -31,9 +24,6 @@ pub trait TraitEngine<'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>, @@ -62,8 +52,19 @@ pub trait TraitEngine<'tcx> { fn pending_obligations(&self) -> Vec>; } -impl<'tcx> dyn TraitEngine<'tcx> { - pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { - Box::new(FulfillmentContext::new()) - } +impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> +'tcx { + pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box + { + Box::new(FulfillmentContext::new()) + } + + pub fn register_predicate_obligations(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: I) + where I: IntoIterator> + { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 3e4c4b2cae05b..1c091d68a2ef1 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -85,7 +85,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { register_region_obligations: false } } - + pub fn register_predicate_obligations(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligations: I) @@ -217,8 +217,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { } fn select_all_or_error<'a, 'gcx>(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<(),Vec>> + infcx: &InferCtxt<'a, 'gcx, 'tcx>) + -> Result<(),Vec>> { self.select_where_possible(infcx)?; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 64b939dddc98d..1d5d3e41c9c9a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -45,6 +45,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; pub use self::select::IntercrateAmbiguityCause; pub use self::specialize::{OverlapError, specialization_graph, translate_substs}; pub use self::specialize::{SpecializesCache, find_associated_item}; +pub use self::engine::TraitEngine; pub use self::util::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 5ea089abb8e86..a9d1c8bcc3d99 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -26,7 +26,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use ty::subst::{Subst, Substs}; -use traits::{self, ObligationCause}; +use traits::{self, ObligationCause, TraitEngine}; use traits::select::IntercrateAmbiguityCause; use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index ba39d79614709..31e851126d76a 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -18,7 +18,8 @@ use std::marker::PhantomData; use syntax_pos::DUMMY_SP; use infer::InferCtxt; use syntax_pos::Span; -use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, 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_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 022831b5a9259..b9ba0af2346b8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -20,7 +20,7 @@ use dataflow::move_paths::MoveData; use rustc::hir::def_id::DefId; use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult}; use rustc::infer::region_constraints::{GenericKind, RegionConstraintData}; -use rustc::traits::{self, Normalized, FulfillmentContext}; +use rustc::traits::{self, Normalized, TraitEngine}; use rustc::traits::query::NoSolution; use rustc::ty::error::TypeError; use rustc::ty::fold::TypeFoldable; @@ -662,7 +662,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { where OP: FnOnce(&mut Self) -> InferResult<'tcx, R>, { - let mut fulfill_cx = FulfillmentContext::new(); + let mut fulfill_cx = TraitEngine::new(self.infcx.tcx); let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?; fulfill_cx.register_predicate_obligations(self.infcx, obligations); if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 59a872a23b060..8fe9f6bad1b3d 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -21,7 +21,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; -use rustc::traits; +use rustc::traits::{self, TraitEngine}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; use rustc::ty::maps::Providers; diff --git a/src/librustc_traits/util.rs b/src/librustc_traits/util.rs index 976eb442a0d13..bff070ab73de3 100644 --- a/src/librustc_traits/util.rs +++ b/src/librustc_traits/util.rs @@ -12,7 +12,7 @@ use rustc::infer::InferCtxt; use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints, QueryResult}; use rustc::infer::region_constraints::{Constraint, RegionConstraintData}; -use rustc::traits::FulfillmentContext; +use rustc::traits::{FulfillmentContext, TraitEngine}; use rustc::traits::query::NoSolution; use rustc::ty; use std::fmt::Debug; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 3a13e2fe2944d..d508b6df924c2 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, TraitEngine}; +use rustc::traits::{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 = TraitEngine::new(); + let mut fulfillment_cx = TraitEngine::new(tcx); 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 3ecdb4e5cece7..2336742968b96 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,8 +95,7 @@ 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, ObligationCause, ObligationCauseCode}; -use rustc::traits::engine::TraitEngine; +use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; @@ -635,7 +634,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { maybe_tables: infcx.in_progress_tables, }, infcx, - fulfillment_cx: RefCell::new(TraitEngine::new()), + fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), locals: RefCell::new(NodeMap()), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), @@ -2883,7 +2882,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = self.misc(call_span); - let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret); + let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); // FIXME(#27336) can't use ? here, Try::from_error doesn't default // to identity so the resulting type is not constrained. @@ -2894,7 +2893,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 = TraitEngine::new(); + let mut fulfill = TraitEngine::new(self.tcx); 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 9700aa6bc54a0..8a1f827749a73 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -372,7 +372,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let mut fulfill_cx = TraitEngine::new(); + let mut fulfill_cx = TraitEngine::new(tcx); // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_node_id); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 7f61ecb83dbbc..de81de59a053c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -88,6 +88,7 @@ This API is completely unstable and subject to change. #![feature(slice_patterns)] #![feature(i128_type)] #![cfg_attr(stage0, feature(never_type))] +#![feature(dyn_trait)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -111,7 +112,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, TraitEngine}; +use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine}; use session::{CompileIncomplete, config}; use util::common::time; @@ -160,7 +161,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 = TraitEngine::new(); + let mut fulfill_cx = TraitEngine::new(infcx.tcx); match infcx.at(&cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); From 7c2eb1cf4158abc4e6ef9725b59b69e7ca277427 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Mar 2018 12:06:24 -0400 Subject: [PATCH 3/7] fix `Self` --- src/librustc/traits/engine.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 317fe2cc2739d..d843ce0c27ae5 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -53,8 +53,7 @@ pub trait TraitEngine<'tcx> { } impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> +'tcx { - pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box - { + pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { Box::new(FulfillmentContext::new()) } From 012262c4f21cd542cd3d550a6defc2c7e2132848 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Mar 2018 12:06:47 -0400 Subject: [PATCH 4/7] apply rustfmt --- src/librustc/traits/engine.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index d843ce0c27ae5..c2d7a0cdd288b 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -13,7 +13,7 @@ use ty::{self, Ty, TyCtxt}; use hir::def_id::DefId; use super::{FulfillmentContext, FulfillmentError}; -use super::{ObligationCause, PredicateObligation, PendingPredicateObligation}; +use super::{ObligationCause, PendingPredicateObligation, PredicateObligation}; pub trait TraitEngine<'tcx> { fn normalize_projection_type<'a, 'gcx>( @@ -52,18 +52,20 @@ pub trait TraitEngine<'tcx> { fn pending_obligations(&self) -> Vec>; } -impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> +'tcx { - pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { - Box::new(FulfillmentContext::new()) - } +impl<'a, 'gcx, 'tcx> TraitEngine<'tcx> + 'tcx { + pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { + Box::new(FulfillmentContext::new()) + } - pub fn register_predicate_obligations(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligations: I) - where I: IntoIterator> - { - for obligation in obligations { - self.register_predicate_obligation(infcx, obligation); - } - } + pub fn register_predicate_obligations( + &mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: I, + ) where + I: IntoIterator>, + { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } } From bad80fe4ba4420bf58b7e11929ef40f458845037 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Mar 2018 12:21:38 -0400 Subject: [PATCH 5/7] move the defaut object lifetime bound into the trait This way, we don't have to repeat it. --- src/librustc/traits/engine.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index c2d7a0cdd288b..8eee6f35ab956 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use super::{FulfillmentContext, FulfillmentError}; use super::{ObligationCause, PendingPredicateObligation, PredicateObligation}; -pub trait TraitEngine<'tcx> { +pub trait TraitEngine<'tcx>: 'tcx { fn normalize_projection_type<'a, 'gcx>( &mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, @@ -52,7 +52,7 @@ pub trait TraitEngine<'tcx> { fn pending_obligations(&self) -> Vec>; } -impl<'a, 'gcx, 'tcx> TraitEngine<'tcx> + 'tcx { +impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> { pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { Box::new(FulfillmentContext::new()) } From 8179a4be8aa2aeff32d1e8aca1bb58aee4271533 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Mar 2018 12:22:03 -0400 Subject: [PATCH 6/7] use infcx.tcx, so we get the local tcx The use of tcx/gcx in this function is subtle. --- src/librustc_typeck/coherence/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 8a1f827749a73..bc674aa15fdcc 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -372,7 +372,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let mut fulfill_cx = TraitEngine::new(tcx); + let mut fulfill_cx = TraitEngine::new(infcx.tcx); // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_node_id); From 39712e5721f92ca94f556d3b67f5bd60b592ebc2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Mar 2018 12:22:55 -0400 Subject: [PATCH 7/7] rename `'tcx` and `tcx` to `'gcx` and `gcx` This helps to make clear where *global* lifetimes are needed in `coerce_unsized_info` --- src/librustc_typeck/coherence/builtin.rs | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index bc674aa15fdcc..aa4322783c606 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -172,34 +172,34 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, impl_did: DefId) -> CoerceUnsizedInfo { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); - let coerce_unsized_trait = tcx.lang_items().coerce_unsized_trait().unwrap(); + let coerce_unsized_trait = gcx.lang_items().coerce_unsized_trait().unwrap(); - let unsize_trait = match tcx.lang_items().require(UnsizeTraitLangItem) { + let unsize_trait = match gcx.lang_items().require(UnsizeTraitLangItem) { Ok(id) => id, Err(err) => { - tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); + gcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); } }; // this provider should only get invoked for local def-ids - let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| { + let impl_node_id = gcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| { bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did) }); - let source = tcx.type_of(impl_did); - let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); + let source = gcx.type_of(impl_did); + let trait_ref = gcx.impl_trait_ref(impl_did).unwrap(); assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.substs.type_at(1); debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); - let span = tcx.hir.span(impl_node_id); - let param_env = tcx.param_env(impl_did); + let span = gcx.hir.span(impl_node_id); + let param_env = gcx.param_env(impl_did); assert!(!source.has_escaping_regions()); let err_info = CoerceUnsizedInfo { custom_kind: None }; @@ -208,11 +208,11 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source, target); - tcx.infer_ctxt().enter(|infcx| { + gcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::misc(span, impl_node_id); - let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, - mt_b: ty::TypeAndMut<'tcx>, - mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { + let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, + mt_b: ty::TypeAndMut<'gcx>, + mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { infcx.report_mismatched_types(&cause, mk_ptr(mt_b.ty), @@ -225,20 +225,20 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) + check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ref(r_b, ty)) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) | (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => { - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) + check_mutbl(mt_a, mt_b, &|ty| gcx.mk_imm_ptr(ty)) } (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { - let source_path = tcx.item_path_str(def_a.did); - let target_path = tcx.item_path_str(def_b.did); - span_err!(tcx.sess, + let source_path = gcx.item_path_str(def_a.did); + let target_path = gcx.item_path_str(def_b.did); + span_err!(gcx.sess, span, E0377, "the trait `CoerceUnsized` may only be implemented \ @@ -292,9 +292,9 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let diff_fields = fields.iter() .enumerate() .filter_map(|(i, f)| { - let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); + let (a, b) = (f.ty(gcx, substs_a), f.ty(gcx, substs_b)); - if tcx.type_of(f.did).is_phantom_data() { + if gcx.type_of(f.did).is_phantom_data() { // Ignore PhantomData fields return None; } @@ -321,7 +321,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .collect::>(); if diff_fields.is_empty() { - span_err!(tcx.sess, + span_err!(gcx.sess, span, E0374, "the trait `CoerceUnsized` may only be implemented \ @@ -329,14 +329,14 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, being coerced, none found"); return err_info; } else if diff_fields.len() > 1 { - let item = tcx.hir.expect_item(impl_node_id); + let item = gcx.hir.expect_item(impl_node_id); let span = if let ItemImpl(.., Some(ref t), _, _) = item.node { t.path.span } else { - tcx.hir.span(impl_node_id) + gcx.hir.span(impl_node_id) }; - let mut err = struct_span_err!(tcx.sess, + let mut err = struct_span_err!(gcx.sess, span, E0375, "implementing the trait \ @@ -363,7 +363,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } _ => { - span_err!(tcx.sess, + span_err!(gcx.sess, span, E0376, "the trait `CoerceUnsized` may only be implemented \ @@ -376,7 +376,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_node_id); - let predicate = tcx.predicate_for_trait_def(param_env, + let predicate = gcx.predicate_for_trait_def(param_env, cause, trait_def_id, 0,