diff --git a/Cargo.lock b/Cargo.lock index aefd40bfaa59e..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", @@ -3826,6 +3822,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", "rustc_traits", "rustc_ty", "rustc_typeck", @@ -3860,6 +3857,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", "unicode-security", ] @@ -3929,6 +3927,7 @@ dependencies = [ "rustc_macros", "rustc_span", "rustc_target", + "rustc_trait_selection", "serialize", "smallvec 1.0.0", ] @@ -3952,6 +3951,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", "serialize", "smallvec 1.0.0", ] @@ -3992,6 +3992,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_trait_selection", ] [[package]] @@ -4039,7 +4040,6 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_hir", - "rustc_infer", "rustc_metadata", "rustc_session", "rustc_span", @@ -4119,6 +4119,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 +4153,7 @@ dependencies = [ "rustc_macros", "rustc_span", "rustc_target", + "rustc_trait_selection", "smallvec 1.0.0", ] @@ -4146,6 +4168,7 @@ dependencies = [ "rustc_infer", "rustc_span", "rustc_target", + "rustc_trait_selection", ] [[package]] @@ -4164,6 +4187,7 @@ dependencies = [ "rustc_infer", "rustc_span", "rustc_target", + "rustc_trait_selection", "smallvec 1.0.0", ] 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/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/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 7e418898910dc..4a39403f211cc 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, @@ -2077,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 aac6c7640ca6b..6c1e86bf408b0 100644 --- a/src/librustc_infer/infer/outlives/env.rs +++ b/src/librustc_infer/infer/outlives/env.rs @@ -1,10 +1,11 @@ use crate::infer::{GenericKind, InferCtxt}; -use crate::traits::query::outlives_bounds::{self, OutlivesBound}; +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; /// The `OutlivesEnvironment` collects information about what outlives /// what in a given type-checking setting. For example, if we have a @@ -76,7 +77,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 } @@ -142,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 = @@ -188,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/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/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_infer/traits/engine.rs b/src/librustc_infer/traits/engine.rs index e23810dd1612d..9ad722342a19e 100644 --- a/src/librustc_infer/traits/engine.rs +++ b/src/librustc_infer/traits/engine.rs @@ -1,9 +1,9 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc::ty::{self, ToPredicate, Ty, WithConstness}; use rustc_hir::def_id::DefId; -use super::{FulfillmentContext, FulfillmentError}; +use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { @@ -76,9 +76,3 @@ impl> TraitEngineExt<'tcx> for T { } } } - -impl dyn TraitEngine<'tcx> { - pub fn new(_tcx: TyCtxt<'tcx>) -> Box { - Box::new(FulfillmentContext::new()) - } -} diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs index 10143ae015f2f..8943ce4e6c505 100644 --- a/src/librustc_infer/traits/error_reporting/mod.rs +++ b/src/librustc_infer/traits/error_reporting/mod.rs @@ -1,452 +1,16 @@ -pub mod on_unimplemented; -pub mod suggestions; +use super::ObjectSafetyViolation; -use super::{ - ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode, - MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause, - ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, - OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError, - TraitNotObjectSafe, -}; - -use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc::mir::interpret::ErrorHandled; -use rustc::session::DiagnosticMessageId; -use rustc::ty::error::ExpectedFound; -use rustc::ty::fast_reject; -use rustc::ty::fold::TypeFolder; -use rustc::ty::SubtypePredicate; -use rustc::ty::{ - self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use crate::infer::InferCtxt; +use rustc::ty::TyCtxt; use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +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, LOCAL_CRATE}; -use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; -use rustc_span::source_map::SourceMap; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_hir::def_id::DefId; +use rustc_span::Span; use std::fmt; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_fulfillment_errors( - &self, - errors: &[FulfillmentError<'tcx>], - body_id: Option, - fallback_has_occurred: bool, - ) { - #[derive(Debug)] - struct ErrorDescriptor<'tcx> { - predicate: ty::Predicate<'tcx>, - index: Option, // None if this is an old error - } - - let mut error_map: FxHashMap<_, Vec<_>> = self - .reported_trait_errors - .borrow() - .iter() - .map(|(&span, predicates)| { - ( - span, - predicates - .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) - .collect(), - ) - }) - .collect(); - - for (index, error) in errors.iter().enumerate() { - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - - error_map.entry(span).or_default().push(ErrorDescriptor { - predicate: error.obligation.predicate, - index: Some(index), - }); - - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_default() - .push(error.obligation.predicate.clone()); - } - - // We do this in 2 passes because we want to display errors in order, though - // maybe it *is* better to sort errors by span or something. - let mut is_suppressed = vec![false; errors.len()]; - for (_, error_set) in error_map.iter() { - // We want to suppress "duplicate" errors with the same span. - for error in error_set { - if let Some(index) = error.index { - // Suppress errors that are either: - // 1) strictly implied by another error. - // 2) implied by an error with a smaller index. - for error2 in error_set { - if error2.index.map_or(false, |index2| is_suppressed[index2]) { - // Avoid errors being suppressed by already-suppressed - // errors, to prevent all errors from being suppressed - // at once. - continue; - } - - if self.error_implies(&error2.predicate, &error.predicate) - && !(error2.index >= error.index - && self.error_implies(&error.predicate, &error2.predicate)) - { - info!("skipping {:?} (implied by {:?})", error, error2); - is_suppressed[index] = true; - break; - } - } - } - } - } - - for (error, suppressed) in errors.iter().zip(is_suppressed) { - if !suppressed { - self.report_fulfillment_error(error, body_id, fallback_has_occurred); - } - } - } - - // 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; - } - }; - - 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; - } - } - } - - false - } - - 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(); - } - } - } - - fn report_projection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - ) { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - - if predicate.references_error() { - return; - } - - self.probe(|_| { - let err_buf; - let mut err = &error.err; - let mut values = None; - - // 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, - ); - - debug!( - "report_projection_error obligation.cause={:?} obligation.param_env={:?}", - obligation.cause, obligation.param_env - ); - - debug!( - "report_projection_error normalized_ty={:?} data.ty={:?}", - normalized_ty, data.ty - ); - - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, - }; - - 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, - ))); - - err_buf = error; - err = &err_buf; - } - } - - 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(); - } - }); - } - - 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"), - } - } - - 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, - } - } - - 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", - }) - } - - 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; - } - } - - Some(imp) - }) - .collect(), - None => { - all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() - } - } - } - - fn report_similar_impl_candidates( - &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 }; - - 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), - } - }) - }; - - // 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() } - )); - } - - /// 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 - ); - - 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.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); - } - - /// 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()); - - debug!("report_overflow_error_cycle: cycle={:?}", cycle); - - self.report_overflow_error(&cycle[0], false); - } - pub fn report_extra_impl_obligation( &self, error_span: Span, @@ -469,550 +33,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } - - /// 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, - } - } - - pub fn report_selection_error( - &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) - }; - - 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 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, - }; - - 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 - - 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(), - ) - } - } - - 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; - } - - Overflow => { - bug!("overflow should be handled before the `report_selection_error` path"); - } - }; - - self.note_obligation_cause(&mut err, obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - - err.emit(); - } - - /// 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>, - ) { - let get_trait_impl = |trait_def_id| { - let mut trait_impl = None; - self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| { - if trait_impl.is_none() { - trait_impl = Some(impl_def_id); - } - }); - trait_impl - }; - let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); - let all_traits = self.tcx.all_traits(LOCAL_CRATE); - let traits_with_same_path: std::collections::BTreeSet<_> = all_traits - .iter() - .filter(|trait_def_id| **trait_def_id != trait_ref.def_id()) - .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path) - .collect(); - for trait_with_same_path in traits_with_same_path { - if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) { - let impl_span = self.tcx.def_span(impl_def_id); - err.span_help(impl_span, "trait impl with same name found"); - let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); - let crate_msg = format!( - "perhaps two different versions of crate `{}` are being used?", - trait_crate - ); - err.note(&crate_msg); - } - } - } - - fn mk_obligation_for_def_id( - &self, - def_id: DefId, - output_ty: Ty<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> PredicateObligation<'tcx> { - let new_trait_ref = - 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( @@ -1084,560 +104,3 @@ pub fn report_object_safety_error( err } - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn maybe_report_ambiguity( - &self, - obligation: &PredicateObligation<'tcx>, - body_id: Option, - ) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - let span = obligation.cause.span; - - debug!( - "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", - predicate, obligation, body_id, obligation.cause.code, - ); - - // Ambiguity errors are often caused as fallout from earlier - // errors. So just ignore them if this infcx is tainted. - if self.is_tainted_by_errors() { - return; - } - - let mut err = match predicate { - ty::Predicate::Trait(ref data, _) => { - let trait_ref = data.to_poly_trait_ref(); - let self_ty = trait_ref.self_ty(); - debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); - - if predicate.references_error() { - return; - } - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. We used to check for `self.tcx.sess.has_errors()` to - // avoid inundating the user with unnecessary errors, but we now - // check upstream for type errors and don't add the obligations to - // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); - return; - } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); - err.note(&format!("cannot resolve `{}`", predicate)); - if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } else if let ( - Ok(ref snippet), - ObligationCauseCode::BindingObligation(ref def_id, _), - ) = - (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code) - { - let generics = self.tcx.generics_of(*def_id); - if !generics.params.is_empty() && !snippet.ends_with('>') { - // FIXME: To avoid spurious suggestions in functions where type arguments - // where already supplied, we check the snippet to make sure it doesn't - // end with a turbofish. Ideally we would have access to a `PathSegment` - // instead. Otherwise we would produce the following output: - // - // error[E0283]: type annotations needed - // --> $DIR/issue-54954.rs:3:24 - // | - // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - // | | - // | cannot infer type - // | help: consider specifying the type argument - // | in the function call: - // | `Tt::const_val::<[i8; 123]>::` - // ... - // LL | const fn const_val() -> usize { - // | --------- - required by this bound in `Tt::const_val` - // | - // = note: cannot resolve `_: Tt` - - err.span_suggestion( - span, - &format!( - "consider specifying the type argument{} in the function call", - if generics.params.len() > 1 { "s" } else { "" }, - ), - format!( - "{}::<{}>", - snippet, - generics - .params - .iter() - .map(|p| p.name.to_string()) - .collect::>() - .join(", ") - ), - Applicability::HasPlaceholders, - ); - } - } - err - } - - ty::Predicate::WellFormed(ty) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if ty.references_error() || self.tcx.sess.has_errors() { - return; - } - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - - ty::Predicate::Subtype(ref data) => { - if data.references_error() || self.tcx.sess.has_errors() { - // no need to overload user in such cases - return; - } - let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); - // both must be type variables, or the other would've been instantiated - assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a, ErrorCode::E0282) - } - ty::Predicate::Projection(ref data) => { - let trait_ref = data.to_poly_trait_ref(self.tcx); - let self_ty = trait_ref.self_ty(); - if predicate.references_error() { - return; - } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); - err.note(&format!("cannot resolve `{}`", predicate)); - err - } - - _ => { - if self.tcx.sess.has_errors() { - return; - } - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0284, - "type annotations needed: cannot resolve `{}`", - predicate, - ); - err.span_label(span, &format!("cannot resolve `{}`", predicate)); - err - } - }; - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } - - /// Returns `true` if the trait predicate may apply for *some* assignment - /// to the type parameters. - fn predicate_can_apply( - &self, - param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitRef<'tcx>, - ) -> bool { - struct ParamToVarFolder<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - var_map: FxHashMap, Ty<'tcx>>, - } - - impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy { name, .. }) = ty.kind { - let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| { - infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), - span: DUMMY_SP, - }) - }) - } else { - ty.super_fold_with(self) - } - } - } - - self.probe(|_| { - let mut selcx = SelectionContext::new(self); - - let cleaned_pred = - pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() }); - - let cleaned_pred = super::project::normalize( - &mut selcx, - param_env, - ObligationCause::dummy(), - &cleaned_pred, - ) - .value; - - let obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - cleaned_pred.without_const().to_predicate(), - ); - - self.predicate_may_hold(&obligation) - }) - } - - fn note_obligation_cause( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - // First, attempt to add note to this error with an async-await-specific - // message, and fall back to regular note otherwise. - if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { - self.note_obligation_cause_code( - err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![], - ); - self.suggest_unsized_bound_if_applicable(err, obligation); - } - } - - fn suggest_unsized_bound_if_applicable( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - if let ( - ty::Predicate::Trait(pred, _), - ObligationCauseCode::BindingObligation(item_def_id, span), - ) = (&obligation.predicate, &obligation.cause.code) - { - if let (Some(generics), true) = ( - self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), - ) { - for param in generics.params { - if param.span == *span - && !param.bounds.iter().any(|bound| { - bound.trait_def_id() == self.tcx.lang_items().sized_trait() - }) - { - let (span, separator) = match param.bounds { - [] => (span.shrink_to_hi(), ":"), - [.., bound] => (bound.span().shrink_to_hi(), " + "), - }; - err.span_suggestion( - span, - "consider relaxing the implicit `Sized` restriction", - format!("{} ?Sized", separator), - Applicability::MachineApplicable, - ); - return; - } - } - } - } - } - - fn is_recursive_obligation( - &self, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, - cause_code: &ObligationCauseCode<'tcx>, - ) -> bool { - if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - - if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { - return true; - } - } - false - } -} - -/// Summarizes information -#[derive(Clone)] -pub enum ArgKind { - /// An argument of non-tuple type. Parameters are (name, ty) - Arg(String, String), - - /// An argument of tuple type. For a "found" argument, the span is - /// the locationo in the source of the pattern. For a "expected" - /// argument, it will be None. The vector is a list of (name, ty) - /// strings for the components of the tuple. - Tuple(Option, Vec<(String, String)>), -} - -impl ArgKind { - fn empty() -> ArgKind { - ArgKind::Arg("_".to_owned(), "_".to_owned()) - } - - /// Creates an `ArgKind` from the expected type of an - /// argument. It has no name (`_`) and an optional source span. - pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { - match t.kind { - ty::Tuple(ref tys) => ArgKind::Tuple( - span, - tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::>(), - ), - _ => ArgKind::Arg("_".to_owned(), t.to_string()), - } - } -} - -/// Suggest restricting a type param with a new bound. -pub fn suggest_constraining_type_param( - tcx: TyCtxt<'_>, - generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, - param_name: &str, - constraint: &str, - source_map: &SourceMap, - span: Span, - def_id: Option, -) -> bool { - const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound with"; - const MSG_RESTRICT_TYPE: &str = "consider restricting this type parameter with"; - const MSG_RESTRICT_TYPE_FURTHER: &str = "consider further restricting this type parameter with"; - - let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - - let param = if let Some(param) = param { - param - } else { - return false; - }; - - if def_id == tcx.lang_items().sized_trait() { - // Type parameters are already `Sized` by default. - err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); - return true; - } - - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` - - err.span_help(param.span, &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint)); - - err.tool_only_span_suggestion( - param.span, - MSG_RESTRICT_BOUND_FURTHER, - format!("{} + {}", param_name, constraint), - Applicability::MachineApplicable, - ); - - return true; - } - - if generics.where_clause.predicates.is_empty() { - if let Some(bounds_span) = param.bounds_span() { - // If user has provided some bounds, suggest restricting them: - // - // fn foo(t: T) { ... } - // --- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - - err.span_help( - bounds_span, - &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), - ); - - let span_hi = param.span.with_hi(span.hi()); - let span_with_colon = source_map.span_through_char(span_hi, ':'); - - if span_hi != param.span && span_with_colon != span_hi { - err.tool_only_span_suggestion( - span_with_colon, - MSG_RESTRICT_BOUND_FURTHER, - format!("{}: {} + ", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } else { - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - - err.span_help( - param.span, - &format!("{} `{}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), - ); - - err.tool_only_span_suggestion( - param.span, - MSG_RESTRICT_TYPE, - format!("{}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - - true - } else { - // This part is a bit tricky, because using the `where` clause user can - // provide zero, one or many bounds for the same type parameter, so we - // have following cases to consider: - // - // 1) When the type parameter has been provided zero bounds - // - // Message: - // fn foo(x: X, y: Y) where Y: Foo { ... } - // - help: consider restricting this type parameter with `where X: Bar` - // - // Suggestion: - // fn foo(x: X, y: Y) where Y: Foo { ... } - // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - - let mut param_spans = Vec::new(); - - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); - } - } - } - } - } - - let where_clause_span = - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); - - match ¶m_spans[..] { - &[] => { - err.span_help( - param.span, - &format!("{} `where {}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), - ); - - err.tool_only_span_suggestion( - where_clause_span, - MSG_RESTRICT_TYPE, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - - &[¶m_span] => { - err.span_help( - param_span, - &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), - ); - - let span_hi = param_span.with_hi(span.hi()); - let span_with_colon = source_map.span_through_char(span_hi, ':'); - - if span_hi != param_span && span_with_colon != span_hi { - err.tool_only_span_suggestion( - span_with_colon, - MSG_RESTRICT_BOUND_FURTHER, - format!("{}: {} +", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - _ => { - err.span_help( - param.span, - &format!( - "{} `where {}: {}`", - MSG_RESTRICT_TYPE_FURTHER, param_name, constraint, - ), - ); - - err.tool_only_span_suggestion( - where_clause_span, - MSG_RESTRICT_BOUND_FURTHER, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - true - } -} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index aa0cfedff9e8b..1c0785497be22 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -1,115 +1,33 @@ -//! Trait Resolution. See the [rustc dev guide] for more information on how this works. +//! Trait Resolution. See the [rustc guide] for more information on how this works. //! -//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html +//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html -#[allow(dead_code)] -pub mod auto_trait; -pub mod codegen; -mod coherence; mod engine; pub mod error_reporting; -mod fulfill; -pub mod misc; -mod object_safety; -mod on_unimplemented; mod project; -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 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}; -use rustc::util::common::ErrorReported; +use rustc::ty::{self, Ty}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::{Span, DUMMY_SP}; - -use std::fmt::Debug; +use rustc_span::Span; pub use self::FulfillmentErrorCode::*; pub use self::ObligationCauseCode::*; pub use self::SelectionError::*; 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::fulfill::{FulfillmentContext, PendingPredicateObligation}; -pub use self::object_safety::astconv_object_safety_violations; -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::select::{EvaluationCache, SelectionCache, SelectionContext}; -pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; -pub use self::specialize::find_associated_item; -pub use self::specialize::specialization_graph::FutureCompatOverlapError; -pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; -pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; -pub use self::structural_match::search_for_structural_match_violation; -pub use self::structural_match::type_marked_structural; -pub use self::structural_match::NonStructuralMatchTy; -pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; -pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{ - get_vtable_index_of_object_method, impl_is_default, impl_item_is_final, - predicate_for_trait_def, upcast_choices, -}; -pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, + Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, + ProjectionCacheSnapshot, Reveal, }; +crate use self::util::elaborate_predicates; pub use rustc::traits::*; -/// Whether to skip the leak check, as part of a future compatibility warning step. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum SkipLeakCheck { - Yes, - No, -} - -impl SkipLeakCheck { - fn is_yes(self) -> bool { - self == SkipLeakCheck::Yes - } -} - -/// The "default" for skip-leak-check corresponds to the current -/// behavior (do not skip the leak check) -- not the behavior we are -/// transitioning into. -impl Default for SkipLeakCheck { - fn default() -> Self { - SkipLeakCheck::No - } -} - -/// The mode that trait queries run in. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TraitQueryMode { - // Standard/un-canonicalized queries get accurate - // spans etc. passed in and hence can do reasonable - // error reporting on their own. - Standard, - // Canonicalized queries get dummy spans and hence - // must generally propagate errors to - // pre-canonicalization callsites. - 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 @@ -165,418 +83,6 @@ pub enum FulfillmentErrorCode<'tcx> { CodeAmbiguity, } -/// Creates predicate obligations from the generic bounds. -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> PredicateObligations<'tcx> { - util::predicates_for_generics(cause, 0, param_env, generic_bounds) -} - -/// Determines whether the type `ty` is known to meet `bound` and -/// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound (note that this is -/// conservative towards *no impl*, which is the opposite of the -/// `evaluate` methods). -pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - span: Span, -) -> bool { - debug!( - "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})", - ty, - infcx.tcx.def_path_str(def_id) - ); - - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; - let obligation = Obligation { - param_env, - cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), - recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(), - }; - - let result = infcx.predicate_must_hold_modulo_regions(&obligation); - debug!( - "type_known_to_meet_ty={:?} bound={} => {:?}", - ty, - infcx.tcx.def_path_str(def_id), - result - ); - - if result && ty.has_infer_types_or_consts() { - // Because of inference "guessing", selection can sometimes claim - // to succeed while the success requires a guess. To ensure - // this function's result remains infallible, we must confirm - // that guess. While imperfect, I believe this is sound. - - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); - - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID); - - fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); - - // Note: we only assume something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { - debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", - ty, - infcx.tcx.def_path_str(def_id) - ); - true - } - Err(e) => { - debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", - ty, - infcx.tcx.def_path_str(def_id), - e - ); - false - } - } - } else { - result - } -} - -fn do_normalize_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - region_context: DefId, - cause: ObligationCause<'tcx>, - elaborated_env: ty::ParamEnv<'tcx>, - predicates: Vec>, -) -> Result>, ErrorReported> { - debug!( - "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})", - predicates, region_context, cause, - ); - let span = cause.span; - tcx.infer_ctxt().enter(|infcx| { - // FIXME. We should really... do something with these region - // obligations. But this call just continues the older - // behavior (i.e., doesn't cause any new bugs), and it would - // take some further refactoring to actually solve them. In - // particular, we would have to handle implied bounds - // properly, and that code is currently largely confined to - // regionck (though I made some efforts to extract it - // out). -nmatsakis - // - // @arielby: In any case, these obligations are checked - // by wfcheck anyway, so I'm not sure we have to check - // them here too, and we will remove this function when - // we move over to lazy normalization *anyway*. - let fulfill_cx = FulfillmentContext::new_ignoring_regions(); - let predicates = - match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { - Ok(predicates) => predicates, - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - return Err(ErrorReported); - } - }; - - debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); - - let region_scope_tree = region::ScopeTree::default(); - - // We can use the `elaborated_env` here; the region code only - // cares about declarations like `'a: 'b`. - let outlives_env = OutlivesEnvironment::new(elaborated_env); - - infcx.resolve_regions_and_report_errors( - region_context, - ®ion_scope_tree, - &outlives_env, - SuppressRegionErrors::default(), - ); - - let predicates = match infcx.fully_resolve(&predicates) { - Ok(predicates) => predicates, - Err(fixup_err) => { - // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable, and it seems better not to ICE, - // all things considered. - tcx.sess.span_err(span, &fixup_err.to_string()); - return Err(ErrorReported); - } - }; - if predicates.has_local_value() { - // FIXME: shouldn't we, you know, actually report an error here? or an ICE? - Err(ErrorReported) - } else { - Ok(predicates) - } - }) -} - -// FIXME: this is gonna need to be removed ... -/// Normalizes the parameter environment, reporting errors if they occur. -pub fn normalize_param_env_or_error<'tcx>( - tcx: TyCtxt<'tcx>, - region_context: DefId, - unnormalized_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, -) -> ty::ParamEnv<'tcx> { - // I'm not wild about reporting errors here; I'd prefer to - // have the errors get reported at a defined place (e.g., - // during typeck). Instead I have all parameter - // environments, in effect, going through this function - // and hence potentially reporting errors. This ensures of - // course that we never forget to normalize (the - // alternative seemed like it would involve a lot of - // manual invocations of this fn -- and then we'd have to - // deal with the errors at each of those sites). - // - // In any case, in practice, typeck constructs all the - // parameter environments once for every fn as it goes, - // and errors will get reported then; so after typeck we - // can be sure that no errors should occur. - - debug!( - "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})", - region_context, unnormalized_env, cause - ); - - let mut predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect(); - - debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - - let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal, - unnormalized_env.def_id, - ); - - // HACK: we are trying to normalize the param-env inside *itself*. The problem is that - // normalization expects its param-env to be already normalized, which means we have - // a circularity. - // - // The way we handle this is by normalizing the param-env inside an unnormalized version - // of the param-env, which means that if the param-env contains unnormalized projections, - // we'll have some normalization failures. This is unfortunate. - // - // Lazy normalization would basically handle this by treating just the - // normalizing-a-trait-ref-requires-itself cycles as evaluation failures. - // - // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated - // types, so to make the situation less bad, we normalize all the predicates *but* - // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and - // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment. - // - // This works fairly well because trait matching does not actually care about param-env - // TypeOutlives predicates - these are normally used by regionck. - let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate { - ty::Predicate::TypeOutlives(..) => true, - _ => false, - }) - .collect(); - - debug!( - "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", - predicates, outlives_predicates - ); - let non_outlives_predicates = match do_normalize_predicates( - tcx, - region_context, - cause.clone(), - elaborated_env, - predicates, - ) { - Ok(predicates) => predicates, - // An unnormalized env is better than nothing. - Err(ErrorReported) => { - debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); - return elaborated_env; - } - }; - - debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); - - // Not sure whether it is better to include the unnormalized TypeOutlives predicates - // here. I believe they should not matter, because we are ignoring TypeOutlives param-env - // predicates here anyway. Keeping them here anyway because it seems safer. - let outlives_env: Vec<_> = - non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); - let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None); - let outlives_predicates = match do_normalize_predicates( - tcx, - region_context, - cause, - outlives_env, - outlives_predicates, - ) { - Ok(predicates) => predicates, - // An unnormalized env is better than nothing. - Err(ErrorReported) => { - debug!("normalize_param_env_or_error: errored resolving outlives predicates"); - return elaborated_env; - } - }; - debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); - - let mut predicates = non_outlives_predicates; - predicates.extend(outlives_predicates); - debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal, - unnormalized_env.def_id, - ) -} - -pub fn fully_normalize<'a, 'tcx, T>( - infcx: &InferCtxt<'a, 'tcx>, - mut fulfill_cx: FulfillmentContext<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, -) -> Result>> -where - T: TypeFoldable<'tcx>, -{ - debug!("fully_normalize_with_fulfillcx(value={:?})", value); - let selcx = &mut SelectionContext::new(infcx); - let Normalized { value: normalized_value, obligations } = - project::normalize(selcx, param_env, cause, value); - debug!( - "fully_normalize: normalized_value={:?} obligations={:?}", - normalized_value, obligations - ); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); - } - - debug!("fully_normalize: select_all_or_error start"); - fulfill_cx.select_all_or_error(infcx)?; - debug!("fully_normalize: select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); - debug!("fully_normalize: resolved_value={:?}", resolved_value); - Ok(resolved_value) -} - -/// Normalizes the predicates and checks whether they hold in an empty -/// environment. If this returns false, then either normalize -/// encountered an error or one of the predicates did not hold. Used -/// when creating vtables to check for unsatisfiable methods. -pub fn normalize_and_test_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: Vec>, -) -> bool { - debug!("normalize_and_test_predicates(predicates={:?})", predicates); - - let result = tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::reveal_all(); - let mut selcx = SelectionContext::new(&infcx); - let mut fulfill_cx = FulfillmentContext::new(); - let cause = ObligationCause::dummy(); - let Normalized { value: predicates, obligations } = - normalize(&mut selcx, param_env, cause.clone(), &predicates); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - for predicate in predicates { - let obligation = Obligation::new(cause.clone(), param_env, predicate); - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - - fulfill_cx.select_all_or_error(&infcx).is_ok() - }); - debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result); - result -} - -fn substitute_normalize_and_test_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - key: (DefId, SubstsRef<'tcx>), -) -> bool { - debug!("substitute_normalize_and_test_predicates(key={:?})", key); - - let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; - let result = normalize_and_test_predicates(tcx, predicates); - - debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); - result -} - -/// Given a trait `trait_ref`, iterates the vtable entries -/// that come from `trait_ref`, including its supertraits. -#[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`. -fn vtable_methods<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { - debug!("vtable_methods({:?})", trait_ref); - - tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| { - let trait_methods = tcx - .associated_items(trait_ref.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Method); - - // Now list each method's DefId and InternalSubsts (for within its trait). - // If the method can never be called from this object, produce None. - trait_methods.map(move |trait_method| { - debug!("vtable_methods: trait_method={:?}", trait_method); - let def_id = trait_method.def_id; - - // Some methods cannot be called on an object; skip those. - if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { - debug!("vtable_methods: not vtable safe"); - return None; - } - - // The method may have some early-bound lifetimes; add regions for those. - let substs = trait_ref.map_bound(|trait_ref| { - InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize] - } - }) - }); - - // The trait type may have higher-ranked lifetimes in it; - // erase them if they appear, so that we get the type - // at some particular call site. - let substs = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); - - // It's possible that the method relies on where-clauses that - // do not hold for this particular set of type parameters. - // Note that this method could then never be called, so we - // do not want to try and codegen it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if !normalize_and_test_predicates(tcx, predicates.predicates) { - debug!("vtable_methods: predicates do not hold"); - return None; - } - - Some((def_id, substs)) - }) - })) -} - impl<'tcx, O> Obligation<'tcx, O> { pub fn new( cause: ObligationCause<'tcx>, @@ -586,7 +92,7 @@ impl<'tcx, O> Obligation<'tcx, O> { Obligation { cause, param_env, recursion_depth: 0, predicate } } - fn with_depth( + pub fn with_depth( cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, @@ -615,7 +121,7 @@ impl<'tcx, O> Obligation<'tcx, O> { } impl<'tcx> FulfillmentError<'tcx> { - fn new( + pub fn new( obligation: PredicateObligation<'tcx>, code: FulfillmentErrorCode<'tcx>, ) -> FulfillmentError<'tcx> { @@ -624,19 +130,7 @@ impl<'tcx> FulfillmentError<'tcx> { } impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> ty::Binder> { + pub 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 { - specialization_graph_of: specialize::specialization_graph_provider, - specializes: specialize::specializes, - codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, - vtable_methods, - substitute_normalize_and_test_predicates, - ..*providers - }; -} diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 78483cf6577de..183e4be189022 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -1,398 +1,18 @@ //! Code for projecting associated types out of trait references. -use super::elaborate_predicates; -use super::specialization_graph; -use super::translate_substs; -use super::util; -use super::Obligation; -use super::ObligationCause; use super::PredicateObligation; -use super::Selection; -use super::SelectionContext; -use super::SelectionError; -use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData}; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -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::ty::fold::TypeFoldable; +use rustc::ty::{self, Ty}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::sym; -use rustc_span::DUMMY_SP; pub use rustc::traits::Reveal; -pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; - -pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; - -pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>; - -/// When attempting to resolve `::Name` ... -#[derive(Debug)] -pub enum ProjectionTyError<'tcx> { - /// ...we found multiple sources of information and couldn't resolve the ambiguity. - TooManyCandidates, - - /// ...an error occurred matching `T : TraitRef` - 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 - ParamEnv(ty::PolyProjectionPredicate<'tcx>), - - // from the definition of `Trait` when you have something like <::B as Trait2>::C - TraitDef(ty::PolyProjectionPredicate<'tcx>), - - // from a "impl" (or a "pseudo-impl" returned by select) - Select(Selection<'tcx>), -} - -enum ProjectionTyCandidateSet<'tcx> { - None, - Single(ProjectionTyCandidate<'tcx>), - Ambiguous, - Error(SelectionError<'tcx>), -} - -impl<'tcx> ProjectionTyCandidateSet<'tcx> { - fn mark_ambiguous(&mut self) { - *self = ProjectionTyCandidateSet::Ambiguous; - } - - fn mark_error(&mut self, err: SelectionError<'tcx>) { - *self = ProjectionTyCandidateSet::Error(err); - } - - // Returns true if the push was successful, or false if the candidate - // was discarded -- this could be because of ambiguity, or because - // a higher-priority candidate is already there. - fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { - use self::ProjectionTyCandidate::*; - use self::ProjectionTyCandidateSet::*; - - // This wacky variable is just used to try and - // make code readable and avoid confusing paths. - // It is assigned a "value" of `()` only on those - // paths in which we wish to convert `*self` to - // ambiguous (and return false, because the candidate - // was not used). On other paths, it is not assigned, - // and hence if those paths *could* reach the code that - // comes after the match, this fn would not compile. - let convert_to_ambiguous; - - match self { - None => { - *self = Single(candidate); - return true; - } - - Single(current) => { - // Duplicates can happen inside ParamEnv. In the case, we - // perform a lazy deduplication. - if current == &candidate { - return false; - } - - // Prefer where-clauses. As in select, if there are multiple - // candidates, we prefer where-clause candidates over impls. This - // may seem a bit surprising, since impls are the source of - // "truth" in some sense, but in fact some of the impls that SEEM - // applicable are not, because of nested obligations. Where - // clauses are the safer choice. See the comment on - // `select::SelectionCandidate` and #21974 for more details. - match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), - (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => unreachable!(), - (_, _) => convert_to_ambiguous = (), - } - } - - Ambiguous | Error(..) => { - return false; - } - } - - // We only ever get here when we moved from a single candidate - // to ambiguous. - let () = convert_to_ambiguous; - *self = Ambiguous; - false - } -} - -/// Evaluates constraints of the form: -/// -/// for<...> ::U == V -/// -/// If successful, this may result in additional obligations. Also returns -/// the projection cache key used to track these additional obligations. -pub fn poly_project_and_unify_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &PolyProjectionObligation<'tcx>, -) -> Result>>, MismatchedProjectionTypes<'tcx>> { - debug!("poly_project_and_unify_type(obligation={:?})", obligation); - - let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { - let (placeholder_predicate, placeholder_map) = - infcx.replace_bound_vars_with_placeholders(&obligation.predicate); - - let placeholder_obligation = obligation.with(placeholder_predicate); - let result = project_and_unify_type(selcx, &placeholder_obligation)?; - infcx - .leak_check(false, &placeholder_map, snapshot) - .map_err(|err| MismatchedProjectionTypes { err })?; - Ok(result) - }) -} - -/// Evaluates constraints of the form: -/// -/// ::U == V -/// -/// If successful, this may result in additional obligations. -fn project_and_unify_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionObligation<'tcx>, -) -> Result>>, MismatchedProjectionTypes<'tcx>> { - debug!("project_and_unify_type(obligation={:?})", obligation); - - let mut obligations = vec![]; - let normalized_ty = match opt_normalize_projection_type( - selcx, - obligation.param_env, - obligation.predicate.projection_ty, - obligation.cause.clone(), - obligation.recursion_depth, - &mut obligations, - ) { - Some(n) => n, - None => return Ok(None), - }; - - debug!( - "project_and_unify_type: normalized_ty={:?} obligations={:?}", - normalized_ty, obligations - ); - - let infcx = selcx.infcx(); - match infcx - .at(&obligation.cause, obligation.param_env) - .eq(normalized_ty, obligation.predicate.ty) - { - Ok(InferOk { obligations: inferred_obligations, value: () }) => { - obligations.extend(inferred_obligations); - Ok(Some(obligations)) - } - Err(err) => { - debug!("project_and_unify_type: equating types encountered error {:?}", err); - Err(MismatchedProjectionTypes { err }) - } - } -} - -/// Normalizes any associated type projections in `value`, replacing -/// them with a fully resolved type where possible. The return value -/// combines the normalized result and any additional obligations that -/// were incurred as result. -pub fn normalize<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: &T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_to(selcx, param_env, cause, value, &mut obligations); - Normalized { value, obligations } -} - -pub fn normalize_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: &T, - obligations: &mut Vec>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) -} - -/// As `normalize`, but with a custom depth. -pub fn normalize_with_depth<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); - Normalized { value, obligations } -} - -pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T, - obligations: &mut Vec>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("normalize_with_depth(depth={}, value={:?})", depth, value); - let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = normalizer.fold(value); - debug!( - "normalize_with_depth: depth={} result={:?} with {} obligations", - depth, - result, - normalizer.obligations.len() - ); - debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations); - result -} - -struct AssocTypeNormalizer<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - obligations: &'a mut Vec>, - depth: usize, -} - -impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { - fn new( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &'a mut Vec>, - ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } - } - - fn fold>(&mut self, value: &T) -> T { - let value = self.selcx.infcx().resolve_vars_if_possible(value); - - if !value.has_projections() { value } else { value.fold_with(self) } - } -} - -impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { - self.selcx.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - return ty; - } - // We don't want to normalize associated types that occur inside of region - // binders, because they may contain bound regions, and we can't cope with that. - // - // Example: - // - // for<'a> fn(>::A) - // - // Instead of normalizing `>::A` here, we'll - // normalize it when we instantiate those bound regions (which - // should occur eventually). - - let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // (*) - // Only normalize `impl Trait` after type-checking, usually in codegen. - match self.param_env.reveal { - Reveal::UserFacing => ty, - - Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); - if self.depth >= recursion_limit { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit, - self.param_env, - ty, - ); - self.selcx.infcx().report_overflow_error(&obligation, true); - } - - let generic_ty = self.tcx().type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.depth += 1; - let folded_ty = self.fold_ty(concrete_ty); - self.depth -= 1; - folded_ty - } - } - } - - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { - // (*) - - // (*) This is kind of hacky -- we need to be able to - // handle normalization within binders because - // otherwise we wind up a need to normalize when doing - // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but - // we can't normalize with bound regions in scope. So - // far now we just ignore binders but only normalize - // if all bound regions are gone (and then we still - // have to renormalize whenever we instantiate a - // binder). It would be better to normalize in a - // binding-aware fashion. - - let normalized_ty = normalize_projection_type( - self.selcx, - self.param_env, - *data, - self.cause.clone(), - self.depth, - &mut self.obligations, - ); - debug!( - "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \ - now with {} obligations", - self.depth, - ty, - normalized_ty, - self.obligations.len() - ); - normalized_ty - } - - _ => ty, - } - } - - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - constant.eval(self.selcx.tcx(), self.param_env) - } -} - #[derive(Clone, TypeFoldable)] pub struct Normalized<'tcx, T> { pub value: T, @@ -403,1100 +23,7 @@ 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 -/// there are unresolved type variables in the projection, we will -/// substitute a fresh type variable `$X` and generate a new -/// obligation `::Item == $X` for later. -pub fn normalize_projection_type<'a, 'b, 'tcx>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &mut Vec>, -) -> Ty<'tcx> { - opt_normalize_projection_type( - selcx, - param_env, - projection_ty, - cause.clone(), - depth, - obligations, - ) - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. - - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); - let obligation = - Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate()); - obligations.push(obligation); - ty_var - }) -} - -/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly -/// additional obligations). Returns `None` in the case of ambiguity, -/// which indicates that there are unbound type variables. -/// -/// This function used to return `Option>`, which contains a -/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very -/// often immediately appended to another obligations vector. So now this -/// function takes an obligations vector and appends to it directly, which is -/// slightly uglier but avoids the need for an extra short-lived allocation. -fn opt_normalize_projection_type<'a, 'b, 'tcx>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &mut Vec>, -) -> Option> { - let infcx = selcx.infcx(); - - let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); - let cache_key = ProjectionCacheKey { ty: projection_ty }; - - debug!( - "opt_normalize_projection_type(\ - projection_ty={:?}, \ - depth={})", - projection_ty, depth - ); - - // FIXME(#20304) For now, I am caching here, which is good, but it - // means we don't capture the type variables that are created in - // the case of ambiguity. Which means we may create a large stream - // of such variables. OTOH, if we move the caching up a level, we - // would not benefit from caching when proving `T: Trait` - // bounds. It might be the case that we want two distinct caches, - // or else another kind of cache entry. - - let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key); - match cache_result { - Ok(()) => {} - Err(ProjectionCacheEntry::Ambiguous) => { - // If we found ambiguity the last time, that means we will continue - // to do so until some type in the key changes (and we know it - // hasn't, because we just fully resolved it). - debug!( - "opt_normalize_projection_type: \ - found cache entry: ambiguous" - ); - return None; - } - Err(ProjectionCacheEntry::InProgress) => { - // If while normalized A::B, we are asked to normalize - // A::B, just return A::B itself. This is a conservative - // answer, in the sense that A::B *is* clearly equivalent - // to A::B, though there may be a better value we can - // find. - - // Under lazy normalization, this can arise when - // bootstrapping. That is, imagine an environment with a - // where-clause like `A::B == u32`. Now, if we are asked - // to normalize `A::B`, we will want to check the - // where-clauses in scope. So we will try to unify `A::B` - // with `A::B`, which can trigger a recursive - // normalization. In that case, I think we will want this code: - // - // ``` - // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id, - // projection_ty.substs; - // return Some(NormalizedTy { value: v, obligations: vec![] }); - // ``` - - debug!( - "opt_normalize_projection_type: \ - found cache entry: in-progress" - ); - - // But for now, let's classify this as an overflow: - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); - let obligation = - Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); - selcx.infcx().report_overflow_error(&obligation, false); - } - Err(ProjectionCacheEntry::NormalizedTy(ty)) => { - // This is the hottest path in this function. - // - // If we find the value in the cache, then return it along - // with the obligations that went along with it. Note - // that, when using a fulfillment context, these - // obligations could in principle be ignored: they have - // already been registered when the cache entry was - // created (and hence the new ones will quickly be - // discarded as duplicated). But when doing trait - // evaluation this is not the case, and dropping the trait - // evaluations can causes ICEs (e.g., #43132). - debug!( - "opt_normalize_projection_type: \ - found normalized ty `{:?}`", - ty - ); - - // Once we have inferred everything we need to know, we - // can ignore the `obligations` from that point on. - if infcx.unresolved_type_vars(&ty.value).is_none() { - infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty); - // No need to extend `obligations`. - } else { - obligations.extend(ty.obligations); - } - - obligations.push(get_paranoid_cache_value_obligation( - infcx, - param_env, - projection_ty, - cause, - depth, - )); - return Some(ty.value); - } - Err(ProjectionCacheEntry::Error) => { - debug!( - "opt_normalize_projection_type: \ - found error" - ); - let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); - obligations.extend(result.obligations); - return Some(result.value); - } - } - - let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); - match project_type(selcx, &obligation) { - Ok(ProjectedTy::Progress(Progress { - ty: projected_ty, - obligations: mut projected_obligations, - })) => { - // if projection succeeded, then what we get out of this - // is also non-normalized (consider: it was derived from - // an impl, where-clause etc) and hence we must - // re-normalize it - - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} \ - depth={} \ - projected_obligations={:?}", - projected_ty, depth, projected_obligations - ); - - let result = if projected_ty.has_projections() { - let mut normalizer = AssocTypeNormalizer::new( - selcx, - param_env, - cause, - depth + 1, - &mut projected_obligations, - ); - let normalized_ty = normalizer.fold(&projected_ty); - - debug!( - "opt_normalize_projection_type: \ - normalized_ty={:?} depth={}", - normalized_ty, depth - ); - - Normalized { value: normalized_ty, obligations: projected_obligations } - } else { - Normalized { value: projected_ty, obligations: projected_obligations } - }; - - let cache_value = prune_cache_value_obligations(infcx, &result); - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value); - obligations.extend(result.obligations); - Some(result.value) - } - Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} no progress", - projected_ty - ); - let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone()); - // No need to extend `obligations`. - Some(result.value) - } - Err(ProjectionTyError::TooManyCandidates) => { - debug!( - "opt_normalize_projection_type: \ - too many candidates" - ); - infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); - None - } - Err(ProjectionTyError::TraitSelectionError(_)) => { - debug!("opt_normalize_projection_type: ERROR"); - // if we got an error processing the `T as Trait` part, - // just return `ty::err` but add the obligation `T : - // Trait`, which when processed will cause the error to be - // reported later - - infcx.inner.borrow_mut().projection_cache.error(cache_key); - let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); - obligations.extend(result.obligations); - Some(result.value) - } - } -} - -/// If there are unresolved type variables, then we need to include -/// any subobligations that bind them, at least until those type -/// variables are fully resolved. -fn prune_cache_value_obligations<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - result: &NormalizedTy<'tcx>, -) -> NormalizedTy<'tcx> { - if infcx.unresolved_type_vars(&result.value).is_none() { - return NormalizedTy { value: result.value, obligations: vec![] }; - } - - let mut obligations: Vec<_> = result - .obligations - .iter() - .filter(|obligation| match obligation.predicate { - // We found a `T: Foo` predicate, let's check - // if `U` references any unresolved type - // variables. In principle, we only care if this - // projection can help resolve any of the type - // variables found in `result.value` -- but we just - // check for any type variables here, for fear of - // indirect obligations (e.g., we project to `?0`, - // but we have `T: Foo` and `?1: Bar`). - ty::Predicate::Projection(ref data) => infcx.unresolved_type_vars(&data.ty()).is_some(), - - // We are only interested in `T: Foo` predicates, whre - // `U` references one of `unresolved_type_vars`. =) - _ => false, - }) - .cloned() - .collect(); - - obligations.shrink_to_fit(); - - NormalizedTy { value: result.value, obligations } -} - -/// Whenever we give back a cache result for a projection like `::Item ==> X`, we *always* include the obligation to prove -/// that `T: Trait` (we may also include some other obligations). This -/// may or may not be necessary -- in principle, all the obligations -/// that must be proven to show that `T: Trait` were also returned -/// when the cache was first populated. But there are some vague concerns, -/// and so we take the precautionary measure of including `T: Trait` in -/// the result: -/// -/// Concern #1. The current setup is fragile. Perhaps someone could -/// have failed to prove the concerns from when the cache was -/// populated, but also not have used a snapshot, in which case the -/// cache could remain populated even though `T: Trait` has not been -/// shown. In this case, the "other code" is at fault -- when you -/// project something, you are supposed to either have a snapshot or -/// else prove all the resulting obligations -- but it's still easy to -/// get wrong. -/// -/// Concern #2. Even within the snapshot, if those original -/// obligations are not yet proven, then we are able to do projections -/// that may yet turn out to be wrong. This *may* lead to some sort -/// of trouble, though we don't have a concrete example of how that -/// can occur yet. But it seems risky at best. -fn get_paranoid_cache_value_obligation<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> PredicateObligation<'tcx> { - let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(), - } -} - -/// If we are projecting `::Item`, but `T: Trait` does not -/// hold. In various error cases, we cannot generate a valid -/// normalized projection. Therefore, we create an inference variable -/// return an associated obligation that, when fulfilled, will lead to -/// an error. -/// -/// Note that we used to return `Error` here, but that was quite -/// dubious -- the premise was that an error would *eventually* be -/// reported, when the obligation was processed. But in general once -/// you see a `Error` you are supposed to be able to assume that an -/// error *has been* reported, so that you can take whatever heuristic -/// paths you want to take. To make things worse, it was possible for -/// cycles to arise, where you basically had a setup like ` -/// as Trait>::Foo == $0`. Here, normalizing ` as -/// Trait>::Foo> to `[type error]` would lead to an obligation of -/// ` as Trait>::Foo`. We are supposed to report -/// an error for this obligation, but we legitimately should not, -/// because it contains `[type error]`. Yuck! (See issue #29857 for -/// one case where this arose.) -fn normalize_to_error<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); - let trait_obligation = Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(), - }; - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - Normalized { value: new_value, obligations: vec![trait_obligation] } -} - -enum ProjectedTy<'tcx> { - Progress(Progress<'tcx>), - NoProgress(Ty<'tcx>), -} - -struct Progress<'tcx> { - ty: Ty<'tcx>, - obligations: Vec>, -} - -impl<'tcx> Progress<'tcx> { - fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { ty: tcx.types.err, obligations: vec![] } - } - - fn with_addl_obligations(mut self, mut obligations: Vec>) -> Self { - debug!( - "with_addl_obligations: self.obligations.len={} obligations.len={}", - self.obligations.len(), - obligations.len() - ); - - debug!( - "with_addl_obligations: self.obligations={:?} obligations={:?}", - self.obligations, obligations - ); - - self.obligations.append(&mut obligations); - self - } -} - -/// Computes the result of a projection type (if we can). -/// -/// IMPORTANT: -/// - `obligation` must be fully normalized -fn project_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, -) -> Result, ProjectionTyError<'tcx>> { - debug!("project(obligation={:?})", obligation); - - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - debug!("project: overflow!"); - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); - } - - let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - - debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); - - if obligation_trait_ref.references_error() { - return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); - } - - let mut candidates = ProjectionTyCandidateSet::None; - - // Make sure that the following procedures are kept in order. ParamEnv - // needs to be first because it has highest priority, and Select checks - // the return value of push_candidate which assumes it's ran at last. - assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates); - - assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); - - assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); - - match candidates { - ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( - confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate), - )), - ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( - selcx - .tcx() - .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs), - )), - // Error occurred while trying to processing impls. - ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), - // Inherent ambiguity that prevents us from even enumerating the - // candidates. - ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), - } -} - -/// The first thing we have to do is scan through the parameter -/// environment to see whether there are any projection predicates -/// there that can answer this question. -fn assemble_candidates_from_param_env<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - debug!("assemble_candidates_from_param_env(..)"); - assemble_candidates_from_predicates( - selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::ParamEnv, - obligation.param_env.caller_bounds.iter().cloned(), - ); -} - -/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find -/// that the definition of `Foo` has some clues: -/// -/// ``` -/// trait Foo { -/// type FooT : Bar -/// } -/// ``` -/// -/// Here, for example, we could conclude that the result is `i32`. -fn assemble_candidates_from_trait_def<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - debug!("assemble_candidates_from_trait_def(..)"); - - let tcx = selcx.tcx(); - // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), - ty::Infer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.mark_ambiguous(); - return; - } - _ => return, - }; - - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = tcx.predicates_of(def_id); - let bounds = trait_predicates.instantiate(tcx, substs); - let bounds = elaborate_predicates(tcx, bounds.predicates); - assemble_candidates_from_predicates( - selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::TraitDef, - bounds, - ) -} - -fn assemble_candidates_from_predicates<'cx, 'tcx, I>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, - ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, - env_predicates: I, -) where - I: IntoIterator>, -{ - debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); - let infcx = selcx.infcx(); - for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - if let ty::Predicate::Projection(data) = predicate { - let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; - - let is_match = same_def_id - && infcx.probe(|_| { - let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() - }); - - debug!( - "assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id - ); - - if is_match { - candidate_set.push_candidate(ctor(data)); - } - } - } -} - -fn assemble_candidates_from_impls<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - // If we are resolving `>::Item == Type`, - // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let _ = selcx.infcx().commit_if_ok(|_| { - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - Ok(None) => { - candidate_set.mark_ambiguous(); - return Err(()); - } - Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", e); - candidate_set.mark_error(e); - return Err(()); - } - }; - - let eligible = match &vtable { - super::VtableClosure(_) - | super::VtableGenerator(_) - | super::VtableFnPointer(_) - | super::VtableObject(_) - | super::VtableTraitAlias(_) => { - debug!("assemble_candidates_from_impls: vtable={:?}", vtable); - true - } - super::VtableImpl(impl_data) => { - // We have to be careful when projecting out of an - // impl because of specialization. If we are not in - // codegen (i.e., projection mode is not "any"), and the - // impl's type is declared as default, then we disable - // projection (even if the trait ref is fully - // monomorphic). In the case where trait ref is not - // fully monomorphic (i.e., includes type parameters), - // this is because those type parameters may - // ultimately be bound to types from other crates that - // may have specialized impls we can't see. In the - // case where the trait ref IS fully monomorphic, this - // is a policy decision that we made in the RFC in - // order to preserve flexibility for the crate that - // defined the specializable impl to specialize later - // for existing types. - // - // In either case, we handle this by not adding a - // candidate for an impl if it contains a `default` - // type. - // - // NOTE: This should be kept in sync with the similar code in - // `rustc::ty::instance::resolve_associated_item()`. - let node_item = - assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id); - - let is_default = if node_item.node.is_from_trait() { - // If true, the impl inherited a `type Foo = Bar` - // given in the trait, which is implicitly default. - // Otherwise, the impl did not specify `type` and - // neither did the trait: - // - // ```rust - // trait Foo { type T; } - // impl Foo for Bar { } - // ``` - // - // This is an error, but it will be - // reported in `check_impl_items_against_trait`. - // We accept it here but will flag it as - // an error when we confirm the candidate - // (which will ultimately lead to `normalize_to_error` - // being invoked). - false - } else { - // If we're looking at a trait *impl*, the item is - // specializable if the impl or the item are marked - // `default`. - node_item.item.defaultness.is_default() - || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) - }; - - match is_default { - // Non-specializable items are always projectable - false => true, - - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - true if obligation.param_env.reveal == Reveal::All => { - // NOTE(eddyb) inference variables can resolve to parameters, so - // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = - selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); - !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() - } - - true => { - debug!( - "assemble_candidates_from_impls: not eligible due to default: \ - assoc_ty={} predicate={}", - selcx.tcx().def_path_str(node_item.item.def_id), - obligation.predicate, - ); - false - } - } - } - super::VtableParam(..) => { - // This case tell us nothing about the value of an - // associated type. Consider: - // - // ``` - // trait SomeTrait { type Foo; } - // fn foo(...) { } - // ``` - // - // If the user writes `::Foo`, then the `T - // : SomeTrait` binding does not help us decide what the - // type `Foo` is (at least, not more specifically than - // what we already knew). - // - // But wait, you say! What about an example like this: - // - // ``` - // fn bar>(...) { ... } - // ``` - // - // Doesn't the `T : Sometrait` predicate help - // resolve `T::Foo`? And of course it does, but in fact - // that single predicate is desugared into two predicates - // in the compiler: a trait predicate (`T : SomeTrait`) and a - // projection. And the projection where clause is handled - // in `assemble_candidates_from_param_env`. - false - } - super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { - // These traits have no associated types. - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable - ); - } - }; - - if eligible { - if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { - Ok(()) - } else { - Err(()) - } - } else { - Err(()) - } - }); -} - -fn confirm_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate: ProjectionTyCandidate<'tcx>, -) -> Progress<'tcx> { - debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); - - match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) - | ProjectionTyCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection) - } - - ProjectionTyCandidate::Select(vtable) => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) - } - } -} - -fn confirm_select_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - vtable: Selection<'tcx>, -) -> Progress<'tcx> { - match vtable { - super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), - super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref), - super::VtableAutoImpl(..) - | super::VtableParam(..) - | super::VtableBuiltin(..) - | super::VtableTraitAlias(..) => - // we don't create Select candidates with this kind of resolution - { - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable - ) - } - } -} - -fn confirm_object_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, -) -> Progress<'tcx> { - let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); - debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.kind { - ty::Dynamic(ref data, ..) => data, - _ => span_bug!( - obligation.cause.span, - "confirm_object_candidate called with non-object: {:?}", - object_ty - ), - }; - let env_predicates = data - .projection_bounds() - .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate()) - .collect(); - let env_predicate = { - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - - // select only those projections that are actually projecting an - // item with the correct name - let env_predicates = env_predicates.filter_map(|p| match p { - ty::Predicate::Projection(data) => { - if data.projection_def_id() == obligation.predicate.item_def_id { - Some(data) - } else { - None - } - } - _ => None, - }); - - // select those with a relevant trait-ref - let mut env_predicates = env_predicates.filter(|data| { - let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - selcx.infcx().probe(|_| { - selcx - .infcx() - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .is_ok() - }) - }); - - // select the first matching one; there really ought to be one or - // else the object type is not WF, since an object type should - // include all of its projections explicitly - match env_predicates.next() { - Some(env_predicate) => env_predicate, - None => { - debug!( - "confirm_object_candidate: no env-predicate \ - found in object type `{:?}`; ill-formed", - object_ty - ); - return Progress::error(selcx.tcx()); - } - } - }; - - confirm_param_env_candidate(selcx, obligation, env_predicate) -} - -fn confirm_generator_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx()); - let Normalized { value: gen_sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &gen_sig, - ); - - debug!( - "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", - obligation, gen_sig, obligations - ); - - let tcx = selcx.tcx(); - - let gen_def_id = tcx.lang_items().gen_trait().unwrap(); - - let predicate = super::util::generator_trait_ref_and_outputs( - tcx, - gen_def_id, - obligation.predicate.self_ty(), - gen_sig, - ) - .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; - let ty = if name == sym::Return { - return_ty - } else if name == sym::Yield { - yield_ty - } else { - bug!() - }; - - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, - ty, - } - }); - - confirm_param_env_candidate(selcx, obligation, predicate) - .with_addl_obligations(vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_fn_pointer_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); - let sig = fn_type.fn_sig(selcx.tcx()); - let Normalized { value: sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &sig, - ); - - confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) - .with_addl_obligations(fn_pointer_vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_closure_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - let infcx = selcx.infcx(); - let closure_sig_ty = vtable.substs.as_closure().sig_ty(vtable.closure_def_id, tcx); - let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx); - let Normalized { value: closure_sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &closure_sig, - ); - - debug!( - "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}", - obligation, closure_sig, obligations - ); - - confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) - .with_addl_obligations(vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_callable_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_sig: ty::PolyFnSig<'tcx>, - flag: util::TupleArgumentsFlag, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - - debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); - - // the `Output` associated type is declared on `FnOnce` - let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap(); - - let predicate = super::util::closure_trait_ref_and_return_type( - tcx, - fn_once_def_id, - obligation.predicate.self_ty(), - fn_sig, - flag, - ) - .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME), - ), - ty: ret_type, - }); - - confirm_param_env_candidate(selcx, obligation, predicate) -} - -fn confirm_param_env_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, -) -> Progress<'tcx> { - let infcx = selcx.infcx(); - let cause = &obligation.cause; - let param_env = obligation.param_env; - - let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars( - cause.span, - LateBoundRegionConversionTime::HigherRankedType, - &poly_cache_entry, - ); - - let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); - let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); - match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { - Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations }, - Err(e) => { - let msg = format!( - "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", - obligation, poly_cache_entry, e, - ); - debug!("confirm_param_env_candidate: {}", msg); - infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); - Progress { ty: infcx.tcx.types.err, obligations: vec![] } - } - } -} - -fn confirm_impl_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - - let VtableImplData { impl_def_id, substs, nested } = impl_vtable; - let assoc_item_id = obligation.predicate.item_def_id; - let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); - - let param_env = obligation.param_env; - let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id); - - if !assoc_ty.item.defaultness.has_value() { - // This means that the impl is missing a definition for the - // associated type. This error will be reported by the type - // checker method `check_impl_items_against_trait`, so here we - // just return Error. - debug!( - "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.ident, obligation.predicate - ); - return Progress { ty: tcx.types.err, obligations: nested }; - } - let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); - let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); - let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind { - let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); - tcx.mk_opaque(assoc_ty.item.def_id, item_substs) - } else { - tcx.type_of(assoc_ty.item.def_id) - }; - if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { - tcx.sess - .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); - Progress { ty: tcx.types.err, obligations: nested } - } else { - Progress { ty: ty.subst(tcx, substs), obligations: nested } - } -} - -/// Locate the definition of an associated type in the specialization hierarchy, -/// starting from the given impl. -/// -/// Based on the "projection mode", this lookup may in fact only examine the -/// topmost impl. See the comments for `Reveal` for more details. -fn assoc_ty_def( - selcx: &SelectionContext<'_, '_>, - impl_def_id: DefId, - assoc_ty_def_id: DefId, -) -> specialization_graph::NodeItem { - let tcx = selcx.tcx(); - let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; - let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; - let trait_def = tcx.trait_def(trait_def_id); - - // This function may be called while we are still building the - // specialization graph that is queried below (via TraidDef::ancestors()), - // so, in order to avoid unnecessary infinite recursion, we manually look - // for the associated item at the given impl. - // If there is no such item in that impl, this function will fail with a - // cycle error if the specialization graph is currently being built. - let impl_node = specialization_graph::Node::Impl(impl_def_id); - for item in impl_node.items(tcx) { - if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) - && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) - { - return specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: *item, - }; - } - } - - if let Some(assoc_item) = - trait_def.ancestors(tcx, impl_def_id).leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) - { - assoc_item - } else { - // This is saying that neither the trait nor - // the impl contain a definition for this - // associated type. Normally this situation - // could only arise through a compiler bug -- - // if the user wrote a bad item name, it - // should have failed in astconv. - bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id)) + Normalized { value: value, obligations: self.obligations } } } @@ -1541,26 +68,14 @@ pub struct ProjectionCacheKey<'tcx> { ty: ty::ProjectionTy<'tcx>, } -impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { - pub 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), - }) +impl ProjectionCacheKey<'tcx> { + pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self { + Self { ty } } } #[derive(Clone, Debug)] -enum ProjectionCacheEntry<'tcx> { +pub enum ProjectionCacheEntry<'tcx> { InProgress, Ambiguous, Error, @@ -1596,7 +111,7 @@ impl<'tcx> ProjectionCache<'tcx> { /// 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( + pub fn try_start( &mut self, key: ProjectionCacheKey<'tcx>, ) -> Result<(), ProjectionCacheEntry<'tcx>> { @@ -1609,7 +124,7 @@ impl<'tcx> ProjectionCache<'tcx> { } /// Indicates that `key` was normalized to `value`. - fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { + pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { debug!( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value @@ -1662,14 +177,14 @@ impl<'tcx> ProjectionCache<'tcx> { /// 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>) { + 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. - fn error(&mut self, key: ProjectionCacheKey<'tcx>) { + 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/util.rs b/src/librustc_infer/traits/util.rs index cd4595e76ccec..a7c0267111522 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -1,16 +1,8 @@ -use rustc_errors::DiagnosticBuilder; -use rustc_span::Span; use smallvec::smallvec; -use smallvec::SmallVec; use rustc::ty::outlives::Component; -use rustc::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc::ty::{self, ToPolyTraitRef, TyCtxt}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; - -use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { @@ -55,7 +47,7 @@ struct PredicateSet<'tcx> { impl PredicateSet<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx, set: Default::default() } + Self { tcx: tcx, set: Default::default() } } fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { @@ -96,21 +88,6 @@ pub struct Elaborator<'tcx> { visited: PredicateSet<'tcx>, } -pub fn elaborate_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> Elaborator<'tcx> { - elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()]) -} - -pub fn elaborate_trait_refs<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator>, -) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect(); - elaborate_predicates(tcx, predicates) -} - pub fn elaborate_predicates<'tcx>( tcx: TyCtxt<'tcx>, mut predicates: Vec>, @@ -121,10 +98,6 @@ pub fn elaborate_predicates<'tcx>( } impl Elaborator<'tcx> { - pub fn filter_to_traits(self) -> FilterToTraits { - FilterToTraits::new(self) - } - fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { let tcx = self.visited.tcx; match *predicate { @@ -250,426 +223,3 @@ impl Iterator for Elaborator<'tcx> { } } } - -/////////////////////////////////////////////////////////////////////////// -// Supertrait iterator -/////////////////////////////////////////////////////////////////////////// - -pub type Supertraits<'tcx> = FilterToTraits>; - -pub fn supertraits<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> Supertraits<'tcx> { - elaborate_trait_ref(tcx, trait_ref).filter_to_traits() -} - -pub fn transitive_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - bounds: impl Iterator>, -) -> Supertraits<'tcx> { - elaborate_trait_refs(tcx, bounds).filter_to_traits() -} - -/////////////////////////////////////////////////////////////////////////// -// `TraitAliasExpander` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Trait alias expansion" is the process of expanding a sequence of trait -/// references into another sequence by transitively following all trait -/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias -/// `trait Foo = Bar + Sync;`, and another trait alias -/// `trait Bar = Read + Write`, then the bounds would expand to -/// `Read + Write + Sync + Send`. -/// Expansion is done via a DFS (depth-first search), and the `visited` field -/// is used to avoid cycles. -pub struct TraitAliasExpander<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec>, -} - -/// Stores information about the expansion of a trait via a path of zero or more trait aliases. -#[derive(Debug, Clone)] -pub struct TraitAliasExpansionInfo<'tcx> { - pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, -} - -impl<'tcx> TraitAliasExpansionInfo<'tcx> { - fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - Self { path: smallvec![(trait_ref, span)] } - } - - /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate - /// trait aliases. - pub fn label_with_exp_info( - &self, - diag: &mut DiagnosticBuilder<'_>, - top_label: &str, - use_desc: &str, - ) { - diag.span_label(self.top().1, top_label); - if self.path.len() > 1 { - for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { - diag.span_label(*sp, format!("referenced here ({})", use_desc)); - } - } - diag.span_label( - self.bottom().1, - format!("trait alias used in trait object type ({})", use_desc), - ); - } - - pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> { - &self.top().0 - } - - pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.last().unwrap() - } - - pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.first().unwrap() - } - - fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - let mut path = self.path.clone(); - path.push((trait_ref, span)); - - Self { path } - } -} - -pub fn expand_trait_aliases<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl IntoIterator, Span)>, -) -> TraitAliasExpander<'tcx> { - let items: Vec<_> = trait_refs - .into_iter() - .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)) - .collect(); - TraitAliasExpander { tcx, stack: items } -} - -impl<'tcx> TraitAliasExpander<'tcx> { - /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item` - /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`. - /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a - /// trait alias. - /// The return value indicates whether `item` should be yielded to the user. - fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { - let tcx = self.tcx; - let trait_ref = item.trait_ref(); - let pred = trait_ref.without_const().to_predicate(); - - debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); - - // Don't recurse if this bound is not a trait alias. - let is_alias = tcx.is_trait_alias(trait_ref.def_id()); - if !is_alias { - return true; - } - - // Don't recurse if this trait alias is already on the stack for the DFS search. - let anon_pred = anonymize_predicate(tcx, &pred); - if item.path.iter().rev().skip(1).any(|(tr, _)| { - anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred - }) { - return false; - } - - // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); - - let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.subst_supertrait(tcx, &trait_ref) - .to_opt_poly_trait_ref() - .map(|trait_ref| item.clone_and_push(trait_ref, *span)) - }); - debug!("expand_trait_aliases: items={:?}", items.clone()); - - self.stack.extend(items); - - false - } -} - -impl<'tcx> Iterator for TraitAliasExpander<'tcx> { - type Item = TraitAliasExpansionInfo<'tcx>; - - fn size_hint(&self) -> (usize, Option) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option> { - while let Some(item) = self.stack.pop() { - if self.expand(&item) { - return Some(item); - } - } - None - } -} - -/////////////////////////////////////////////////////////////////////////// -// Iterator over def-IDs of supertraits -/////////////////////////////////////////////////////////////////////////// - -pub struct SupertraitDefIds<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec, - visited: FxHashSet, -} - -pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> { - SupertraitDefIds { - tcx, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } -} - -impl Iterator for SupertraitDefIds<'tcx> { - type Item = DefId; - - fn next(&mut self) -> Option { - let def_id = self.stack.pop()?; - let predicates = self.tcx.super_predicates_of(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates - .predicates - .iter() - .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref()) - .map(|trait_ref| trait_ref.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id)), - ); - Some(def_id) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// A filter around an iterator of predicates that makes it yield up -/// just trait references. -pub struct FilterToTraits { - base_iterator: I, -} - -impl FilterToTraits { - fn new(base: I) -> FilterToTraits { - FilterToTraits { base_iterator: base } - } -} - -impl<'tcx, I: Iterator>> Iterator for FilterToTraits { - type Item = ty::PolyTraitRef<'tcx>; - - fn next(&mut self) -> Option> { - while let Some(pred) = self.base_iterator.next() { - if let ty::Predicate::Trait(data, _) = pred { - return Some(data.to_poly_trait_ref()); - } - } - None - } - - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.base_iterator.size_hint(); - (0, upper) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// Instantiate all bound parameters of the impl with the given substs, -/// returning the resulting trait ref and all obligations that arise. -/// The obligations are closed under normalization. -pub fn impl_trait_ref_and_oblig<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: DefId, - impl_substs: SubstsRef<'tcx>, -) -> (ty::TraitRef<'tcx>, Vec>) { - let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); - let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); - let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); - - let predicates = selcx.tcx().predicates_of(impl_def_id); - let predicates = predicates.instantiate(selcx.tcx(), impl_substs); - let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); - let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates); - - let impl_obligations: Vec<_> = impl_obligations - .into_iter() - .chain(normalization_obligations1) - .chain(normalization_obligations2) - .collect(); - - (impl_trait_ref, impl_obligations) -} - -/// See [`super::obligations_for_generics`]. -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> Vec> { - debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); - - generic_bounds - .predicates - .iter() - .map(|&predicate| Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }) - .collect() -} - -pub fn predicate_for_trait_ref<'tcx>( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize, -) -> PredicateObligation<'tcx> { - Obligation { - cause, - param_env, - recursion_depth, - predicate: trait_ref.without_const().to_predicate(), - } -} - -pub fn predicate_for_trait_def( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - self_ty: Ty<'tcx>, - params: &[GenericArg<'tcx>], -) -> PredicateObligation<'tcx> { - let trait_ref = - ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) }; - predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) -} - -/// Casts a trait reference into a reference to one of its super -/// traits; returns `None` if `target_trait_def_id` is not a -/// supertrait. -pub fn upcast_choices( - tcx: TyCtxt<'tcx>, - source_trait_ref: ty::PolyTraitRef<'tcx>, - target_trait_def_id: DefId, -) -> Vec> { - if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // Shortcut the most common case. - } - - supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() -} - -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() { - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } - } - entries -} - -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method( - tcx: TyCtxt<'tcx>, - object: &super::VtableObjectData<'tcx, N>, - method_def_id: DefId, -) -> usize { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - // Skip over associated types and constants. - let mut entries = object.vtable_base; - for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() { - if trait_item.def_id == method_def_id { - // The item with the ID we were given really ought to be a method. - assert_eq!(trait_item.kind, ty::AssocKind::Method); - return entries; - } - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } - } - - bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); -} - -pub fn closure_trait_ref_and_return_type( - tcx: TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyFnSig<'tcx>, - tuple_arguments: TupleArgumentsFlag, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), - }; - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().output())) -} - -pub fn generator_trait_ref_and_outputs( - tcx: TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) -} - -pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool { - match tcx.hir().as_local_hir_id(node_item_def_id) { - Some(hir_id) => { - let item = tcx.hir().expect_item(hir_id); - if let hir::ItemKind::Impl { defaultness, .. } = item.kind { - defaultness.is_default() - } else { - false - } - } - None => tcx.impl_defaultness(node_item_def_id).is_default(), - } -} - -pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { - assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id()) -} - -pub enum TupleArgumentsFlag { - Yes, - No, -} 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_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/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_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/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/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/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, 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 137216531a369..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 @@ -1,13 +1,14 @@ 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 rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use crate::borrow_check::{ @@ -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` 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/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_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/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_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_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 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_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..739aff4fb94c9 --- /dev/null +++ b/src/librustc_trait_selection/lib.rs @@ -0,0 +1,32 @@ +//! This crates defines the trait resolution method. +//! +//! - **Traits.** Trait resolution is implemented in the `traits` module. +//! +//! 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(drain_filter)] +#![feature(in_band_lifetimes)] +#![feature(crate_visibility_modifier)] +#![recursion_limit = "512"] // For rustdoc + +#[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_infer/infer/opaque_types/mod.rs b/src/librustc_trait_selection/opaque_types.rs similarity index 93% rename from src/librustc_infer/infer/opaque_types/mod.rs rename to src/librustc_trait_selection/opaque_types.rs index 4d264008ee3ed..6cf1302783c0b 100644 --- a/src/librustc_infer/infer/opaque_types/mod.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1,7 +1,5 @@ -use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region}; -use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::InferCtxtExt as _; 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,10 +7,12 @@ 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; +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>; @@ -105,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: /// @@ -131,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, @@ -319,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, @@ -337,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>, @@ -579,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>, @@ -618,86 +669,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_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 71% rename from src/librustc_infer/traits/codegen/mod.rs rename to src/librustc_trait_selection/traits/codegen/mod.rs index f499565e9192a..5c2fc3f305c1f 100644 --- a/src/librustc_infer/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_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_trait_selection/traits/engine.rs b/src/librustc_trait_selection/traits/engine.rs new file mode 100644 index 0000000000000..ee4715e0c20f6 --- /dev/null +++ b/src/librustc_trait_selection/traits/engine.rs @@ -0,0 +1,14 @@ +use rustc::ty::TyCtxt; + +use super::FulfillmentContext; +use super::TraitEngine; + +pub trait TraitEngineExt<'tcx> { + 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 new file mode 100644 index 0000000000000..abd9638bfa78b --- /dev/null +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -0,0 +1,1900 @@ +pub mod on_unimplemented; +pub mod suggestions; + +use super::{ + ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode, + MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, + OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, + PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe, +}; + +use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc::mir::interpret::ErrorHandled; +use rustc::session::DiagnosticMessageId; +use rustc::ty::error::ExpectedFound; +use rustc::ty::fast_reject; +use rustc::ty::fold::TypeFolder; +use rustc::ty::SubtypePredicate; +use rustc::ty::{ + self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; +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::{Node, QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_span::source_map::SourceMap; +use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use std::fmt; + +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, + fallback_has_occurred: bool, + ) { + #[derive(Debug)] + struct ErrorDescriptor<'tcx> { + predicate: ty::Predicate<'tcx>, + index: Option, // None if this is an old error + } + + let mut error_map: FxHashMap<_, Vec<_>> = self + .reported_trait_errors + .borrow() + .iter() + .map(|(&span, predicates)| { + ( + span, + predicates + .iter() + .map(|&predicate| ErrorDescriptor { predicate, index: None }) + .collect(), + ) + }) + .collect(); + + for (index, error) in errors.iter().enumerate() { + // We want to ignore desugarings here: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let mut span = error.obligation.cause.span; + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { + span = expn_data.call_site; + } + + error_map.entry(span).or_default().push(ErrorDescriptor { + predicate: error.obligation.predicate, + index: Some(index), + }); + + self.reported_trait_errors + .borrow_mut() + .entry(span) + .or_default() + .push(error.obligation.predicate.clone()); + } + + // We do this in 2 passes because we want to display errors in order, though + // maybe it *is* better to sort errors by span or something. + let mut is_suppressed = vec![false; errors.len()]; + for (_, error_set) in error_map.iter() { + // We want to suppress "duplicate" errors with the same span. + for error in error_set { + if let Some(index) = error.index { + // Suppress errors that are either: + // 1) strictly implied by another error. + // 2) implied by an error with a smaller index. + for error2 in error_set { + if error2.index.map_or(false, |index2| is_suppressed[index2]) { + // Avoid errors being suppressed by already-suppressed + // errors, to prevent all errors from being suppressed + // at once. + continue; + } + + if self.error_implies(&error2.predicate, &error.predicate) + && !(error2.index >= error.index + && self.error_implies(&error.predicate, &error2.predicate)) + { + info!("skipping {:?} (implied by {:?})", error, error2); + is_suppressed[index] = true; + break; + } + } + } + } + } + + for (error, suppressed) in errors.iter().zip(is_suppressed) { + if !suppressed { + self.report_fulfillment_error(error, body_id, fallback_has_occurred); + } + } + } + + /// 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 + ); + + 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.emit(); + self.tcx.sess.abort_if_errors(); + bug!(); + } + + /// 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_selection_error( + &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) + }; + + 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 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, + }; + + 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 + + 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(), + ) + } + } + + 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; + } + + Overflow => { + bug!("overflow should be handled before the `report_selection_error` path"); + } + }; + + self.note_obligation_cause(&mut err, obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + + err.emit(); + } + + /// 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()) + } + }) + .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. + 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 + } +} + +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; + + fn report_fulfillment_error( + &self, + error: &FulfillmentError<'tcx>, + body_id: Option, + fallback_has_occurred: bool, + ); + + fn report_projection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + ); + + fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool; + + fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; + + fn find_similar_impl_candidates( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Vec>; + + 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)>; + + /// 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>; + + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option, + ); + + fn predicate_can_apply( + &self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>, + ) -> bool; + + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ); + + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ); + + fn is_recursive_obligation( + &self, + obligated_types: &mut Vec<&ty::TyS<'tcx>>, + cause_code: &ObligationCauseCode<'tcx>, + ) -> bool; +} + +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; + } + + 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; + } + }; + + 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; + } + } + } + + false + } + + 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(); + } + } + } + + fn report_projection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + ) { + let predicate = self.resolve_vars_if_possible(&obligation.predicate); + + if predicate.references_error() { + return; + } + + self.probe(|_| { + let err_buf; + let mut err = &error.err; + let mut values = None; + + // 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, + ); + + debug!( + "report_projection_error obligation.cause={:?} obligation.param_env={:?}", + obligation.cause, obligation.param_env + ); + + debug!( + "report_projection_error normalized_ty={:?} data.ty={:?}", + normalized_ty, data.ty + ); + + let is_normalized_ty_expected = match &obligation.cause.code { + ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::BindingObligation(_, _) + | ObligationCauseCode::ObjectCastObligation(_) => false, + _ => true, + }; + + 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, + ))); + + err_buf = error; + err = &err_buf; + } + } + + 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(); + } + }); + } + + 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"), + } + } + + 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, + } + } + + 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", + }) + } + + 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; + } + } + + Some(imp) + }) + .collect(), + None => { + all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() + } + } + } + + fn report_similar_impl_candidates( + &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 }; + + 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), + } + }) + }; + + // 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() } + )); + } + + /// 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, + } + } + + /// 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>, + ) { + let get_trait_impl = |trait_def_id| { + let mut trait_impl = None; + self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| { + if trait_impl.is_none() { + trait_impl = Some(impl_def_id); + } + }); + trait_impl + }; + let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); + let all_traits = self.tcx.all_traits(LOCAL_CRATE); + let traits_with_same_path: std::collections::BTreeSet<_> = all_traits + .iter() + .filter(|trait_def_id| **trait_def_id != trait_ref.def_id()) + .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path) + .collect(); + for trait_with_same_path in traits_with_same_path { + if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) { + let impl_span = self.tcx.def_span(impl_def_id); + err.span_help(impl_span, "trait impl with same name found"); + let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); + let crate_msg = format!( + "perhaps two different versions of crate `{}` are being used?", + trait_crate + ); + err.note(&crate_msg); + } + } + } + + fn mk_obligation_for_def_id( + &self, + def_id: DefId, + output_ty: Ty<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> PredicateObligation<'tcx> { + let new_trait_ref = + ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; + Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) + } + + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option, + ) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + + let predicate = self.resolve_vars_if_possible(&obligation.predicate); + let span = obligation.cause.span; + + debug!( + "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", + predicate, obligation, body_id, obligation.cause.code, + ); + + // Ambiguity errors are often caused as fallout from earlier + // errors. So just ignore them if this infcx is tainted. + if self.is_tainted_by_errors() { + return; + } + + let mut err = match predicate { + ty::Predicate::Trait(ref data, _) => { + let trait_ref = data.to_poly_trait_ref(); + let self_ty = trait_ref.self_ty(); + debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); + + if predicate.references_error() { + return; + } + // Typically, this ambiguity should only happen if + // there are unresolved type inference variables + // (otherwise it would suggest a coherence + // failure). But given #21974 that is not necessarily + // the case -- we can have multiple where clauses that + // are only distinguished by a region, which results + // in an ambiguity even when all types are fully + // known, since we don't dispatch based on region + // relationships. + + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // avoid inundating the user with unnecessary errors, but we now + // check upstream for type errors and don't add the obligations to + // begin with in those cases. + if self + .tcx + .lang_items() + .sized_trait() + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) + { + self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); + return; + } + let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); + err.note(&format!("cannot resolve `{}`", predicate)); + if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { + self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); + } else if let ( + Ok(ref snippet), + ObligationCauseCode::BindingObligation(ref def_id, _), + ) = + (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code) + { + let generics = self.tcx.generics_of(*def_id); + if !generics.params.is_empty() && !snippet.ends_with('>') { + // FIXME: To avoid spurious suggestions in functions where type arguments + // where already supplied, we check the snippet to make sure it doesn't + // end with a turbofish. Ideally we would have access to a `PathSegment` + // instead. Otherwise we would produce the following output: + // + // error[E0283]: type annotations needed + // --> $DIR/issue-54954.rs:3:24 + // | + // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); + // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // | | + // | cannot infer type + // | help: consider specifying the type argument + // | in the function call: + // | `Tt::const_val::<[i8; 123]>::` + // ... + // LL | const fn const_val() -> usize { + // | --------- - required by this bound in `Tt::const_val` + // | + // = note: cannot resolve `_: Tt` + + err.span_suggestion( + span, + &format!( + "consider specifying the type argument{} in the function call", + if generics.params.len() > 1 { "s" } else { "" }, + ), + format!( + "{}::<{}>", + snippet, + generics + .params + .iter() + .map(|p| p.name.to_string()) + .collect::>() + .join(", ") + ), + Applicability::HasPlaceholders, + ); + } + } + err + } + + ty::Predicate::WellFormed(ty) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if ty.references_error() || self.tcx.sess.has_errors() { + return; + } + self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) + } + + ty::Predicate::Subtype(ref data) => { + if data.references_error() || self.tcx.sess.has_errors() { + // no need to overload user in such cases + return; + } + let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); + // both must be type variables, or the other would've been instantiated + assert!(a.is_ty_var() && b.is_ty_var()); + self.need_type_info_err(body_id, span, a, ErrorCode::E0282) + } + ty::Predicate::Projection(ref data) => { + let trait_ref = data.to_poly_trait_ref(self.tcx); + let self_ty = trait_ref.self_ty(); + if predicate.references_error() { + return; + } + let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); + err.note(&format!("cannot resolve `{}`", predicate)); + err + } + + _ => { + if self.tcx.sess.has_errors() { + return; + } + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0284, + "type annotations needed: cannot resolve `{}`", + predicate, + ); + err.span_label(span, &format!("cannot resolve `{}`", predicate)); + err + } + }; + self.note_obligation_cause(&mut err, obligation); + err.emit(); + } + + /// Returns `true` if the trait predicate may apply for *some* assignment + /// to the type parameters. + fn predicate_can_apply( + &self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>, + ) -> bool { + struct ParamToVarFolder<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + var_map: FxHashMap, Ty<'tcx>>, + } + + impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Param(ty::ParamTy { name, .. }) = ty.kind { + let infcx = self.infcx; + self.var_map.entry(ty).or_insert_with(|| { + infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), + span: DUMMY_SP, + }) + }) + } else { + ty.super_fold_with(self) + } + } + } + + self.probe(|_| { + let mut selcx = SelectionContext::new(self); + + let cleaned_pred = + pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() }); + + let cleaned_pred = super::project::normalize( + &mut selcx, + param_env, + ObligationCause::dummy(), + &cleaned_pred, + ) + .value; + + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + cleaned_pred.without_const().to_predicate(), + ); + + self.predicate_may_hold(&obligation) + }) + } + + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + // First, attempt to add note to this error with an async-await-specific + // message, and fall back to regular note otherwise. + if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { + self.note_obligation_cause_code( + err, + &obligation.predicate, + &obligation.cause.code, + &mut vec![], + ); + self.suggest_unsized_bound_if_applicable(err, obligation); + } + } + + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + if let ( + ty::Predicate::Trait(pred, _), + ObligationCauseCode::BindingObligation(item_def_id, span), + ) = (&obligation.predicate, &obligation.cause.code) + { + if let (Some(generics), true) = ( + self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), + Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + ) { + for param in generics.params { + if param.span == *span + && !param.bounds.iter().any(|bound| { + bound.trait_def_id() == self.tcx.lang_items().sized_trait() + }) + { + let (span, separator) = match param.bounds { + [] => (span.shrink_to_hi(), ":"), + [.., bound] => (bound.span().shrink_to_hi(), " + "), + }; + err.span_suggestion( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{} ?Sized", separator), + Applicability::MachineApplicable, + ); + return; + } + } + } + } + } + + fn is_recursive_obligation( + &self, + obligated_types: &mut Vec<&ty::TyS<'tcx>>, + cause_code: &ObligationCauseCode<'tcx>, + ) -> bool { + if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { + let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + + if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { + return true; + } + } + false + } +} + +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 { + /// An argument of non-tuple type. Parameters are (name, ty) + Arg(String, String), + + /// An argument of tuple type. For a "found" argument, the span is + /// the locationo in the source of the pattern. For a "expected" + /// argument, it will be None. The vector is a list of (name, ty) + /// strings for the components of the tuple. + Tuple(Option, Vec<(String, String)>), +} + +impl ArgKind { + fn empty() -> ArgKind { + ArgKind::Arg("_".to_owned(), "_".to_owned()) + } + + /// Creates an `ArgKind` from the expected type of an + /// argument. It has no name (`_`) and an optional source span. + pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { + match t.kind { + ty::Tuple(ref tys) => ArgKind::Tuple( + span, + tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::>(), + ), + _ => ArgKind::Arg("_".to_owned(), t.to_string()), + } + } +} + +/// Suggest restricting a type param with a new bound. +pub fn suggest_constraining_type_param( + tcx: TyCtxt<'_>, + generics: &hir::Generics<'_>, + err: &mut DiagnosticBuilder<'_>, + param_name: &str, + constraint: &str, + source_map: &SourceMap, + span: Span, + def_id: Option, +) -> bool { + const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound with"; + const MSG_RESTRICT_TYPE: &str = "consider restricting this type parameter with"; + const MSG_RESTRICT_TYPE_FURTHER: &str = "consider further restricting this type parameter with"; + + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); + + let param = if let Some(param) = param { + param + } else { + return false; + }; + + if def_id == tcx.lang_items().sized_trait() { + // Type parameters are already `Sized` by default. + err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); + return true; + } + + if param_name.starts_with("impl ") { + // If there's an `impl Trait` used in argument position, suggest + // restricting it: + // + // fn foo(t: impl Foo) { ... } + // -------- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo(t: impl Foo) { ... } + // -------- + // | + // replace with: `impl Foo + Bar` + + err.span_help(param.span, &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint)); + + err.tool_only_span_suggestion( + param.span, + MSG_RESTRICT_BOUND_FURTHER, + format!("{} + {}", param_name, constraint), + Applicability::MachineApplicable, + ); + + return true; + } + + if generics.where_clause.predicates.is_empty() { + if let Some(bounds_span) = param.bounds_span() { + // If user has provided some bounds, suggest restricting them: + // + // fn foo(t: T) { ... } + // --- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo(t: T) { ... } + // -- + // | + // replace with: `T: Bar +` + + err.span_help( + bounds_span, + &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), + ); + + let span_hi = param.span.with_hi(span.hi()); + let span_with_colon = source_map.span_through_char(span_hi, ':'); + + if span_hi != param.span && span_with_colon != span_hi { + err.tool_only_span_suggestion( + span_with_colon, + MSG_RESTRICT_BOUND_FURTHER, + format!("{}: {} + ", param_name, constraint), + Applicability::MachineApplicable, + ); + } + } else { + // If user hasn't provided any bounds, suggest adding a new one: + // + // fn foo(t: T) { ... } + // - help: consider restricting this type parameter with `T: Foo` + + err.span_help( + param.span, + &format!("{} `{}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), + ); + + err.tool_only_span_suggestion( + param.span, + MSG_RESTRICT_TYPE, + format!("{}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } + + true + } else { + // This part is a bit tricky, because using the `where` clause user can + // provide zero, one or many bounds for the same type parameter, so we + // have following cases to consider: + // + // 1) When the type parameter has been provided zero bounds + // + // Message: + // fn foo(x: X, y: Y) where Y: Foo { ... } + // - help: consider restricting this type parameter with `where X: Bar` + // + // Suggestion: + // fn foo(x: X, y: Y) where Y: Foo { ... } + // - insert: `, X: Bar` + // + // + // 2) When the type parameter has been provided one bound + // + // Message: + // fn foo(t: T) where T: Foo { ... } + // ^^^^^^ + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion: + // fn foo(t: T) where T: Foo { ... } + // ^^ + // | + // replace with: `T: Bar +` + // + // + // 3) When the type parameter has been provided many bounds + // + // Message: + // fn foo(t: T) where T: Foo, T: Bar {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // fn foo(t: T) where T: Foo, T: Bar {... } + // - insert: `, T: Zar` + + let mut param_spans = Vec::new(); + + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, bounded_ty, .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } + } + } + } + } + + let where_clause_span = + generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); + + match ¶m_spans[..] { + &[] => { + err.span_help( + param.span, + &format!("{} `where {}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), + ); + + err.tool_only_span_suggestion( + where_clause_span, + MSG_RESTRICT_TYPE, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } + + &[¶m_span] => { + err.span_help( + param_span, + &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), + ); + + let span_hi = param_span.with_hi(span.hi()); + let span_with_colon = source_map.span_through_char(span_hi, ':'); + + if span_hi != param_span && span_with_colon != span_hi { + err.tool_only_span_suggestion( + span_with_colon, + MSG_RESTRICT_BOUND_FURTHER, + format!("{}: {} +", param_name, constraint), + Applicability::MachineApplicable, + ); + } + } + + _ => { + err.span_help( + param.span, + &format!( + "{} `where {}: {}`", + MSG_RESTRICT_TYPE_FURTHER, param_name, constraint, + ), + ); + + err.tool_only_span_suggestion( + where_clause_span, + MSG_RESTRICT_BOUND_FURTHER, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } + } + + true + } +} 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 93% rename from src/librustc_infer/traits/error_reporting/on_unimplemented.rs rename to src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs index eb34a4875961c..6e3074cd3ca98 100644 --- a/src/librustc_infer/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_infer/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs similarity index 86% rename from src/librustc_infer/traits/error_reporting/suggestions.rs rename to src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 228747c3f89e9..351e557d40b30 100644 --- a/src/librustc_infer/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_infer/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs similarity index 99% rename from src/librustc_infer/traits/fulfill.rs rename to src/librustc_trait_selection/traits/fulfill.rs index ac9ff484a0274..5def77ce7324c 100644 --- a/src/librustc_infer/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_infer/traits/misc.rs b/src/librustc_trait_selection/traits/misc.rs similarity index 94% rename from src/librustc_infer/traits/misc.rs rename to src/librustc_trait_selection/traits/misc.rs index 7ab918c159e1f..d500cff67c64b 100644 --- a/src/librustc_infer/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 new file mode 100644 index 0000000000000..7b93982db974b --- /dev/null +++ b/src/librustc_trait_selection/traits/mod.rs @@ -0,0 +1,533 @@ +//! Trait Resolution. See the [rustc dev guide] for more information on how this works. +//! +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html + +#[allow(dead_code)] +pub mod auto_trait; +pub mod codegen; +mod coherence; +mod engine; +pub mod error_reporting; +mod fulfill; +pub mod misc; +mod object_safety; +mod on_unimplemented; +mod project; +pub mod query; +mod select; +mod specialize; +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::fold::TypeFoldable; +use rustc::ty::subst::{InternalSubsts, SubstsRef}; +use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc::util::common::ErrorReported; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_span::{Span, DUMMY_SP}; + +use std::fmt::Debug; + +pub use self::FulfillmentErrorCode::*; +pub use self::ObligationCauseCode::*; +pub use self::SelectionError::*; +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::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; +pub use self::object_safety::MethodViolationCode; +pub use self::object_safety::ObjectSafetyViolation; +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::select::{EvaluationCache, SelectionCache, SelectionContext}; +pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; +pub use self::specialize::find_associated_item; +pub use self::specialize::specialization_graph::FutureCompatOverlapError; +pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; +pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; +pub use self::structural_match::search_for_structural_match_violation; +pub use self::structural_match::type_marked_structural; +pub use self::structural_match::NonStructuralMatchTy; +pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; +pub use self::util::{expand_trait_aliases, TraitAliasExpander}; +pub use self::util::{ + get_vtable_index_of_object_method, impl_is_default, impl_item_is_final, + predicate_for_trait_def, upcast_choices, +}; +pub use self::util::{ + supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, +}; + +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)] +pub enum SkipLeakCheck { + Yes, + No, +} + +impl SkipLeakCheck { + fn is_yes(self) -> bool { + self == SkipLeakCheck::Yes + } +} + +/// The "default" for skip-leak-check corresponds to the current +/// behavior (do not skip the leak check) -- not the behavior we are +/// transitioning into. +impl Default for SkipLeakCheck { + fn default() -> Self { + SkipLeakCheck::No + } +} + +/// The mode that trait queries run in. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum TraitQueryMode { + // Standard/un-canonicalized queries get accurate + // spans etc. passed in and hence can do reasonable + // error reporting on their own. + Standard, + // Canonicalized queries get dummy spans and hence + // must generally propagate errors to + // pre-canonicalization callsites. + Canonical, +} + +/// Creates predicate obligations from the generic bounds. +pub fn predicates_for_generics<'tcx>( + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + generic_bounds: &ty::InstantiatedPredicates<'tcx>, +) -> PredicateObligations<'tcx> { + util::predicates_for_generics(cause, 0, param_env, generic_bounds) +} + +/// Determines whether the type `ty` is known to meet `bound` and +/// returns true if so. Returns false if `ty` either does not meet +/// `bound` or is not known to meet bound (note that this is +/// conservative towards *no impl*, which is the opposite of the +/// `evaluate` methods). +pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + span: Span, +) -> bool { + debug!( + "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})", + ty, + infcx.tcx.def_path_str(def_id) + ); + + let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; + let obligation = Obligation { + param_env, + cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), + recursion_depth: 0, + predicate: trait_ref.without_const().to_predicate(), + }; + + let result = infcx.predicate_must_hold_modulo_regions(&obligation); + debug!( + "type_known_to_meet_ty={:?} bound={} => {:?}", + ty, + infcx.tcx.def_path_str(def_id), + result + ); + + if result && ty.has_infer_types_or_consts() { + // Because of inference "guessing", selection can sometimes claim + // to succeed while the success requires a guess. To ensure + // this function's result remains infallible, we must confirm + // that guess. While imperfect, I believe this is sound. + + // The handling of regions in this area of the code is terrible, + // see issue #29149. We should be able to improve on this with + // NLL. + let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); + + // We can use a dummy node-id here because we won't pay any mind + // to region obligations that arise (there shouldn't really be any + // anyhow). + let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID); + + fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); + + // Note: we only assume something is `Copy` if we can + // *definitively* show that it implements `Copy`. Otherwise, + // assume it is move; linear is always ok. + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => { + debug!( + "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", + ty, + infcx.tcx.def_path_str(def_id) + ); + true + } + Err(e) => { + debug!( + "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", + ty, + infcx.tcx.def_path_str(def_id), + e + ); + false + } + } + } else { + result + } +} + +fn do_normalize_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + region_context: DefId, + cause: ObligationCause<'tcx>, + elaborated_env: ty::ParamEnv<'tcx>, + predicates: Vec>, +) -> Result>, ErrorReported> { + debug!( + "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})", + predicates, region_context, cause, + ); + let span = cause.span; + tcx.infer_ctxt().enter(|infcx| { + // FIXME. We should really... do something with these region + // obligations. But this call just continues the older + // behavior (i.e., doesn't cause any new bugs), and it would + // take some further refactoring to actually solve them. In + // particular, we would have to handle implied bounds + // properly, and that code is currently largely confined to + // regionck (though I made some efforts to extract it + // out). -nmatsakis + // + // @arielby: In any case, these obligations are checked + // by wfcheck anyway, so I'm not sure we have to check + // them here too, and we will remove this function when + // we move over to lazy normalization *anyway*. + let fulfill_cx = FulfillmentContext::new_ignoring_regions(); + let predicates = + match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { + Ok(predicates) => predicates, + Err(errors) => { + infcx.report_fulfillment_errors(&errors, None, false); + return Err(ErrorReported); + } + }; + + debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); + + let region_scope_tree = region::ScopeTree::default(); + + // We can use the `elaborated_env` here; the region code only + // cares about declarations like `'a: 'b`. + let outlives_env = OutlivesEnvironment::new(elaborated_env); + + infcx.resolve_regions_and_report_errors( + region_context, + ®ion_scope_tree, + &outlives_env, + SuppressRegionErrors::default(), + ); + + let predicates = match infcx.fully_resolve(&predicates) { + Ok(predicates) => predicates, + Err(fixup_err) => { + // If we encounter a fixup error, it means that some type + // variable wound up unconstrained. I actually don't know + // if this can happen, and I certainly don't expect it to + // happen often, but if it did happen it probably + // represents a legitimate failure due to some kind of + // unconstrained variable, and it seems better not to ICE, + // all things considered. + tcx.sess.span_err(span, &fixup_err.to_string()); + return Err(ErrorReported); + } + }; + if predicates.has_local_value() { + // FIXME: shouldn't we, you know, actually report an error here? or an ICE? + Err(ErrorReported) + } else { + Ok(predicates) + } + }) +} + +// FIXME: this is gonna need to be removed ... +/// Normalizes the parameter environment, reporting errors if they occur. +pub fn normalize_param_env_or_error<'tcx>( + tcx: TyCtxt<'tcx>, + region_context: DefId, + unnormalized_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, +) -> ty::ParamEnv<'tcx> { + // I'm not wild about reporting errors here; I'd prefer to + // have the errors get reported at a defined place (e.g., + // during typeck). Instead I have all parameter + // environments, in effect, going through this function + // and hence potentially reporting errors. This ensures of + // course that we never forget to normalize (the + // alternative seemed like it would involve a lot of + // manual invocations of this fn -- and then we'd have to + // deal with the errors at each of those sites). + // + // In any case, in practice, typeck constructs all the + // parameter environments once for every fn as it goes, + // and errors will get reported then; so after typeck we + // can be sure that no errors should occur. + + debug!( + "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})", + region_context, unnormalized_env, cause + ); + + let mut predicates: Vec<_> = + util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect(); + + debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); + + let elaborated_env = ty::ParamEnv::new( + tcx.intern_predicates(&predicates), + unnormalized_env.reveal, + unnormalized_env.def_id, + ); + + // HACK: we are trying to normalize the param-env inside *itself*. The problem is that + // normalization expects its param-env to be already normalized, which means we have + // a circularity. + // + // The way we handle this is by normalizing the param-env inside an unnormalized version + // of the param-env, which means that if the param-env contains unnormalized projections, + // we'll have some normalization failures. This is unfortunate. + // + // Lazy normalization would basically handle this by treating just the + // normalizing-a-trait-ref-requires-itself cycles as evaluation failures. + // + // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated + // types, so to make the situation less bad, we normalize all the predicates *but* + // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and + // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment. + // + // This works fairly well because trait matching does not actually care about param-env + // TypeOutlives predicates - these are normally used by regionck. + let outlives_predicates: Vec<_> = predicates + .drain_filter(|predicate| match predicate { + ty::Predicate::TypeOutlives(..) => true, + _ => false, + }) + .collect(); + + debug!( + "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", + predicates, outlives_predicates + ); + let non_outlives_predicates = match do_normalize_predicates( + tcx, + region_context, + cause.clone(), + elaborated_env, + predicates, + ) { + Ok(predicates) => predicates, + // An unnormalized env is better than nothing. + Err(ErrorReported) => { + debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); + return elaborated_env; + } + }; + + debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); + + // Not sure whether it is better to include the unnormalized TypeOutlives predicates + // here. I believe they should not matter, because we are ignoring TypeOutlives param-env + // predicates here anyway. Keeping them here anyway because it seems safer. + let outlives_env: Vec<_> = + non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); + let outlives_env = + ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None); + let outlives_predicates = match do_normalize_predicates( + tcx, + region_context, + cause, + outlives_env, + outlives_predicates, + ) { + Ok(predicates) => predicates, + // An unnormalized env is better than nothing. + Err(ErrorReported) => { + debug!("normalize_param_env_or_error: errored resolving outlives predicates"); + return elaborated_env; + } + }; + debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); + + let mut predicates = non_outlives_predicates; + predicates.extend(outlives_predicates); + debug!("normalize_param_env_or_error: final predicates={:?}", predicates); + ty::ParamEnv::new( + tcx.intern_predicates(&predicates), + unnormalized_env.reveal, + unnormalized_env.def_id, + ) +} + +pub fn fully_normalize<'a, 'tcx, T>( + infcx: &InferCtxt<'a, 'tcx>, + mut fulfill_cx: FulfillmentContext<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T, +) -> Result>> +where + T: TypeFoldable<'tcx>, +{ + debug!("fully_normalize_with_fulfillcx(value={:?})", value); + let selcx = &mut SelectionContext::new(infcx); + let Normalized { value: normalized_value, obligations } = + project::normalize(selcx, param_env, cause, value); + debug!( + "fully_normalize: normalized_value={:?} obligations={:?}", + normalized_value, obligations + ); + for obligation in obligations { + fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); + } + + debug!("fully_normalize: select_all_or_error start"); + fulfill_cx.select_all_or_error(infcx)?; + debug!("fully_normalize: select_all_or_error complete"); + let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); + debug!("fully_normalize: resolved_value={:?}", resolved_value); + Ok(resolved_value) +} + +/// Normalizes the predicates and checks whether they hold in an empty +/// environment. If this returns false, then either normalize +/// encountered an error or one of the predicates did not hold. Used +/// when creating vtables to check for unsatisfiable methods. +pub fn normalize_and_test_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: Vec>, +) -> bool { + debug!("normalize_and_test_predicates(predicates={:?})", predicates); + + let result = tcx.infer_ctxt().enter(|infcx| { + let param_env = ty::ParamEnv::reveal_all(); + let mut selcx = SelectionContext::new(&infcx); + let mut fulfill_cx = FulfillmentContext::new(); + let cause = ObligationCause::dummy(); + let Normalized { value: predicates, obligations } = + normalize(&mut selcx, param_env, cause.clone(), &predicates); + for obligation in obligations { + fulfill_cx.register_predicate_obligation(&infcx, obligation); + } + for predicate in predicates { + let obligation = Obligation::new(cause.clone(), param_env, predicate); + fulfill_cx.register_predicate_obligation(&infcx, obligation); + } + + fulfill_cx.select_all_or_error(&infcx).is_ok() + }); + debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result); + result +} + +fn substitute_normalize_and_test_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + key: (DefId, SubstsRef<'tcx>), +) -> bool { + debug!("substitute_normalize_and_test_predicates(key={:?})", key); + + let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; + let result = normalize_and_test_predicates(tcx, predicates); + + debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); + result +} + +/// Given a trait `trait_ref`, iterates the vtable entries +/// that come from `trait_ref`, including its supertraits. +#[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`. +fn vtable_methods<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, +) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { + debug!("vtable_methods({:?})", trait_ref); + + tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| { + let trait_methods = tcx + .associated_items(trait_ref.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Method); + + // Now list each method's DefId and InternalSubsts (for within its trait). + // If the method can never be called from this object, produce None. + trait_methods.map(move |trait_method| { + debug!("vtable_methods: trait_method={:?}", trait_method); + let def_id = trait_method.def_id; + + // Some methods cannot be called on an object; skip those. + if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { + debug!("vtable_methods: not vtable safe"); + return None; + } + + // The method may have some early-bound lifetimes; add regions for those. + let substs = trait_ref.map_bound(|trait_ref| { + InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { + GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { + trait_ref.substs[param.index as usize] + } + }) + }); + + // The trait type may have higher-ranked lifetimes in it; + // erase them if they appear, so that we get the type + // at some particular call site. + let substs = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); + + // It's possible that the method relies on where-clauses that + // do not hold for this particular set of type parameters. + // Note that this method could then never be called, so we + // do not want to try and codegen it, in that case (see #23435). + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); + if !normalize_and_test_predicates(tcx, predicates.predicates) { + debug!("vtable_methods: predicates do not hold"); + return None; + } + + Some((def_id, substs)) + }) + })) +} + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + object_safety::provide(providers); + *providers = ty::query::Providers { + specialization_graph_of: specialize::specialization_graph_provider, + specializes: specialize::specializes, + codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, + vtable_methods, + substitute_normalize_and_test_predicates, + ..*providers + }; +} diff --git a/src/librustc_infer/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs similarity index 99% rename from src/librustc_infer/traits/object_safety.rs rename to src/librustc_trait_selection/traits/object_safety.rs index 6f20f5ac47e57..d0d41f3ae32ad 100644 --- a/src/librustc_infer/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_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_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs new file mode 100644 index 0000000000000..dde78aa4357e9 --- /dev/null +++ b/src/librustc_trait_selection/traits/project.rs @@ -0,0 +1,1511 @@ +//! Code for projecting associated types out of trait references. + +use super::elaborate_predicates; +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, 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}; +use rustc_ast::ast::Ident; +use rustc_hir::def_id::DefId; +use rustc_span::symbol::sym; +use rustc_span::DUMMY_SP; + +pub use rustc::traits::Reveal; + +pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; + +pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; + +pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>; + +/// When attempting to resolve `::Name` ... +#[derive(Debug)] +pub enum ProjectionTyError<'tcx> { + /// ...we found multiple sources of information and couldn't resolve the ambiguity. + TooManyCandidates, + + /// ...an error occurred matching `T : TraitRef` + TraitSelectionError(SelectionError<'tcx>), +} + +#[derive(PartialEq, Eq, Debug)] +enum ProjectionTyCandidate<'tcx> { + // from a where-clause in the env or object type + ParamEnv(ty::PolyProjectionPredicate<'tcx>), + + // from the definition of `Trait` when you have something like <::B as Trait2>::C + TraitDef(ty::PolyProjectionPredicate<'tcx>), + + // from a "impl" (or a "pseudo-impl" returned by select) + Select(Selection<'tcx>), +} + +enum ProjectionTyCandidateSet<'tcx> { + None, + Single(ProjectionTyCandidate<'tcx>), + Ambiguous, + Error(SelectionError<'tcx>), +} + +impl<'tcx> ProjectionTyCandidateSet<'tcx> { + fn mark_ambiguous(&mut self) { + *self = ProjectionTyCandidateSet::Ambiguous; + } + + fn mark_error(&mut self, err: SelectionError<'tcx>) { + *self = ProjectionTyCandidateSet::Error(err); + } + + // Returns true if the push was successful, or false if the candidate + // was discarded -- this could be because of ambiguity, or because + // a higher-priority candidate is already there. + fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { + use self::ProjectionTyCandidate::*; + use self::ProjectionTyCandidateSet::*; + + // This wacky variable is just used to try and + // make code readable and avoid confusing paths. + // It is assigned a "value" of `()` only on those + // paths in which we wish to convert `*self` to + // ambiguous (and return false, because the candidate + // was not used). On other paths, it is not assigned, + // and hence if those paths *could* reach the code that + // comes after the match, this fn would not compile. + let convert_to_ambiguous; + + match self { + None => { + *self = Single(candidate); + return true; + } + + Single(current) => { + // Duplicates can happen inside ParamEnv. In the case, we + // perform a lazy deduplication. + if current == &candidate { + return false; + } + + // Prefer where-clauses. As in select, if there are multiple + // candidates, we prefer where-clause candidates over impls. This + // may seem a bit surprising, since impls are the source of + // "truth" in some sense, but in fact some of the impls that SEEM + // applicable are not, because of nested obligations. Where + // clauses are the safer choice. See the comment on + // `select::SelectionCandidate` and #21974 for more details. + match (current, candidate) { + (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), + (ParamEnv(..), _) => return false, + (_, ParamEnv(..)) => unreachable!(), + (_, _) => convert_to_ambiguous = (), + } + } + + Ambiguous | Error(..) => { + return false; + } + } + + // We only ever get here when we moved from a single candidate + // to ambiguous. + let () = convert_to_ambiguous; + *self = Ambiguous; + false + } +} + +/// Evaluates constraints of the form: +/// +/// for<...> ::U == V +/// +/// If successful, this may result in additional obligations. Also returns +/// the projection cache key used to track these additional obligations. +pub fn poly_project_and_unify_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &PolyProjectionObligation<'tcx>, +) -> Result>>, MismatchedProjectionTypes<'tcx>> { + debug!("poly_project_and_unify_type(obligation={:?})", obligation); + + let infcx = selcx.infcx(); + infcx.commit_if_ok(|snapshot| { + let (placeholder_predicate, placeholder_map) = + infcx.replace_bound_vars_with_placeholders(&obligation.predicate); + + let placeholder_obligation = obligation.with(placeholder_predicate); + let result = project_and_unify_type(selcx, &placeholder_obligation)?; + infcx + .leak_check(false, &placeholder_map, snapshot) + .map_err(|err| MismatchedProjectionTypes { err })?; + Ok(result) + }) +} + +/// Evaluates constraints of the form: +/// +/// ::U == V +/// +/// If successful, this may result in additional obligations. +fn project_and_unify_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionObligation<'tcx>, +) -> Result>>, MismatchedProjectionTypes<'tcx>> { + debug!("project_and_unify_type(obligation={:?})", obligation); + + let mut obligations = vec![]; + let normalized_ty = match opt_normalize_projection_type( + selcx, + obligation.param_env, + obligation.predicate.projection_ty, + obligation.cause.clone(), + obligation.recursion_depth, + &mut obligations, + ) { + Some(n) => n, + None => return Ok(None), + }; + + debug!( + "project_and_unify_type: normalized_ty={:?} obligations={:?}", + normalized_ty, obligations + ); + + let infcx = selcx.infcx(); + match infcx + .at(&obligation.cause, obligation.param_env) + .eq(normalized_ty, obligation.predicate.ty) + { + Ok(InferOk { obligations: inferred_obligations, value: () }) => { + obligations.extend(inferred_obligations); + Ok(Some(obligations)) + } + Err(err) => { + debug!("project_and_unify_type: equating types encountered error {:?}", err); + Err(MismatchedProjectionTypes { err }) + } + } +} + +/// Normalizes any associated type projections in `value`, replacing +/// them with a fully resolved type where possible. The return value +/// combines the normalized result and any additional obligations that +/// were incurred as result. +pub fn normalize<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + value: &T, +) -> Normalized<'tcx, T> +where + T: TypeFoldable<'tcx>, +{ + let mut obligations = Vec::new(); + let value = normalize_to(selcx, param_env, cause, value, &mut obligations); + Normalized { value, obligations } +} + +pub fn normalize_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + value: &T, + obligations: &mut Vec>, +) -> T +where + T: TypeFoldable<'tcx>, +{ + normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) +} + +/// As `normalize`, but with a custom depth. +pub fn normalize_with_depth<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: &T, +) -> Normalized<'tcx, T> +where + T: TypeFoldable<'tcx>, +{ + let mut obligations = Vec::new(); + let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); + Normalized { value, obligations } +} + +pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: &T, + obligations: &mut Vec>, +) -> T +where + T: TypeFoldable<'tcx>, +{ + debug!("normalize_with_depth(depth={}, value={:?})", depth, value); + let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); + let result = normalizer.fold(value); + debug!( + "normalize_with_depth: depth={} result={:?} with {} obligations", + depth, + result, + normalizer.obligations.len() + ); + debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations); + result +} + +struct AssocTypeNormalizer<'a, 'b, 'tcx> { + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + obligations: &'a mut Vec>, + depth: usize, +} + +impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { + fn new( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &'a mut Vec>, + ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { + AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } + } + + fn fold>(&mut self, value: &T) -> T { + let value = self.selcx.infcx().resolve_vars_if_possible(value); + + if !value.has_projections() { value } else { value.fold_with(self) } + } +} + +impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { + self.selcx.tcx() + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_projections() { + return ty; + } + // We don't want to normalize associated types that occur inside of region + // binders, because they may contain bound regions, and we can't cope with that. + // + // Example: + // + // for<'a> fn(>::A) + // + // Instead of normalizing `>::A` here, we'll + // normalize it when we instantiate those bound regions (which + // should occur eventually). + + let ty = ty.super_fold_with(self); + match ty.kind { + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { + // (*) + // Only normalize `impl Trait` after type-checking, usually in codegen. + match self.param_env.reveal { + Reveal::UserFacing => ty, + + Reveal::All => { + let recursion_limit = *self.tcx().sess.recursion_limit.get(); + if self.depth >= recursion_limit { + let obligation = Obligation::with_depth( + self.cause.clone(), + recursion_limit, + self.param_env, + ty, + ); + self.selcx.infcx().report_overflow_error(&obligation, true); + } + + let generic_ty = self.tcx().type_of(def_id); + let concrete_ty = generic_ty.subst(self.tcx(), substs); + self.depth += 1; + let folded_ty = self.fold_ty(concrete_ty); + self.depth -= 1; + folded_ty + } + } + } + + ty::Projection(ref data) if !data.has_escaping_bound_vars() => { + // (*) + + // (*) This is kind of hacky -- we need to be able to + // handle normalization within binders because + // otherwise we wind up a need to normalize when doing + // trait matching (since you can have a trait + // obligation like `for<'a> T::B : Fn(&'a int)`), but + // we can't normalize with bound regions in scope. So + // far now we just ignore binders but only normalize + // if all bound regions are gone (and then we still + // have to renormalize whenever we instantiate a + // binder). It would be better to normalize in a + // binding-aware fashion. + + let normalized_ty = normalize_projection_type( + self.selcx, + self.param_env, + *data, + self.cause.clone(), + self.depth, + &mut self.obligations, + ); + debug!( + "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \ + now with {} obligations", + self.depth, + ty, + normalized_ty, + self.obligations.len() + ); + normalized_ty + } + + _ => ty, + } + } + + fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + constant.eval(self.selcx.tcx(), self.param_env) + } +} + +/// 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 +/// there are unresolved type variables in the projection, we will +/// substitute a fresh type variable `$X` and generate a new +/// obligation `::Item == $X` for later. +pub fn normalize_projection_type<'a, 'b, 'tcx>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &mut Vec>, +) -> Ty<'tcx> { + opt_normalize_projection_type( + selcx, + param_env, + projection_ty, + cause.clone(), + depth, + obligations, + ) + .unwrap_or_else(move || { + // if we bottom out in ambiguity, create a type variable + // and a deferred predicate to resolve this when more type + // information is available. + + let tcx = selcx.infcx().tcx; + let def_id = projection_ty.item_def_id; + let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: tcx.def_span(def_id), + }); + let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); + let obligation = + Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate()); + obligations.push(obligation); + ty_var + }) +} + +/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly +/// additional obligations). Returns `None` in the case of ambiguity, +/// which indicates that there are unbound type variables. +/// +/// This function used to return `Option>`, which contains a +/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very +/// often immediately appended to another obligations vector. So now this +/// function takes an obligations vector and appends to it directly, which is +/// slightly uglier but avoids the need for an extra short-lived allocation. +fn opt_normalize_projection_type<'a, 'b, 'tcx>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &mut Vec>, +) -> Option> { + let infcx = selcx.infcx(); + + let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); + let cache_key = ProjectionCacheKey::new(projection_ty); + + debug!( + "opt_normalize_projection_type(\ + projection_ty={:?}, \ + depth={})", + projection_ty, depth + ); + + // FIXME(#20304) For now, I am caching here, which is good, but it + // means we don't capture the type variables that are created in + // the case of ambiguity. Which means we may create a large stream + // of such variables. OTOH, if we move the caching up a level, we + // would not benefit from caching when proving `T: Trait` + // bounds. It might be the case that we want two distinct caches, + // or else another kind of cache entry. + + let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key); + match cache_result { + Ok(()) => {} + Err(ProjectionCacheEntry::Ambiguous) => { + // If we found ambiguity the last time, that means we will continue + // to do so until some type in the key changes (and we know it + // hasn't, because we just fully resolved it). + debug!( + "opt_normalize_projection_type: \ + found cache entry: ambiguous" + ); + return None; + } + Err(ProjectionCacheEntry::InProgress) => { + // If while normalized A::B, we are asked to normalize + // A::B, just return A::B itself. This is a conservative + // answer, in the sense that A::B *is* clearly equivalent + // to A::B, though there may be a better value we can + // find. + + // Under lazy normalization, this can arise when + // bootstrapping. That is, imagine an environment with a + // where-clause like `A::B == u32`. Now, if we are asked + // to normalize `A::B`, we will want to check the + // where-clauses in scope. So we will try to unify `A::B` + // with `A::B`, which can trigger a recursive + // normalization. In that case, I think we will want this code: + // + // ``` + // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id, + // projection_ty.substs; + // return Some(NormalizedTy { value: v, obligations: vec![] }); + // ``` + + debug!( + "opt_normalize_projection_type: \ + found cache entry: in-progress" + ); + + // But for now, let's classify this as an overflow: + let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); + let obligation = + Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); + selcx.infcx().report_overflow_error(&obligation, false); + } + Err(ProjectionCacheEntry::NormalizedTy(ty)) => { + // This is the hottest path in this function. + // + // If we find the value in the cache, then return it along + // with the obligations that went along with it. Note + // that, when using a fulfillment context, these + // obligations could in principle be ignored: they have + // already been registered when the cache entry was + // created (and hence the new ones will quickly be + // discarded as duplicated). But when doing trait + // evaluation this is not the case, and dropping the trait + // evaluations can causes ICEs (e.g., #43132). + debug!( + "opt_normalize_projection_type: \ + found normalized ty `{:?}`", + ty + ); + + // Once we have inferred everything we need to know, we + // can ignore the `obligations` from that point on. + if infcx.unresolved_type_vars(&ty.value).is_none() { + infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty); + // No need to extend `obligations`. + } else { + obligations.extend(ty.obligations); + } + + obligations.push(get_paranoid_cache_value_obligation( + infcx, + param_env, + projection_ty, + cause, + depth, + )); + return Some(ty.value); + } + Err(ProjectionCacheEntry::Error) => { + debug!( + "opt_normalize_projection_type: \ + found error" + ); + let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); + obligations.extend(result.obligations); + return Some(result.value); + } + } + + let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); + match project_type(selcx, &obligation) { + Ok(ProjectedTy::Progress(Progress { + ty: projected_ty, + obligations: mut projected_obligations, + })) => { + // if projection succeeded, then what we get out of this + // is also non-normalized (consider: it was derived from + // an impl, where-clause etc) and hence we must + // re-normalize it + + debug!( + "opt_normalize_projection_type: \ + projected_ty={:?} \ + depth={} \ + projected_obligations={:?}", + projected_ty, depth, projected_obligations + ); + + let result = if projected_ty.has_projections() { + let mut normalizer = AssocTypeNormalizer::new( + selcx, + param_env, + cause, + depth + 1, + &mut projected_obligations, + ); + let normalized_ty = normalizer.fold(&projected_ty); + + debug!( + "opt_normalize_projection_type: \ + normalized_ty={:?} depth={}", + normalized_ty, depth + ); + + Normalized { value: normalized_ty, obligations: projected_obligations } + } else { + Normalized { value: projected_ty, obligations: projected_obligations } + }; + + let cache_value = prune_cache_value_obligations(infcx, &result); + infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value); + obligations.extend(result.obligations); + Some(result.value) + } + Ok(ProjectedTy::NoProgress(projected_ty)) => { + debug!( + "opt_normalize_projection_type: \ + projected_ty={:?} no progress", + projected_ty + ); + let result = Normalized { value: projected_ty, obligations: vec![] }; + infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone()); + // No need to extend `obligations`. + Some(result.value) + } + Err(ProjectionTyError::TooManyCandidates) => { + debug!( + "opt_normalize_projection_type: \ + too many candidates" + ); + infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); + None + } + Err(ProjectionTyError::TraitSelectionError(_)) => { + debug!("opt_normalize_projection_type: ERROR"); + // if we got an error processing the `T as Trait` part, + // just return `ty::err` but add the obligation `T : + // Trait`, which when processed will cause the error to be + // reported later + + infcx.inner.borrow_mut().projection_cache.error(cache_key); + let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); + obligations.extend(result.obligations); + Some(result.value) + } + } +} + +/// If there are unresolved type variables, then we need to include +/// any subobligations that bind them, at least until those type +/// variables are fully resolved. +fn prune_cache_value_obligations<'a, 'tcx>( + infcx: &'a InferCtxt<'a, 'tcx>, + result: &NormalizedTy<'tcx>, +) -> NormalizedTy<'tcx> { + if infcx.unresolved_type_vars(&result.value).is_none() { + return NormalizedTy { value: result.value, obligations: vec![] }; + } + + let mut obligations: Vec<_> = result + .obligations + .iter() + .filter(|obligation| match obligation.predicate { + // We found a `T: Foo` predicate, let's check + // if `U` references any unresolved type + // variables. In principle, we only care if this + // projection can help resolve any of the type + // variables found in `result.value` -- but we just + // check for any type variables here, for fear of + // indirect obligations (e.g., we project to `?0`, + // but we have `T: Foo` and `?1: Bar`). + ty::Predicate::Projection(ref data) => infcx.unresolved_type_vars(&data.ty()).is_some(), + + // We are only interested in `T: Foo` predicates, whre + // `U` references one of `unresolved_type_vars`. =) + _ => false, + }) + .cloned() + .collect(); + + obligations.shrink_to_fit(); + + NormalizedTy { value: result.value, obligations } +} + +/// Whenever we give back a cache result for a projection like `::Item ==> X`, we *always* include the obligation to prove +/// that `T: Trait` (we may also include some other obligations). This +/// may or may not be necessary -- in principle, all the obligations +/// that must be proven to show that `T: Trait` were also returned +/// when the cache was first populated. But there are some vague concerns, +/// and so we take the precautionary measure of including `T: Trait` in +/// the result: +/// +/// Concern #1. The current setup is fragile. Perhaps someone could +/// have failed to prove the concerns from when the cache was +/// populated, but also not have used a snapshot, in which case the +/// cache could remain populated even though `T: Trait` has not been +/// shown. In this case, the "other code" is at fault -- when you +/// project something, you are supposed to either have a snapshot or +/// else prove all the resulting obligations -- but it's still easy to +/// get wrong. +/// +/// Concern #2. Even within the snapshot, if those original +/// obligations are not yet proven, then we are able to do projections +/// that may yet turn out to be wrong. This *may* lead to some sort +/// of trouble, though we don't have a concrete example of how that +/// can occur yet. But it seems risky at best. +fn get_paranoid_cache_value_obligation<'a, 'tcx>( + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, +) -> PredicateObligation<'tcx> { + let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); + Obligation { + cause, + recursion_depth: depth, + param_env, + predicate: trait_ref.without_const().to_predicate(), + } +} + +/// If we are projecting `::Item`, but `T: Trait` does not +/// hold. In various error cases, we cannot generate a valid +/// normalized projection. Therefore, we create an inference variable +/// return an associated obligation that, when fulfilled, will lead to +/// an error. +/// +/// Note that we used to return `Error` here, but that was quite +/// dubious -- the premise was that an error would *eventually* be +/// reported, when the obligation was processed. But in general once +/// you see a `Error` you are supposed to be able to assume that an +/// error *has been* reported, so that you can take whatever heuristic +/// paths you want to take. To make things worse, it was possible for +/// cycles to arise, where you basically had a setup like ` +/// as Trait>::Foo == $0`. Here, normalizing ` as +/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// ` as Trait>::Foo`. We are supposed to report +/// an error for this obligation, but we legitimately should not, +/// because it contains `[type error]`. Yuck! (See issue #29857 for +/// one case where this arose.) +fn normalize_to_error<'a, 'tcx>( + selcx: &mut SelectionContext<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, +) -> NormalizedTy<'tcx> { + let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let trait_obligation = Obligation { + cause, + recursion_depth: depth, + param_env, + predicate: trait_ref.without_const().to_predicate(), + }; + let tcx = selcx.infcx().tcx; + let def_id = projection_ty.item_def_id; + let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: tcx.def_span(def_id), + }); + Normalized { value: new_value, obligations: vec![trait_obligation] } +} + +enum ProjectedTy<'tcx> { + Progress(Progress<'tcx>), + NoProgress(Ty<'tcx>), +} + +struct Progress<'tcx> { + ty: Ty<'tcx>, + obligations: Vec>, +} + +impl<'tcx> Progress<'tcx> { + fn error(tcx: TyCtxt<'tcx>) -> Self { + Progress { ty: tcx.types.err, obligations: vec![] } + } + + fn with_addl_obligations(mut self, mut obligations: Vec>) -> Self { + debug!( + "with_addl_obligations: self.obligations.len={} obligations.len={}", + self.obligations.len(), + obligations.len() + ); + + debug!( + "with_addl_obligations: self.obligations={:?} obligations={:?}", + self.obligations, obligations + ); + + self.obligations.append(&mut obligations); + self + } +} + +/// Computes the result of a projection type (if we can). +/// +/// IMPORTANT: +/// - `obligation` must be fully normalized +fn project_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, +) -> Result, ProjectionTyError<'tcx>> { + debug!("project(obligation={:?})", obligation); + + let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); + if obligation.recursion_depth >= recursion_limit { + debug!("project: overflow!"); + return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); + } + + let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); + + debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); + + if obligation_trait_ref.references_error() { + return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); + } + + let mut candidates = ProjectionTyCandidateSet::None; + + // Make sure that the following procedures are kept in order. ParamEnv + // needs to be first because it has highest priority, and Select checks + // the return value of push_candidate which assumes it's ran at last. + assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates); + + assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); + + assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); + + match candidates { + ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( + confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate), + )), + ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( + selcx + .tcx() + .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs), + )), + // Error occurred while trying to processing impls. + ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), + // Inherent ambiguity that prevents us from even enumerating the + // candidates. + ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), + } +} + +/// The first thing we have to do is scan through the parameter +/// environment to see whether there are any projection predicates +/// there that can answer this question. +fn assemble_candidates_from_param_env<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, +) { + debug!("assemble_candidates_from_param_env(..)"); + assemble_candidates_from_predicates( + selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::ParamEnv, + obligation.param_env.caller_bounds.iter().cloned(), + ); +} + +/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find +/// that the definition of `Foo` has some clues: +/// +/// ``` +/// trait Foo { +/// type FooT : Bar +/// } +/// ``` +/// +/// Here, for example, we could conclude that the result is `i32`. +fn assemble_candidates_from_trait_def<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, +) { + debug!("assemble_candidates_from_trait_def(..)"); + + let tcx = selcx.tcx(); + // Check whether the self-type is itself a projection. + let (def_id, substs) = match obligation_trait_ref.self_ty().kind { + ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), + ty::Opaque(def_id, substs) => (def_id, substs), + ty::Infer(ty::TyVar(_)) => { + // If the self-type is an inference variable, then it MAY wind up + // being a projected type, so induce an ambiguity. + candidate_set.mark_ambiguous(); + return; + } + _ => return, + }; + + // If so, extract what we know from the trait and try to come up with a good answer. + let trait_predicates = tcx.predicates_of(def_id); + let bounds = trait_predicates.instantiate(tcx, substs); + let bounds = elaborate_predicates(tcx, bounds.predicates); + assemble_candidates_from_predicates( + selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::TraitDef, + bounds, + ) +} + +fn assemble_candidates_from_predicates<'cx, 'tcx, I>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, + env_predicates: I, +) where + I: IntoIterator>, +{ + debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); + let infcx = selcx.infcx(); + for predicate in env_predicates { + debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); + if let ty::Predicate::Projection(data) = predicate { + let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; + + let is_match = same_def_id + && infcx.probe(|_| { + let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx); + let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .map(|InferOk { obligations: _, value: () }| { + // FIXME(#32730) -- do we need to take obligations + // into account in any way? At the moment, no. + }) + .is_ok() + }); + + debug!( + "assemble_candidates_from_predicates: candidate={:?} \ + is_match={} same_def_id={}", + data, is_match, same_def_id + ); + + if is_match { + candidate_set.push_candidate(ctor(data)); + } + } + } +} + +fn assemble_candidates_from_impls<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, +) { + // If we are resolving `>::Item == Type`, + // start out by selecting the predicate `T as TraitRef<...>`: + let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); + let _ = selcx.infcx().commit_if_ok(|_| { + let vtable = match selcx.select(&trait_obligation) { + Ok(Some(vtable)) => vtable, + Ok(None) => { + candidate_set.mark_ambiguous(); + return Err(()); + } + Err(e) => { + debug!("assemble_candidates_from_impls: selection error {:?}", e); + candidate_set.mark_error(e); + return Err(()); + } + }; + + let eligible = match &vtable { + super::VtableClosure(_) + | super::VtableGenerator(_) + | super::VtableFnPointer(_) + | super::VtableObject(_) + | super::VtableTraitAlias(_) => { + debug!("assemble_candidates_from_impls: vtable={:?}", vtable); + true + } + super::VtableImpl(impl_data) => { + // We have to be careful when projecting out of an + // impl because of specialization. If we are not in + // codegen (i.e., projection mode is not "any"), and the + // impl's type is declared as default, then we disable + // projection (even if the trait ref is fully + // monomorphic). In the case where trait ref is not + // fully monomorphic (i.e., includes type parameters), + // this is because those type parameters may + // ultimately be bound to types from other crates that + // may have specialized impls we can't see. In the + // case where the trait ref IS fully monomorphic, this + // is a policy decision that we made in the RFC in + // order to preserve flexibility for the crate that + // defined the specializable impl to specialize later + // for existing types. + // + // In either case, we handle this by not adding a + // candidate for an impl if it contains a `default` + // type. + // + // NOTE: This should be kept in sync with the similar code in + // `rustc::ty::instance::resolve_associated_item()`. + let node_item = + assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id); + + let is_default = if node_item.node.is_from_trait() { + // If true, the impl inherited a `type Foo = Bar` + // given in the trait, which is implicitly default. + // Otherwise, the impl did not specify `type` and + // neither did the trait: + // + // ```rust + // trait Foo { type T; } + // impl Foo for Bar { } + // ``` + // + // This is an error, but it will be + // reported in `check_impl_items_against_trait`. + // We accept it here but will flag it as + // an error when we confirm the candidate + // (which will ultimately lead to `normalize_to_error` + // being invoked). + false + } else { + // If we're looking at a trait *impl*, the item is + // specializable if the impl or the item are marked + // `default`. + node_item.item.defaultness.is_default() + || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) + }; + + match is_default { + // Non-specializable items are always projectable + false => true, + + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + true if obligation.param_env.reveal == Reveal::All => { + // NOTE(eddyb) inference variables can resolve to parameters, so + // assume `poly_trait_ref` isn't monomorphic, if it contains any. + let poly_trait_ref = + selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); + !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() + } + + true => { + debug!( + "assemble_candidates_from_impls: not eligible due to default: \ + assoc_ty={} predicate={}", + selcx.tcx().def_path_str(node_item.item.def_id), + obligation.predicate, + ); + false + } + } + } + super::VtableParam(..) => { + // This case tell us nothing about the value of an + // associated type. Consider: + // + // ``` + // trait SomeTrait { type Foo; } + // fn foo(...) { } + // ``` + // + // If the user writes `::Foo`, then the `T + // : SomeTrait` binding does not help us decide what the + // type `Foo` is (at least, not more specifically than + // what we already knew). + // + // But wait, you say! What about an example like this: + // + // ``` + // fn bar>(...) { ... } + // ``` + // + // Doesn't the `T : Sometrait` predicate help + // resolve `T::Foo`? And of course it does, but in fact + // that single predicate is desugared into two predicates + // in the compiler: a trait predicate (`T : SomeTrait`) and a + // projection. And the projection where clause is handled + // in `assemble_candidates_from_param_env`. + false + } + super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { + // These traits have no associated types. + span_bug!( + obligation.cause.span, + "Cannot project an associated type from `{:?}`", + vtable + ); + } + }; + + if eligible { + if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + }); +} + +fn confirm_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + candidate: ProjectionTyCandidate<'tcx>, +) -> Progress<'tcx> { + debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); + + match candidate { + ProjectionTyCandidate::ParamEnv(poly_projection) + | ProjectionTyCandidate::TraitDef(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection) + } + + ProjectionTyCandidate::Select(vtable) => { + confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) + } + } +} + +fn confirm_select_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + vtable: Selection<'tcx>, +) -> Progress<'tcx> { + match vtable { + super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), + super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data), + super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data), + super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref), + super::VtableAutoImpl(..) + | super::VtableParam(..) + | super::VtableBuiltin(..) + | super::VtableTraitAlias(..) => + // we don't create Select candidates with this kind of resolution + { + span_bug!( + obligation.cause.span, + "Cannot project an associated type from `{:?}`", + vtable + ) + } + } +} + +fn confirm_object_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, +) -> Progress<'tcx> { + let self_ty = obligation_trait_ref.self_ty(); + let object_ty = selcx.infcx().shallow_resolve(self_ty); + debug!("confirm_object_candidate(object_ty={:?})", object_ty); + let data = match object_ty.kind { + ty::Dynamic(ref data, ..) => data, + _ => span_bug!( + obligation.cause.span, + "confirm_object_candidate called with non-object: {:?}", + object_ty + ), + }; + let env_predicates = data + .projection_bounds() + .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate()) + .collect(); + let env_predicate = { + let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); + + // select only those projections that are actually projecting an + // item with the correct name + let env_predicates = env_predicates.filter_map(|p| match p { + ty::Predicate::Projection(data) => { + if data.projection_def_id() == obligation.predicate.item_def_id { + Some(data) + } else { + None + } + } + _ => None, + }); + + // select those with a relevant trait-ref + let mut env_predicates = env_predicates.filter(|data| { + let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); + let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + selcx.infcx().probe(|_| { + selcx + .infcx() + .at(&obligation.cause, obligation.param_env) + .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .is_ok() + }) + }); + + // select the first matching one; there really ought to be one or + // else the object type is not WF, since an object type should + // include all of its projections explicitly + match env_predicates.next() { + Some(env_predicate) => env_predicate, + None => { + debug!( + "confirm_object_candidate: no env-predicate \ + found in object type `{:?}`; ill-formed", + object_ty + ); + return Progress::error(selcx.tcx()); + } + } + }; + + confirm_param_env_candidate(selcx, obligation, env_predicate) +} + +fn confirm_generator_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx()); + let Normalized { value: gen_sig, obligations } = normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &gen_sig, + ); + + debug!( + "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", + obligation, gen_sig, obligations + ); + + let tcx = selcx.tcx(); + + let gen_def_id = tcx.lang_items().gen_trait().unwrap(); + + let predicate = super::util::generator_trait_ref_and_outputs( + tcx, + gen_def_id, + obligation.predicate.self_ty(), + gen_sig, + ) + .map_bound(|(trait_ref, yield_ty, return_ty)| { + let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; + let ty = if name == sym::Return { + return_ty + } else if name == sym::Yield { + yield_ty + } else { + bug!() + }; + + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: trait_ref.substs, + item_def_id: obligation.predicate.item_def_id, + }, + ty, + } + }); + + confirm_param_env_candidate(selcx, obligation, predicate) + .with_addl_obligations(vtable.nested) + .with_addl_obligations(obligations) +} + +fn confirm_fn_pointer_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); + let sig = fn_type.fn_sig(selcx.tcx()); + let Normalized { value: sig, obligations } = normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &sig, + ); + + confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) + .with_addl_obligations(fn_pointer_vtable.nested) + .with_addl_obligations(obligations) +} + +fn confirm_closure_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + let infcx = selcx.infcx(); + let closure_sig_ty = vtable.substs.as_closure().sig_ty(vtable.closure_def_id, tcx); + let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx); + let Normalized { value: closure_sig, obligations } = normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &closure_sig, + ); + + debug!( + "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}", + obligation, closure_sig, obligations + ); + + confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) + .with_addl_obligations(vtable.nested) + .with_addl_obligations(obligations) +} + +fn confirm_callable_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, + flag: util::TupleArgumentsFlag, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + + debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); + + // the `Output` associated type is declared on `FnOnce` + let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap(); + + let predicate = super::util::closure_trait_ref_and_return_type( + tcx, + fn_once_def_id, + obligation.predicate.self_ty(), + fn_sig, + flag, + ) + .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME), + ), + ty: ret_type, + }); + + confirm_param_env_candidate(selcx, obligation, predicate) +} + +fn confirm_param_env_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, +) -> Progress<'tcx> { + let infcx = selcx.infcx(); + let cause = &obligation.cause; + let param_env = obligation.param_env; + + let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars( + cause.span, + LateBoundRegionConversionTime::HigherRankedType, + &poly_cache_entry, + ); + + let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); + let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); + match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { + Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations }, + Err(e) => { + let msg = format!( + "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", + obligation, poly_cache_entry, e, + ); + debug!("confirm_param_env_candidate: {}", msg); + infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); + Progress { ty: infcx.tcx.types.err, obligations: vec![] } + } + } +} + +fn confirm_impl_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + + let VtableImplData { impl_def_id, substs, nested } = impl_vtable; + let assoc_item_id = obligation.predicate.item_def_id; + let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); + + let param_env = obligation.param_env; + let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id); + + if !assoc_ty.item.defaultness.has_value() { + // This means that the impl is missing a definition for the + // associated type. This error will be reported by the type + // checker method `check_impl_items_against_trait`, so here we + // just return Error. + debug!( + "confirm_impl_candidate: no associated type {:?} for {:?}", + assoc_ty.item.ident, obligation.predicate + ); + return Progress { ty: tcx.types.err, obligations: nested }; + } + let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); + let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); + let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind { + let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); + tcx.mk_opaque(assoc_ty.item.def_id, item_substs) + } else { + tcx.type_of(assoc_ty.item.def_id) + }; + if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { + tcx.sess + .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); + Progress { ty: tcx.types.err, obligations: nested } + } else { + Progress { ty: ty.subst(tcx, substs), obligations: nested } + } +} + +/// Locate the definition of an associated type in the specialization hierarchy, +/// starting from the given impl. +/// +/// Based on the "projection mode", this lookup may in fact only examine the +/// topmost impl. See the comments for `Reveal` for more details. +fn assoc_ty_def( + selcx: &SelectionContext<'_, '_>, + impl_def_id: DefId, + assoc_ty_def_id: DefId, +) -> specialization_graph::NodeItem { + let tcx = selcx.tcx(); + let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; + let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; + let trait_def = tcx.trait_def(trait_def_id); + + // This function may be called while we are still building the + // specialization graph that is queried below (via TraidDef::ancestors()), + // so, in order to avoid unnecessary infinite recursion, we manually look + // for the associated item at the given impl. + // If there is no such item in that impl, this function will fail with a + // cycle error if the specialization graph is currently being built. + let impl_node = specialization_graph::Node::Impl(impl_def_id); + for item in impl_node.items(tcx) { + if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) + && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) + { + return specialization_graph::NodeItem { + node: specialization_graph::Node::Impl(impl_def_id), + item: *item, + }; + } + } + + if let Some(assoc_item) = + trait_def.ancestors(tcx, impl_def_id).leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) + { + assoc_item + } else { + // This is saying that neither the trait nor + // the impl contain a definition for this + // associated type. Normally this situation + // could only arise through a compiler bug -- + // if the user wrote a bad item name, it + // should have failed in astconv. + bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id)) + } +} + +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::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_infer/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs similarity index 95% rename from src/librustc_infer/traits/query/dropck_outlives.rs rename to src/librustc_trait_selection/traits/query/dropck_outlives.rs index a1d7a2836e42d..40a21b5a6ed4a 100644 --- a/src/librustc_infer/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_infer/traits/query/evaluate_obligation.rs b/src/librustc_trait_selection/traits/query/evaluate_obligation.rs similarity index 71% rename from src/librustc_infer/traits/query/evaluate_obligation.rs rename to src/librustc_trait_selection/traits/query/evaluate_obligation.rs index b9ce3ccff2748..0569f6217da65 100644 --- a/src/librustc_infer/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_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 95% rename from src/librustc_infer/traits/query/normalize.rs rename to src/librustc_trait_selection/traits/query/normalize.rs index 4577e3d2e1cf8..adec2ddb25322 100644 --- a/src/librustc_infer/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::project::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_infer/traits/query/outlives_bounds.rs b/src/librustc_trait_selection/traits/query/outlives_bounds.rs similarity index 78% rename from src/librustc_infer/traits/query/outlives_bounds.rs rename to src/librustc_trait_selection/traits/query/outlives_bounds.rs index eb32ebf5c4db4..05c96dd520ab7 100644 --- a/src/librustc_infer/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, @@ -82,22 +93,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_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 96% rename from src/librustc_infer/traits/query/type_op/custom.rs rename to src/librustc_trait_selection/traits/query/type_op/custom.rs index c1c9030b88805..915e8ae4a7ad6 100644 --- a/src/librustc_infer/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_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 98% rename from src/librustc_infer/traits/select.rs rename to src/librustc_trait_selection/traits/select.rs index b50f14475fceb..ab3214d8d2d23 100644 --- a/src/librustc_infer/traits/select.rs +++ b/src/librustc_trait_selection/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}; @@ -34,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; @@ -95,47 +96,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>, @@ -3506,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_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_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_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs new file mode 100644 index 0000000000000..cd4595e76ccec --- /dev/null +++ b/src/librustc_trait_selection/traits/util.rs @@ -0,0 +1,675 @@ +use rustc_errors::DiagnosticBuilder; +use rustc_span::Span; +use smallvec::smallvec; +use smallvec::SmallVec; + +use rustc::ty::outlives::Component; +use rustc::ty::subst::{GenericArg, Subst, SubstsRef}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; + +use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; + +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, 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_trait_ref<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, +) -> Elaborator<'tcx> { + elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()]) +} + +pub fn elaborate_trait_refs<'tcx>( + tcx: TyCtxt<'tcx>, + trait_refs: impl Iterator>, +) -> Elaborator<'tcx> { + let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect(); + elaborate_predicates(tcx, predicates) +} + +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> { + pub fn filter_to_traits(self) -> FilterToTraits { + FilterToTraits::new(self) + } + + 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 + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Supertrait iterator +/////////////////////////////////////////////////////////////////////////// + +pub type Supertraits<'tcx> = FilterToTraits>; + +pub fn supertraits<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, +) -> Supertraits<'tcx> { + elaborate_trait_ref(tcx, trait_ref).filter_to_traits() +} + +pub fn transitive_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: impl Iterator>, +) -> Supertraits<'tcx> { + elaborate_trait_refs(tcx, bounds).filter_to_traits() +} + +/////////////////////////////////////////////////////////////////////////// +// `TraitAliasExpander` iterator +/////////////////////////////////////////////////////////////////////////// + +/// "Trait alias expansion" is the process of expanding a sequence of trait +/// references into another sequence by transitively following all trait +/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias +/// `trait Foo = Bar + Sync;`, and another trait alias +/// `trait Bar = Read + Write`, then the bounds would expand to +/// `Read + Write + Sync + Send`. +/// Expansion is done via a DFS (depth-first search), and the `visited` field +/// is used to avoid cycles. +pub struct TraitAliasExpander<'tcx> { + tcx: TyCtxt<'tcx>, + stack: Vec>, +} + +/// Stores information about the expansion of a trait via a path of zero or more trait aliases. +#[derive(Debug, Clone)] +pub struct TraitAliasExpansionInfo<'tcx> { + pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, +} + +impl<'tcx> TraitAliasExpansionInfo<'tcx> { + fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { + Self { path: smallvec![(trait_ref, span)] } + } + + /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate + /// trait aliases. + pub fn label_with_exp_info( + &self, + diag: &mut DiagnosticBuilder<'_>, + top_label: &str, + use_desc: &str, + ) { + diag.span_label(self.top().1, top_label); + if self.path.len() > 1 { + for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { + diag.span_label(*sp, format!("referenced here ({})", use_desc)); + } + } + diag.span_label( + self.bottom().1, + format!("trait alias used in trait object type ({})", use_desc), + ); + } + + pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> { + &self.top().0 + } + + pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { + self.path.last().unwrap() + } + + pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { + self.path.first().unwrap() + } + + fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { + let mut path = self.path.clone(); + path.push((trait_ref, span)); + + Self { path } + } +} + +pub fn expand_trait_aliases<'tcx>( + tcx: TyCtxt<'tcx>, + trait_refs: impl IntoIterator, Span)>, +) -> TraitAliasExpander<'tcx> { + let items: Vec<_> = trait_refs + .into_iter() + .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)) + .collect(); + TraitAliasExpander { tcx, stack: items } +} + +impl<'tcx> TraitAliasExpander<'tcx> { + /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item` + /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`. + /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a + /// trait alias. + /// The return value indicates whether `item` should be yielded to the user. + fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { + let tcx = self.tcx; + let trait_ref = item.trait_ref(); + let pred = trait_ref.without_const().to_predicate(); + + debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); + + // Don't recurse if this bound is not a trait alias. + let is_alias = tcx.is_trait_alias(trait_ref.def_id()); + if !is_alias { + return true; + } + + // Don't recurse if this trait alias is already on the stack for the DFS search. + let anon_pred = anonymize_predicate(tcx, &pred); + if item.path.iter().rev().skip(1).any(|(tr, _)| { + anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred + }) { + return false; + } + + // Get components of trait alias. + let predicates = tcx.super_predicates_of(trait_ref.def_id()); + + let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { + pred.subst_supertrait(tcx, &trait_ref) + .to_opt_poly_trait_ref() + .map(|trait_ref| item.clone_and_push(trait_ref, *span)) + }); + debug!("expand_trait_aliases: items={:?}", items.clone()); + + self.stack.extend(items); + + false + } +} + +impl<'tcx> Iterator for TraitAliasExpander<'tcx> { + type Item = TraitAliasExpansionInfo<'tcx>; + + fn size_hint(&self) -> (usize, Option) { + (self.stack.len(), None) + } + + fn next(&mut self) -> Option> { + while let Some(item) = self.stack.pop() { + if self.expand(&item) { + return Some(item); + } + } + None + } +} + +/////////////////////////////////////////////////////////////////////////// +// Iterator over def-IDs of supertraits +/////////////////////////////////////////////////////////////////////////// + +pub struct SupertraitDefIds<'tcx> { + tcx: TyCtxt<'tcx>, + stack: Vec, + visited: FxHashSet, +} + +pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> { + SupertraitDefIds { + tcx, + stack: vec![trait_def_id], + visited: Some(trait_def_id).into_iter().collect(), + } +} + +impl Iterator for SupertraitDefIds<'tcx> { + type Item = DefId; + + fn next(&mut self) -> Option { + let def_id = self.stack.pop()?; + let predicates = self.tcx.super_predicates_of(def_id); + let visited = &mut self.visited; + self.stack.extend( + predicates + .predicates + .iter() + .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref()) + .map(|trait_ref| trait_ref.def_id()) + .filter(|&super_def_id| visited.insert(super_def_id)), + ); + Some(def_id) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Other +/////////////////////////////////////////////////////////////////////////// + +/// A filter around an iterator of predicates that makes it yield up +/// just trait references. +pub struct FilterToTraits { + base_iterator: I, +} + +impl FilterToTraits { + fn new(base: I) -> FilterToTraits { + FilterToTraits { base_iterator: base } + } +} + +impl<'tcx, I: Iterator>> Iterator for FilterToTraits { + type Item = ty::PolyTraitRef<'tcx>; + + fn next(&mut self) -> Option> { + while let Some(pred) = self.base_iterator.next() { + if let ty::Predicate::Trait(data, _) = pred { + return Some(data.to_poly_trait_ref()); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.base_iterator.size_hint(); + (0, upper) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Other +/////////////////////////////////////////////////////////////////////////// + +/// Instantiate all bound parameters of the impl with the given substs, +/// returning the resulting trait ref and all obligations that arise. +/// The obligations are closed under normalization. +pub fn impl_trait_ref_and_oblig<'a, 'tcx>( + selcx: &mut SelectionContext<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: DefId, + impl_substs: SubstsRef<'tcx>, +) -> (ty::TraitRef<'tcx>, Vec>) { + let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); + let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); + let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = + super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); + + let predicates = selcx.tcx().predicates_of(impl_def_id); + let predicates = predicates.instantiate(selcx.tcx(), impl_substs); + let Normalized { value: predicates, obligations: normalization_obligations2 } = + super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); + let impl_obligations = + predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates); + + let impl_obligations: Vec<_> = impl_obligations + .into_iter() + .chain(normalization_obligations1) + .chain(normalization_obligations2) + .collect(); + + (impl_trait_ref, impl_obligations) +} + +/// See [`super::obligations_for_generics`]. +pub fn predicates_for_generics<'tcx>( + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + generic_bounds: &ty::InstantiatedPredicates<'tcx>, +) -> Vec> { + debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); + + generic_bounds + .predicates + .iter() + .map(|&predicate| Obligation { + cause: cause.clone(), + recursion_depth, + param_env, + predicate, + }) + .collect() +} + +pub fn predicate_for_trait_ref<'tcx>( + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + recursion_depth: usize, +) -> PredicateObligation<'tcx> { + Obligation { + cause, + param_env, + recursion_depth, + predicate: trait_ref.without_const().to_predicate(), + } +} + +pub fn predicate_for_trait_def( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + trait_def_id: DefId, + recursion_depth: usize, + self_ty: Ty<'tcx>, + params: &[GenericArg<'tcx>], +) -> PredicateObligation<'tcx> { + let trait_ref = + ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) }; + predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) +} + +/// Casts a trait reference into a reference to one of its super +/// traits; returns `None` if `target_trait_def_id` is not a +/// supertrait. +pub fn upcast_choices( + tcx: TyCtxt<'tcx>, + source_trait_ref: ty::PolyTraitRef<'tcx>, + target_trait_def_id: DefId, +) -> Vec> { + if source_trait_ref.def_id() == target_trait_def_id { + return vec![source_trait_ref]; // Shortcut the most common case. + } + + supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() +} + +/// Given a trait `trait_ref`, returns the number of vtable entries +/// that come from `trait_ref`, excluding its supertraits. Used in +/// computing the vtable base for an upcast trait of a trait object. +pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { + let mut entries = 0; + // Count number of methods and add them to the total offset. + // Skip over associated types and constants. + for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() { + if trait_item.kind == ty::AssocKind::Method { + entries += 1; + } + } + entries +} + +/// Given an upcast trait object described by `object`, returns the +/// index of the method `method_def_id` (which should be part of +/// `object.upcast_trait_ref`) within the vtable for `object`. +pub fn get_vtable_index_of_object_method( + tcx: TyCtxt<'tcx>, + object: &super::VtableObjectData<'tcx, N>, + method_def_id: DefId, +) -> usize { + // Count number of methods preceding the one we are selecting and + // add them to the total offset. + // Skip over associated types and constants. + let mut entries = object.vtable_base; + for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() { + if trait_item.def_id == method_def_id { + // The item with the ID we were given really ought to be a method. + assert_eq!(trait_item.kind, ty::AssocKind::Method); + return entries; + } + if trait_item.kind == ty::AssocKind::Method { + entries += 1; + } + } + + bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); +} + +pub fn closure_trait_ref_and_return_type( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyFnSig<'tcx>, + tuple_arguments: TupleArgumentsFlag, +) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { + let arguments_tuple = match tuple_arguments { + TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], + TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), + }; + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), + }; + ty::Binder::bind((trait_ref, sig.skip_binder().output())) +} + +pub fn generator_trait_ref_and_outputs( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyGenSig<'tcx>, +) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), + }; + ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) +} + +pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool { + match tcx.hir().as_local_hir_id(node_item_def_id) { + Some(hir_id) => { + let item = tcx.hir().expect_item(hir_id); + if let hir::ItemKind::Impl { defaultness, .. } = item.kind { + defaultness.is_default() + } else { + false + } + } + None => tcx.impl_defaultness(node_item_def_id).is_default(), + } +} + +pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { + assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id()) +} + +pub enum TupleArgumentsFlag { + Yes, + No, +} diff --git a/src/librustc_infer/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs similarity index 99% rename from src/librustc_infer/traits/wf.rs rename to src/librustc_trait_selection/traits/wf.rs index 980a3f0478134..b69c5bdce2abc 100644 --- a/src/librustc_infer/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; 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_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/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_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 6bc29d0493e68..e8d06ca3107f9 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/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" } 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 3720b74d92e07..8c43f6c9510a3 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 bf3511a26143c..b1ddd8ecc8a64 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 aa39a191b3df6..f82e00aa06c7a 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]