From 3e5259d3eb727244f4196e4a4c835ab0792a1606 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 10 Feb 2020 20:50:16 +0100 Subject: [PATCH 1/8] Move IntercrateAmbiguityCause back to rustc::traits::select. --- src/librustc/traits/select.rs | 41 +++++++++++++++++++++++++++++ src/librustc_infer/traits/select.rs | 41 ----------------------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 08d78b3a0b24b..d316d7659e222 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -288,3 +288,44 @@ impl WithDepNode { self.cached_value.clone() } } + +#[derive(Clone, Debug)] +pub enum IntercrateAmbiguityCause { + DownstreamCrate { trait_desc: String, self_desc: Option }, + UpstreamCrateUpdate { trait_desc: String, self_desc: Option }, + ReservationImpl { message: String }, +} + +impl IntercrateAmbiguityCause { + /// Emits notes when the overlap is caused by complex intercrate ambiguities. + /// See #23980 for details. + pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) { + err.note(&self.intercrate_ambiguity_hint()); + } + + pub fn intercrate_ambiguity_hint(&self) -> String { + match self { + &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => { + let self_desc = if let &Some(ref ty) = self_desc { + format!(" for type `{}`", ty) + } else { + String::new() + }; + format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) + } + &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => { + let self_desc = if let &Some(ref ty) = self_desc { + format!(" for type `{}`", ty) + } else { + String::new() + }; + format!( + "upstream crates may add a new impl of trait `{}`{} \ + in future versions", + trait_desc, self_desc + ) + } + &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(), + } + } +} diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs index b50f14475fceb..5c805731f2564 100644 --- a/src/librustc_infer/traits/select.rs +++ b/src/librustc_infer/traits/select.rs @@ -95,47 +95,6 @@ pub struct SelectionContext<'cx, 'tcx> { query_mode: TraitQueryMode, } -#[derive(Clone, Debug)] -pub enum IntercrateAmbiguityCause { - DownstreamCrate { trait_desc: String, self_desc: Option }, - UpstreamCrateUpdate { trait_desc: String, self_desc: Option }, - ReservationImpl { message: String }, -} - -impl IntercrateAmbiguityCause { - /// Emits notes when the overlap is caused by complex intercrate ambiguities. - /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) { - err.note(&self.intercrate_ambiguity_hint()); - } - - pub fn intercrate_ambiguity_hint(&self) -> String { - match self { - &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => { - let self_desc = if let &Some(ref ty) = self_desc { - format!(" for type `{}`", ty) - } else { - String::new() - }; - format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) - } - &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => { - let self_desc = if let &Some(ref ty) = self_desc { - format!(" for type `{}`", ty) - } else { - String::new() - }; - format!( - "upstream crates may add a new impl of trait `{}`{} \ - in future versions", - trait_desc, self_desc - ) - } - &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(), - } - } -} - // A stack that walks back up the stack frame. struct TraitObligationStack<'prev, 'tcx> { obligation: &'prev TraitObligation<'tcx>, From 98444ca53e8a589cd681fb2788fc37c4859d399c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 10 Feb 2020 20:26:24 +0100 Subject: [PATCH 2/8] Move opaque_types::unexpected_hidden_region_diagnostic to error_reporting. --- .../infer/error_reporting/mod.rs | 83 +++++++++++++++++- src/librustc_infer/infer/opaque_types/mod.rs | 84 +------------------ .../borrow_check/diagnostics/region_errors.rs | 5 +- 3 files changed, 85 insertions(+), 87 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 7e418898910dc..85c9e32a19512 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -49,7 +49,6 @@ use super::lexical_region_resolve::RegionResolutionError; use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; -use crate::infer::opaque_types; use crate::infer::{self, SuppressRegionErrors}; use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ @@ -288,6 +287,86 @@ fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) } +pub fn unexpected_hidden_region_diagnostic( + tcx: TyCtxt<'tcx>, + region_scope_tree: Option<®ion::ScopeTree>, + span: Span, + hidden_ty: Ty<'tcx>, + hidden_region: ty::Region<'tcx>, +) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + tcx.sess, + span, + E0700, + "hidden type for `impl Trait` captures lifetime that does not appear in bounds", + ); + + // Explain the region we are capturing. + if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region { + // Assuming regionck succeeded (*), we ought to always be + // capturing *some* region from the fn header, and hence it + // ought to be free. So under normal circumstances, we will go + // down this path which gives a decent human readable + // explanation. + // + // (*) if not, the `tainted_by_errors` flag would be set to + // true in any case, so we wouldn't be here at all. + note_and_explain_free_region( + tcx, + &mut err, + &format!("hidden type `{}` captures ", hidden_ty), + hidden_region, + "", + ); + } else { + // Ugh. This is a painful case: the hidden region is not one + // that we can easily summarize or explain. This can happen + // in a case like + // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: + // + // ``` + // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { + // if condition() { a } else { b } + // } + // ``` + // + // Here the captured lifetime is the intersection of `'a` and + // `'b`, which we can't quite express. + + if let Some(region_scope_tree) = region_scope_tree { + // If the `region_scope_tree` is available, this is being + // invoked from the "region inferencer error". We can at + // least report a really cryptic error for now. + note_and_explain_region( + tcx, + region_scope_tree, + &mut err, + &format!("hidden type `{}` captures ", hidden_ty), + hidden_region, + "", + ); + } else { + // If the `region_scope_tree` is *unavailable*, this is + // being invoked by the code that comes *after* region + // inferencing. This is a bug, as the region inferencer + // ought to have noticed the failed constraint and invoked + // error reporting, which in turn should have prevented us + // from getting trying to infer the hidden type + // completely. + tcx.sess.delay_span_bug( + span, + &format!( + "hidden type captures unexpected lifetime `{:?}` \ + but no region inference failure", + hidden_region, + ), + ); + } + } + + err +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_region_errors( &self, @@ -410,7 +489,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, } => { let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); - opaque_types::unexpected_hidden_region_diagnostic( + unexpected_hidden_region_diagnostic( self.tcx, Some(region_scope_tree), span, diff --git a/src/librustc_infer/infer/opaque_types/mod.rs b/src/librustc_infer/infer/opaque_types/mod.rs index 4d264008ee3ed..c18c275528133 100644 --- a/src/librustc_infer/infer/opaque_types/mod.rs +++ b/src/librustc_infer/infer/opaque_types/mod.rs @@ -1,7 +1,6 @@ -use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region}; +use crate::infer::error_reporting::unexpected_hidden_region_diagnostic; use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::{self, PredicateObligation}; -use rustc::middle::region; use rustc::session::config::nightly_options; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::free_region_map::FreeRegionRelations; @@ -9,7 +8,6 @@ use rustc::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; use rustc::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_hir::Node; @@ -618,86 +616,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } -pub fn unexpected_hidden_region_diagnostic( - tcx: TyCtxt<'tcx>, - region_scope_tree: Option<®ion::ScopeTree>, - span: Span, - hidden_ty: Ty<'tcx>, - hidden_region: ty::Region<'tcx>, -) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - tcx.sess, - span, - E0700, - "hidden type for `impl Trait` captures lifetime that does not appear in bounds", - ); - - // Explain the region we are capturing. - if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region { - // Assuming regionck succeeded (*), we ought to always be - // capturing *some* region from the fn header, and hence it - // ought to be free. So under normal circumstances, we will go - // down this path which gives a decent human readable - // explanation. - // - // (*) if not, the `tainted_by_errors` flag would be set to - // true in any case, so we wouldn't be here at all. - note_and_explain_free_region( - tcx, - &mut err, - &format!("hidden type `{}` captures ", hidden_ty), - hidden_region, - "", - ); - } else { - // Ugh. This is a painful case: the hidden region is not one - // that we can easily summarize or explain. This can happen - // in a case like - // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: - // - // ``` - // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { - // if condition() { a } else { b } - // } - // ``` - // - // Here the captured lifetime is the intersection of `'a` and - // `'b`, which we can't quite express. - - if let Some(region_scope_tree) = region_scope_tree { - // If the `region_scope_tree` is available, this is being - // invoked from the "region inferencer error". We can at - // least report a really cryptic error for now. - note_and_explain_region( - tcx, - region_scope_tree, - &mut err, - &format!("hidden type `{}` captures ", hidden_ty), - hidden_region, - "", - ); - } else { - // If the `region_scope_tree` is *unavailable*, this is - // being invoked by the code that comes *after* region - // inferencing. This is a bug, as the region inferencer - // ought to have noticed the failed constraint and invoked - // error reporting, which in turn should have prevented us - // from getting trying to infer the hidden type - // completely. - tcx.sess.delay_span_bug( - span, - &format!( - "hidden type captures unexpected lifetime `{:?}` \ - but no region inference failure", - hidden_region, - ), - ); - } - } - - err -} - // Visitor that requires that (almost) all regions in the type visited outlive // `least_region`. We cannot use `push_outlives_components` because regions in // closure signatures are not included in their outlives components. We need to diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 8cd75d4a2fd27..f751a16cfce7c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -4,7 +4,8 @@ use rustc::mir::ConstraintCategory; use rustc::ty::{self, RegionVid, Ty}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_infer::infer::{ - error_reporting::nice_region_error::NiceRegionError, opaque_types, NLLRegionVariableOrigin, + error_reporting::nice_region_error::NiceRegionError, + error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin, }; use rustc_span::symbol::kw; use rustc_span::Span; @@ -197,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); - opaque_types::unexpected_hidden_region_diagnostic( + unexpected_hidden_region_diagnostic( self.infcx.tcx, Some(region_scope_tree), span, From 796ca64e9ad95a8cba0f2ab8d252fb4c5b5fb9b4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 10 Feb 2020 20:39:11 +0100 Subject: [PATCH 3/8] Move traits::query::outlives_bounds::explicit_outlives_bounds to infer::outlives. --- src/librustc_infer/infer/outlives/env.rs | 6 +++-- src/librustc_infer/infer/outlives/mod.rs | 22 +++++++++++++++++++ .../traits/query/outlives_bounds.rs | 19 ---------------- .../type_check/free_region_relations.rs | 5 +++-- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/librustc_infer/infer/outlives/env.rs b/src/librustc_infer/infer/outlives/env.rs index aac6c7640ca6b..714108f88ecf6 100644 --- a/src/librustc_infer/infer/outlives/env.rs +++ b/src/librustc_infer/infer/outlives/env.rs @@ -1,11 +1,13 @@ use crate::infer::{GenericKind, InferCtxt}; -use crate::traits::query::outlives_bounds::{self, OutlivesBound}; +use crate::traits::query::OutlivesBound; use rustc::ty::free_region_map::FreeRegionMap; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_span::Span; +use super::explicit_outlives_bounds; + /// The `OutlivesEnvironment` collects information about what outlives /// what in a given type-checking setting. For example, if we have a /// where-clause like `where T: 'a` in scope, then the @@ -76,7 +78,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { region_bound_pairs_accum: vec![], }; - env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env)); + env.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); env } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index 6fc72470c9fb7..75cf742de31a7 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -3,3 +3,25 @@ pub mod env; pub mod obligations; pub mod verify; + +use rustc::traits::query::OutlivesBound; +use rustc::ty; + +pub fn explicit_outlives_bounds<'tcx>( + param_env: ty::ParamEnv<'tcx>, +) -> impl Iterator> + 'tcx { + debug!("explicit_outlives_bounds()"); + param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { + ty::Predicate::Projection(..) + | ty::Predicate::Trait(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::TypeOutlives(..) + | ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::RegionOutlives(ref data) => data + .no_bound_vars() + .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), + }) +} diff --git a/src/librustc_infer/traits/query/outlives_bounds.rs b/src/librustc_infer/traits/query/outlives_bounds.rs index eb32ebf5c4db4..9ce17bcec2732 100644 --- a/src/librustc_infer/traits/query/outlives_bounds.rs +++ b/src/librustc_infer/traits/query/outlives_bounds.rs @@ -82,22 +82,3 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { result.value } } - -pub fn explicit_outlives_bounds<'tcx>( - param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator> + 'tcx { - debug!("explicit_outlives_bounds()"); - param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data - .no_bound_vars() - .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), - }) -} diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 137216531a369..283d78062f361 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -1,11 +1,12 @@ use rustc::mir::ConstraintCategory; +use rustc::traits::query::OutlivesBound; use rustc::ty::free_region_map::FreeRegionRelations; use rustc::ty::{self, RegionVid, Ty, TyCtxt}; use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::outlives; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::outlives_bounds::{self, OutlivesBound}; use rustc_infer::traits::query::type_op::{self, TypeOp}; use rustc_span::DUMMY_SP; use std::rc::Rc; @@ -266,7 +267,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { // Insert the facts we know from the predicates. Why? Why not. let param_env = self.param_env; - self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env)); + self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); // Finally: // - outlives is reflexive, so `'r: 'r` for every region `'r` From 21d4e063bca7d9f5a5d0f705e0f11092cbf2cf98 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 11 Feb 2020 19:46:31 +0100 Subject: [PATCH 4/8] Mode ProjectionCache to its own module. --- src/librustc_infer/traits/mod.rs | 8 +- src/librustc_infer/traits/project.rs | 180 +---------------- src/librustc_infer/traits/projection_cache.rs | 185 ++++++++++++++++++ src/librustc_infer/traits/query/normalize.rs | 2 +- src/librustc_infer/traits/select.rs | 5 +- src/librustc_infer/traits/structural_impls.rs | 2 +- 6 files changed, 198 insertions(+), 184 deletions(-) create mode 100644 src/librustc_infer/traits/projection_cache.rs diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index aa0cfedff9e8b..9f7d019e8fd69 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -13,6 +13,7 @@ pub mod misc; mod object_safety; mod on_unimplemented; mod project; +mod projection_cache; pub mod query; mod select; mod specialize; @@ -49,11 +50,14 @@ pub use self::object_safety::is_vtable_safe_method; pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; -pub use self::project::MismatchedProjectionTypes; pub use self::project::{ normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type, }; -pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal}; +pub use self::projection_cache::MismatchedProjectionTypes; +pub use self::projection_cache::{ + Normalized, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot, + Reveal, +}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::find_associated_item; diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 78483cf6577de..551b8618af1f5 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -1,15 +1,18 @@ //! Code for projecting associated types out of trait references. use super::elaborate_predicates; +use super::projection_cache::NormalizedTy; use super::specialization_graph; use super::translate_substs; use super::util; +use super::MismatchedProjectionTypes; use super::Obligation; use super::ObligationCause; use super::PredicateObligation; use super::Selection; use super::SelectionContext; use super::SelectionError; +use super::{Normalized, ProjectionCacheEntry, ProjectionCacheKey}; use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -18,7 +21,6 @@ use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_ast::ast::Ident; -use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_hir::def_id::DefId; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; @@ -41,11 +43,6 @@ pub enum ProjectionTyError<'tcx> { TraitSelectionError(SelectionError<'tcx>), } -#[derive(Clone)] -pub struct MismatchedProjectionTypes<'tcx> { - pub err: ty::error::TypeError<'tcx>, -} - #[derive(PartialEq, Eq, Debug)] enum ProjectionTyCandidate<'tcx> { // from a where-clause in the env or object type @@ -393,20 +390,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } -#[derive(Clone, TypeFoldable)] -pub struct Normalized<'tcx, T> { - pub value: T, - pub obligations: Vec>, -} - -pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; - -impl<'tcx, T> Normalized<'tcx, T> { - pub fn with(self, value: U) -> Normalized<'tcx, U> { - Normalized { value, obligations: self.obligations } - } -} - /// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly /// additional obligations). If ambiguity arises, which implies that @@ -1500,47 +1483,6 @@ fn assoc_ty_def( } } -// # Cache - -/// The projection cache. Unlike the standard caches, this can include -/// infcx-dependent type variables, therefore we have to roll the -/// cache back each time we roll a snapshot back, to avoid assumptions -/// on yet-unresolved inference variables. Types with placeholder -/// regions also have to be removed when the respective snapshot ends. -/// -/// Because of that, projection cache entries can be "stranded" and left -/// inaccessible when type variables inside the key are resolved. We make no -/// attempt to recover or remove "stranded" entries, but rather let them be -/// (for the lifetime of the infcx). -/// -/// Entries in the projection cache might contain inference variables -/// that will be resolved by obligations on the projection cache entry (e.g., -/// when a type parameter in the associated type is constrained through -/// an "RFC 447" projection on the impl). -/// -/// When working with a fulfillment context, the derived obligations of each -/// projection cache entry will be registered on the fulfillcx, so any users -/// that can wait for a fulfillcx fixed point need not care about this. However, -/// users that don't wait for a fixed point (e.g., trait evaluation) have to -/// resolve the obligations themselves to make sure the projected result is -/// ok and avoid issues like #43132. -/// -/// If that is done, after evaluation the obligations, it is a good idea to -/// call `ProjectionCache::complete` to make sure the obligations won't be -/// re-evaluated and avoid an exponential worst-case. -// -// FIXME: we probably also want some sort of cross-infcx cache here to -// reduce the amount of duplication. Let's see what we get with the Chalk reforms. -#[derive(Default)] -pub struct ProjectionCache<'tcx> { - map: SnapshotMap, ProjectionCacheEntry<'tcx>>, -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct ProjectionCacheKey<'tcx> { - ty: ty::ProjectionTy<'tcx>, -} - impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { pub fn from_poly_projection_predicate( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -1558,119 +1500,3 @@ impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { }) } } - -#[derive(Clone, Debug)] -enum ProjectionCacheEntry<'tcx> { - InProgress, - Ambiguous, - Error, - NormalizedTy(NormalizedTy<'tcx>), -} - -// N.B., intentionally not Clone -pub struct ProjectionCacheSnapshot { - snapshot: Snapshot, -} - -impl<'tcx> ProjectionCache<'tcx> { - pub fn clear(&mut self) { - self.map.clear(); - } - - pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { - ProjectionCacheSnapshot { snapshot: self.map.snapshot() } - } - - pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); - } - - pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { - self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); - } - - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); - } - - /// Try to start normalize `key`; returns an error if - /// normalization already occurred (this error corresponds to a - /// cache hit, so it's actually a good thing). - fn try_start( - &mut self, - key: ProjectionCacheKey<'tcx>, - ) -> Result<(), ProjectionCacheEntry<'tcx>> { - if let Some(entry) = self.map.get(&key) { - return Err(entry.clone()); - } - - self.map.insert(key, ProjectionCacheEntry::InProgress); - Ok(()) - } - - /// Indicates that `key` was normalized to `value`. - fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { - debug!( - "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", - key, value - ); - let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); - assert!(!fresh_key, "never started projecting `{:?}`", key); - } - - /// Mark the relevant projection cache key as having its derived obligations - /// complete, so they won't have to be re-computed (this is OK to do in a - /// snapshot - if the snapshot is rolled back, the obligations will be - /// marked as incomplete again). - pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { - let ty = match self.map.get(&key) { - Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { - debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); - ty.value - } - ref value => { - // Type inference could "strand behind" old cache entries. Leave - // them alone for now. - debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value); - return; - } - }; - - self.map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), - ); - } - - /// A specialized version of `complete` for when the key's value is known - /// to be a NormalizedTy. - pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { - // We want to insert `ty` with no obligations. If the existing value - // already has no obligations (as is common) we don't insert anything. - if !ty.obligations.is_empty() { - self.map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { - value: ty.value, - obligations: vec![], - }), - ); - } - } - - /// Indicates that trying to normalize `key` resulted in - /// ambiguity. No point in trying it again then until we gain more - /// type information (in which case, the "fully resolved" key will - /// be different). - fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); - assert!(!fresh, "never started projecting `{:?}`", key); - } - - /// Indicates that trying to normalize `key` resulted in - /// error. - fn error(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Error); - assert!(!fresh, "never started projecting `{:?}`", key); - } -} diff --git a/src/librustc_infer/traits/projection_cache.rs b/src/librustc_infer/traits/projection_cache.rs new file mode 100644 index 0000000000000..fb7b5fdb8eacb --- /dev/null +++ b/src/librustc_infer/traits/projection_cache.rs @@ -0,0 +1,185 @@ +//! Code for projecting associated types out of trait references. + +use super::PredicateObligation; + +use rustc::ty::fold::TypeFoldable; +use rustc::ty::{self, Ty}; +use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; + +pub use rustc::traits::Reveal; + +#[derive(Clone)] +pub struct MismatchedProjectionTypes<'tcx> { + pub err: ty::error::TypeError<'tcx>, +} + +#[derive(Clone, TypeFoldable)] +pub struct Normalized<'tcx, T> { + pub value: T, + pub obligations: Vec>, +} + +pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; + +impl<'tcx, T> Normalized<'tcx, T> { + pub fn with(self, value: U) -> Normalized<'tcx, U> { + Normalized { value: value, obligations: self.obligations } + } +} + +// # Cache + +/// The projection cache. Unlike the standard caches, this can include +/// infcx-dependent type variables, therefore we have to roll the +/// cache back each time we roll a snapshot back, to avoid assumptions +/// on yet-unresolved inference variables. Types with placeholder +/// regions also have to be removed when the respective snapshot ends. +/// +/// Because of that, projection cache entries can be "stranded" and left +/// inaccessible when type variables inside the key are resolved. We make no +/// attempt to recover or remove "stranded" entries, but rather let them be +/// (for the lifetime of the infcx). +/// +/// Entries in the projection cache might contain inference variables +/// that will be resolved by obligations on the projection cache entry (e.g., +/// when a type parameter in the associated type is constrained through +/// an "RFC 447" projection on the impl). +/// +/// When working with a fulfillment context, the derived obligations of each +/// projection cache entry will be registered on the fulfillcx, so any users +/// that can wait for a fulfillcx fixed point need not care about this. However, +/// users that don't wait for a fixed point (e.g., trait evaluation) have to +/// resolve the obligations themselves to make sure the projected result is +/// ok and avoid issues like #43132. +/// +/// If that is done, after evaluation the obligations, it is a good idea to +/// call `ProjectionCache::complete` to make sure the obligations won't be +/// re-evaluated and avoid an exponential worst-case. +// +// FIXME: we probably also want some sort of cross-infcx cache here to +// reduce the amount of duplication. Let's see what we get with the Chalk reforms. +#[derive(Default)] +pub struct ProjectionCache<'tcx> { + map: SnapshotMap, ProjectionCacheEntry<'tcx>>, +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ProjectionCacheKey<'tcx> { + pub ty: ty::ProjectionTy<'tcx>, +} + +#[derive(Clone, Debug)] +pub enum ProjectionCacheEntry<'tcx> { + InProgress, + Ambiguous, + Error, + NormalizedTy(NormalizedTy<'tcx>), +} + +// N.B., intentionally not Clone +pub struct ProjectionCacheSnapshot { + snapshot: Snapshot, +} + +impl<'tcx> ProjectionCache<'tcx> { + pub fn clear(&mut self) { + self.map.clear(); + } + + pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { + ProjectionCacheSnapshot { snapshot: self.map.snapshot() } + } + + pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { + self.map.rollback_to(snapshot.snapshot); + } + + pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { + self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); + } + + pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { + self.map.commit(snapshot.snapshot); + } + + /// Try to start normalize `key`; returns an error if + /// normalization already occurred (this error corresponds to a + /// cache hit, so it's actually a good thing). + pub fn try_start( + &mut self, + key: ProjectionCacheKey<'tcx>, + ) -> Result<(), ProjectionCacheEntry<'tcx>> { + if let Some(entry) = self.map.get(&key) { + return Err(entry.clone()); + } + + self.map.insert(key, ProjectionCacheEntry::InProgress); + Ok(()) + } + + /// Indicates that `key` was normalized to `value`. + pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { + debug!( + "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", + key, value + ); + let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); + assert!(!fresh_key, "never started projecting `{:?}`", key); + } + + /// Mark the relevant projection cache key as having its derived obligations + /// complete, so they won't have to be re-computed (this is OK to do in a + /// snapshot - if the snapshot is rolled back, the obligations will be + /// marked as incomplete again). + pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { + let ty = match self.map.get(&key) { + Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { + debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); + ty.value + } + ref value => { + // Type inference could "strand behind" old cache entries. Leave + // them alone for now. + debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value); + return; + } + }; + + self.map.insert( + key, + ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), + ); + } + + /// A specialized version of `complete` for when the key's value is known + /// to be a NormalizedTy. + pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { + // We want to insert `ty` with no obligations. If the existing value + // already has no obligations (as is common) we don't insert anything. + if !ty.obligations.is_empty() { + self.map.insert( + key, + ProjectionCacheEntry::NormalizedTy(Normalized { + value: ty.value, + obligations: vec![], + }), + ); + } + } + + /// Indicates that trying to normalize `key` resulted in + /// ambiguity. No point in trying it again then until we gain more + /// type information (in which case, the "fully resolved" key will + /// be different). + pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); + assert!(!fresh, "never started projecting `{:?}`", key); + } + + /// Indicates that trying to normalize `key` resulted in + /// error. + pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map.insert(key, ProjectionCacheEntry::Error); + assert!(!fresh, "never started projecting `{:?}`", key); + } +} diff --git a/src/librustc_infer/traits/query/normalize.rs b/src/librustc_infer/traits/query/normalize.rs index 4577e3d2e1cf8..365bf9e295b56 100644 --- a/src/librustc_infer/traits/query/normalize.rs +++ b/src/librustc_infer/traits/query/normalize.rs @@ -5,7 +5,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::project::Normalized; +use crate::traits::Normalized; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::subst::Subst; diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs index 5c805731f2564..12f39b12c7268 100644 --- a/src/librustc_infer/traits/select.rs +++ b/src/librustc_infer/traits/select.rs @@ -9,9 +9,7 @@ use self::SelectionCandidate::*; use super::coherence::{self, Conflict}; use super::project; -use super::project::{ - normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey, -}; +use super::project::{normalize_with_depth, normalize_with_depth_to}; use super::util; use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::wf; @@ -21,6 +19,7 @@ use super::SelectionResult; use super::TraitNotObjectSafe; use super::TraitQueryMode; use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode}; +use super::{Normalized, ProjectionCacheKey}; use super::{ObjectCastObligation, Obligation}; use super::{ObligationCause, PredicateObligation, TraitObligation}; use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented}; diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs index 6630f664f96e4..a164995255a9d 100644 --- a/src/librustc_infer/traits/structural_impls.rs +++ b/src/librustc_infer/traits/structural_impls.rs @@ -1,5 +1,5 @@ use crate::traits; -use crate::traits::project::Normalized; +use crate::traits::Normalized; use rustc::ty; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; From c1e3d556bffa1a3a5a80fe1c5687cd2f062ce30d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 11 Feb 2020 19:53:40 +0100 Subject: [PATCH 5/8] Move rustc_infer::traits to new crate rustc_trait_selection. --- Cargo.lock | 29 +++++++++++++++++++ src/librustc_interface/Cargo.toml | 1 + src/librustc_lint/Cargo.toml | 1 + src/librustc_mir/Cargo.toml | 1 + src/librustc_mir_build/Cargo.toml | 1 + src/librustc_passes/Cargo.toml | 1 + src/librustc_trait_selection/Cargo.toml | 27 +++++++++++++++++ .../opaque_types.rs} | 0 .../traits/auto_trait.rs | 0 .../traits/codegen/mod.rs | 0 .../traits/coherence.rs | 0 .../traits/engine.rs | 0 .../traits/error_reporting/mod.rs | 0 .../error_reporting/on_unimplemented.rs | 0 .../traits/error_reporting/suggestions.rs | 0 .../traits/fulfill.rs | 0 .../traits/misc.rs | 0 .../traits/mod.rs | 0 .../traits/object_safety.rs | 0 .../traits/on_unimplemented.rs | 0 .../traits/project.rs | 0 .../traits/projection_cache.rs | 0 .../traits/query/dropck_outlives.rs | 0 .../traits/query/evaluate_obligation.rs | 0 .../traits/query/method_autoderef.rs | 0 .../traits/query/mod.rs | 0 .../traits/query/normalize.rs | 0 .../traits/query/outlives_bounds.rs | 0 .../traits/query/type_op/ascribe_user_type.rs | 0 .../traits/query/type_op/custom.rs | 0 .../traits/query/type_op/eq.rs | 0 .../query/type_op/implied_outlives_bounds.rs | 0 .../traits/query/type_op/mod.rs | 0 .../traits/query/type_op/normalize.rs | 0 .../traits/query/type_op/outlives.rs | 0 .../traits/query/type_op/prove_predicate.rs | 0 .../traits/query/type_op/subtype.rs | 0 .../traits/select.rs | 0 .../traits/specialize/mod.rs | 0 .../traits/specialize/specialization_graph.rs | 0 .../traits/structural_impls.rs | 0 .../traits/structural_match.rs | 0 .../traits/util.rs | 0 .../traits/wf.rs | 0 src/librustc_traits/Cargo.toml | 1 + src/librustc_ty/Cargo.toml | 1 + src/librustc_typeck/Cargo.toml | 1 + 47 files changed, 64 insertions(+) create mode 100644 src/librustc_trait_selection/Cargo.toml rename src/{librustc_infer/infer/opaque_types/mod.rs => librustc_trait_selection/opaque_types.rs} (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/auto_trait.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/codegen/mod.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/coherence.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/engine.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/error_reporting/mod.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/error_reporting/on_unimplemented.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/error_reporting/suggestions.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/fulfill.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/misc.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/mod.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/object_safety.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/on_unimplemented.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/project.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/projection_cache.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/dropck_outlives.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/evaluate_obligation.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/method_autoderef.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/mod.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/normalize.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/outlives_bounds.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/ascribe_user_type.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/custom.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/eq.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/implied_outlives_bounds.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/mod.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/normalize.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/outlives.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/prove_predicate.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/query/type_op/subtype.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/select.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/specialize/mod.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/specialize/specialization_graph.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/structural_impls.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/structural_match.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/util.rs (100%) rename src/{librustc_infer => librustc_trait_selection}/traits/wf.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index aefd40bfaa59e..ffb85dfc4daaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3826,6 +3826,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", "rustc_traits", "rustc_ty", "rustc_typeck", @@ -3860,6 +3861,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", "unicode-security", ] @@ -3929,6 +3931,7 @@ dependencies = [ "rustc_macros", "rustc_span", "rustc_target", + "rustc_trait_selection", "serialize", "smallvec 1.0.0", ] @@ -3952,6 +3955,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", "serialize", "smallvec 1.0.0", ] @@ -3992,6 +3996,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", ] [[package]] @@ -4119,6 +4124,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" +[[package]] +name = "rustc_trait_selection" +version = "0.0.0" +dependencies = [ + "fmt_macros", + "log", + "rustc", + "rustc_ast", + "rustc_attr", + "rustc_data_structures", + "rustc_errors", + "rustc_hir", + "rustc_index", + "rustc_infer", + "rustc_macros", + "rustc_session", + "rustc_span", + "rustc_target", + "smallvec 1.0.0", +] + [[package]] name = "rustc_traits" version = "0.0.0" @@ -4132,6 +4158,7 @@ dependencies = [ "rustc_macros", "rustc_span", "rustc_target", + "rustc_trait_selection", "smallvec 1.0.0", ] @@ -4146,6 +4173,7 @@ dependencies = [ "rustc_infer", "rustc_span", "rustc_target", + "rustc_trait_selection", ] [[package]] @@ -4164,6 +4192,7 @@ dependencies = [ "rustc_infer", "rustc_span", "rustc_target", + "rustc_trait_selection", "smallvec 1.0.0", ] diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index b29480a88109f..e84181f1d75e7 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -42,6 +42,7 @@ rustc_errors = { path = "../librustc_errors" } rustc_plugin_impl = { path = "../librustc_plugin_impl" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } +rustc_trait_selection = { path = "../librustc_trait_selection" } rustc_ty = { path = "../librustc_ty" } tempfile = "3.0.5" once_cell = "1" diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 6470d25fe0a2e..9785af5eab2fd 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -24,3 +24,4 @@ rustc_feature = { path = "../librustc_feature" } rustc_index = { path = "../librustc_index" } rustc_session = { path = "../librustc_session" } rustc_infer = { path = "../librustc_infer" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 1ee581e64aa7e..cad50d50f3cec 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -28,6 +28,7 @@ rustc_lexer = { path = "../librustc_lexer" } rustc_macros = { path = "../librustc_macros" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_target = { path = "../librustc_target" } +rustc_trait_selection = { path = "../librustc_trait_selection" } rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_apfloat = { path = "../librustc_apfloat" } diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml index d53188a39e5e0..96716dbd604d5 100644 --- a/src/librustc_mir_build/Cargo.toml +++ b/src/librustc_mir_build/Cargo.toml @@ -25,5 +25,6 @@ rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } +rustc_trait_selection = { path = "../librustc_trait_selection" } rustc_ast = { path = "../librustc_ast" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index af8e7a5b71e46..8acb88f58d379 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -22,3 +22,4 @@ rustc_session = { path = "../librustc_session" } rustc_target = { path = "../librustc_target" } rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml new file mode 100644 index 0000000000000..5b2da41d06672 --- /dev/null +++ b/src/librustc_trait_selection/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_trait_selection" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_trait_selection" +path = "lib.rs" +doctest = false + +[dependencies] +fmt_macros = { path = "../libfmt_macros" } +log = { version = "0.4", features = ["release_max_level_info", "std"] } +rustc_attr = { path = "../librustc_attr" } +rustc = { path = "../librustc" } +rustc_ast = { path = "../librustc_ast" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +rustc_hir = { path = "../librustc_hir" } +rustc_index = { path = "../librustc_index" } +rustc_infer = { path = "../librustc_infer" } +rustc_macros = { path = "../librustc_macros" } +rustc_session = { path = "../librustc_session" } +rustc_span = { path = "../librustc_span" } +rustc_target = { path = "../librustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_infer/infer/opaque_types/mod.rs b/src/librustc_trait_selection/opaque_types.rs similarity index 100% rename from src/librustc_infer/infer/opaque_types/mod.rs rename to src/librustc_trait_selection/opaque_types.rs diff --git a/src/librustc_infer/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs similarity index 100% rename from src/librustc_infer/traits/auto_trait.rs rename to src/librustc_trait_selection/traits/auto_trait.rs diff --git a/src/librustc_infer/traits/codegen/mod.rs b/src/librustc_trait_selection/traits/codegen/mod.rs similarity index 100% rename from src/librustc_infer/traits/codegen/mod.rs rename to src/librustc_trait_selection/traits/codegen/mod.rs diff --git a/src/librustc_infer/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs similarity index 100% rename from src/librustc_infer/traits/coherence.rs rename to src/librustc_trait_selection/traits/coherence.rs diff --git a/src/librustc_infer/traits/engine.rs b/src/librustc_trait_selection/traits/engine.rs similarity index 100% rename from src/librustc_infer/traits/engine.rs rename to src/librustc_trait_selection/traits/engine.rs diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs similarity index 100% rename from src/librustc_infer/traits/error_reporting/mod.rs rename to src/librustc_trait_selection/traits/error_reporting/mod.rs diff --git a/src/librustc_infer/traits/error_reporting/on_unimplemented.rs b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs similarity index 100% rename from src/librustc_infer/traits/error_reporting/on_unimplemented.rs rename to src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs diff --git a/src/librustc_infer/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs similarity index 100% rename from src/librustc_infer/traits/error_reporting/suggestions.rs rename to src/librustc_trait_selection/traits/error_reporting/suggestions.rs diff --git a/src/librustc_infer/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs similarity index 100% rename from src/librustc_infer/traits/fulfill.rs rename to src/librustc_trait_selection/traits/fulfill.rs diff --git a/src/librustc_infer/traits/misc.rs b/src/librustc_trait_selection/traits/misc.rs similarity index 100% rename from src/librustc_infer/traits/misc.rs rename to src/librustc_trait_selection/traits/misc.rs diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs similarity index 100% rename from src/librustc_infer/traits/mod.rs rename to src/librustc_trait_selection/traits/mod.rs diff --git a/src/librustc_infer/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs similarity index 100% rename from src/librustc_infer/traits/object_safety.rs rename to src/librustc_trait_selection/traits/object_safety.rs diff --git a/src/librustc_infer/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs similarity index 100% rename from src/librustc_infer/traits/on_unimplemented.rs rename to src/librustc_trait_selection/traits/on_unimplemented.rs diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_trait_selection/traits/project.rs similarity index 100% rename from src/librustc_infer/traits/project.rs rename to src/librustc_trait_selection/traits/project.rs diff --git a/src/librustc_infer/traits/projection_cache.rs b/src/librustc_trait_selection/traits/projection_cache.rs similarity index 100% rename from src/librustc_infer/traits/projection_cache.rs rename to src/librustc_trait_selection/traits/projection_cache.rs diff --git a/src/librustc_infer/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs similarity index 100% rename from src/librustc_infer/traits/query/dropck_outlives.rs rename to src/librustc_trait_selection/traits/query/dropck_outlives.rs diff --git a/src/librustc_infer/traits/query/evaluate_obligation.rs b/src/librustc_trait_selection/traits/query/evaluate_obligation.rs similarity index 100% rename from src/librustc_infer/traits/query/evaluate_obligation.rs rename to src/librustc_trait_selection/traits/query/evaluate_obligation.rs diff --git a/src/librustc_infer/traits/query/method_autoderef.rs b/src/librustc_trait_selection/traits/query/method_autoderef.rs similarity index 100% rename from src/librustc_infer/traits/query/method_autoderef.rs rename to src/librustc_trait_selection/traits/query/method_autoderef.rs diff --git a/src/librustc_infer/traits/query/mod.rs b/src/librustc_trait_selection/traits/query/mod.rs similarity index 100% rename from src/librustc_infer/traits/query/mod.rs rename to src/librustc_trait_selection/traits/query/mod.rs diff --git a/src/librustc_infer/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs similarity index 100% rename from src/librustc_infer/traits/query/normalize.rs rename to src/librustc_trait_selection/traits/query/normalize.rs diff --git a/src/librustc_infer/traits/query/outlives_bounds.rs b/src/librustc_trait_selection/traits/query/outlives_bounds.rs similarity index 100% rename from src/librustc_infer/traits/query/outlives_bounds.rs rename to src/librustc_trait_selection/traits/query/outlives_bounds.rs diff --git a/src/librustc_infer/traits/query/type_op/ascribe_user_type.rs b/src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/ascribe_user_type.rs rename to src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs diff --git a/src/librustc_infer/traits/query/type_op/custom.rs b/src/librustc_trait_selection/traits/query/type_op/custom.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/custom.rs rename to src/librustc_trait_selection/traits/query/type_op/custom.rs diff --git a/src/librustc_infer/traits/query/type_op/eq.rs b/src/librustc_trait_selection/traits/query/type_op/eq.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/eq.rs rename to src/librustc_trait_selection/traits/query/type_op/eq.rs diff --git a/src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs rename to src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs diff --git a/src/librustc_infer/traits/query/type_op/mod.rs b/src/librustc_trait_selection/traits/query/type_op/mod.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/mod.rs rename to src/librustc_trait_selection/traits/query/type_op/mod.rs diff --git a/src/librustc_infer/traits/query/type_op/normalize.rs b/src/librustc_trait_selection/traits/query/type_op/normalize.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/normalize.rs rename to src/librustc_trait_selection/traits/query/type_op/normalize.rs diff --git a/src/librustc_infer/traits/query/type_op/outlives.rs b/src/librustc_trait_selection/traits/query/type_op/outlives.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/outlives.rs rename to src/librustc_trait_selection/traits/query/type_op/outlives.rs diff --git a/src/librustc_infer/traits/query/type_op/prove_predicate.rs b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/prove_predicate.rs rename to src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs diff --git a/src/librustc_infer/traits/query/type_op/subtype.rs b/src/librustc_trait_selection/traits/query/type_op/subtype.rs similarity index 100% rename from src/librustc_infer/traits/query/type_op/subtype.rs rename to src/librustc_trait_selection/traits/query/type_op/subtype.rs diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_trait_selection/traits/select.rs similarity index 100% rename from src/librustc_infer/traits/select.rs rename to src/librustc_trait_selection/traits/select.rs diff --git a/src/librustc_infer/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs similarity index 100% rename from src/librustc_infer/traits/specialize/mod.rs rename to src/librustc_trait_selection/traits/specialize/mod.rs diff --git a/src/librustc_infer/traits/specialize/specialization_graph.rs b/src/librustc_trait_selection/traits/specialize/specialization_graph.rs similarity index 100% rename from src/librustc_infer/traits/specialize/specialization_graph.rs rename to src/librustc_trait_selection/traits/specialize/specialization_graph.rs diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_trait_selection/traits/structural_impls.rs similarity index 100% rename from src/librustc_infer/traits/structural_impls.rs rename to src/librustc_trait_selection/traits/structural_impls.rs diff --git a/src/librustc_infer/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs similarity index 100% rename from src/librustc_infer/traits/structural_match.rs rename to src/librustc_trait_selection/traits/structural_match.rs diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_trait_selection/traits/util.rs similarity index 100% rename from src/librustc_infer/traits/util.rs rename to src/librustc_trait_selection/traits/util.rs diff --git a/src/librustc_infer/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs similarity index 100% rename from src/librustc_infer/traits/wf.rs rename to src/librustc_trait_selection/traits/wf.rs diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml index 0dc3ad2983333..5e33efb1cf9b5 100644 --- a/src/librustc_traits/Cargo.toml +++ b/src/librustc_traits/Cargo.toml @@ -19,3 +19,4 @@ rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_infer = { path = "../librustc_infer" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_ty/Cargo.toml b/src/librustc_ty/Cargo.toml index 6e64df3492b0f..3c790bc4cb13d 100644 --- a/src/librustc_ty/Cargo.toml +++ b/src/librustc_ty/Cargo.toml @@ -16,3 +16,4 @@ rustc_hir = { path = "../librustc_hir" } rustc_infer = { path = "../librustc_infer" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 51a9b259c8f70..83a48ee3995ac 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -24,3 +24,4 @@ rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_index = { path = "../librustc_index" } rustc_infer = { path = "../librustc_infer" } +rustc_trait_selection = { path = "../librustc_trait_selection" } From 0535dd3721816f0df997976632fd5b133dbde1b3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 22 Feb 2020 11:44:18 +0100 Subject: [PATCH 6/8] Split librustc_infer. --- Cargo.lock | 2 + .../infer/canonical/query_response.rs | 46 +- .../infer/error_reporting/mod.rs | 2 +- src/librustc_infer/infer/mod.rs | 52 +- src/librustc_infer/infer/outlives/env.rs | 43 +- src/librustc_infer/traits/engine.rs | 78 + .../traits/error_reporting/mod.rs | 106 + src/librustc_infer/traits/mod.rs | 136 ++ .../traits/project.rs} | 8 +- .../traits/structural_impls.rs | 2 +- src/librustc_infer/traits/util.rs | 225 ++ src/librustc_trait_selection/Cargo.toml | 2 + src/librustc_trait_selection/infer.rs | 182 ++ src/librustc_trait_selection/lib.rs | 39 + src/librustc_trait_selection/opaque_types.rs | 67 +- .../traits/codegen/mod.rs | 56 +- src/librustc_trait_selection/traits/engine.rs | 82 +- .../traits/error_reporting/mod.rs | 1913 ++++++++++------- .../error_reporting/on_unimplemented.rs | 24 +- .../traits/error_reporting/suggestions.rs | 384 ++-- .../traits/fulfill.rs | 5 +- src/librustc_trait_selection/traits/misc.rs | 5 +- src/librustc_trait_selection/traits/mod.rs | 121 +- .../traits/object_safety.rs | 1 + .../traits/project.rs | 31 +- .../traits/query/dropck_outlives.rs | 8 +- .../traits/query/evaluate_obligation.rs | 40 +- .../traits/query/normalize.rs | 13 +- .../traits/query/outlives_bounds.rs | 17 +- .../traits/query/type_op/custom.rs | 4 +- src/librustc_trait_selection/traits/select.rs | 13 +- src/librustc_trait_selection/traits/wf.rs | 2 +- 32 files changed, 2245 insertions(+), 1464 deletions(-) create mode 100644 src/librustc_infer/traits/engine.rs create mode 100644 src/librustc_infer/traits/error_reporting/mod.rs create mode 100644 src/librustc_infer/traits/mod.rs rename src/{librustc_trait_selection/traits/projection_cache.rs => librustc_infer/traits/project.rs} (97%) rename src/{librustc_trait_selection => librustc_infer}/traits/structural_impls.rs (98%) create mode 100644 src/librustc_infer/traits/util.rs create mode 100644 src/librustc_trait_selection/infer.rs create mode 100644 src/librustc_trait_selection/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ffb85dfc4daaa..f453705db9e58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4129,11 +4129,13 @@ name = "rustc_trait_selection" version = "0.0.0" dependencies = [ "fmt_macros", + "graphviz", "log", "rustc", "rustc_ast", "rustc_attr", "rustc_data_structures", + "rustc_error_codes", "rustc_errors", "rustc_hir", "rustc_index", diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index b6c0dc3939bff..9322df4823511 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -14,7 +14,7 @@ use crate::infer::canonical::{ }; use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::{InferCtxt, InferCtxtBuilder, InferOk, InferResult, NLLRegionVariableOrigin}; +use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; use crate::traits::{DomainGoal, TraitEngine}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; @@ -26,52 +26,8 @@ use rustc::ty::{self, BoundVar, Ty, TyCtxt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; -use rustc_span::DUMMY_SP; use std::fmt::Debug; -impl<'tcx> InferCtxtBuilder<'tcx> { - /// The "main method" for a canonicalized trait query. Given the - /// canonical key `canonical_key`, this method will create a new - /// inference context, instantiate the key, and run your operation - /// `op`. The operation should yield up a result (of type `R`) as - /// well as a set of trait obligations that must be fully - /// satisfied. These obligations will be processed and the - /// canonical result created. - /// - /// Returns `NoSolution` in the event of any error. - /// - /// (It might be mildly nicer to implement this on `TyCtxt`, and - /// not `InferCtxtBuilder`, but that is a bit tricky right now. - /// In part because we would need a `for<'tcx>` sort of - /// bound for the closure and in part because it is convenient to - /// have `'tcx` be free on this function so that we can talk about - /// `K: TypeFoldable<'tcx>`.) - pub fn enter_canonical_trait_query( - &mut self, - canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, - ) -> Fallible> - where - K: TypeFoldable<'tcx>, - R: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable, - { - self.enter_with_canonical( - DUMMY_SP, - canonical_key, - |ref infcx, key, canonical_inference_vars| { - let mut fulfill_cx = TraitEngine::new(infcx.tcx); - let value = operation(infcx, &mut *fulfill_cx, key)?; - infcx.make_canonicalized_query_response( - canonical_inference_vars, - value, - &mut *fulfill_cx, - ) - }, - ) - } -} - impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// This method is meant to be invoked as the final step of a canonical query /// implementation. It is given: diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 85c9e32a19512..4a39403f211cc 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -2156,7 +2156,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks /// extra information about each type, but we only care about the category. #[derive(Clone, Copy, PartialEq, Eq, Hash)] -crate enum TyCategory { +pub enum TyCategory { Closure, Opaque, Generator, diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 938a0e7ab39df..9ae131c568d0d 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -13,11 +13,11 @@ use rustc::infer::canonical::{Canonical, CanonicalVarValues}; use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc::middle::free_region::RegionRelations; -use rustc::middle::lang_items; use rustc::middle::region; use rustc::mir; use rustc::mir::interpret::ConstEvalResult; use rustc::session::config::BorrowckMode; +use rustc::traits::select; use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::relate::RelateResult; @@ -58,7 +58,6 @@ pub mod lattice; mod lexical_region_resolve; mod lub; pub mod nll_relate; -pub mod opaque_types; pub mod outlives; pub mod region_constraints; pub mod resolve; @@ -215,10 +214,10 @@ pub struct InferCtxt<'a, 'tcx> { /// Caches the results of trait selection. This cache is used /// for things that have to do with the parameters in scope. - pub selection_cache: traits::SelectionCache<'tcx>, + pub selection_cache: select::SelectionCache<'tcx>, /// Caches the results of trait evaluation. - pub evaluation_cache: traits::EvaluationCache<'tcx>, + pub evaluation_cache: select::EvaluationCache<'tcx>, /// the set of predicates on which errors have been reported, to /// avoid reporting the same error twice. @@ -1474,27 +1473,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .verify_generic_bound(origin, kind, a, bound); } - pub fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { - let ty = self.resolve_vars_if_possible(&ty); - - if !(param_env, ty).has_local_value() { - return ty.is_copy_modulo_regions(self.tcx, param_env, span); - } - - let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None); - - // This can get called from typeck (by euv), and `moves_by_default` - // rightly refuses to work with inference variables, but - // moves_by_default has a cache, which we want to use in other - // cases. - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) - } - /// Obtains the latest type of the given closure; this may be a /// closure in the current function, in which case its /// `ClosureKind` may not yet be known. @@ -1518,30 +1496,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { closure_sig_ty.fn_sig(self.tcx) } - /// Normalizes associated types in `value`, potentially returning - /// new obligations that must further be processed. - pub fn partially_normalize_associated_types_in( - &self, - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> InferOk<'tcx, T> - where - T: TypeFoldable<'tcx>, - { - debug!("partially_normalize_associated_types_in(value={:?})", value); - let mut selcx = traits::SelectionContext::new(self); - let cause = ObligationCause::misc(span, body_id); - let traits::Normalized { value, obligations } = - traits::normalize(&mut selcx, param_env, cause, value); - debug!( - "partially_normalize_associated_types_in: result={:?} predicates={:?}", - value, obligations - ); - InferOk { value, obligations } - } - /// Clears the selection, evaluation, and projection caches. This is useful when /// repeatedly attempting to select an `Obligation` while changing only /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing. diff --git a/src/librustc_infer/infer/outlives/env.rs b/src/librustc_infer/infer/outlives/env.rs index 714108f88ecf6..6c1e86bf408b0 100644 --- a/src/librustc_infer/infer/outlives/env.rs +++ b/src/librustc_infer/infer/outlives/env.rs @@ -1,10 +1,9 @@ use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; +use rustc::ty; use rustc::ty::free_region_map::FreeRegionMap; -use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_span::Span; use super::explicit_outlives_bounds; @@ -144,39 +143,6 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { self.region_bound_pairs_accum.truncate(len); } - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// add those assumptions into the outlives-environment. - /// - /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` - pub fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], - body_id: hir::HirId, - span: Span, - ) { - debug!("add_implied_bounds()"); - - for &ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(&ty); - debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } - /// Save the current set of region-bound pairs under the given `body_id`. pub fn save_implied_bounds(&mut self, body_id: hir::HirId) { let old = @@ -190,8 +156,11 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// contain inference variables, it must be supplied, in which /// case we will register "givens" on the inference context. (See /// `RegionConstraintData`.) - fn add_outlives_bounds(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I) - where + pub fn add_outlives_bounds( + &mut self, + infcx: Option<&InferCtxt<'a, 'tcx>>, + outlives_bounds: I, + ) where I: IntoIterator>, { // Record relationships such as `T:'x` that don't go into the diff --git a/src/librustc_infer/traits/engine.rs b/src/librustc_infer/traits/engine.rs new file mode 100644 index 0000000000000..9ad722342a19e --- /dev/null +++ b/src/librustc_infer/traits/engine.rs @@ -0,0 +1,78 @@ +use crate::infer::InferCtxt; +use crate::traits::Obligation; +use rustc::ty::{self, ToPredicate, Ty, WithConstness}; +use rustc_hir::def_id::DefId; + +use super::FulfillmentError; +use super::{ObligationCause, PredicateObligation}; + +pub trait TraitEngine<'tcx>: 'tcx { + fn normalize_projection_type( + &mut self, + infcx: &InferCtxt<'_, '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( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + cause: ObligationCause<'tcx>, + ) { + let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; + self.register_predicate_obligation( + infcx, + Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: trait_ref.without_const().to_predicate(), + }, + ); + } + + fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligation: PredicateObligation<'tcx>, + ); + + fn select_all_or_error( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec>>; + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec>>; + + fn pending_obligations(&self) -> Vec>; +} + +pub trait TraitEngineExt<'tcx> { + fn register_predicate_obligations( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligations: impl IntoIterator>, + ); +} + +impl> TraitEngineExt<'tcx> for T { + fn register_predicate_obligations( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligations: impl IntoIterator>, + ) { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } +} diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs new file mode 100644 index 0000000000000..8943ce4e6c505 --- /dev/null +++ b/src/librustc_infer/traits/error_reporting/mod.rs @@ -0,0 +1,106 @@ +use super::ObjectSafetyViolation; + +use crate::infer::InferCtxt; +use rustc::ty::TyCtxt; +use rustc_ast::ast; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_span::Span; +use std::fmt; + +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn report_extra_impl_obligation( + &self, + error_span: Span, + item_name: ast::Name, + _impl_item_def_id: DefId, + trait_item_def_id: DefId, + requirement: &dyn fmt::Display, + ) -> DiagnosticBuilder<'tcx> { + let msg = "impl has stricter requirements than trait"; + let sp = self.tcx.sess.source_map().def_span(error_span); + + let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg); + + if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { + let span = self.tcx.sess.source_map().def_span(trait_item_span); + err.span_label(span, format!("definition of `{}` from trait", item_name)); + } + + err.span_label(sp, format!("impl has extra requirement {}", requirement)); + + err + } +} + +pub fn report_object_safety_error( + tcx: TyCtxt<'tcx>, + span: Span, + trait_def_id: DefId, + violations: Vec, +) -> DiagnosticBuilder<'tcx> { + let trait_str = tcx.def_path_str(trait_def_id); + let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { + hir::Node::Item(item) => Some(item.ident.span), + _ => None, + }); + let span = tcx.sess.source_map().def_span(span); + let mut err = struct_span_err!( + tcx.sess, + span, + E0038, + "the trait `{}` cannot be made into an object", + trait_str + ); + err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str)); + + let mut reported_violations = FxHashSet::default(); + let mut had_span_label = false; + for violation in violations { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation { + if !sp.is_empty() { + // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations + // with a `Span`. + reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + } + } + if reported_violations.insert(violation.clone()) { + let spans = violation.spans(); + let msg = if trait_span.is_none() || spans.is_empty() { + format!("the trait cannot be made into an object because {}", violation.error_msg()) + } else { + had_span_label = true; + format!("...because {}", violation.error_msg()) + }; + if spans.is_empty() { + err.note(&msg); + } else { + for span in spans { + err.span_label(span, &msg); + } + } + match (trait_span, violation.solution()) { + (Some(_), Some((note, None))) => { + err.help(¬e); + } + (Some(_), Some((note, Some((sugg, span))))) => { + err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable); + } + // Only provide the help if its a local trait, otherwise it's not actionable. + _ => {} + } + } + } + if let (Some(trait_span), true) = (trait_span, had_span_label) { + err.span_label(trait_span, "this trait cannot be made into an object..."); + } + + if tcx.sess.trait_methods_not_found.borrow().contains(&span) { + // Avoid emitting error caused by non-existing method (#58734) + err.cancel(); + } + + err +} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs new file mode 100644 index 0000000000000..1c0785497be22 --- /dev/null +++ b/src/librustc_infer/traits/mod.rs @@ -0,0 +1,136 @@ +//! Trait Resolution. See the [rustc guide] for more information on how this works. +//! +//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html + +mod engine; +pub mod error_reporting; +mod project; +mod structural_impls; +mod util; + +use rustc::ty::error::{ExpectedFound, TypeError}; +use rustc::ty::{self, Ty}; +use rustc_hir as hir; +use rustc_span::Span; + +pub use self::FulfillmentErrorCode::*; +pub use self::ObligationCauseCode::*; +pub use self::SelectionError::*; +pub use self::Vtable::*; + +pub use self::engine::{TraitEngine, TraitEngineExt}; +pub use self::project::MismatchedProjectionTypes; +pub use self::project::{ + Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, + ProjectionCacheSnapshot, Reveal, +}; +crate use self::util::elaborate_predicates; + +pub use rustc::traits::*; + +/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for +/// which the vtable must be found. The process of finding a vtable is +/// called "resolving" the `Obligation`. This process consists of +/// either identifying an `impl` (e.g., `impl Eq for int`) that +/// provides the required vtable, or else finding a bound that is in +/// scope. The eventual result is usually a `Selection` (defined below). +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Obligation<'tcx, T> { + /// The reason we have to prove this thing. + pub cause: ObligationCause<'tcx>, + + /// The environment in which we should prove this thing. + pub param_env: ty::ParamEnv<'tcx>, + + /// The thing we are trying to prove. + pub predicate: T, + + /// If we started proving this as a result of trying to prove + /// something else, track the total depth to ensure termination. + /// If this goes over a certain threshold, we abort compilation -- + /// in such cases, we can not say whether or not the predicate + /// holds for certain. Stupid halting problem; such a drag. + pub recursion_depth: usize, +} + +pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; + +// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PredicateObligation<'_>, 112); + +pub type Obligations<'tcx, O> = Vec>; +pub type PredicateObligations<'tcx> = Vec>; +pub type TraitObligations<'tcx> = Vec>; + +pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; + +pub struct FulfillmentError<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub code: FulfillmentErrorCode<'tcx>, + /// Diagnostics only: we opportunistically change the `code.span` when we encounter an + /// obligation error caused by a call argument. When this is the case, we also signal that in + /// this field to ensure accuracy of suggestions. + pub points_at_arg_span: bool, +} + +#[derive(Clone)] +pub enum FulfillmentErrorCode<'tcx> { + CodeSelectionError(SelectionError<'tcx>), + CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate + CodeAmbiguity, +} + +impl<'tcx, O> Obligation<'tcx, O> { + pub fn new( + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: O, + ) -> Obligation<'tcx, O> { + Obligation { cause, param_env, recursion_depth: 0, predicate } + } + + pub fn with_depth( + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + predicate: O, + ) -> Obligation<'tcx, O> { + Obligation { cause, param_env, recursion_depth, predicate } + } + + pub fn misc( + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + trait_ref: O, + ) -> Obligation<'tcx, O> { + Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref) + } + + pub fn with

(&self, value: P) -> Obligation<'tcx, P> { + Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + recursion_depth: self.recursion_depth, + predicate: value, + } + } +} + +impl<'tcx> FulfillmentError<'tcx> { + pub fn new( + obligation: PredicateObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>, + ) -> FulfillmentError<'tcx> { + FulfillmentError { obligation, code, points_at_arg_span: false } + } +} + +impl<'tcx> TraitObligation<'tcx> { + pub fn self_ty(&self) -> ty::Binder> { + self.predicate.map_bound(|p| p.self_ty()) + } +} diff --git a/src/librustc_trait_selection/traits/projection_cache.rs b/src/librustc_infer/traits/project.rs similarity index 97% rename from src/librustc_trait_selection/traits/projection_cache.rs rename to src/librustc_infer/traits/project.rs index fb7b5fdb8eacb..183e4be189022 100644 --- a/src/librustc_trait_selection/traits/projection_cache.rs +++ b/src/librustc_infer/traits/project.rs @@ -65,7 +65,13 @@ pub struct ProjectionCache<'tcx> { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct ProjectionCacheKey<'tcx> { - pub ty: ty::ProjectionTy<'tcx>, + ty: ty::ProjectionTy<'tcx>, +} + +impl ProjectionCacheKey<'tcx> { + pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self { + Self { ty } + } } #[derive(Clone, Debug)] diff --git a/src/librustc_trait_selection/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs similarity index 98% rename from src/librustc_trait_selection/traits/structural_impls.rs rename to src/librustc_infer/traits/structural_impls.rs index a164995255a9d..6630f664f96e4 100644 --- a/src/librustc_trait_selection/traits/structural_impls.rs +++ b/src/librustc_infer/traits/structural_impls.rs @@ -1,5 +1,5 @@ use crate::traits; -use crate::traits::Normalized; +use crate::traits::project::Normalized; use rustc::ty; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs new file mode 100644 index 0000000000000..a7c0267111522 --- /dev/null +++ b/src/librustc_infer/traits/util.rs @@ -0,0 +1,225 @@ +use smallvec::smallvec; + +use rustc::ty::outlives::Component; +use rustc::ty::{self, ToPolyTraitRef, TyCtxt}; +use rustc_data_structures::fx::FxHashSet; + +fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + match *pred { + ty::Predicate::Trait(ref data, constness) => { + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) + } + + ty::Predicate::RegionOutlives(ref data) => { + ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::TypeOutlives(ref data) => { + ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::Projection(ref data) => { + ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data), + + ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data), + + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) + } + + ty::Predicate::Subtype(ref data) => { + ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::Predicate::ConstEvaluatable(def_id, substs) + } + } +} + +struct PredicateSet<'tcx> { + tcx: TyCtxt<'tcx>, + set: FxHashSet>, +} + +impl PredicateSet<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { tcx: tcx, set: Default::default() } + } + + fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { + // We have to be careful here because we want + // + // for<'a> Foo<&'a int> + // + // and + // + // for<'b> Foo<&'b int> + // + // to be considered equivalent. So normalize all late-bound + // regions before we throw things into the underlying set. + self.set.insert(anonymize_predicate(self.tcx, pred)) + } +} + +impl>> Extend for PredicateSet<'tcx> { + fn extend>(&mut self, iter: I) { + for pred in iter { + self.insert(pred.as_ref()); + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// `Elaboration` iterator +/////////////////////////////////////////////////////////////////////////// + +/// "Elaboration" is the process of identifying all the predicates that +/// are implied by a source predicate. Currently, this basically means +/// walking the "supertraits" and other similar assumptions. For example, +/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd` +/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that +/// `T: Foo`, then we know that `T: 'static`. +pub struct Elaborator<'tcx> { + stack: Vec>, + visited: PredicateSet<'tcx>, +} + +pub fn elaborate_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + mut predicates: Vec>, +) -> Elaborator<'tcx> { + let mut visited = PredicateSet::new(tcx); + predicates.retain(|pred| visited.insert(pred)); + Elaborator { stack: predicates, visited } +} + +impl Elaborator<'tcx> { + fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { + let tcx = self.visited.tcx; + match *predicate { + ty::Predicate::Trait(ref data, _) => { + // Get predicates declared on the trait. + let predicates = tcx.super_predicates_of(data.def_id()); + + let predicates = predicates + .predicates + .iter() + .map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref())); + debug!("super_predicates: data={:?} predicates={:?}", data, predicates.clone()); + + // Only keep those bounds that we haven't already seen. + // This is necessary to prevent infinite recursion in some + // cases. One common case is when people define + // `trait Sized: Sized { }` rather than `trait Sized { }`. + let visited = &mut self.visited; + let predicates = predicates.filter(|pred| visited.insert(pred)); + + self.stack.extend(predicates); + } + ty::Predicate::WellFormed(..) => { + // Currently, we do not elaborate WF predicates, + // although we easily could. + } + ty::Predicate::ObjectSafe(..) => { + // Currently, we do not elaborate object-safe + // predicates. + } + ty::Predicate::Subtype(..) => { + // Currently, we do not "elaborate" predicates like `X <: Y`, + // though conceivably we might. + } + ty::Predicate::Projection(..) => { + // Nothing to elaborate in a projection predicate. + } + ty::Predicate::ClosureKind(..) => { + // Nothing to elaborate when waiting for a closure's kind to be inferred. + } + ty::Predicate::ConstEvaluatable(..) => { + // Currently, we do not elaborate const-evaluatable + // predicates. + } + ty::Predicate::RegionOutlives(..) => { + // Nothing to elaborate from `'a: 'b`. + } + ty::Predicate::TypeOutlives(ref data) => { + // We know that `T: 'a` for some type `T`. We can + // often elaborate this. For example, if we know that + // `[U]: 'a`, that implies that `U: 'a`. Similarly, if + // we know `&'a U: 'b`, then we know that `'a: 'b` and + // `U: 'b`. + // + // We can basically ignore bound regions here. So for + // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to + // `'a: 'b`. + + // Ignore `for<'a> T: 'a` -- we might in the future + // consider this as evidence that `T: 'static`, but + // I'm a bit wary of such constructions and so for now + // I want to be conservative. --nmatsakis + let ty_max = data.skip_binder().0; + let r_min = data.skip_binder().1; + if r_min.is_late_bound() { + return; + } + + let visited = &mut self.visited; + let mut components = smallvec![]; + tcx.push_outlives_components(ty_max, &mut components); + self.stack.extend( + components + .into_iter() + .filter_map(|component| match component { + Component::Region(r) => { + if r.is_late_bound() { + None + } else { + Some(ty::Predicate::RegionOutlives(ty::Binder::dummy( + ty::OutlivesPredicate(r, r_min), + ))) + } + } + + Component::Param(p) => { + let ty = tcx.mk_ty_param(p.index, p.name); + Some(ty::Predicate::TypeOutlives(ty::Binder::dummy( + ty::OutlivesPredicate(ty, r_min), + ))) + } + + Component::UnresolvedInferenceVariable(_) => None, + + Component::Projection(_) | Component::EscapingProjection(_) => { + // We can probably do more here. This + // corresponds to a case like `>::U: 'b`. + None + } + }) + .filter(|p| visited.insert(p)), + ); + } + } + } +} + +impl Iterator for Elaborator<'tcx> { + type Item = ty::Predicate<'tcx>; + + fn size_hint(&self) -> (usize, Option) { + (self.stack.len(), None) + } + + fn next(&mut self) -> Option> { + // Extract next item from top-most stack frame, if any. + if let Some(pred) = self.stack.pop() { + self.elaborate(&pred); + Some(pred) + } else { + None + } + } +} diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml index 5b2da41d06672..c7f2cc34b8470 100644 --- a/src/librustc_trait_selection/Cargo.toml +++ b/src/librustc_trait_selection/Cargo.toml @@ -11,12 +11,14 @@ doctest = false [dependencies] fmt_macros = { path = "../libfmt_macros" } +graphviz = { path = "../libgraphviz" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_attr = { path = "../librustc_attr" } rustc = { path = "../librustc" } rustc_ast = { path = "../librustc_ast" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } +rustc_error_codes = { path = "../librustc_error_codes" } rustc_hir = { path = "../librustc_hir" } rustc_index = { path = "../librustc_index" } rustc_infer = { path = "../librustc_infer" } diff --git a/src/librustc_trait_selection/infer.rs b/src/librustc_trait_selection/infer.rs new file mode 100644 index 0000000000000..7abcbf45277fb --- /dev/null +++ b/src/librustc_trait_selection/infer.rs @@ -0,0 +1,182 @@ +use crate::traits::query::outlives_bounds::InferCtxtExt as _; +use crate::traits::{self, TraitEngine, TraitEngineExt}; + +use rustc::arena::ArenaAllocatable; +use rustc::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse}; +use rustc::middle::lang_items; +use rustc::traits::query::Fallible; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc_hir as hir; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::traits::ObligationCause; +use rustc_span::{Span, DUMMY_SP}; + +use std::fmt::Debug; + +pub use rustc_infer::infer::*; + +pub trait InferCtxtExt<'tcx> { + fn type_is_copy_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool; + + fn partially_normalize_associated_types_in( + &self, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>; +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { + fn type_is_copy_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool { + let ty = self.resolve_vars_if_possible(&ty); + + if !(param_env, ty).has_local_value() { + return ty.is_copy_modulo_regions(self.tcx, param_env, span); + } + + let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None); + + // This can get called from typeck (by euv), and `moves_by_default` + // rightly refuses to work with inference variables, but + // moves_by_default has a cache, which we want to use in other + // cases. + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) + } + + /// Normalizes associated types in `value`, potentially returning + /// new obligations that must further be processed. + fn partially_normalize_associated_types_in( + &self, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>, + { + debug!("partially_normalize_associated_types_in(value={:?})", value); + let mut selcx = traits::SelectionContext::new(self); + let cause = ObligationCause::misc(span, body_id); + let traits::Normalized { value, obligations } = + traits::normalize(&mut selcx, param_env, cause, value); + debug!( + "partially_normalize_associated_types_in: result={:?} predicates={:?}", + value, obligations + ); + InferOk { value, obligations } + } +} + +pub trait InferCtxtBuilderExt<'tcx> { + fn enter_canonical_trait_query( + &mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, + ) -> Fallible> + where + K: TypeFoldable<'tcx>, + R: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable; +} + +impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { + /// The "main method" for a canonicalized trait query. Given the + /// canonical key `canonical_key`, this method will create a new + /// inference context, instantiate the key, and run your operation + /// `op`. The operation should yield up a result (of type `R`) as + /// well as a set of trait obligations that must be fully + /// satisfied. These obligations will be processed and the + /// canonical result created. + /// + /// Returns `NoSolution` in the event of any error. + /// + /// (It might be mildly nicer to implement this on `TyCtxt`, and + /// not `InferCtxtBuilder`, but that is a bit tricky right now. + /// In part because we would need a `for<'tcx>` sort of + /// bound for the closure and in part because it is convenient to + /// have `'tcx` be free on this function so that we can talk about + /// `K: TypeFoldable<'tcx>`.) + fn enter_canonical_trait_query( + &mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, + ) -> Fallible> + where + K: TypeFoldable<'tcx>, + R: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable, + { + self.enter_with_canonical( + DUMMY_SP, + canonical_key, + |ref infcx, key, canonical_inference_vars| { + let mut fulfill_cx = TraitEngine::new(infcx.tcx); + let value = operation(infcx, &mut *fulfill_cx, key)?; + infcx.make_canonicalized_query_response( + canonical_inference_vars, + value, + &mut *fulfill_cx, + ) + }, + ) + } +} + +pub trait OutlivesEnvironmentExt<'tcx> { + fn add_implied_bounds( + &mut self, + infcx: &InferCtxt<'a, 'tcx>, + fn_sig_tys: &[Ty<'tcx>], + body_id: hir::HirId, + span: Span, + ); +} + +impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { + /// This method adds "implied bounds" into the outlives environment. + /// Implied bounds are outlives relationships that we can deduce + /// on the basis that certain types must be well-formed -- these are + /// either the types that appear in the function signature or else + /// the input types to an impl. For example, if you have a function + /// like + /// + /// ``` + /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } + /// ``` + /// + /// we can assume in the caller's body that `'b: 'a` and that `T: + /// 'b` (and hence, transitively, that `T: 'a`). This method would + /// add those assumptions into the outlives-environment. + /// + /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` + fn add_implied_bounds( + &mut self, + infcx: &InferCtxt<'a, 'tcx>, + fn_sig_tys: &[Ty<'tcx>], + body_id: hir::HirId, + span: Span, + ) { + debug!("add_implied_bounds()"); + + for &ty in fn_sig_tys { + let ty = infcx.resolve_vars_if_possible(&ty); + debug!("add_implied_bounds: ty = {}", ty); + let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); + self.add_outlives_bounds(Some(infcx), implied_bounds) + } + } +} diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs new file mode 100644 index 0000000000000..8b5cf223826a9 --- /dev/null +++ b/src/librustc_trait_selection/lib.rs @@ -0,0 +1,39 @@ +//! This crates defines the trait resolution method and the type inference engine. +//! +//! - **Traits.** Trait resolution is implemented in the `traits` module. +//! - **Type inference.** The type inference code can be found in the `infer` module; +//! this code handles low-level equality and subtyping operations. The +//! type check pass in the compiler is found in the `librustc_typeck` crate. +//! +//! For more information about how rustc works, see the [rustc guide]. +//! +//! [rustc guide]: https://rust-lang.github.io/rustc-guide/ +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(drain_filter)] +#![feature(never_type)] +#![feature(range_is_empty)] +#![feature(in_band_lifetimes)] +#![feature(crate_visibility_modifier)] +#![recursion_limit = "512"] + +#[macro_use] +extern crate rustc_macros; +#[cfg(target_arch = "x86_64")] +#[macro_use] +extern crate rustc_data_structures; +#[macro_use] +extern crate log; +#[macro_use] +extern crate rustc; + +pub mod infer; +pub mod opaque_types; +pub mod traits; diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index c18c275528133..6cf1302783c0b 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1,5 +1,4 @@ -use crate::infer::error_reporting::unexpected_hidden_region_diagnostic; -use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::InferCtxtExt as _; use crate::traits::{self, PredicateObligation}; use rustc::session::config::nightly_options; use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; @@ -11,6 +10,9 @@ use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_hir::Node; +use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_span::Span; pub type OpaqueTypeMap<'tcx> = DefIdMap>; @@ -103,7 +105,58 @@ pub enum GenerateMemberConstraints { IfNoStaticBound, } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +pub trait InferCtxtExt<'tcx> { + fn instantiate_opaque_types>( + &self, + parent_def_id: DefId, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + value_span: Span, + ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>; + + fn constrain_opaque_types>( + &self, + opaque_types: &OpaqueTypeMap<'tcx>, + free_region_relations: &FRR, + ); + + fn constrain_opaque_type>( + &self, + def_id: DefId, + opaque_defn: &OpaqueTypeDecl<'tcx>, + mode: GenerateMemberConstraints, + free_region_relations: &FRR, + ); + + /*private*/ + fn generate_member_constraint( + &self, + concrete_ty: Ty<'tcx>, + opaque_type_generics: &ty::Generics, + opaque_defn: &OpaqueTypeDecl<'tcx>, + opaque_type_def_id: DefId, + ); + + /*private*/ + fn member_constraint_feature_gate( + &self, + opaque_defn: &OpaqueTypeDecl<'tcx>, + opaque_type_def_id: DefId, + conflict1: ty::Region<'tcx>, + conflict2: ty::Region<'tcx>, + ) -> bool; + + fn infer_opaque_definition_from_instantiation( + &self, + def_id: DefId, + substs: SubstsRef<'tcx>, + instantiated_ty: Ty<'tcx>, + span: Span, + ) -> Ty<'tcx>; +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// Replaces all opaque types in `value` with fresh inference variables /// and creates appropriate obligations. For example, given the input: /// @@ -129,7 +182,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// obligations /// - `value` -- the value within which we are instantiating opaque types /// - `value_span` -- the span where the value came from, used in error reporting - pub fn instantiate_opaque_types>( + fn instantiate_opaque_types>( &self, parent_def_id: DefId, body_id: hir::HirId, @@ -317,7 +370,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// - `opaque_types` -- the map produced by `instantiate_opaque_types` /// - `free_region_relations` -- something that can be used to relate /// the free regions (`'a`) that appear in the impl trait. - pub fn constrain_opaque_types>( + fn constrain_opaque_types>( &self, opaque_types: &OpaqueTypeMap<'tcx>, free_region_relations: &FRR, @@ -335,7 +388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// See `constrain_opaque_types` for documentation. - pub fn constrain_opaque_type>( + fn constrain_opaque_type>( &self, def_id: DefId, opaque_defn: &OpaqueTypeDecl<'tcx>, @@ -577,7 +630,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// - `substs`, the substs used to instantiate this opaque type /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of /// `opaque_defn.concrete_ty` - pub fn infer_opaque_definition_from_instantiation( + fn infer_opaque_definition_from_instantiation( &self, def_id: DefId, substs: SubstsRef<'tcx>, diff --git a/src/librustc_trait_selection/traits/codegen/mod.rs b/src/librustc_trait_selection/traits/codegen/mod.rs index f499565e9192a..5c2fc3f305c1f 100644 --- a/src/librustc_trait_selection/traits/codegen/mod.rs +++ b/src/librustc_trait_selection/traits/codegen/mod.rs @@ -72,7 +72,7 @@ pub fn codegen_fulfill_obligation<'tcx>( debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let vtable = infcx.drain_fulfillment_cx_or_panic(&mut fulfill_cx, &vtable); + let vtable = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &vtable); info!("Cache miss: {:?} => {:?}", trait_ref, vtable); Some(vtable) @@ -81,34 +81,32 @@ pub fn codegen_fulfill_obligation<'tcx>( // # Global Cache -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - fn drain_fulfillment_cx_or_panic( - &self, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!("drain_fulfillment_cx_or_panic()"); +/// Finishes processes any obligations that remain in the +/// fulfillment context, and then returns the result with all type +/// variables removed and regions erased. Because this is intended +/// for use after type-check has completed, if any errors occur, +/// it will panic. It is used during normalization and other cases +/// where processing the obligations in `fulfill_cx` may cause +/// type inference variables that appear in `result` to be +/// unified, and hence we need to process those obligations to get +/// the complete picture of the type. +fn drain_fulfillment_cx_or_panic( + infcx: &InferCtxt<'_, 'tcx>, + fulfill_cx: &mut FulfillmentContext<'tcx>, + result: &T, +) -> T +where + T: TypeFoldable<'tcx>, +{ + debug!("drain_fulfillment_cx_or_panic()"); - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - if let Err(errors) = fulfill_cx.select_all_or_error(self) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); - } - - let result = self.resolve_vars_if_possible(result); - self.tcx.erase_regions(&result) + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { + bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); } + + let result = infcx.resolve_vars_if_possible(result); + infcx.tcx.erase_regions(&result) } diff --git a/src/librustc_trait_selection/traits/engine.rs b/src/librustc_trait_selection/traits/engine.rs index e23810dd1612d..ee4715e0c20f6 100644 --- a/src/librustc_trait_selection/traits/engine.rs +++ b/src/librustc_trait_selection/traits/engine.rs @@ -1,84 +1,14 @@ -use crate::infer::InferCtxt; -use crate::traits::Obligation; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; -use rustc_hir::def_id::DefId; +use rustc::ty::TyCtxt; -use super::{FulfillmentContext, FulfillmentError}; -use super::{ObligationCause, PredicateObligation}; - -pub trait TraitEngine<'tcx>: 'tcx { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'_, '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( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - cause: ObligationCause<'tcx>, - ) { - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; - self.register_predicate_obligation( - infcx, - Obligation { - cause, - recursion_depth: 0, - param_env, - predicate: trait_ref.without_const().to_predicate(), - }, - ); - } - - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, - ); - - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec>>; - - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec>>; - - fn pending_obligations(&self) -> Vec>; -} +use super::FulfillmentContext; +use super::TraitEngine; pub trait TraitEngineExt<'tcx> { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligations: impl IntoIterator>, - ); -} - -impl> TraitEngineExt<'tcx> for T { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligations: impl IntoIterator>, - ) { - for obligation in obligations { - self.register_predicate_obligation(infcx, obligation); - } - } + fn new(tcx: TyCtxt<'tcx>) -> Box; } -impl dyn TraitEngine<'tcx> { - pub fn new(_tcx: TyCtxt<'tcx>) -> Box { +impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { + fn new(_tcx: TyCtxt<'tcx>) -> Box { Box::new(FulfillmentContext::new()) } } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 10143ae015f2f..abd9638bfa78b 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -3,10 +3,9 @@ pub mod suggestions; use super::{ ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode, - MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause, - ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, - OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError, - TraitNotObjectSafe, + MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, + OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, + PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe, }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; @@ -21,18 +20,69 @@ use rustc::ty::SubtypePredicate; use rustc::ty::{ self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; -use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_hir::{Node, QPath, TyKind, WhereBoundPredicate, WherePredicate}; use rustc_span::source_map::SourceMap; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_fulfillment_errors( +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use crate::traits::query::normalize::AtExt as _; +use on_unimplemented::InferCtxtExt as _; +use suggestions::InferCtxtExt as _; + +pub use rustc_infer::traits::error_reporting::*; + +pub trait InferCtxtExt<'tcx> { + fn report_fulfillment_errors( + &self, + errors: &[FulfillmentError<'tcx>], + body_id: Option, + fallback_has_occurred: bool, + ); + + fn report_overflow_error( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: fmt::Display + TypeFoldable<'tcx>; + + fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; + + fn report_selection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>, + fallback_has_occurred: bool, + points_at_arg: bool, + ); + + /// Given some node representing a fn-like thing in the HIR map, + /// returns a span and `ArgKind` information that describes the + /// arguments it expects. This can be supplied to + /// `report_arg_count_mismatch`. + fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec); + + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + fn report_arg_count_mismatch( + &self, + span: Span, + found_span: Option, + expected_args: Vec, + found_args: Vec, + is_closure: bool, + ) -> DiagnosticBuilder<'tcx>; +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { + fn report_fulfillment_errors( &self, errors: &[FulfillmentError<'tcx>], body_id: Option, @@ -118,827 +168,1106 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool { - if cond == error { - return true; - } - - let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), - _ => { - // FIXME: make this work in other cases too. - return false; - } - }; + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + fn report_overflow_error( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: fmt::Display + TypeFoldable<'tcx>, + { + let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let mut err = struct_span_err!( + self.tcx.sess, + obligation.cause.span, + E0275, + "overflow evaluating the requirement `{}`", + predicate + ); - for implication in super::elaborate_predicates(self.tcx, vec![*cond]) { - if let ty::Predicate::Trait(implication, _) = implication { - let error = error.to_poly_trait_ref(); - let implication = implication.to_poly_trait_ref(); - // FIXME: I'm just not taking associated types at all here. - // Eventually I'll need to implement param-env-aware - // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. - let param_env = ty::ParamEnv::empty(); - if self.can_sub(param_env, error, implication).is_ok() { - debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); - return true; - } - } + if suggest_increasing_limit { + self.suggest_new_overflow_limit(&mut err); } - false + self.note_obligation_cause_code( + &mut err, + &obligation.predicate, + &obligation.cause.code, + &mut vec![], + ); + + err.emit(); + self.tcx.sess.abort_if_errors(); + bug!(); } - fn report_fulfillment_error( - &self, - error: &FulfillmentError<'tcx>, - body_id: Option, - fallback_has_occurred: bool, - ) { - debug!("report_fulfillment_error({:?})", error); - match error.code { - FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { - self.report_selection_error( - &error.obligation, - selection_error, - fallback_has_occurred, - error.points_at_arg_span, - ); - } - FulfillmentErrorCode::CodeProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e); - } - FulfillmentErrorCode::CodeAmbiguity => { - self.maybe_report_ambiguity(&error.obligation, body_id); - } - FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { - self.report_mismatched_types( - &error.obligation.cause, - expected_found.expected, - expected_found.found, - err.clone(), - ) - .emit(); - } - } + /// Reports that a cycle was detected which led to overflow and halts + /// compilation. This is equivalent to `report_overflow_error` except + /// that we can give a more helpful error message (and, in particular, + /// we do not suggest increasing the overflow limit, which is not + /// going to help). + fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + let cycle = self.resolve_vars_if_possible(&cycle.to_owned()); + assert!(!cycle.is_empty()); + + debug!("report_overflow_error_cycle: cycle={:?}", cycle); + + self.report_overflow_error(&cycle[0], false); } - fn report_projection_error( + fn report_selection_error( &self, obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, + error: &SelectionError<'tcx>, + fallback_has_occurred: bool, + points_at_arg: bool, ) { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - - if predicate.references_error() { - return; - } + let tcx = self.tcx; + let span = obligation.cause.span; - self.probe(|_| { - let err_buf; - let mut err = &error.err; - let mut values = None; + let mut err = match *error { + SelectionError::Unimplemented => { + if let ObligationCauseCode::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } + | ObligationCauseCode::CompareImplTypeObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } = obligation.cause.code + { + self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}`", obligation.predicate), + ) + .emit(); + return; + } + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate, _) => { + let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - // try to find the mismatched types to report the error with. - // - // this can fail if the problem was higher-ranked, in which - // cause I have no idea for a good error message. - if let ty::Predicate::Projection(ref data) = predicate { - let mut selcx = SelectionContext::new(self); - let (data, _) = self.replace_bound_vars_with_fresh_vars( - obligation.cause.span, - infer::LateBoundRegionConversionTime::HigherRankedType, - data, - ); - let mut obligations = vec![]; - let normalized_ty = super::normalize_projection_type( - &mut selcx, - obligation.param_env, - data.projection_ty, - obligation.cause.clone(), - 0, - &mut obligations, - ); + if self.tcx.sess.has_errors() && trait_predicate.references_error() { + return; + } + let trait_ref = trait_predicate.to_poly_trait_ref(); + let (post_message, pre_message, type_def) = self + .get_parent_trait_ref(&obligation.cause.code) + .map(|(t, s)| { + ( + format!(" in `{}`", t), + format!("within `{}`, ", t), + s.map(|s| (format!("within this `{}`", t), s)), + ) + }) + .unwrap_or_default(); - debug!( - "report_projection_error obligation.cause={:?} obligation.param_env={:?}", - obligation.cause, obligation.param_env - ); + let OnUnimplementedNote { message, label, note, enclosing_scope } = + self.on_unimplemented_note(trait_ref, obligation); + let have_alt_message = message.is_some() || label.is_some(); + let is_try = self + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|s| &s == "?") + .unwrap_or(false); + let is_from = format!("{}", trait_ref.print_only_trait_path()) + .starts_with("std::convert::From<"); + let (message, note) = if is_try && is_from { + ( + Some(format!( + "`?` couldn't convert the error to `{}`", + trait_ref.self_ty(), + )), + Some( + "the question mark operation (`?`) implicitly performs a \ + conversion on the error value using the `From` trait" + .to_owned(), + ), + ) + } else { + (message, note) + }; - debug!( - "report_projection_error normalized_ty={:?} data.ty={:?}", - normalized_ty, data.ty - ); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0277, + "{}", + message.unwrap_or_else(|| format!( + "the trait bound `{}` is not satisfied{}", + trait_ref.without_const().to_predicate(), + post_message, + )) + ); - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, + let explanation = + if obligation.cause.code == ObligationCauseCode::MainFunctionType { + "consider using `()`, or a `Result`".to_owned() + } else { + format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref.print_only_trait_path(), + trait_ref.self_ty(), + ) + }; + + if self.suggest_add_reference_to_arg( + &obligation, + &mut err, + &trait_ref, + points_at_arg, + have_alt_message, + ) { + self.note_obligation_cause(&mut err, obligation); + err.emit(); + return; + } + if let Some(ref s) = label { + // If it has a custom `#[rustc_on_unimplemented]` + // error message, let's display it as the label! + err.span_label(span, s.as_str()); + err.help(&explanation); + } else { + err.span_label(span, explanation); + } + if let Some((msg, span)) = type_def { + err.span_label(span, &msg); + } + if let Some(ref s) = note { + // If it has a custom `#[rustc_on_unimplemented]` note, let's display it + err.note(s.as_str()); + } + if let Some(ref s) = enclosing_scope { + let enclosing_scope_span = tcx.def_span( + tcx.hir() + .opt_local_def_id(obligation.cause.body_id) + .unwrap_or_else(|| { + tcx.hir().body_owner_def_id(hir::BodyId { + hir_id: obligation.cause.body_id, + }) + }), + ); + + err.span_label(enclosing_scope_span, s.as_str()); + } + + self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); + self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); + self.suggest_remove_reference(&obligation, &mut err, &trait_ref); + self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); + self.note_version_mismatch(&mut err, &trait_ref); + if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { + err.emit(); + return; + } + + // Try to report a help message + if !trait_ref.has_infer_types_or_consts() + && self.predicate_can_apply(obligation.param_env, trait_ref) + { + // If a where-clause may be useful, remind the + // user that they can add it. + // + // don't display an on-unimplemented note, as + // these notes will often be of the form + // "the type `T` can't be frobnicated" + // which is somewhat confusing. + self.suggest_restricting_param_bound( + &mut err, + &trait_ref, + obligation.cause.body_id, + ); + } else { + if !have_alt_message { + // Can't show anything else useful, try to find similar impls. + let impl_candidates = self.find_similar_impl_candidates(trait_ref); + self.report_similar_impl_candidates(impl_candidates, &mut err); + } + self.suggest_change_mut( + &obligation, + &mut err, + &trait_ref, + points_at_arg, + ); + } + + // If this error is due to `!: Trait` not implemented but `(): Trait` is + // implemented, and fallback has occurred, then it could be due to a + // variable that used to fallback to `()` now falling back to `!`. Issue a + // note informing about the change in behaviour. + if trait_predicate.skip_binder().self_ty().is_never() + && fallback_has_occurred + { + let predicate = trait_predicate.map_bound(|mut trait_pred| { + trait_pred.trait_ref.substs = self.tcx.mk_substs_trait( + self.tcx.mk_unit(), + &trait_pred.trait_ref.substs[1..], + ); + trait_pred + }); + let unit_obligation = Obligation { + predicate: ty::Predicate::Trait( + predicate, + hir::Constness::NotConst, + ), + ..obligation.clone() + }; + if self.predicate_may_hold(&unit_obligation) { + err.note( + "the trait is implemented for `()`. \ + Possibly this error has been caused by changes to \ + Rust's type-inference algorithm (see issue #48950 \ + \ + for more information). Consider whether you meant to use \ + the type `()` here instead.", + ); + } + } + + err + } + + ty::Predicate::Subtype(ref predicate) => { + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) + } + + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = self.resolve_vars_if_possible(predicate); + let err = self + .region_outlives_predicate(&obligation.cause, &predicate) + .err() + .unwrap(); + struct_span_err!( + self.tcx.sess, + span, + E0279, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err, + ) + } + + ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + let predicate = self.resolve_vars_if_possible(&obligation.predicate); + struct_span_err!( + self.tcx.sess, + span, + E0280, + "the requirement `{}` is not satisfied", + predicate + ) + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + let violations = self.tcx.object_safety_violations(trait_def_id); + report_object_safety_error(self.tcx, span, trait_def_id, violations) + } + + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap(); + let closure_span = self + .tcx + .sess + .source_map() + .def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap()); + let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap(); + let mut err = struct_span_err!( + self.tcx.sess, + closure_span, + E0525, + "expected a closure that implements the `{}` trait, \ + but this closure only implements `{}`", + kind, + found_kind + ); + + err.span_label( + closure_span, + format!("this closure implements `{}`, not `{}`", found_kind, kind), + ); + err.span_label( + obligation.cause.span, + format!("the requirement to implement `{}` derives from here", kind), + ); + + // Additional context information explaining why the closure only implements + // a particular trait. + if let Some(tables) = self.in_progress_tables { + let tables = tables.borrow(); + match (found_kind, tables.closure_kind_origins().get(hir_id)) { + (ty::ClosureKind::FnOnce, Some((span, name))) => { + err.span_label( + *span, + format!( + "closure is `FnOnce` because it moves the \ + variable `{}` out of its environment", + name + ), + ); + } + (ty::ClosureKind::FnMut, Some((span, name))) => { + err.span_label( + *span, + format!( + "closure is `FnMut` because it mutates the \ + variable `{}` here", + name + ), + ); + } + _ => {} + } + } + + err.emit(); + return; + } + + ty::Predicate::WellFormed(ty) => { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "WF predicate not satisfied for {:?}", ty); + } + + ty::Predicate::ConstEvaluatable(..) => { + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-evaluatable requirement gave wrong error: `{:?}`", + obligation + ) + } + } + } + + OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { + let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref); + let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref); + + if expected_trait_ref.self_ty().references_error() { + return; + } + + let found_trait_ty = found_trait_ref.self_ty(); + + let found_did = match found_trait_ty.kind { + ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), + ty::Adt(def, _) => Some(def.did), + _ => None, }; - if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( - is_normalized_ty_expected, - normalized_ty, - data.ty, - ) { - values = Some(infer::ValuePairs::Types(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data.ty, - ))); + let found_span = found_did + .and_then(|did| self.tcx.hir().span_if_local(did)) + .map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def - err_buf = error; - err = &err_buf; + if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { + // We check closures twice, with obligations flowing in different directions, + // but we want to complain about them only once. + return; + } + + self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { + ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], + _ => vec![ArgKind::empty()], + }; + + let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); + let expected = match expected_ty.kind { + ty::Tuple(ref tys) => tys + .iter() + .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) + .collect(), + _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], + }; + + if found.len() == expected.len() { + self.report_closure_arg_mismatch( + span, + found_span, + found_trait_ref, + expected_trait_ref, + ) + } else { + let (closure_span, found) = found_did + .and_then(|did| self.tcx.hir().get_if_local(did)) + .map(|node| { + let (found_span, found) = self.get_fn_like_arguments(node); + (Some(found_span), found) + }) + .unwrap_or((found_span, found)); + + self.report_arg_count_mismatch( + span, + closure_span, + expected, + found, + found_trait_ty.is_closure(), + ) } } - let msg = format!("type mismatch resolving `{}`", predicate); - let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg); - let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - let mut diag = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0271, - "type mismatch resolving `{}`", - predicate - ); - self.note_type_err(&mut diag, &obligation.cause, None, values, err); - self.note_obligation_cause(&mut diag, obligation); - diag.emit(); + TraitNotObjectSafe(did) => { + let violations = self.tcx.object_safety_violations(did); + report_object_safety_error(self.tcx, span, did, violations) + } + + ConstEvalFailure(ErrorHandled::TooGeneric) => { + // In this instance, we have a const expression containing an unevaluated + // generic parameter. We have no idea whether this expression is valid or + // not (e.g. it might result in an error), but we don't want to just assume + // that it's okay, because that might result in post-monomorphisation time + // errors. The onus is really on the caller to provide values that it can + // prove are well-formed. + let mut err = self + .tcx + .sess + .struct_span_err(span, "constant expression depends on a generic parameter"); + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + err.note("this may fail depending on what value the parameter takes"); + err + } + + // Already reported in the query. + ConstEvalFailure(ErrorHandled::Reported) => { + self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error"); + return; } - }); - } - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - /// returns the fuzzy category of a given type, or None - /// if the type can be equated to any type. - fn type_category(t: Ty<'_>) -> Option { - match t.kind { - ty::Bool => Some(0), - ty::Char => Some(1), - ty::Str => Some(2), - ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3), - ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4), - ty::Ref(..) | ty::RawPtr(..) => Some(5), - ty::Array(..) | ty::Slice(..) => Some(6), - ty::FnDef(..) | ty::FnPtr(..) => Some(7), - ty::Dynamic(..) => Some(8), - ty::Closure(..) => Some(9), - ty::Tuple(..) => Some(10), - ty::Projection(..) => Some(11), - ty::Param(..) => Some(12), - ty::Opaque(..) => Some(13), - ty::Never => Some(14), - ty::Adt(adt, ..) => match adt.adt_kind() { - AdtKind::Struct => Some(15), - AdtKind::Union => Some(16), - AdtKind::Enum => Some(17), - }, - ty::Generator(..) => Some(18), - ty::Foreign(..) => Some(19), - ty::GeneratorWitness(..) => Some(20), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + Overflow => { + bug!("overflow should be handled before the `report_selection_error` path"); } - } + }; - match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, - _ => cat_a == cat_b, - }, - // infer and error can be equated to all types - _ => true, - } - } + self.note_obligation_cause(&mut err, obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); - fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> { - self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind { - hir::GeneratorKind::Gen => "a generator", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure", - }) + err.emit(); } - fn find_similar_impl_candidates( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec> { - let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); - let all_impls = self.tcx.all_impls(trait_ref.def_id()); - - match simp { - Some(simp) => all_impls - .iter() - .filter_map(|&def_id| { - let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); - if let Some(imp_simp) = imp_simp { - if simp != imp_simp { - return None; + /// Given some node representing a fn-like thing in the HIR map, + /// returns a span and `ArgKind` information that describes the + /// arguments it expects. This can be supplied to + /// `report_arg_count_mismatch`. + fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec) { + match node { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), + .. + }) => ( + self.tcx.sess.source_map().def_span(span), + self.tcx + .hir() + .body(id) + .params + .iter() + .map(|arg| { + if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = + *arg.pat + { + ArgKind::Tuple( + Some(span), + args.iter() + .map(|pat| { + let snippet = self + .tcx + .sess + .source_map() + .span_to_snippet(pat.span) + .unwrap(); + (snippet, "_".to_owned()) + }) + .collect::>(), + ) + } else { + let name = + self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap(); + ArgKind::Arg(name, "_".to_owned()) } - } - - Some(imp) - }) - .collect(), - None => { - all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() + }) + .collect::>(), + ), + Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) + | Node::ImplItem(&hir::ImplItem { + span, + kind: hir::ImplItemKind::Method(ref sig, _), + .. + }) + | Node::TraitItem(&hir::TraitItem { + span, + kind: hir::TraitItemKind::Fn(ref sig, _), + .. + }) => ( + self.tcx.sess.source_map().def_span(span), + sig.decl + .inputs + .iter() + .map(|arg| match arg.clone().kind { + hir::TyKind::Tup(ref tys) => ArgKind::Tuple( + Some(arg.span), + vec![("_".to_owned(), "_".to_owned()); tys.len()], + ), + _ => ArgKind::empty(), + }) + .collect::>(), + ), + Node::Ctor(ref variant_data) => { + let span = variant_data + .ctor_hir_id() + .map(|hir_id| self.tcx.hir().span(hir_id)) + .unwrap_or(DUMMY_SP); + let span = self.tcx.sess.source_map().def_span(span); + + (span, vec![ArgKind::empty(); variant_data.fields().len()]) } + _ => panic!("non-FnLike node found: {:?}", node), } } - fn report_similar_impl_candidates( + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + fn report_arg_count_mismatch( &self, - impl_candidates: Vec>, - err: &mut DiagnosticBuilder<'_>, - ) { - if impl_candidates.is_empty() { - return; - } - - let len = impl_candidates.len(); - let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 }; + span: Span, + found_span: Option, + expected_args: Vec, + found_args: Vec, + is_closure: bool, + ) -> DiagnosticBuilder<'tcx> { + let kind = if is_closure { "closure" } else { "function" }; - let normalize = |candidate| { - self.tcx.infer_ctxt().enter(|ref infcx| { - let normalized = infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(candidate) - .ok(); - match normalized { - Some(normalized) => format!("\n {:?}", normalized.value), - None => format!("\n {:?}", candidate), + let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { + let arg_length = arguments.len(); + let distinct = match &other[..] { + &[ArgKind::Tuple(..)] => true, + _ => false, + }; + match (arg_length, arguments.get(0)) { + (1, Some(&ArgKind::Tuple(_, ref fields))) => { + format!("a single {}-tuple as argument", fields.len()) } - }) + _ => format!( + "{} {}argument{}", + arg_length, + if distinct && arg_length > 1 { "distinct " } else { "" }, + pluralize!(arg_length) + ), + } }; - // Sort impl candidates so that ordering is consistent for UI tests. - let mut normalized_impl_candidates = - impl_candidates.iter().map(normalize).collect::>(); - - // Sort before taking the `..end` range, - // because the ordering of `impl_candidates` may not be deterministic: - // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 - normalized_impl_candidates.sort(); - - err.help(&format!( - "the following implementations were found:{}{}", - normalized_impl_candidates[..end].join(""), - if len > 5 { format!("\nand {} others", len - 4) } else { String::new() } - )); - } + let expected_str = args_str(&expected_args, &found_args); + let found_str = args_str(&found_args, &expected_args); - /// Reports that an overflow has occurred and halts compilation. We - /// halt compilation unconditionally because it is important that - /// overflows never be masked -- they basically represent computations - /// whose result could not be truly determined and thus we can't say - /// if the program type checks or not -- and they are unusual - /// occurrences in any case. - pub fn report_overflow_error( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: fmt::Display + TypeFoldable<'tcx>, - { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); let mut err = struct_span_err!( self.tcx.sess, - obligation.cause.span, - E0275, - "overflow evaluating the requirement `{}`", - predicate + span, + E0593, + "{} is expected to take {}, but it takes {}", + kind, + expected_str, + found_str, ); - if suggest_increasing_limit { - self.suggest_new_overflow_limit(&mut err); - } - - self.note_obligation_cause_code( - &mut err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![], - ); + err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); - } + if let Some(found_span) = found_span { + err.span_label(found_span, format!("takes {}", found_str)); - /// Reports that a cycle was detected which led to overflow and halts - /// compilation. This is equivalent to `report_overflow_error` except - /// that we can give a more helpful error message (and, in particular, - /// we do not suggest increasing the overflow limit, which is not - /// going to help). - pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(&cycle.to_owned()); - assert!(!cycle.is_empty()); + // move |_| { ... } + // ^^^^^^^^-- def_span + // + // move |_| { ... } + // ^^^^^-- prefix + let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); + // move |_| { ... } + // ^^^-- pipe_span + let pipe_span = + if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; + + // Suggest to take and ignore the arguments with expected_args_length `_`s if + // found arguments is empty (assume the user just wants to ignore args in this case). + // For example, if `expected_args_length` is 2, suggest `|_, _|`. + if found_args.is_empty() && is_closure { + let underscores = vec!["_"; expected_args.len()].join(", "); + err.span_suggestion( + pipe_span, + &format!( + "consider changing the closure to take and ignore the expected argument{}", + if expected_args.len() < 2 { "" } else { "s" } + ), + format!("|{}|", underscores), + Applicability::MachineApplicable, + ); + } - debug!("report_overflow_error_cycle: cycle={:?}", cycle); + if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { + if fields.len() == expected_args.len() { + let sugg = fields + .iter() + .map(|(name, _)| name.to_owned()) + .collect::>() + .join(", "); + err.span_suggestion( + found_span, + "change the closure to take multiple arguments instead of a single tuple", + format!("|{}|", sugg), + Applicability::MachineApplicable, + ); + } + } + if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { + if fields.len() == found_args.len() && is_closure { + let sugg = format!( + "|({}){}|", + found_args + .iter() + .map(|arg| match arg { + ArgKind::Arg(name, _) => name.to_owned(), + _ => "_".to_owned(), + }) + .collect::>() + .join(", "), + // add type annotations if available + if found_args.iter().any(|arg| match arg { + ArgKind::Arg(_, ty) => ty != "_", + _ => false, + }) { + format!( + ": ({})", + fields + .iter() + .map(|(_, ty)| ty.to_owned()) + .collect::>() + .join(", ") + ) + } else { + String::new() + }, + ); + err.span_suggestion( + found_span, + "change the closure to accept a tuple instead of individual arguments", + sugg, + Applicability::MachineApplicable, + ); + } + } + } - self.report_overflow_error(&cycle[0], false); + err } +} + +trait InferCtxtPrivExt<'tcx> { + // returns if `cond` not occurring implies that `error` does not occur - i.e., that + // `error` occurring implies that `cond` occurs. + fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool; - pub fn report_extra_impl_obligation( + fn report_fulfillment_error( &self, - error_span: Span, - item_name: ast::Name, - _impl_item_def_id: DefId, - trait_item_def_id: DefId, - requirement: &dyn fmt::Display, - ) -> DiagnosticBuilder<'tcx> { - let msg = "impl has stricter requirements than trait"; - let sp = self.tcx.sess.source_map().def_span(error_span); + error: &FulfillmentError<'tcx>, + body_id: Option, + fallback_has_occurred: bool, + ); + + fn report_projection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + ); - let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg); + fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool; - if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let span = self.tcx.sess.source_map().def_span(trait_item_span); - err.span_label(span, format!("definition of `{}` from trait", item_name)); - } + fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; - err.span_label(sp, format!("impl has extra requirement {}", requirement)); + fn find_similar_impl_candidates( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Vec>; - err - } + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec>, + err: &mut DiagnosticBuilder<'_>, + ); /// Gets the parent trait chain start fn get_parent_trait_ref( &self, code: &ObligationCauseCode<'tcx>, - ) -> Option<(String, Option)> { - match code { - &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - match self.get_parent_trait_ref(&data.parent_code) { - Some(t) => Some(t), - None => { - let ty = parent_trait_ref.skip_binder().self_ty(); - let span = - TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); - Some((ty.to_string(), span)) - } - } - } - _ => None, - } - } + ) -> Option<(String, Option)>; + + /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait + /// with the same path as `trait_ref`, a help message about + /// a probable version mismatch is added to `err` + fn note_version_mismatch( + &self, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::PolyTraitRef<'tcx>, + ); + + fn mk_obligation_for_def_id( + &self, + def_id: DefId, + output_ty: Ty<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> PredicateObligation<'tcx>; - pub fn report_selection_error( + fn maybe_report_ambiguity( &self, obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - fallback_has_occurred: bool, - points_at_arg: bool, - ) { - let tcx = self.tcx; - let span = obligation.cause.span; - - let mut err = match *error { - SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } - | ObligationCauseCode::CompareImplTypeObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } = obligation.cause.code - { - self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}`", obligation.predicate), - ) - .emit(); - return; - } - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate, _) => { - let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - - if self.tcx.sess.has_errors() && trait_predicate.references_error() { - return; - } - let trait_ref = trait_predicate.to_poly_trait_ref(); - let (post_message, pre_message, type_def) = self - .get_parent_trait_ref(&obligation.cause.code) - .map(|(t, s)| { - ( - format!(" in `{}`", t), - format!("within `{}`, ", t), - s.map(|s| (format!("within this `{}`", t), s)), - ) - }) - .unwrap_or_default(); - - let OnUnimplementedNote { message, label, note, enclosing_scope } = - self.on_unimplemented_note(trait_ref, obligation); - let have_alt_message = message.is_some() || label.is_some(); - let is_try = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|s| &s == "?") - .unwrap_or(false); - let is_from = format!("{}", trait_ref.print_only_trait_path()) - .starts_with("std::convert::From<"); - let (message, note) = if is_try && is_from { - ( - Some(format!( - "`?` couldn't convert the error to `{}`", - trait_ref.self_ty(), - )), - Some( - "the question mark operation (`?`) implicitly performs a \ - conversion on the error value using the `From` trait" - .to_owned(), - ), - ) - } else { - (message, note) - }; + body_id: Option, + ); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0277, - "{}", - message.unwrap_or_else(|| format!( - "the trait bound `{}` is not satisfied{}", - trait_ref.without_const().to_predicate(), - post_message, - )) - ); + fn predicate_can_apply( + &self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>, + ) -> bool; - let explanation = - if obligation.cause.code == ObligationCauseCode::MainFunctionType { - "consider using `()`, or a `Result`".to_owned() - } else { - format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref.print_only_trait_path(), - trait_ref.self_ty(), - ) - }; + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ); - if self.suggest_add_reference_to_arg( - &obligation, - &mut err, - &trait_ref, - points_at_arg, - have_alt_message, - ) { - self.note_obligation_cause(&mut err, obligation); - err.emit(); - return; - } - if let Some(ref s) = label { - // If it has a custom `#[rustc_on_unimplemented]` - // error message, let's display it as the label! - err.span_label(span, s.as_str()); - err.help(&explanation); - } else { - err.span_label(span, explanation); - } - if let Some((msg, span)) = type_def { - err.span_label(span, &msg); - } - if let Some(ref s) = note { - // If it has a custom `#[rustc_on_unimplemented]` note, let's display it - err.note(s.as_str()); - } - if let Some(ref s) = enclosing_scope { - let enclosing_scope_span = tcx.def_span( - tcx.hir() - .opt_local_def_id(obligation.cause.body_id) - .unwrap_or_else(|| { - tcx.hir().body_owner_def_id(hir::BodyId { - hir_id: obligation.cause.body_id, - }) - }), - ); + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ); - err.span_label(enclosing_scope_span, s.as_str()); - } + fn is_recursive_obligation( + &self, + obligated_types: &mut Vec<&ty::TyS<'tcx>>, + cause_code: &ObligationCauseCode<'tcx>, + ) -> bool; +} - self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); - self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_remove_reference(&obligation, &mut err, &trait_ref); - self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); - self.note_version_mismatch(&mut err, &trait_ref); - if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { - err.emit(); - return; - } +impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { + // returns if `cond` not occurring implies that `error` does not occur - i.e., that + // `error` occurring implies that `cond` occurs. + fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool { + if cond == error { + return true; + } - // Try to report a help message - if !trait_ref.has_infer_types_or_consts() - && self.predicate_can_apply(obligation.param_env, trait_ref) - { - // If a where-clause may be useful, remind the - // user that they can add it. - // - // don't display an on-unimplemented note, as - // these notes will often be of the form - // "the type `T` can't be frobnicated" - // which is somewhat confusing. - self.suggest_restricting_param_bound( - &mut err, - &trait_ref, - obligation.cause.body_id, - ); - } else { - if !have_alt_message { - // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_ref); - self.report_similar_impl_candidates(impl_candidates, &mut err); - } - self.suggest_change_mut( - &obligation, - &mut err, - &trait_ref, - points_at_arg, - ); - } + let (cond, error) = match (cond, error) { + (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), + _ => { + // FIXME: make this work in other cases too. + return false; + } + }; - // If this error is due to `!: Trait` not implemented but `(): Trait` is - // implemented, and fallback has occurred, then it could be due to a - // variable that used to fallback to `()` now falling back to `!`. Issue a - // note informing about the change in behaviour. - if trait_predicate.skip_binder().self_ty().is_never() - && fallback_has_occurred - { - let predicate = trait_predicate.map_bound(|mut trait_pred| { - trait_pred.trait_ref.substs = self.tcx.mk_substs_trait( - self.tcx.mk_unit(), - &trait_pred.trait_ref.substs[1..], - ); - trait_pred - }); - let unit_obligation = Obligation { - predicate: ty::Predicate::Trait( - predicate, - hir::Constness::NotConst, - ), - ..obligation.clone() - }; - if self.predicate_may_hold(&unit_obligation) { - err.note( - "the trait is implemented for `()`. \ - Possibly this error has been caused by changes to \ - Rust's type-inference algorithm (see issue #48950 \ - \ - for more information). Consider whether you meant to use \ - the type `()` here instead.", - ); - } - } + for implication in super::elaborate_predicates(self.tcx, vec![*cond]) { + if let ty::Predicate::Trait(implication, _) = implication { + let error = error.to_poly_trait_ref(); + let implication = implication.to_poly_trait_ref(); + // FIXME: I'm just not taking associated types at all here. + // Eventually I'll need to implement param-env-aware + // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. + let param_env = ty::ParamEnv::empty(); + if self.can_sub(param_env, error, implication).is_ok() { + debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); + return true; + } + } + } - err - } + false + } - ty::Predicate::Subtype(ref predicate) => { - // Errors for Subtype predicates show up as - // `FulfillmentErrorCode::CodeSubtypeError`, - // not selection error. - span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) - } + fn report_fulfillment_error( + &self, + error: &FulfillmentError<'tcx>, + body_id: Option, + fallback_has_occurred: bool, + ) { + debug!("report_fulfillment_error({:?})", error); + match error.code { + FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { + self.report_selection_error( + &error.obligation, + selection_error, + fallback_has_occurred, + error.points_at_arg_span, + ); + } + FulfillmentErrorCode::CodeProjectionError(ref e) => { + self.report_projection_error(&error.obligation, e); + } + FulfillmentErrorCode::CodeAmbiguity => { + self.maybe_report_ambiguity(&error.obligation, body_id); + } + FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { + self.report_mismatched_types( + &error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone(), + ) + .emit(); + } + } + } - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = self.resolve_vars_if_possible(predicate); - let err = self - .region_outlives_predicate(&obligation.cause, &predicate) - .err() - .unwrap(); - struct_span_err!( - self.tcx.sess, - span, - E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err, - ) - } + fn report_projection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + ) { + let predicate = self.resolve_vars_if_possible(&obligation.predicate); - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - struct_span_err!( - self.tcx.sess, - span, - E0280, - "the requirement `{}` is not satisfied", - predicate - ) - } + if predicate.references_error() { + return; + } - ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); - report_object_safety_error(self.tcx, span, trait_def_id, violations) - } + self.probe(|_| { + let err_buf; + let mut err = &error.err; + let mut values = None; - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap(); - let closure_span = self - .tcx - .sess - .source_map() - .def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap()); - let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap(); - let mut err = struct_span_err!( - self.tcx.sess, - closure_span, - E0525, - "expected a closure that implements the `{}` trait, \ - but this closure only implements `{}`", - kind, - found_kind - ); + // try to find the mismatched types to report the error with. + // + // this can fail if the problem was higher-ranked, in which + // cause I have no idea for a good error message. + if let ty::Predicate::Projection(ref data) = predicate { + let mut selcx = SelectionContext::new(self); + let (data, _) = self.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + data, + ); + let mut obligations = vec![]; + let normalized_ty = super::normalize_projection_type( + &mut selcx, + obligation.param_env, + data.projection_ty, + obligation.cause.clone(), + 0, + &mut obligations, + ); - err.span_label( - closure_span, - format!("this closure implements `{}`, not `{}`", found_kind, kind), - ); - err.span_label( - obligation.cause.span, - format!("the requirement to implement `{}` derives from here", kind), - ); + debug!( + "report_projection_error obligation.cause={:?} obligation.param_env={:?}", + obligation.cause, obligation.param_env + ); - // Additional context information explaining why the closure only implements - // a particular trait. - if let Some(tables) = self.in_progress_tables { - let tables = tables.borrow(); - match (found_kind, tables.closure_kind_origins().get(hir_id)) { - (ty::ClosureKind::FnOnce, Some((span, name))) => { - err.span_label( - *span, - format!( - "closure is `FnOnce` because it moves the \ - variable `{}` out of its environment", - name - ), - ); - } - (ty::ClosureKind::FnMut, Some((span, name))) => { - err.span_label( - *span, - format!( - "closure is `FnMut` because it mutates the \ - variable `{}` here", - name - ), - ); - } - _ => {} - } - } + debug!( + "report_projection_error normalized_ty={:?} data.ty={:?}", + normalized_ty, data.ty + ); - err.emit(); - return; - } + let is_normalized_ty_expected = match &obligation.cause.code { + ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::BindingObligation(_, _) + | ObligationCauseCode::ObjectCastObligation(_) => false, + _ => true, + }; - ty::Predicate::WellFormed(ty) => { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "WF predicate not satisfied for {:?}", ty); - } + if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( + is_normalized_ty_expected, + normalized_ty, + data.ty, + ) { + values = Some(infer::ValuePairs::Types(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ty, + data.ty, + ))); - ty::Predicate::ConstEvaluatable(..) => { - // Errors for `ConstEvaluatable` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. - span_bug!( - span, - "const-evaluatable requirement gave wrong error: `{:?}`", - obligation - ) - } + err_buf = error; + err = &err_buf; } } - OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { - let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref); - - if expected_trait_ref.self_ty().references_error() { - return; - } + let msg = format!("type mismatch resolving `{}`", predicate); + let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg); + let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + let mut diag = struct_span_err!( + self.tcx.sess, + obligation.cause.span, + E0271, + "type mismatch resolving `{}`", + predicate + ); + self.note_type_err(&mut diag, &obligation.cause, None, values, err); + self.note_obligation_cause(&mut diag, obligation); + diag.emit(); + } + }); + } - let found_trait_ty = found_trait_ref.self_ty(); + fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + /// returns the fuzzy category of a given type, or None + /// if the type can be equated to any type. + fn type_category(t: Ty<'_>) -> Option { + match t.kind { + ty::Bool => Some(0), + ty::Char => Some(1), + ty::Str => Some(2), + ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3), + ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4), + ty::Ref(..) | ty::RawPtr(..) => Some(5), + ty::Array(..) | ty::Slice(..) => Some(6), + ty::FnDef(..) | ty::FnPtr(..) => Some(7), + ty::Dynamic(..) => Some(8), + ty::Closure(..) => Some(9), + ty::Tuple(..) => Some(10), + ty::Projection(..) => Some(11), + ty::Param(..) => Some(12), + ty::Opaque(..) => Some(13), + ty::Never => Some(14), + ty::Adt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct => Some(15), + AdtKind::Union => Some(16), + AdtKind::Enum => Some(17), + }, + ty::Generator(..) => Some(18), + ty::Foreign(..) => Some(19), + ty::GeneratorWitness(..) => Some(20), + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + } + } - let found_did = match found_trait_ty.kind { - ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), - ty::Adt(def, _) => Some(def.did), - _ => None, - }; + match (type_category(a), type_category(b)) { + (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { + (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, + _ => cat_a == cat_b, + }, + // infer and error can be equated to all types + _ => true, + } + } - let found_span = found_did - .and_then(|did| self.tcx.hir().span_if_local(did)) - .map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def + fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> { + self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind { + hir::GeneratorKind::Gen => "a generator", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure", + }) + } - if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { - // We check closures twice, with obligations flowing in different directions, - // but we want to complain about them only once. - return; - } + fn find_similar_impl_candidates( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Vec> { + let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); + let all_impls = self.tcx.all_impls(trait_ref.def_id()); - self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + match simp { + Some(simp) => all_impls + .iter() + .filter_map(|&def_id| { + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); + if let Some(imp_simp) = imp_simp { + if simp != imp_simp { + return None; + } + } - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { - ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], - _ => vec![ArgKind::empty()], - }; + Some(imp) + }) + .collect(), + None => { + all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() + } + } + } - let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.kind { - ty::Tuple(ref tys) => tys - .iter() - .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) - .collect(), - _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], - }; + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec>, + err: &mut DiagnosticBuilder<'_>, + ) { + if impl_candidates.is_empty() { + return; + } - if found.len() == expected.len() { - self.report_closure_arg_mismatch( - span, - found_span, - found_trait_ref, - expected_trait_ref, - ) - } else { - let (closure_span, found) = found_did - .and_then(|did| self.tcx.hir().get_if_local(did)) - .map(|node| { - let (found_span, found) = self.get_fn_like_arguments(node); - (Some(found_span), found) - }) - .unwrap_or((found_span, found)); + let len = impl_candidates.len(); + let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 }; - self.report_arg_count_mismatch( - span, - closure_span, - expected, - found, - found_trait_ty.is_closure(), - ) + let normalize = |candidate| { + self.tcx.infer_ctxt().enter(|ref infcx| { + let normalized = infcx + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .normalize(candidate) + .ok(); + match normalized { + Some(normalized) => format!("\n {:?}", normalized.value), + None => format!("\n {:?}", candidate), } - } + }) + }; - TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, did, violations) - } + // Sort impl candidates so that ordering is consistent for UI tests. + let mut normalized_impl_candidates = + impl_candidates.iter().map(normalize).collect::>(); - ConstEvalFailure(ErrorHandled::TooGeneric) => { - // In this instance, we have a const expression containing an unevaluated - // generic parameter. We have no idea whether this expression is valid or - // not (e.g. it might result in an error), but we don't want to just assume - // that it's okay, because that might result in post-monomorphisation time - // errors. The onus is really on the caller to provide values that it can - // prove are well-formed. - let mut err = self - .tcx - .sess - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - err.note("this may fail depending on what value the parameter takes"); - err - } + // Sort before taking the `..end` range, + // because the ordering of `impl_candidates` may not be deterministic: + // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 + normalized_impl_candidates.sort(); - // Already reported in the query. - ConstEvalFailure(ErrorHandled::Reported) => { - self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error"); - return; - } + err.help(&format!( + "the following implementations were found:{}{}", + normalized_impl_candidates[..end].join(""), + if len > 5 { format!("\nand {} others", len - 4) } else { String::new() } + )); + } - Overflow => { - bug!("overflow should be handled before the `report_selection_error` path"); + /// Gets the parent trait chain start + fn get_parent_trait_ref( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(String, Option)> { + match code { + &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + match self.get_parent_trait_ref(&data.parent_code) { + Some(t) => Some(t), + None => { + let ty = parent_trait_ref.skip_binder().self_ty(); + let span = + TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); + Some((ty.to_string(), span)) + } + } } - }; - - self.note_obligation_cause(&mut err, obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - - err.emit(); + _ => None, + } } /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait @@ -990,102 +1319,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) } -} - -pub fn recursive_type_with_infinite_size_error( - tcx: TyCtxt<'tcx>, - type_def_id: DefId, -) -> DiagnosticBuilder<'tcx> { - assert!(type_def_id.is_local()); - let span = tcx.hir().span_if_local(type_def_id).unwrap(); - let span = tcx.sess.source_map().def_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0072, - "recursive type `{}` has infinite size", - tcx.def_path_str(type_def_id) - ); - err.span_label(span, "recursive type has infinite size"); - err.help(&format!( - "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.def_path_str(type_def_id) - )); - err -} - -pub fn report_object_safety_error( - tcx: TyCtxt<'tcx>, - span: Span, - trait_def_id: DefId, - violations: Vec, -) -> DiagnosticBuilder<'tcx> { - let trait_str = tcx.def_path_str(trait_def_id); - let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { - hir::Node::Item(item) => Some(item.ident.span), - _ => None, - }); - let span = tcx.sess.source_map().def_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0038, - "the trait `{}` cannot be made into an object", - trait_str - ); - err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str)); - - let mut reported_violations = FxHashSet::default(); - let mut had_span_label = false; - for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation { - if !sp.is_empty() { - // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations - // with a `Span`. - reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); - } - } - if reported_violations.insert(violation.clone()) { - let spans = violation.spans(); - let msg = if trait_span.is_none() || spans.is_empty() { - format!("the trait cannot be made into an object because {}", violation.error_msg()) - } else { - had_span_label = true; - format!("...because {}", violation.error_msg()) - }; - if spans.is_empty() { - err.note(&msg); - } else { - for span in spans { - err.span_label(span, &msg); - } - } - match (trait_span, violation.solution()) { - (Some(_), Some((note, None))) => { - err.help(¬e); - } - (Some(_), Some((note, Some((sugg, span))))) => { - err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable); - } - // Only provide the help if its a local trait, otherwise it's not actionable. - _ => {} - } - } - } - if let (Some(trait_span), true) = (trait_span, had_span_label) { - err.span_label(trait_span, "this trait cannot be made into an object..."); - } - - if tcx.sess.trait_methods_not_found.borrow().contains(&span) { - // Avoid emitting error caused by non-existing method (#58734) - err.cancel(); - } - - err -} -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn maybe_report_ambiguity( &self, obligation: &PredicateObligation<'tcx>, @@ -1385,6 +1619,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } +pub fn recursive_type_with_infinite_size_error( + tcx: TyCtxt<'tcx>, + type_def_id: DefId, +) -> DiagnosticBuilder<'tcx> { + assert!(type_def_id.is_local()); + let span = tcx.hir().span_if_local(type_def_id).unwrap(); + let span = tcx.sess.source_map().def_span(span); + let mut err = struct_span_err!( + tcx.sess, + span, + E0072, + "recursive type `{}` has infinite size", + tcx.def_path_str(type_def_id) + ); + err.span_label(span, "recursive type has infinite size"); + err.help(&format!( + "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ + at some point to make `{}` representable", + tcx.def_path_str(type_def_id) + )); + err +} + /// Summarizes information #[derive(Clone)] pub enum ArgKind { diff --git a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs index eb34a4875961c..6e3074cd3ca98 100644 --- a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs @@ -8,7 +8,27 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::sym; -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +use super::InferCtxtPrivExt; + +crate trait InferCtxtExt<'tcx> { + /*private*/ + fn impl_similar_to( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) -> Option; + + /*private*/ + fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>; + + fn on_unimplemented_note( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) -> OnUnimplementedNote; +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn impl_similar_to( &self, trait_ref: ty::PolyTraitRef<'tcx>, @@ -101,7 +121,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - crate fn on_unimplemented_note( + fn on_unimplemented_note( &self, trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 228747c3f89e9..351e557d40b30 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1,6 +1,5 @@ use super::{ - ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, - PredicateObligation, + EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, }; use crate::infer::InferCtxt; @@ -8,9 +7,7 @@ use crate::traits::error_reporting::suggest_constraining_type_param; use rustc::ty::TypeckTables; use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, -}; +use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -20,8 +17,136 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - crate fn suggest_restricting_param_bound( +use super::InferCtxtPrivExt; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; + +crate trait InferCtxtExt<'tcx> { + fn suggest_restricting_param_bound( + &self, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::PolyTraitRef<'_>, + body_id: hir::HirId, + ); + + fn suggest_borrow_on_unsized_slice( + &self, + code: &ObligationCauseCode<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + ); + + fn get_closure_name( + &self, + def_id: DefId, + err: &mut DiagnosticBuilder<'_>, + msg: &str, + ) -> Option; + + fn suggest_fn_call( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder>, + points_at_arg: bool, + ); + + fn suggest_add_reference_to_arg( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + points_at_arg: bool, + has_custom_message: bool, + ) -> bool; + + fn suggest_remove_reference( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + ); + + fn suggest_change_mut( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + points_at_arg: bool, + ); + + fn suggest_semicolon_removal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + span: Span, + trait_ref: &ty::Binder>, + ); + + fn suggest_impl_trait( + &self, + err: &mut DiagnosticBuilder<'tcx>, + span: Span, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder>, + ) -> bool; + + fn point_at_returns_when_relevant( + &self, + err: &mut DiagnosticBuilder<'tcx>, + obligation: &PredicateObligation<'tcx>, + ); + + fn report_closure_arg_mismatch( + &self, + span: Span, + found_span: Option, + expected_ref: ty::PolyTraitRef<'tcx>, + found: ty::PolyTraitRef<'tcx>, + ) -> DiagnosticBuilder<'tcx>; + + fn suggest_fully_qualified_path( + &self, + err: &mut DiagnosticBuilder<'_>, + def_id: DefId, + span: Span, + trait_ref: DefId, + ); + + fn maybe_note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) -> bool; + + fn note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + target_span: Span, + scope_span: &Option, + expr: Option, + snippet: String, + first_generator: DefId, + last_generator: Option, + trait_ref: ty::TraitRef<'_>, + target_ty: Ty<'tcx>, + tables: &ty::TypeckTables<'_>, + obligation: &PredicateObligation<'tcx>, + next_code: Option<&ObligationCauseCode<'tcx>>, + ); + + fn note_obligation_cause_code( + &self, + err: &mut DiagnosticBuilder<'_>, + predicate: &T, + cause_code: &ObligationCauseCode<'tcx>, + obligated_types: &mut Vec<&ty::TyS<'tcx>>, + ) where + T: fmt::Display; + + fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>); +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { + fn suggest_restricting_param_bound( &self, mut err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::PolyTraitRef<'_>, @@ -168,7 +293,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a /// suggestion to borrow the initializer in order to use have a slice instead. - crate fn suggest_borrow_on_unsized_slice( + fn suggest_borrow_on_unsized_slice( &self, code: &ObligationCauseCode<'tcx>, err: &mut DiagnosticBuilder<'tcx>, @@ -195,7 +320,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Given a closure's `DefId`, return the given name of the closure. /// /// This doesn't account for reassignments, but it's only used for suggestions. - crate fn get_closure_name( + fn get_closure_name( &self, def_id: DefId, err: &mut DiagnosticBuilder<'_>, @@ -233,7 +358,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// We tried to apply the bound to an `fn` or closure. Check whether calling it would /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. - crate fn suggest_fn_call( + fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, @@ -317,7 +442,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - crate fn suggest_add_reference_to_arg( + fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, @@ -389,7 +514,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. - crate fn suggest_remove_reference( + fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, @@ -451,7 +576,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Check if the trait bound is implemented for a different mutability and note it in the /// final error. - crate fn suggest_change_mut( + fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, @@ -513,7 +638,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - crate fn suggest_semicolon_removal( + fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, @@ -549,7 +674,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if /// applicable and signal that the error has been expanded appropriately and needs to be /// emitted. - crate fn suggest_impl_trait( + fn suggest_impl_trait( &self, err: &mut DiagnosticBuilder<'tcx>, span: Span, @@ -723,7 +848,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { true } - crate fn point_at_returns_when_relevant( + fn point_at_returns_when_relevant( &self, err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, @@ -753,220 +878,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec) { - match node { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), - .. - }) => ( - self.tcx.sess.source_map().def_span(span), - self.tcx - .hir() - .body(id) - .params - .iter() - .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = - *arg.pat - { - ArgKind::Tuple( - Some(span), - args.iter() - .map(|pat| { - let snippet = self - .tcx - .sess - .source_map() - .span_to_snippet(pat.span) - .unwrap(); - (snippet, "_".to_owned()) - }) - .collect::>(), - ) - } else { - let name = - self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap(); - ArgKind::Arg(name, "_".to_owned()) - } - }) - .collect::>(), - ), - Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) - | Node::ImplItem(&hir::ImplItem { - span, - kind: hir::ImplItemKind::Method(ref sig, _), - .. - }) - | Node::TraitItem(&hir::TraitItem { - span, - kind: hir::TraitItemKind::Fn(ref sig, _), - .. - }) => ( - self.tcx.sess.source_map().def_span(span), - sig.decl - .inputs - .iter() - .map(|arg| match arg.clone().kind { - hir::TyKind::Tup(ref tys) => ArgKind::Tuple( - Some(arg.span), - vec![("_".to_owned(), "_".to_owned()); tys.len()], - ), - _ => ArgKind::empty(), - }) - .collect::>(), - ), - Node::Ctor(ref variant_data) => { - let span = variant_data - .ctor_hir_id() - .map(|hir_id| self.tcx.hir().span(hir_id)) - .unwrap_or(DUMMY_SP); - let span = self.tcx.sess.source_map().def_span(span); - - (span, vec![ArgKind::empty(); variant_data.fields().len()]) - } - _ => panic!("non-FnLike node found: {:?}", node), - } - } - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - pub fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option, - expected_args: Vec, - found_args: Vec, - is_closure: bool, - ) -> DiagnosticBuilder<'tcx> { - let kind = if is_closure { "closure" } else { "function" }; - - let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { - let arg_length = arguments.len(); - let distinct = match &other[..] { - &[ArgKind::Tuple(..)] => true, - _ => false, - }; - match (arg_length, arguments.get(0)) { - (1, Some(&ArgKind::Tuple(_, ref fields))) => { - format!("a single {}-tuple as argument", fields.len()) - } - _ => format!( - "{} {}argument{}", - arg_length, - if distinct && arg_length > 1 { "distinct " } else { "" }, - pluralize!(arg_length) - ), - } - }; - - let expected_str = args_str(&expected_args, &found_args); - let found_str = args_str(&found_args, &expected_args); - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0593, - "{} is expected to take {}, but it takes {}", - kind, - expected_str, - found_str, - ); - - err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); - - if let Some(found_span) = found_span { - err.span_label(found_span, format!("takes {}", found_str)); - - // move |_| { ... } - // ^^^^^^^^-- def_span - // - // move |_| { ... } - // ^^^^^-- prefix - let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); - // move |_| { ... } - // ^^^-- pipe_span - let pipe_span = - if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; - - // Suggest to take and ignore the arguments with expected_args_length `_`s if - // found arguments is empty (assume the user just wants to ignore args in this case). - // For example, if `expected_args_length` is 2, suggest `|_, _|`. - if found_args.is_empty() && is_closure { - let underscores = vec!["_"; expected_args.len()].join(", "); - err.span_suggestion( - pipe_span, - &format!( - "consider changing the closure to take and ignore the expected argument{}", - if expected_args.len() < 2 { "" } else { "s" } - ), - format!("|{}|", underscores), - Applicability::MachineApplicable, - ); - } - - if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { - if fields.len() == expected_args.len() { - let sugg = fields - .iter() - .map(|(name, _)| name.to_owned()) - .collect::>() - .join(", "); - err.span_suggestion( - found_span, - "change the closure to take multiple arguments instead of a single tuple", - format!("|{}|", sugg), - Applicability::MachineApplicable, - ); - } - } - if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { - if fields.len() == found_args.len() && is_closure { - let sugg = format!( - "|({}){}|", - found_args - .iter() - .map(|arg| match arg { - ArgKind::Arg(name, _) => name.to_owned(), - _ => "_".to_owned(), - }) - .collect::>() - .join(", "), - // add type annotations if available - if found_args.iter().any(|arg| match arg { - ArgKind::Arg(_, ty) => ty != "_", - _ => false, - }) { - format!( - ": ({})", - fields - .iter() - .map(|(_, ty)| ty.to_owned()) - .collect::>() - .join(", ") - ) - } else { - String::new() - }, - ); - err.span_suggestion( - found_span, - "change the closure to accept a tuple instead of individual arguments", - sugg, - Applicability::MachineApplicable, - ); - } - } - } - - err - } - - crate fn report_closure_arg_mismatch( + fn report_closure_arg_mismatch( &self, span: Span, found_span: Option, @@ -1022,10 +934,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } -} -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - crate fn suggest_fully_qualified_path( + fn suggest_fully_qualified_path( &self, err: &mut DiagnosticBuilder<'_>, def_id: DefId, @@ -1091,7 +1001,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// ``` /// /// Returns `true` if an async-await specific note was added to the diagnostic. - crate fn maybe_note_obligation_cause_for_async_await( + fn maybe_note_obligation_cause_for_async_await( &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, @@ -1271,7 +1181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Unconditionally adds the diagnostic note described in /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. - crate fn note_obligation_cause_for_async_await( + fn note_obligation_cause_for_async_await( &self, err: &mut DiagnosticBuilder<'_>, target_span: Span, @@ -1423,7 +1333,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } - crate fn note_obligation_cause_code( + fn note_obligation_cause_code( &self, err: &mut DiagnosticBuilder<'_>, predicate: &T, @@ -1638,7 +1548,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - crate fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { let current_limit = self.tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; err.help(&format!( diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index ac9ff484a0274..5def77ce7324c 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -4,9 +4,9 @@ use rustc::ty::{self, ToPolyTraitRef, Ty, TypeFoldable}; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; +use rustc_infer::traits::{TraitEngine, TraitEngineExt as _}; use std::marker::PhantomData; -use super::engine::{TraitEngine, TraitEngineExt}; use super::project; use super::select::SelectionContext; use super::wf; @@ -17,6 +17,9 @@ use super::{ConstEvalFailure, Unimplemented}; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation}; +use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; + impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { /// Note that we include both the `ParamEnv` and the `Predicate`, /// as the `ParamEnv` can influence whether fulfillment succeeds diff --git a/src/librustc_trait_selection/traits/misc.rs b/src/librustc_trait_selection/traits/misc.rs index 7ab918c159e1f..d500cff67c64b 100644 --- a/src/librustc_trait_selection/traits/misc.rs +++ b/src/librustc_trait_selection/traits/misc.rs @@ -1,10 +1,13 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use crate::infer::TyCtxtInferExt; +use crate::infer::InferCtxtExt as _; use crate::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; +use rustc_infer::infer::TyCtxtInferExt; + +use crate::traits::error_reporting::InferCtxtExt; #[derive(Clone)] pub enum CopyImplementationError<'tcx> { diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 9f7d019e8fd69..7b93982db974b 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -13,19 +13,18 @@ pub mod misc; mod object_safety; mod on_unimplemented; mod project; -mod projection_cache; pub mod query; mod select; mod specialize; -mod structural_impls; mod structural_match; mod util; pub mod wf; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt}; +use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc::middle::region; -use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; @@ -43,7 +42,7 @@ pub use self::Vtable::*; pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; -pub use self::engine::{TraitEngine, TraitEngineExt}; +pub use self::engine::TraitEngineExt; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; @@ -53,11 +52,6 @@ pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; pub use self::project::{ normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type, }; -pub use self::projection_cache::MismatchedProjectionTypes; -pub use self::projection_cache::{ - Normalized, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot, - Reveal, -}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::find_associated_item; @@ -77,7 +71,7 @@ pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, }; -pub use rustc::traits::*; +pub use rustc_infer::traits::*; /// Whether to skip the leak check, as part of a future compatibility warning step. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -114,61 +108,6 @@ pub enum TraitQueryMode { Canonical, } -/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for -/// which the vtable must be found. The process of finding a vtable is -/// called "resolving" the `Obligation`. This process consists of -/// either identifying an `impl` (e.g., `impl Eq for int`) that -/// provides the required vtable, or else finding a bound that is in -/// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Obligation<'tcx, T> { - /// The reason we have to prove this thing. - pub cause: ObligationCause<'tcx>, - - /// The environment in which we should prove this thing. - pub param_env: ty::ParamEnv<'tcx>, - - /// The thing we are trying to prove. - pub predicate: T, - - /// If we started proving this as a result of trying to prove - /// something else, track the total depth to ensure termination. - /// If this goes over a certain threshold, we abort compilation -- - /// in such cases, we can not say whether or not the predicate - /// holds for certain. Stupid halting problem; such a drag. - pub recursion_depth: usize, -} - -pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; - -// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(PredicateObligation<'_>, 112); - -pub type Obligations<'tcx, O> = Vec>; -pub type PredicateObligations<'tcx> = Vec>; -pub type TraitObligations<'tcx> = Vec>; - -pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; - -pub struct FulfillmentError<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub code: FulfillmentErrorCode<'tcx>, - /// Diagnostics only: we opportunistically change the `code.span` when we encounter an - /// obligation error caused by a call argument. When this is the case, we also signal that in - /// this field to ensure accuracy of suggestions. - pub points_at_arg_span: bool, -} - -#[derive(Clone)] -pub enum FulfillmentErrorCode<'tcx> { - CodeSelectionError(SelectionError<'tcx>), - CodeProjectionError(MismatchedProjectionTypes<'tcx>), - CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate - CodeAmbiguity, -} - /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>( cause: ObligationCause<'tcx>, @@ -581,58 +520,6 @@ fn vtable_methods<'tcx>( })) } -impl<'tcx, O> Obligation<'tcx, O> { - pub fn new( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: O, - ) -> Obligation<'tcx, O> { - Obligation { cause, param_env, recursion_depth: 0, predicate } - } - - fn with_depth( - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - predicate: O, - ) -> Obligation<'tcx, O> { - Obligation { cause, param_env, recursion_depth, predicate } - } - - pub fn misc( - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - trait_ref: O, - ) -> Obligation<'tcx, O> { - Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref) - } - - pub fn with

(&self, value: P) -> Obligation<'tcx, P> { - Obligation { - cause: self.cause.clone(), - param_env: self.param_env, - recursion_depth: self.recursion_depth, - predicate: value, - } - } -} - -impl<'tcx> FulfillmentError<'tcx> { - fn new( - obligation: PredicateObligation<'tcx>, - code: FulfillmentErrorCode<'tcx>, - ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation, code, points_at_arg_span: false } - } -} - -impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> ty::Binder> { - self.predicate.map_bound(|p| p.self_ty()) - } -} - pub fn provide(providers: &mut ty::query::Providers<'_>) { object_safety::provide(providers); *providers = ty::query::Providers { diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 6f20f5ac47e57..d0d41f3ae32ad 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -11,6 +11,7 @@ use super::elaborate_predicates; use crate::infer::TyCtxtInferExt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, Obligation, ObligationCause}; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 551b8618af1f5..dde78aa4357e9 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -1,7 +1,6 @@ //! Code for projecting associated types out of trait references. use super::elaborate_predicates; -use super::projection_cache::NormalizedTy; use super::specialization_graph; use super::translate_substs; use super::util; @@ -12,11 +11,12 @@ use super::PredicateObligation; use super::Selection; use super::SelectionContext; use super::SelectionError; -use super::{Normalized, ProjectionCacheEntry, ProjectionCacheKey}; +use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; +use crate::traits::error_reporting::InferCtxtExt; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; @@ -452,7 +452,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let infcx = selcx.infcx(); let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); - let cache_key = ProjectionCacheKey { ty: projection_ty }; + let cache_key = ProjectionCacheKey::new(projection_ty); debug!( "opt_normalize_projection_type(\ @@ -1483,20 +1483,29 @@ fn assoc_ty_def( } } -impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { - pub fn from_poly_projection_predicate( +crate trait ProjectionCacheKeyExt<'tcx>: Sized { + fn from_poly_projection_predicate( + selcx: &mut SelectionContext<'cx, 'tcx>, + predicate: &ty::PolyProjectionPredicate<'tcx>, + ) -> Option; +} + +impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> { + fn from_poly_projection_predicate( selcx: &mut SelectionContext<'cx, 'tcx>, predicate: &ty::PolyProjectionPredicate<'tcx>, ) -> Option { let infcx = selcx.infcx(); // We don't do cross-snapshot caching of obligations with escaping regions, // so there's no cache key to use - predicate.no_bound_vars().map(|predicate| ProjectionCacheKey { - // We don't attempt to match up with a specific type-variable state - // from a specific call to `opt_normalize_projection_type` - if - // there's no precise match, the original cache entry is "stranded" - // anyway. - ty: infcx.resolve_vars_if_possible(&predicate.projection_ty), + predicate.no_bound_vars().map(|predicate| { + ProjectionCacheKey::new( + // We don't attempt to match up with a specific type-variable state + // from a specific call to `opt_normalize_projection_type` - if + // there's no precise match, the original cache entry is "stranded" + // anyway. + infcx.resolve_vars_if_possible(&predicate.projection_ty), + ) }) } } diff --git a/src/librustc_trait_selection/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs index a1d7a2836e42d..40a21b5a6ed4a 100644 --- a/src/librustc_trait_selection/traits/query/dropck_outlives.rs +++ b/src/librustc_trait_selection/traits/query/dropck_outlives.rs @@ -7,7 +7,11 @@ use rustc::ty::{self, Ty, TyCtxt}; pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint}; -impl<'cx, 'tcx> At<'cx, 'tcx> { +pub trait AtExt<'tcx> { + fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>>; +} + +impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// Given a type `ty` of some value being dropped, computes a set /// of "kinds" (types, regions) that must be outlive the execution /// of the destructor. These basically correspond to data that the @@ -25,7 +29,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { /// /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md - pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { + fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,); // Quick check: there are a number of cases that we know do not require diff --git a/src/librustc_trait_selection/traits/query/evaluate_obligation.rs b/src/librustc_trait_selection/traits/query/evaluate_obligation.rs index b9ce3ccff2748..0569f6217da65 100644 --- a/src/librustc_trait_selection/traits/query/evaluate_obligation.rs +++ b/src/librustc_trait_selection/traits/query/evaluate_obligation.rs @@ -4,10 +4,35 @@ use crate::traits::{ EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode, }; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +pub trait InferCtxtExt<'tcx> { + fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool; + + fn predicate_must_hold_considering_regions( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool; + + fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool; + + fn evaluate_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> Result; + + // Helper function that canonicalizes and runs the query. If an + // overflow results, we re-run it in the local context so we can + // report a nice error. + /*crate*/ + fn evaluate_obligation_no_overflow( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> EvaluationResult; +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. - pub fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { + fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { self.evaluate_obligation_no_overflow(obligation).may_apply() } @@ -17,7 +42,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// /// This version may conservatively fail when outlives obligations /// are required. - pub fn predicate_must_hold_considering_regions( + fn predicate_must_hold_considering_regions( &self, obligation: &PredicateObligation<'tcx>, ) -> bool { @@ -29,15 +54,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// not entirely accurate if inference variables are involved. /// /// This version ignores all outlives constraints. - pub fn predicate_must_hold_modulo_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool { + fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool { self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions() } /// Evaluate a given predicate, capturing overflow and propagating it back. - pub fn evaluate_obligation( + fn evaluate_obligation( &self, obligation: &PredicateObligation<'tcx>, ) -> Result { @@ -53,7 +75,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Helper function that canonicalizes and runs the query. If an // overflow results, we re-run it in the local context so we can // report a nice error. - crate fn evaluate_obligation_no_overflow( + fn evaluate_obligation_no_overflow( &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 365bf9e295b56..adec2ddb25322 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -5,17 +5,24 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::Normalized; +use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt}; +use rustc_infer::traits::Normalized; use super::NoSolution; pub use rustc::traits::query::NormalizationResult; -impl<'cx, 'tcx> At<'cx, 'tcx> { +pub trait AtExt<'tcx> { + fn normalize(&self, value: &T) -> Result, NoSolution> + where + T: TypeFoldable<'tcx>; +} + +impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be /// normalized. If you don't care about regions, you should prefer @@ -29,7 +36,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". - pub fn normalize(&self, value: &T) -> Result, NoSolution> + fn normalize(&self, value: &T) -> Result, NoSolution> where T: TypeFoldable<'tcx>, { diff --git a/src/librustc_trait_selection/traits/query/outlives_bounds.rs b/src/librustc_trait_selection/traits/query/outlives_bounds.rs index 9ce17bcec2732..05c96dd520ab7 100644 --- a/src/librustc_trait_selection/traits/query/outlives_bounds.rs +++ b/src/librustc_trait_selection/traits/query/outlives_bounds.rs @@ -1,14 +1,25 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; +use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine}; use rustc::ty::{self, Ty}; use rustc_hir as hir; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::Span; pub use rustc::traits::query::OutlivesBound; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +pub trait InferCtxtExt<'tcx> { + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec>; +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a /// function's argument types are well-formed immediately before @@ -30,7 +41,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// - `ty`, the type that we are supposed to assume is WF. /// - `span`, a span to use when normalizing, hopefully not important, /// might be useful if a `bug!` occurs. - pub fn implied_outlives_bounds( + fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, diff --git a/src/librustc_trait_selection/traits/query/type_op/custom.rs b/src/librustc_trait_selection/traits/query/type_op/custom.rs index c1c9030b88805..915e8ae4a7ad6 100644 --- a/src/librustc_trait_selection/traits/query/type_op/custom.rs +++ b/src/librustc_trait_selection/traits/query/type_op/custom.rs @@ -4,7 +4,9 @@ use std::fmt; use crate::infer::canonical::query_response; use crate::infer::canonical::QueryRegionConstraints; -use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; +use crate::traits::engine::TraitEngineExt as _; +use crate::traits::{ObligationCause, TraitEngine}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; use std::rc::Rc; diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 12f39b12c7268..ab3214d8d2d23 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -33,6 +33,8 @@ use super::{ }; use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; +use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::ProjectionCacheKeyExt; use rustc::dep_graph::{DepKind, DepNodeIndex}; use rustc::middle::lang_items; use rustc::ty::fast_reject; @@ -3464,9 +3466,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } -impl<'tcx> TraitObligation<'tcx> { +trait TraitObligationExt<'tcx> { + fn derived_cause( + &self, + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx>; +} + +impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { #[allow(unused_comparisons)] - pub fn derived_cause( + fn derived_cause( &self, variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 980a3f0478134..b69c5bdce2abc 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -1,5 +1,5 @@ -use crate::infer::opaque_types::required_region_bounds; use crate::infer::InferCtxt; +use crate::opaque_types::required_region_bounds; use crate::traits::{self, AssocTypeBoundData}; use rustc::middle::lang_items; use rustc::ty::subst::SubstsRef; From 1fcdc52f707015195b0706ea86ddbe2f749019de Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 11 Feb 2020 21:19:40 +0100 Subject: [PATCH 7/8] Make downstream crates compile. --- src/librustc_interface/passes.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- .../diagnostics/conflict_errors.rs | 2 +- .../borrow_check/region_infer/opaque_types.rs | 1 + .../type_check/free_region_relations.rs | 2 +- .../borrow_check/type_check/liveness/trace.rs | 6 +++--- .../borrow_check/type_check/mod.rs | 12 +++++++----- .../borrow_check/type_check/relate_tys.rs | 4 ++-- .../transform/check_consts/validation.rs | 3 ++- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_mir_build/hair/cx/mod.rs | 1 + .../hair/pattern/const_to_pat.rs | 5 +++-- src/librustc_passes/stability.rs | 2 +- src/librustc_traits/dropck_outlives.rs | 14 ++++++++++---- src/librustc_traits/evaluate_obligation.rs | 6 +++--- src/librustc_traits/implied_outlives_bounds.rs | 12 +++++++----- .../normalize_erasing_regions.rs | 3 ++- src/librustc_traits/normalize_projection_ty.rs | 8 +++++--- src/librustc_traits/type_op.rs | 18 +++++++++++------- src/librustc_ty/common_traits.rs | 2 +- src/librustc_ty/instance.rs | 2 +- src/librustc_ty/ty.rs | 2 +- src/librustc_typeck/astconv.rs | 8 ++++---- src/librustc_typeck/check/_match.rs | 4 ++-- src/librustc_typeck/check/autoderef.rs | 3 ++- src/librustc_typeck/check/cast.rs | 4 ++-- src/librustc_typeck/check/closure.rs | 5 +++-- src/librustc_typeck/check/coercion.rs | 3 ++- src/librustc_typeck/check/compare_method.rs | 3 ++- src/librustc_typeck/check/demand.rs | 4 +++- src/librustc_typeck/check/dropck.rs | 5 ++++- src/librustc_typeck/check/expr.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 3 ++- src/librustc_typeck/check/method/probe.rs | 11 +++++++---- src/librustc_typeck/check/method/suggest.rs | 3 ++- src/librustc_typeck/check/mod.rs | 11 ++++++++--- src/librustc_typeck/check/op.rs | 1 + src/librustc_typeck/check/pat.rs | 2 +- src/librustc_typeck/check/regionck.rs | 2 ++ src/librustc_typeck/check/wfcheck.rs | 5 +++-- src/librustc_typeck/check/writeback.rs | 1 + src/librustc_typeck/coherence/builtin.rs | 7 ++++--- .../coherence/inherent_impls_overlap.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/collect/type_of.rs | 2 +- src/librustc_typeck/lib.rs | 6 +++++- src/librustc_typeck/mem_categorization.rs | 1 + src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 1 + src/librustdoc/lib.rs | 1 + 52 files changed, 136 insertions(+), 83 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 29e9ea1833f8e..bffbcd3366991 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -27,7 +27,6 @@ use rustc_errors::PResult; use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::Crate; -use rustc_infer::traits; use rustc_lint::LintStore; use rustc_mir as mir; use rustc_mir_build as mir_build; @@ -37,6 +36,7 @@ use rustc_plugin_impl as plugin; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_span::symbol::Symbol; use rustc_span::FileName; +use rustc_trait_selection::traits; use rustc_typeck as typeck; use rustc_serialize::json; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 249c9af3d4801..50c2c6f955228 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -39,12 +39,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{GenericParamKind, PatKind}; use rustc_hir::{HirIdSet, Node}; -use rustc_infer::traits::misc::can_type_implement_copy; use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, Span}; +use rustc_trait_selection::traits::misc::can_type_implement_copy; use crate::nonstandard_style::{method_context, MethodLateContext}; diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 8d4afd2c3b3af..e895eec5d52af 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -10,9 +10,9 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_index::vec::Idx; -use rustc_infer::traits::error_reporting::suggest_constraining_type_param; use rustc_span::source_map::DesugaringKind; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::suggest_constraining_type_param; use crate::dataflow::drop_flag_effects; use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex}; diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs index 15bbc5677dadd..49b4943732847 100644 --- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_span::Span; +use rustc_trait_selection::opaque_types::InferCtxtExt; use super::RegionInferenceContext; diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 283d78062f361..c17db926946cd 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -7,8 +7,8 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::type_op::{self, TypeOp}; use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use crate::borrow_check::{ diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs index baa9d1d212ea7..0c49ee44f9a50 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs @@ -3,9 +3,9 @@ use rustc::ty::{Ty, TypeFoldable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::HybridBitSet; use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::traits::query::dropck_outlives::DropckOutlivesResult; -use rustc_infer::traits::query::type_op::outlives::DropckOutlives; -use rustc_infer::traits::query::type_op::TypeOp; +use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; +use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; +use rustc_trait_selection::traits::query::type_op::TypeOp; use std::rc::Rc; use crate::dataflow::generic::ResultsCursor; diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index ace92949814a7..351b30bab614c 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -24,17 +24,19 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; -use rustc_infer::infer::opaque_types::GenerateMemberConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin, }; -use rustc_infer::traits::query::type_op; -use rustc_infer::traits::query::type_op::custom::CustomTypeOp; -use rustc_infer::traits::query::{Fallible, NoSolution}; -use rustc_infer::traits::{self, ObligationCause, PredicateObligations}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; +use rustc_trait_selection::traits::query::{Fallible, NoSolution}; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; use crate::dataflow::generic::ResultsCursor; use crate::dataflow::move_paths::MoveData; diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index b0f048ff1a6fd..ebaafd4026270 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -3,8 +3,8 @@ use rustc::ty::relate::TypeRelation; use rustc::ty::{self, Ty}; use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; -use rustc_infer::traits::query::Fallible; -use rustc_infer::traits::DomainGoal; +use rustc_trait_selection::traits::query::Fallible; +use rustc_trait_selection::traits::DomainGoal; use crate::borrow_check::constraints::OutlivesConstraint; use crate::borrow_check::type_check::{BorrowCheckContext, Locations}; diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 133772407c5dd..adffd444eb68b 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -9,9 +9,10 @@ use rustc_errors::struct_span_err; use rustc_hir::{def_id::DefId, HirId}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{self, TraitEngine}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, TraitEngine}; use std::borrow::Cow; use std::ops::Deref; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f9682a77173f5..289b198d2c949 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -25,8 +25,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::vec::IndexVec; -use rustc_infer::traits; use rustc_span::Span; +use rustc_trait_selection::traits; use crate::const_eval::error_to_const_error; use crate::interpret::{ diff --git a/src/librustc_mir_build/hair/cx/mod.rs b/src/librustc_mir_build/hair/cx/mod.rs index 449e2e7494697..99caa6a0f95b4 100644 --- a/src/librustc_mir_build/hair/cx/mod.rs +++ b/src/librustc_mir_build/hair/cx/mod.rs @@ -19,6 +19,7 @@ use rustc_hir::Node; use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_span::symbol::{sym, Symbol}; +use rustc_trait_selection::infer::InferCtxtExt; #[derive(Clone)] crate struct Cx<'a, 'tcx> { diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 27d1bce76edc5..214e75fbdde43 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -3,8 +3,9 @@ use rustc::mir::Field; use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::predicate_for_trait_def; -use rustc_infer::traits::{self, ObligationCause, PredicateObligation}; +use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use rustc_index::vec::Idx; diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 7ea9ab5335db3..d056d9f0562a3 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -18,9 +18,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Generics, HirId, Item, StructField, Variant}; -use rustc_infer::traits::misc::can_type_implement_copy; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_trait_selection::traits::misc::can_type_implement_copy; use std::cmp::Ordering; use std::mem::replace; diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 2f854c045e50e..b13a7a3acb165 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -5,11 +5,17 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::query::dropck_outlives::trivial_dropck_outlives; -use rustc_infer::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint}; -use rustc_infer::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; +use rustc_trait_selection::traits::query::dropck_outlives::{ + DropckOutlivesResult, DtorckConstraint, +}; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; +use rustc_trait_selection::traits::{ + Normalized, ObligationCause, TraitEngine, TraitEngineExt as _, +}; crate fn provide(p: &mut Providers<'_>) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs index 4cf5b66b3cbeb..87895d8e384da 100644 --- a/src/librustc_traits/evaluate_obligation.rs +++ b/src/librustc_traits/evaluate_obligation.rs @@ -1,11 +1,11 @@ use rustc::ty::query::Providers; use rustc::ty::{ParamEnvAnd, TyCtxt}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::query::CanonicalPredicateGoal; -use rustc_infer::traits::{ +use rustc_span::source_map::DUMMY_SP; +use rustc_trait_selection::traits::query::CanonicalPredicateGoal; +use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, }; -use rustc_span::source_map::DUMMY_SP; crate fn provide(p: &mut Providers<'_>) { *p = Providers { evaluate_obligation, ..*p }; diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 1b6b8735651b5..4505a1e59d9ba 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -7,12 +7,14 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::query::outlives_bounds::OutlivesBound; -use rustc_infer::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; -use rustc_infer::traits::wf; -use rustc_infer::traits::FulfillmentContext; -use rustc_infer::traits::{TraitEngine, TraitEngineExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; +use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound; +use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; +use rustc_trait_selection::traits::wf; +use rustc_trait_selection::traits::FulfillmentContext; +use rustc_trait_selection::traits::TraitEngine; use smallvec::{smallvec, SmallVec}; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 4e5f20d80b0d8..c2fb237a05b54 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -2,7 +2,8 @@ use rustc::traits::query::NoSolution; use rustc::ty::query::Providers; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{Normalized, ObligationCause}; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::{Normalized, ObligationCause}; use std::sync::atomic::Ordering; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index b567895634763..57abff769de9b 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -3,11 +3,13 @@ use rustc::ty::{ParamEnvAnd, TyCtxt}; use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::query::{ +use rustc_infer::traits::TraitEngineExt as _; +use rustc_span::DUMMY_SP; +use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution, }; -use rustc_infer::traits::{self, ObligationCause, SelectionContext, TraitEngineExt}; -use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext}; use std::sync::atomic::Ordering; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 4118133806141..e174c040e0da1 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -8,14 +8,18 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::query::type_op::ascribe_user_type::AscribeUserType; -use rustc_infer::traits::query::type_op::eq::Eq; -use rustc_infer::traits::query::type_op::normalize::Normalize; -use rustc_infer::traits::query::type_op::prove_predicate::ProvePredicate; -use rustc_infer::traits::query::type_op::subtype::Subtype; -use rustc_infer::traits::query::{Fallible, NoSolution}; -use rustc_infer::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::DUMMY_SP; +use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; +use rustc_trait_selection::traits::query::type_op::eq::Eq; +use rustc_trait_selection::traits::query::type_op::normalize::Normalize; +use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; +use rustc_trait_selection::traits::query::type_op::subtype::Subtype; +use rustc_trait_selection::traits::query::{Fallible, NoSolution}; +use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine}; use std::fmt; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_ty/common_traits.rs b/src/librustc_ty/common_traits.rs index e0ce6ad23a650..311ba383f3055 100644 --- a/src/librustc_ty/common_traits.rs +++ b/src/librustc_ty/common_traits.rs @@ -3,8 +3,8 @@ use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits; use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, lang_items::CopyTraitLangItem) diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index 8b1ba57e81945..10cc2c0e3033c 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -1,8 +1,8 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Instance, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; -use rustc_infer::traits; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; use log::debug; diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 5a87cf4c10d0d..4c0903b6b9dfa 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -5,9 +5,9 @@ use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_infer::traits; use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 36461f2400cef..be8090cf21b9c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -26,13 +26,13 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::print; use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs}; -use rustc_infer::traits; -use rustc_infer::traits::astconv_object_safety_violations; -use rustc_infer::traits::error_reporting::report_object_safety_error; -use rustc_infer::traits::wf::object_region_bounds; use rustc_span::symbol::sym; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::astconv_object_safety_violations; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::traits::wf::object_region_bounds; use smallvec::SmallVec; use std::collections::BTreeSet; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 2c71fec6809f7..20737b44e7c17 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -4,9 +4,9 @@ use rustc::ty::Ty; use rustc_hir as hir; use rustc_hir::ExprKind; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::traits::ObligationCauseCode; -use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; use rustc_span::Span; +use rustc_trait_selection::traits::ObligationCauseCode; +use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_match( diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 67bfb090253f0..991347714e841 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -8,7 +8,8 @@ use rustc::ty::{ToPredicate, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_infer::infer::{InferCtxt, InferOk}; -use rustc_infer::traits::{self, TraitEngine}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, TraitEngine}; use rustc_ast::ast::Ident; use rustc_span::Span; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index ff100c261f14a..d52b6c39ab58d 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -44,9 +44,9 @@ use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc_ast::ast; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_infer::traits; -use rustc_infer::traits::error_reporting::report_object_safety_error; use rustc_span::Span; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// Reifies a cast check to be checked once we have full type information for /// a function context. diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8689db1b1eb56..49b7a99731104 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -12,10 +12,11 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; -use rustc_infer::traits::error_reporting::ArgKind; -use rustc_infer::traits::Obligation; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::error_reporting::ArgKind; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::Obligation; use std::cmp; use std::iter; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 022b2e82964e0..d74623a063f8f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -66,10 +66,11 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; -use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode}; use rustc_span::symbol::sym; use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 0c8dec8f8d4a9..ff79d10273c84 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -10,8 +10,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; -use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use super::{potentially_plural_count, FnCtxt, Inherited}; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 6df9d0541952c..0556c80e4f707 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,6 +1,8 @@ use crate::check::FnCtxt; use rustc_infer::infer::InferOk; -use rustc_infer::traits::{self, ObligationCause}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, ObligationCause}; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::{self, AssocItem, Ty}; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index ead7536f8c664..dca4f9e7cbe08 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -10,8 +10,11 @@ use rustc::ty::{self, Predicate, Ty, TyCtxt}; use rustc_errors::struct_span_err; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferOk, SuppressRegionErrors, TyCtxtInferExt}; -use rustc_infer::traits::{ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::query::dropck_outlives::AtExt; +use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt}; /// This function confirms that the `Drop` implementation identified by /// `drop_impl_did` is not any more specialized than the type it is diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 859a219c95a21..93f9050b26eb9 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -34,10 +34,10 @@ use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::traits::{self, ObligationCauseCode}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::fmt::Display; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 108affe5a86c0..48c72567b5c31 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -11,8 +11,8 @@ use rustc::ty::subst::{Subst, SubstsRef}; use rustc::ty::{self, GenericParamDefKind, Ty}; use rustc_hir as hir; use rustc_infer::infer::{self, InferOk}; -use rustc_infer::traits; use rustc_span::Span; +use rustc_trait_selection::traits; use std::ops::Deref; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 189b05a819bab..3cf7b65e30f2f 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -22,8 +22,9 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; -use rustc_infer::traits; use rustc_span::Span; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use self::probe::{IsSuggestion, ProbeScope}; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index d35761a6a21f5..16bab09feeef0 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -28,11 +28,14 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; -use rustc_infer::traits::query::method_autoderef::MethodAutoderefBadTy; -use rustc_infer::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult}; -use rustc_infer::traits::query::CanonicalTyGoal; -use rustc_infer::traits::{self, ObligationCause}; use rustc_span::{symbol::Symbol, Span, DUMMY_SP}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; +use rustc_trait_selection::traits::query::method_autoderef::{ + CandidateStep, MethodAutoderefStepsResult, +}; +use rustc_trait_selection::traits::query::CanonicalTyGoal; +use rustc_trait_selection::traits::{self, ObligationCause}; use std::cmp::max; use std::iter; use std::mem; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 654ec372dedff..bfbad1a0ea961 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -17,9 +17,10 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::traits::Obligation; use rustc_span::symbol::kw; use rustc_span::{source_map, FileName, Span}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::Obligation; use std::cmp::Ordering; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f1f505e18599a..1975b24899960 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -121,17 +121,22 @@ use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, Q use rustc_index::vec::Idx; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, InferOk, InferResult, TyCtxtInferExt}; -use rustc_infer::traits::error_reporting::recursive_type_with_infinite_size_error; -use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl}; +use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, +}; use std::cell::{Cell, Ref, RefCell, RefMut}; use std::cmp; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f7bbde35aa72e..f589805e1e261 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -10,6 +10,7 @@ use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = b` diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 70b39a62cd718..60132dde9caec 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -11,9 +11,9 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{HirId, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::traits::{ObligationCause, Pattern}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{Span, Spanned}; +use rustc_trait_selection::traits::{ObligationCause, Pattern}; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c0e33637fd047..bfa3d75b6b0f0 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -87,6 +87,8 @@ use rustc_hir::PatKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, RegionObligation, SuppressRegionErrors}; use rustc_span::Span; +use rustc_trait_selection::infer::OutlivesEnvironmentExt; +use rustc_trait_selection::opaque_types::InferCtxtExt; use std::mem; use std::ops::Deref; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 335b4a2850116..026e68e10e04d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -12,10 +12,11 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir::def_id::DefId; use rustc_hir::ItemKind; -use rustc_infer::infer::opaque_types::may_define_opaque_type; -use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::opaque_types::may_define_opaque_type; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use rustc_hir as hir; use rustc_hir::itemlikevisit::ParItemLikeVisitor; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 380e256c9fc9a..f4c166b943d6c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -16,6 +16,7 @@ use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::InferCtxt; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::opaque_types::InferCtxtExt; use std::mem; diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 7d7d34e45a634..2ea7601ae6538 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -13,9 +13,10 @@ use rustc_hir::ItemKind; use rustc_infer::infer; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{SuppressRegionErrors, TyCtxtInferExt}; -use rustc_infer::traits::misc::{can_type_implement_copy, CopyImplementationError}; -use rustc_infer::traits::predicate_for_trait_def; -use rustc_infer::traits::{self, ObligationCause, TraitEngine}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; +use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { let lang_items = tcx.lang_items(); diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 778eee3586b4b..1eae9d3b7fa6c 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -3,7 +3,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_infer::traits::{self, SkipLeakCheck}; +use rustc_trait_selection::traits::{self, SkipLeakCheck}; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d24ee5f156bcf..0d0149f967358 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -9,8 +9,8 @@ use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_infer::traits; use rustc_span::Span; +use rustc_trait_selection::traits; mod builtin; mod inherent_impls; diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 0a57449357324..fc77aad8688c6 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -6,7 +6,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits; +use rustc_trait_selection::traits; pub fn check(tcx: TyCtxt<'_>) { let mut orphan = OrphanChecker { tcx }; diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index 815235adc7175..43cf65d81516c 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -11,9 +11,9 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; -use rustc_infer::traits; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::traits; use super::ItemCtxt; use super::{bad_placeholder_type, is_suggestable_infer_ty}; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index c5f339d6b7648..4e7985dd98812 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -101,9 +101,13 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Node; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; -use rustc_infer::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::{ + ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, +}; use std::iter; diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index 8e06948a10953..4350b3dda97ce 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -59,6 +59,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::PatKind; use rustc_infer::infer::InferCtxt; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; #[derive(Clone, Debug)] pub enum PlaceBase { diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 407b50382fa37..c85b21a55007f 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,7 +1,7 @@ use rustc::ty::{self, Region, RegionVid, TypeFoldable}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_infer::traits::auto_trait::{self, AutoTraitResult}; +use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult}; use std::fmt::Debug; diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 4a1e2570d06c5..e66f869771794 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,3 +1,4 @@ +use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc::ty::subst::Subst; use rustc::ty::{ToPredicate, WithConstness}; use rustc_hir as hir; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4ea14ab9077c6..2e90d6082bac9 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -38,6 +38,7 @@ extern crate rustc_resolve; extern crate rustc_session; extern crate rustc_span as rustc_span; extern crate rustc_target; +extern crate rustc_trait_selection; extern crate rustc_typeck; extern crate test as testing; #[macro_use] From 0144a979464744261d1d9b74234a4376a084e9b2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 11 Feb 2020 22:39:02 +0100 Subject: [PATCH 8/8] Trim dependencies and features. --- Cargo.lock | 7 ------- src/librustc_infer/Cargo.toml | 4 ---- src/librustc_infer/lib.rs | 6 ++---- src/librustc_resolve/Cargo.toml | 1 - src/librustc_trait_selection/Cargo.toml | 2 -- src/librustc_trait_selection/lib.rs | 11 ++--------- 6 files changed, 4 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f453705db9e58..303d5ba7eb878 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3774,19 +3774,15 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "fmt_macros", "graphviz", "log", "rustc", "rustc_ast", - "rustc_attr", "rustc_data_structures", - "rustc_error_codes", "rustc_errors", "rustc_hir", "rustc_index", "rustc_macros", - "rustc_session", "rustc_span", "rustc_target", "smallvec 1.0.0", @@ -4044,7 +4040,6 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_hir", - "rustc_infer", "rustc_metadata", "rustc_session", "rustc_span", @@ -4129,13 +4124,11 @@ name = "rustc_trait_selection" version = "0.0.0" dependencies = [ "fmt_macros", - "graphviz", "log", "rustc", "rustc_ast", "rustc_attr", "rustc_data_structures", - "rustc_error_codes", "rustc_errors", "rustc_hir", "rustc_index", diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml index de99214901d9b..4f97fd82874ff 100644 --- a/src/librustc_infer/Cargo.toml +++ b/src/librustc_infer/Cargo.toml @@ -10,18 +10,14 @@ path = "lib.rs" doctest = false [dependencies] -fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } log = { version = "0.4", features = ["release_max_level_info", "std"] } -rustc_attr = { path = "../librustc_attr" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } -rustc_error_codes = { path = "../librustc_error_codes" } rustc_hir = { path = "../librustc_hir" } rustc_index = { path = "../librustc_index" } rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index 49e99b574b892..cb8ae8c592b22 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -1,6 +1,5 @@ -//! This crates defines the trait resolution method and the type inference engine. +//! This crates defines the type inference engine. //! -//! - **Traits.** Trait resolution is implemented in the `traits` module. //! - **Type inference.** The type inference code can be found in the `infer` module; //! this code handles low-level equality and subtyping operations. The //! type check pass in the compiler is found in the `librustc_typeck` crate. @@ -17,12 +16,11 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(drain_filter)] #![feature(never_type)] #![feature(range_is_empty)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] -#![recursion_limit = "512"] +#![recursion_limit = "512"] // For rustdoc #[macro_use] extern crate rustc_macros; diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 11a3cedcc74e9..49f079ad27070 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -24,7 +24,6 @@ rustc_errors = { path = "../librustc_errors" } rustc_expand = { path = "../librustc_expand" } rustc_feature = { path = "../librustc_feature" } rustc_hir = { path = "../librustc_hir" } -rustc_infer = { path = "../librustc_infer" } rustc_metadata = { path = "../librustc_metadata" } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml index c7f2cc34b8470..5b2da41d06672 100644 --- a/src/librustc_trait_selection/Cargo.toml +++ b/src/librustc_trait_selection/Cargo.toml @@ -11,14 +11,12 @@ doctest = false [dependencies] fmt_macros = { path = "../libfmt_macros" } -graphviz = { path = "../libgraphviz" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_attr = { path = "../librustc_attr" } rustc = { path = "../librustc" } rustc_ast = { path = "../librustc_ast" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } -rustc_error_codes = { path = "../librustc_error_codes" } rustc_hir = { path = "../librustc_hir" } rustc_index = { path = "../librustc_index" } rustc_infer = { path = "../librustc_infer" } diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs index 8b5cf223826a9..739aff4fb94c9 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/src/librustc_trait_selection/lib.rs @@ -1,9 +1,6 @@ -//! This crates defines the trait resolution method and the type inference engine. +//! This crates defines the trait resolution method. //! //! - **Traits.** Trait resolution is implemented in the `traits` module. -//! - **Type inference.** The type inference code can be found in the `infer` module; -//! this code handles low-level equality and subtyping operations. The -//! type check pass in the compiler is found in the `librustc_typeck` crate. //! //! For more information about how rustc works, see the [rustc guide]. //! @@ -15,14 +12,10 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] -#![feature(box_patterns)] -#![feature(box_syntax)] #![feature(drain_filter)] -#![feature(never_type)] -#![feature(range_is_empty)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] -#![recursion_limit = "512"] +#![recursion_limit = "512"] // For rustdoc #[macro_use] extern crate rustc_macros;