diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
41 files changed, 19278 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs new file mode 100644 index 00000000000..02eefe56223 --- /dev/null +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -0,0 +1,233 @@ +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{self, TraitEngine}; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ToPredicate, TypeFoldable}; +use rustc_session::DiagnosticMessageId; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::Span; + +#[derive(Copy, Clone, Debug)] +pub enum AutoderefKind { + Builtin, + Overloaded, +} + +struct AutoderefSnapshot<'tcx> { + at_start: bool, + reached_recursion_limit: bool, + steps: Vec<(Ty<'tcx>, AutoderefKind)>, + cur_ty: Ty<'tcx>, + obligations: Vec<traits::PredicateObligation<'tcx>>, +} + +pub struct Autoderef<'a, 'tcx> { + // Meta infos: + infcx: &'a InferCtxt<'a, 'tcx>, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + + // Current state: + state: AutoderefSnapshot<'tcx>, + + // Configurations: + include_raw_pointers: bool, + silence_errors: bool, +} + +impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { + type Item = (Ty<'tcx>, usize); + + fn next(&mut self) -> Option<Self::Item> { + let tcx = self.infcx.tcx; + + debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty); + if self.state.at_start { + self.state.at_start = false; + debug!("autoderef stage #0 is {:?}", self.state.cur_ty); + return Some((self.state.cur_ty, 0)); + } + + // If we have reached the recursion limit, error gracefully. + if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) { + if !self.silence_errors { + report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty); + } + self.state.reached_recursion_limit = true; + return None; + } + + if self.state.cur_ty.is_ty_var() { + return None; + } + + // Otherwise, deref if type is derefable: + let (kind, new_ty) = + if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { + (AutoderefKind::Builtin, mt.ty) + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; + + if new_ty.references_error() { + return None; + } + + self.state.steps.push((self.state.cur_ty, kind)); + debug!( + "autoderef stage #{:?} is {:?} from {:?}", + self.step_count(), + new_ty, + (self.state.cur_ty, kind) + ); + self.state.cur_ty = new_ty; + + Some((self.state.cur_ty, self.step_count())) + } +} + +impl<'a, 'tcx> Autoderef<'a, 'tcx> { + pub fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + span: Span, + base_ty: Ty<'tcx>, + ) -> Autoderef<'a, 'tcx> { + Autoderef { + infcx, + span, + body_id, + param_env, + state: AutoderefSnapshot { + steps: vec![], + cur_ty: infcx.resolve_vars_if_possible(&base_ty), + obligations: vec![], + at_start: true, + reached_recursion_limit: false, + }, + include_raw_pointers: false, + silence_errors: false, + } + } + + fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { + debug!("overloaded_deref_ty({:?})", ty); + + let tcx = self.infcx.tcx; + + // <ty as Deref> + let trait_ref = TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let cause = traits::ObligationCause::misc(self.span, self.body_id); + + let obligation = traits::Obligation::new( + cause.clone(), + self.param_env, + trait_ref.without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + debug!("overloaded_deref_ty: cannot match obligation"); + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + self.param_env, + ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + Ident::with_dummy_span(sym::Target), + ), + cause, + ); + if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { + // This shouldn't happen, except for evaluate/fulfill mismatches, + // but that's not a reason for an ICE (`predicate_may_hold` is conservative + // by design). + debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); + return None; + } + let obligations = fulfillcx.pending_obligations(); + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); + self.state.obligations.extend(obligations); + + Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) + } + + /// Returns the final type we ended up with, which may be an inference + /// variable (we will resolve it first, if we want). + pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> { + if resolve { + self.infcx.resolve_vars_if_possible(&self.state.cur_ty) + } else { + self.state.cur_ty + } + } + + pub fn step_count(&self) -> usize { + self.state.steps.len() + } + + pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> { + self.state.obligations + } + + pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] { + &self.state.steps + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn reached_recursion_limit(&self) -> bool { + self.state.reached_recursion_limit + } + + /// also dereference through raw pointer types + /// e.g., assuming ptr_to_Foo is the type `*const Foo` + /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo] + /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo] + pub fn include_raw_pointers(mut self) -> Self { + self.include_raw_pointers = true; + self + } + + pub fn silence_errors(mut self) -> Self { + self.silence_errors = true; + self + } +} + +pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { + // We've reached the recursion limit, error gracefully. + let suggested_limit = tcx.sess.recursion_limit() * 2; + let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); + let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); + let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + struct_span_err!( + tcx.sess, + span, + E0055, + "reached the recursion limit while auto-dereferencing `{:?}`", + ty + ) + .span_label(span, "deref recursion limit reached") + .help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, tcx.crate_name, + )) + .emit(); + } +} diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs new file mode 100644 index 00000000000..4ec1b29bca4 --- /dev/null +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -0,0 +1,182 @@ +use crate::traits::query::outlives_bounds::InferCtxtExt as _; +use crate::traits::{self, TraitEngine, TraitEngineExt}; + +use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::traits::ObligationCause; +use rustc_middle::arena::ArenaAllocatable; +use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse}; +use rustc_middle::traits::query::Fallible; +use rustc_middle::ty::{self, Ty, TypeFoldable}; +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<T>( + &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).needs_infer() { + return ty.is_copy_modulo_regions(self.tcx.at(span), param_env); + } + + let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, 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<T>( + &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<K, R>( + &mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>> + where + K: TypeFoldable<'tcx>, + R: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>; +} + +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<K, R>( + &mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>> + where + K: TypeFoldable<'tcx>, + R: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, + { + 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/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs new file mode 100644 index 00000000000..b5882df4729 --- /dev/null +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -0,0 +1,34 @@ +//! 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-dev-guide]. +//! +//! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/ +//! +//! # 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)] +#![feature(or_patterns)] +#![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 tracing; +#[macro_use] +extern crate rustc_middle; + +pub mod autoderef; +pub mod infer; +pub mod opaque_types; +pub mod traits; diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs new file mode 100644 index 00000000000..379c976df69 --- /dev/null +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -0,0 +1,1284 @@ +use crate::infer::InferCtxtExt as _; +use crate::traits::{self, PredicateObligation}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lrc; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::Node; +use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; +use rustc_infer::infer::free_regions::FreeRegionRelations; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{self, InferCtxt, InferOk}; +use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::config::nightly_options; +use rustc_span::Span; + +pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>; + +/// Information about the opaque types whose values we +/// are inferring in this function (these are the `impl Trait` that +/// appear in the return type). +#[derive(Copy, Clone, Debug)] +pub struct OpaqueTypeDecl<'tcx> { + /// The opaque type (`ty::Opaque`) for this declaration. + pub opaque_type: Ty<'tcx>, + + /// The substitutions that we apply to the opaque type that this + /// `impl Trait` desugars to. e.g., if: + /// + /// fn foo<'a, 'b, T>() -> impl Trait<'a> + /// + /// winds up desugared to: + /// + /// type Foo<'x, X> = impl Trait<'x> + /// fn foo<'a, 'b, T>() -> Foo<'a, T> + /// + /// then `substs` would be `['a, T]`. + pub substs: SubstsRef<'tcx>, + + /// The span of this particular definition of the opaque type. So + /// for example: + /// + /// ``` + /// type Foo = impl Baz; + /// fn bar() -> Foo { + /// ^^^ This is the span we are looking for! + /// ``` + /// + /// In cases where the fn returns `(impl Trait, impl Trait)` or + /// other such combinations, the result is currently + /// over-approximated, but better than nothing. + pub definition_span: Span, + + /// The type variable that represents the value of the opaque type + /// that we require. In other words, after we compile this function, + /// we will be created a constraint like: + /// + /// Foo<'a, T> = ?C + /// + /// where `?C` is the value of this type variable. =) It may + /// naturally refer to the type and lifetime parameters in scope + /// in this function, though ultimately it should only reference + /// those that are arguments to `Foo` in the constraint above. (In + /// other words, `?C` should not include `'b`, even though it's a + /// lifetime parameter on `foo`.) + pub concrete_ty: Ty<'tcx>, + + /// Returns `true` if the `impl Trait` bounds include region bounds. + /// For example, this would be true for: + /// + /// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b + /// + /// but false for: + /// + /// fn foo<'c>() -> impl Trait<'c> + /// + /// unless `Trait` was declared like: + /// + /// trait Trait<'c>: 'c + /// + /// in which case it would be true. + /// + /// This is used during regionck to decide whether we need to + /// impose any additional constraints to ensure that region + /// variables in `concrete_ty` wind up being constrained to + /// something from `substs` (or, at minimum, things that outlive + /// the fn body). (Ultimately, writeback is responsible for this + /// check.) + pub has_required_region_bounds: bool, + + /// The origin of the opaque type. + pub origin: hir::OpaqueTyOrigin, +} + +/// Whether member constraints should be generated for all opaque types +pub enum GenerateMemberConstraints { + /// The default, used by typeck + WhenRequired, + /// The borrow checker needs member constraints in any case where we don't + /// have a `'static` bound. This is because the borrow checker has more + /// flexibility in the values of regions. For example, given `f<'a, 'b>` + /// the borrow checker can have an inference variable outlive `'a` and `'b`, + /// but not be equal to `'static`. + IfNoStaticBound, +} + +pub trait InferCtxtExt<'tcx> { + fn instantiate_opaque_types<T: TypeFoldable<'tcx>>( + &self, + parent_def_id: LocalDefId, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + value_span: Span, + ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>; + + fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>( + &self, + opaque_types: &OpaqueTypeMap<'tcx>, + free_region_relations: &FRR, + ); + + fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( + &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_defn: &OpaqueTypeDecl<'tcx>, + opaque_type_def_id: DefId, + first_own_region_index: usize, + ); + + /*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: + /// + /// impl Iterator<Item = impl Debug> + /// + /// this method would create two type variables, `?0` and `?1`. It would + /// return the type `?0` but also the obligations: + /// + /// ?0: Iterator<Item = ?1> + /// ?1: Debug + /// + /// Moreover, it returns a `OpaqueTypeMap` that would map `?0` to + /// info about the `impl Iterator<..>` type and `?1` to info about + /// the `impl Debug` type. + /// + /// # Parameters + /// + /// - `parent_def_id` -- the `DefId` of the function in which the opaque type + /// is defined + /// - `body_id` -- the body-id with which the resulting obligations should + /// be associated + /// - `param_env` -- the in-scope parameter environment to be used for + /// obligations + /// - `value` -- the value within which we are instantiating opaque types + /// - `value_span` -- the span where the value came from, used in error reporting + fn instantiate_opaque_types<T: TypeFoldable<'tcx>>( + &self, + parent_def_id: LocalDefId, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + value_span: Span, + ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { + debug!( + "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \ + param_env={:?}, value_span={:?})", + value, parent_def_id, body_id, param_env, value_span, + ); + let mut instantiator = Instantiator { + infcx: self, + parent_def_id, + body_id, + param_env, + value_span, + opaque_types: Default::default(), + obligations: vec![], + }; + let value = instantiator.instantiate_opaque_types_in_map(value); + InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations } + } + + /// Given the map `opaque_types` containing the opaque + /// `impl Trait` types whose underlying, hidden types are being + /// inferred, this method adds constraints to the regions + /// appearing in those underlying hidden types to ensure that they + /// at least do not refer to random scopes within the current + /// function. These constraints are not (quite) sufficient to + /// guarantee that the regions are actually legal values; that + /// final condition is imposed after region inference is done. + /// + /// # The Problem + /// + /// Let's work through an example to explain how it works. Assume + /// the current function is as follows: + /// + /// ```text + /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>) + /// ``` + /// + /// Here, we have two `impl Trait` types whose values are being + /// inferred (the `impl Bar<'a>` and the `impl + /// Bar<'b>`). Conceptually, this is sugar for a setup where we + /// define underlying opaque types (`Foo1`, `Foo2`) and then, in + /// the return type of `foo`, we *reference* those definitions: + /// + /// ```text + /// type Foo1<'x> = impl Bar<'x>; + /// type Foo2<'x> = impl Bar<'x>; + /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } + /// // ^^^^ ^^ + /// // | | + /// // | substs + /// // def_id + /// ``` + /// + /// As indicating in the comments above, each of those references + /// is (in the compiler) basically a substitution (`substs`) + /// applied to the type of a suitable `def_id` (which identifies + /// `Foo1` or `Foo2`). + /// + /// Now, at this point in compilation, what we have done is to + /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with + /// fresh inference variables C1 and C2. We wish to use the values + /// of these variables to infer the underlying types of `Foo1` and + /// `Foo2`. That is, this gives rise to higher-order (pattern) unification + /// constraints like: + /// + /// ```text + /// for<'a> (Foo1<'a> = C1) + /// for<'b> (Foo1<'b> = C2) + /// ``` + /// + /// For these equation to be satisfiable, the types `C1` and `C2` + /// can only refer to a limited set of regions. For example, `C1` + /// can only refer to `'static` and `'a`, and `C2` can only refer + /// to `'static` and `'b`. The job of this function is to impose that + /// constraint. + /// + /// Up to this point, C1 and C2 are basically just random type + /// inference variables, and hence they may contain arbitrary + /// regions. In fact, it is fairly likely that they do! Consider + /// this possible definition of `foo`: + /// + /// ```text + /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) { + /// (&*x, &*y) + /// } + /// ``` + /// + /// Here, the values for the concrete types of the two impl + /// traits will include inference variables: + /// + /// ```text + /// &'0 i32 + /// &'1 i32 + /// ``` + /// + /// Ordinarily, the subtyping rules would ensure that these are + /// sufficiently large. But since `impl Bar<'a>` isn't a specific + /// type per se, we don't get such constraints by default. This + /// is where this function comes into play. It adds extra + /// constraints to ensure that all the regions which appear in the + /// inferred type are regions that could validly appear. + /// + /// This is actually a bit of a tricky constraint in general. We + /// want to say that each variable (e.g., `'0`) can only take on + /// values that were supplied as arguments to the opaque type + /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in + /// scope. We don't have a constraint quite of this kind in the current + /// region checker. + /// + /// # The Solution + /// + /// We generally prefer to make `<=` constraints, since they + /// integrate best into the region solver. To do that, we find the + /// "minimum" of all the arguments that appear in the substs: that + /// is, some region which is less than all the others. In the case + /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after + /// all). Then we apply that as a least bound to the variables + /// (e.g., `'a <= '0`). + /// + /// In some cases, there is no minimum. Consider this example: + /// + /// ```text + /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... } + /// ``` + /// + /// Here we would report a more complex "in constraint", like `'r + /// in ['a, 'b, 'static]` (where `'r` is some region appearing in + /// the hidden type). + /// + /// # Constrain regions, not the hidden concrete type + /// + /// Note that generating constraints on each region `Rc` is *not* + /// the same as generating an outlives constraint on `Tc` iself. + /// For example, if we had a function like this: + /// + /// ```rust + /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> { + /// (x, y) + /// } + /// + /// // Equivalent to: + /// type FooReturn<'a, T> = impl Foo<'a>; + /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. } + /// ``` + /// + /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0` + /// is an inference variable). If we generated a constraint that + /// `Tc: 'a`, then this would incorrectly require that `T: 'a` -- + /// but this is not necessary, because the opaque type we + /// create will be allowed to reference `T`. So we only generate a + /// constraint that `'0: 'a`. + /// + /// # The `free_region_relations` parameter + /// + /// The `free_region_relations` argument is used to find the + /// "minimum" of the regions supplied to a given opaque type. + /// It must be a relation that can answer whether `'a <= 'b`, + /// where `'a` and `'b` are regions that appear in the "substs" + /// for the opaque type references (the `<'a>` in `Foo1<'a>`). + /// + /// Note that we do not impose the constraints based on the + /// generic regions from the `Foo1` definition (e.g., `'x`). This + /// is because the constraints we are imposing here is basically + /// the concern of the one generating the constraining type C1, + /// which is the current function. It also means that we can + /// take "implied bounds" into account in some cases: + /// + /// ```text + /// trait SomeTrait<'a, 'b> { } + /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. } + /// ``` + /// + /// Here, the fact that `'b: 'a` is known only because of the + /// implied bounds from the `&'a &'b u32` parameter, and is not + /// "inherent" to the opaque type definition. + /// + /// # Parameters + /// + /// - `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. + fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>( + &self, + opaque_types: &OpaqueTypeMap<'tcx>, + free_region_relations: &FRR, + ) { + debug!("constrain_opaque_types()"); + + for (&def_id, opaque_defn) in opaque_types { + self.constrain_opaque_type( + def_id, + opaque_defn, + GenerateMemberConstraints::WhenRequired, + free_region_relations, + ); + } + } + + /// See `constrain_opaque_types` for documentation. + fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( + &self, + def_id: DefId, + opaque_defn: &OpaqueTypeDecl<'tcx>, + mode: GenerateMemberConstraints, + free_region_relations: &FRR, + ) { + debug!("constrain_opaque_type()"); + debug!("constrain_opaque_type: def_id={:?}", def_id); + debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn); + + let tcx = self.tcx; + + let concrete_ty = self.resolve_vars_if_possible(&opaque_defn.concrete_ty); + + debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); + + let first_own_region = match opaque_defn.origin { + hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { + // We lower + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // For these types we onlt iterate over `'l0..lm` below. + tcx.generics_of(def_id).parent_count + } + // These opaque type inherit all lifetime parameters from their + // parent, so we have to check them all. + hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => 0, + }; + + let span = tcx.def_span(def_id); + + // If there are required region bounds, we can use them. + if opaque_defn.has_required_region_bounds { + let predicates_of = tcx.predicates_of(def_id); + debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,); + let bounds = predicates_of.instantiate(tcx, opaque_defn.substs); + debug!("constrain_opaque_type: bounds={:#?}", bounds); + let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs); + + let required_region_bounds = + required_region_bounds(tcx, opaque_type, bounds.predicates.into_iter()); + debug_assert!(!required_region_bounds.is_empty()); + + for required_region in required_region_bounds { + concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), + }); + } + if let GenerateMemberConstraints::IfNoStaticBound = mode { + self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region); + } + return; + } + + // There were no `required_region_bounds`, + // so we have to search for a `least_region`. + // Go through all the regions used as arguments to the + // opaque type. These are the parameters to the opaque + // type; so in our example above, `substs` would contain + // `['a]` for the first impl trait and `'b` for the + // second. + let mut least_region = None; + + for subst_arg in &opaque_defn.substs[first_own_region..] { + let subst_region = match subst_arg.unpack() { + GenericArgKind::Lifetime(r) => r, + GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue, + }; + + // Compute the least upper bound of it with the other regions. + debug!("constrain_opaque_types: least_region={:?}", least_region); + debug!("constrain_opaque_types: subst_region={:?}", subst_region); + match least_region { + None => least_region = Some(subst_region), + Some(lr) => { + if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) { + // keep the current least region + } else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) { + // switch to `subst_region` + least_region = Some(subst_region); + } else { + // There are two regions (`lr` and + // `subst_region`) which are not relatable. We + // can't find a best choice. Therefore, + // instead of creating a single bound like + // `'r: 'a` (which is our preferred choice), + // we will create a "in bound" like `'r in + // ['a, 'b, 'c]`, where `'a..'c` are the + // regions that appear in the impl trait. + + // For now, enforce a feature gate outside of async functions. + self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region); + + return self.generate_member_constraint( + concrete_ty, + opaque_defn, + def_id, + first_own_region, + ); + } + } + } + } + + let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); + debug!("constrain_opaque_types: least_region={:?}", least_region); + + if let GenerateMemberConstraints::IfNoStaticBound = mode { + if least_region != tcx.lifetimes.re_static { + self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region); + } + } + concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), + }); + } + + /// As a fallback, we sometimes generate an "in constraint". For + /// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be + /// related, we would generate a constraint `'r in ['a, 'b, + /// 'static]` for each region `'r` that appears in the hidden type + /// (i.e., it must be equal to `'a`, `'b`, or `'static`). + /// + /// `conflict1` and `conflict2` are the two region bounds that we + /// detected which were unrelated. They are used for diagnostics. + fn generate_member_constraint( + &self, + concrete_ty: Ty<'tcx>, + opaque_defn: &OpaqueTypeDecl<'tcx>, + opaque_type_def_id: DefId, + first_own_region: usize, + ) { + // Create the set of choice regions: each region in the hidden + // type can be equal to any of the region parameters of the + // opaque type definition. + let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new( + opaque_defn.substs[first_own_region..] + .iter() + .filter_map(|arg| match arg.unpack() { + GenericArgKind::Lifetime(r) => Some(r), + GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, + }) + .chain(std::iter::once(self.tcx.lifetimes.re_static)) + .collect(), + ); + + concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + op: |r| { + self.member_constraint( + opaque_type_def_id, + opaque_defn.definition_span, + concrete_ty, + r, + &choice_regions, + ) + }, + }); + } + + /// Member constraints are presently feature-gated except for + /// async-await. We expect to lift this once we've had a bit more + /// time. + fn member_constraint_feature_gate( + &self, + opaque_defn: &OpaqueTypeDecl<'tcx>, + opaque_type_def_id: DefId, + conflict1: ty::Region<'tcx>, + conflict2: ty::Region<'tcx>, + ) -> bool { + // If we have `#![feature(member_constraints)]`, no problems. + if self.tcx.features().member_constraints { + return false; + } + + let span = self.tcx.def_span(opaque_type_def_id); + + // Without a feature-gate, we only generate member-constraints for async-await. + let context_name = match opaque_defn.origin { + // No feature-gate required for `async fn`. + hir::OpaqueTyOrigin::AsyncFn => return false, + + // Otherwise, generate the label we'll use in the error message. + hir::OpaqueTyOrigin::Binding + | hir::OpaqueTyOrigin::FnReturn + | hir::OpaqueTyOrigin::Misc => "impl Trait", + }; + let msg = format!("ambiguous lifetime bound in `{}`", context_name); + let mut err = self.tcx.sess.struct_span_err(span, &msg); + + let conflict1_name = conflict1.to_string(); + let conflict2_name = conflict2.to_string(); + let label_owned; + let label = match (&*conflict1_name, &*conflict2_name) { + ("'_", "'_") => "the elided lifetimes here do not outlive one another", + _ => { + label_owned = format!( + "neither `{}` nor `{}` outlives the other", + conflict1_name, conflict2_name, + ); + &label_owned + } + }; + err.span_label(span, label); + + if nightly_options::is_nightly_build() { + err.help("add #![feature(member_constraints)] to the crate attributes to enable"); + } + + err.emit(); + true + } + + /// Given the fully resolved, instantiated type for an opaque + /// type, i.e., the value of an inference variable like C1 or C2 + /// (*), computes the "definition type" for an opaque type + /// definition -- that is, the inferred value of `Foo1<'x>` or + /// `Foo2<'x>` that we would conceptually use in its definition: + /// + /// type Foo1<'x> = impl Bar<'x> = AAA; <-- this type AAA + /// type Foo2<'x> = impl Bar<'x> = BBB; <-- or this type BBB + /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } + /// + /// Note that these values are defined in terms of a distinct set of + /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main + /// purpose of this function is to do that translation. + /// + /// (*) C1 and C2 were introduced in the comments on + /// `constrain_opaque_types`. Read that comment for more context. + /// + /// # Parameters + /// + /// - `def_id`, the `impl Trait` type + /// - `substs`, the substs used to instantiate this opaque type + /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of + /// `opaque_defn.concrete_ty` + fn infer_opaque_definition_from_instantiation( + &self, + def_id: DefId, + substs: SubstsRef<'tcx>, + instantiated_ty: Ty<'tcx>, + span: Span, + ) -> Ty<'tcx> { + debug!( + "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})", + def_id, instantiated_ty + ); + + // Use substs to build up a reverse map from regions to their + // identity mappings. This is necessary because of `impl + // Trait` lifetimes are computed by replacing existing + // lifetimes with 'static and remapping only those used in the + // `impl Trait` return type, resulting in the parameters + // shifting. + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); + let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = + substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); + + // Convert the type from the function into a type valid outside + // the function, by replacing invalid regions with 'static, + // after producing an error for each of them. + let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new( + self.tcx, + self.is_tainted_by_errors(), + def_id, + map, + instantiated_ty, + span, + )); + debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty); + + definition_ty + } +} + +// 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 +// ensure all regions outlive the given bound so that we don't end up with, +// say, `ReVar` appearing in a return type and causing ICEs when other +// functions end up with region constraints involving regions from other +// functions. +// +// We also cannot use `for_each_free_region` because for closures it includes +// the regions parameters from the enclosing item. +// +// We ignore any type parameters because impl trait values are assumed to +// capture all the in-scope type parameters. +struct ConstrainOpaqueTypeRegionVisitor<OP> { + op: OP, +} + +impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP> +where + OP: FnMut(ty::Region<'tcx>), +{ + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { + t.as_ref().skip_binder().visit_with(self); + false // keep visiting + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match *r { + // ignore bound regions, keep visiting + ty::ReLateBound(_, _) => false, + _ => { + (self.op)(r); + false + } + } + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + // We're only interested in types involving regions + if !ty.flags.intersects(ty::TypeFlags::HAS_FREE_REGIONS) { + return false; // keep visiting + } + + match ty.kind { + ty::Closure(_, ref substs) => { + // Skip lifetime parameters of the enclosing item(s) + + for upvar_ty in substs.as_closure().upvar_tys() { + upvar_ty.visit_with(self); + } + + substs.as_closure().sig_as_fn_ptr_ty().visit_with(self); + } + + ty::Generator(_, ref substs, _) => { + // Skip lifetime parameters of the enclosing item(s) + // Also skip the witness type, because that has no free regions. + + for upvar_ty in substs.as_generator().upvar_tys() { + upvar_ty.visit_with(self); + } + + substs.as_generator().return_ty().visit_with(self); + substs.as_generator().yield_ty().visit_with(self); + substs.as_generator().resume_ty().visit_with(self); + } + _ => { + ty.super_visit_with(self); + } + } + + false + } +} + +struct ReverseMapper<'tcx> { + tcx: TyCtxt<'tcx>, + + /// If errors have already been reported in this fn, we suppress + /// our own errors because they are sometimes derivative. + tainted_by_errors: bool, + + opaque_type_def_id: DefId, + map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, + map_missing_regions_to_empty: bool, + + /// initially `Some`, set to `None` once error has been reported + hidden_ty: Option<Ty<'tcx>>, + + /// Span of function being checked. + span: Span, +} + +impl ReverseMapper<'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + tainted_by_errors: bool, + opaque_type_def_id: DefId, + map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, + hidden_ty: Ty<'tcx>, + span: Span, + ) -> Self { + Self { + tcx, + tainted_by_errors, + opaque_type_def_id, + map, + map_missing_regions_to_empty: false, + hidden_ty: Some(hidden_ty), + span, + } + } + + fn fold_kind_mapping_missing_regions_to_empty( + &mut self, + kind: GenericArg<'tcx>, + ) -> GenericArg<'tcx> { + assert!(!self.map_missing_regions_to_empty); + self.map_missing_regions_to_empty = true; + let kind = kind.fold_with(self); + self.map_missing_regions_to_empty = false; + kind + } + + fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.map_missing_regions_to_empty); + kind.fold_with(self) + } +} + +impl TypeFolder<'tcx> for ReverseMapper<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r { + // Ignore bound regions and `'static` regions that appear in the + // type, we only need to remap regions that reference lifetimes + // from the function declaraion. + // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) | ty::ReStatic => return r, + + // If regions have been erased (by writeback), don't try to unerase + // them. + ty::ReErased => return r, + + // The regions that we expect from borrow checking. + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} + + ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { + // All of the regions in the type should either have been + // erased by writeback, or mapped back to named regions by + // borrow checking. + bug!("unexpected region kind in opaque type: {:?}", r); + } + } + + let generics = self.tcx().generics_of(self.opaque_type_def_id); + match self.map.get(&r.into()).map(|k| k.unpack()) { + Some(GenericArgKind::Lifetime(r1)) => r1, + Some(u) => panic!("region mapped to unexpected kind: {:?}", u), + None if self.map_missing_regions_to_empty || self.tainted_by_errors => { + self.tcx.lifetimes.re_root_empty + } + None if generics.parent.is_some() => { + if let Some(hidden_ty) = self.hidden_ty.take() { + unexpected_hidden_region_diagnostic( + self.tcx, + self.tcx.def_span(self.opaque_type_def_id), + hidden_ty, + r, + ) + .emit(); + } + self.tcx.lifetimes.re_root_empty + } + None => { + self.tcx + .sess + .struct_span_err(self.span, "non-defining opaque type use in defining scope") + .span_label( + self.span, + format!( + "lifetime `{}` is part of concrete type but not used in \ + parameter list of the `impl Trait` type alias", + r + ), + ) + .emit(); + + self.tcx().lifetimes.re_static + } + } + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind { + ty::Closure(def_id, substs) => { + // I am a horrible monster and I pray for death. When + // we encounter a closure here, it is always a closure + // from within the function that we are currently + // type-checking -- one that is now being encapsulated + // in an opaque type. Ideally, we would + // go through the types/lifetimes that it references + // and treat them just like we would any other type, + // which means we would error out if we find any + // reference to a type/region that is not in the + // "reverse map". + // + // **However,** in the case of closures, there is a + // somewhat subtle (read: hacky) consideration. The + // problem is that our closure types currently include + // all the lifetime parameters declared on the + // enclosing function, even if they are unused by the + // closure itself. We can't readily filter them out, + // so here we replace those values with `'empty`. This + // can't really make a difference to the rest of the + // compiler; those regions are ignored for the + // outlives relation, and hence don't affect trait + // selection or auto traits, and they are erased + // during codegen. + + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_mapping_missing_regions_to_empty(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_closure(def_id, substs) + } + + ty::Generator(def_id, substs, movability) => { + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_mapping_missing_regions_to_empty(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_generator(def_id, substs, movability) + } + + ty::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ty.into()).map(|k| k.unpack()) { + // Found it in the substitution list; replace with the parameter from the + // opaque type. + Some(GenericArgKind::Type(t1)) => t1, + Some(u) => panic!("type mapped to unexpected kind: {:?}", u), + None => { + self.tcx + .sess + .struct_span_err( + self.span, + &format!( + "type parameter `{}` is part of concrete type but not \ + used in parameter list for the `impl Trait` type alias", + ty + ), + ) + .emit(); + + self.tcx().ty_error() + } + } + } + + _ => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + trace!("checking const {:?}", ct); + // Find a const parameter + match ct.val { + ty::ConstKind::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ct.into()).map(|k| k.unpack()) { + // Found it in the substitution list, replace with the parameter from the + // opaque type. + Some(GenericArgKind::Const(c1)) => c1, + Some(u) => panic!("const mapped to unexpected kind: {:?}", u), + None => { + self.tcx + .sess + .struct_span_err( + self.span, + &format!( + "const parameter `{}` is part of concrete type but not \ + used in parameter list for the `impl Trait` type alias", + ct + ), + ) + .emit(); + + self.tcx().const_error(ct.ty) + } + } + } + + _ => ct, + } + } +} + +struct Instantiator<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + parent_def_id: LocalDefId, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value_span: Span, + opaque_types: OpaqueTypeMap<'tcx>, + obligations: Vec<PredicateObligation<'tcx>>, +} + +impl<'a, 'tcx> Instantiator<'a, 'tcx> { + fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T { + debug!("instantiate_opaque_types_in_map(value={:?})", value); + let tcx = self.infcx.tcx; + value.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| { + if ty.references_error() { + return tcx.ty_error(); + } else if let ty::Opaque(def_id, substs) = ty.kind { + // Check that this is `impl Trait` type is + // declared by `parent_def_id` -- i.e., one whose + // value we are inferring. At present, this is + // always true during the first phase of + // type-check, but not always true later on during + // NLL. Once we support named opaque types more fully, + // this same scenario will be able to arise during all phases. + // + // Here is an example using type alias `impl Trait` + // that indicates the distinction we are checking for: + // + // ```rust + // mod a { + // pub type Foo = impl Iterator; + // pub fn make_foo() -> Foo { .. } + // } + // + // mod b { + // fn foo() -> a::Foo { a::make_foo() } + // } + // ``` + // + // Here, the return type of `foo` references a + // `Opaque` indeed, but not one whose value is + // presently being inferred. You can get into a + // similar situation with closure return types + // today: + // + // ```rust + // fn foo() -> impl Iterator { .. } + // fn bar() { + // let x = || foo(); // returns the Opaque assoc with `foo` + // } + // ``` + if let Some(def_id) = def_id.as_local() { + let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let parent_def_id = self.parent_def_id; + let def_scope_default = || { + let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id); + parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id) + }; + let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) { + Some(Node::Item(item)) => match item.kind { + // Anonymous `impl Trait` + hir::ItemKind::OpaqueTy(hir::OpaqueTy { + impl_trait_fn: Some(parent), + origin, + .. + }) => (parent == self.parent_def_id.to_def_id(), origin), + // Named `type Foo = impl Bar;` + hir::ItemKind::OpaqueTy(hir::OpaqueTy { + impl_trait_fn: None, + origin, + .. + }) => ( + may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id), + origin, + ), + _ => (def_scope_default(), hir::OpaqueTyOrigin::Misc), + }, + _ => bug!( + "expected item, found {}", + tcx.hir().node_to_string(opaque_hir_id), + ), + }; + if in_definition_scope { + return self.fold_opaque_ty(ty, def_id.to_def_id(), substs, origin); + } + + debug!( + "instantiate_opaque_types_in_map: \ + encountered opaque outside its definition scope \ + def_id={:?}", + def_id, + ); + } + } + + ty + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }) + } + + fn fold_opaque_ty( + &mut self, + ty: Ty<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + origin: hir::OpaqueTyOrigin, + ) -> Ty<'tcx> { + let infcx = self.infcx; + let tcx = infcx.tcx; + + debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs); + + // Use the same type variable if the exact same opaque type appears more + // than once in the return type (e.g., if it's passed to a type alias). + if let Some(opaque_defn) = self.opaque_types.get(&def_id) { + debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); + return opaque_defn.concrete_ty; + } + let span = tcx.def_span(def_id); + debug!("fold_opaque_ty {:?} {:?}", self.value_span, span); + let ty_var = infcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + + let predicates_of = tcx.predicates_of(def_id); + debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,); + let bounds = predicates_of.instantiate(tcx, substs); + + let param_env = tcx.param_env(def_id); + let InferOk { value: bounds, obligations } = + infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, &bounds); + self.obligations.extend(obligations); + + debug!("instantiate_opaque_types: bounds={:?}", bounds); + + let required_region_bounds = + required_region_bounds(tcx, ty, bounds.predicates.iter().cloned()); + debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds); + + // Make sure that we are in fact defining the *entire* type + // (e.g., `type Foo<T: Bound> = impl Bar;` needs to be + // defined by a function like `fn foo<T: Bound>() -> Foo<T>`). + debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,); + debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),); + + // Ideally, we'd get the span where *this specific `ty` came + // from*, but right now we just use the span from the overall + // value being folded. In simple cases like `-> impl Foo`, + // these are the same span, but not in cases like `-> (impl + // Foo, impl Bar)`. + let definition_span = self.value_span; + + self.opaque_types.insert( + def_id, + OpaqueTypeDecl { + opaque_type: ty, + substs, + definition_span, + concrete_ty: ty_var, + has_required_region_bounds: !required_region_bounds.is_empty(), + origin, + }, + ); + debug!("instantiate_opaque_types: ty_var={:?}", ty_var); + + for predicate in &bounds.predicates { + if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() { + if projection.ty.references_error() { + // No point on adding these obligations since there's a type error involved. + return ty_var; + } + } + } + + self.obligations.reserve(bounds.predicates.len()); + for predicate in bounds.predicates { + // Change the predicate to refer to the type variable, + // which will be the concrete type instead of the opaque type. + // This also instantiates nested instances of `impl Trait`. + let predicate = self.instantiate_opaque_types_in_map(&predicate); + + let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType); + + // Require that the predicate holds for the concrete type. + debug!("instantiate_opaque_types: predicate={:?}", predicate); + self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate)); + } + + ty_var + } +} + +/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`. +/// +/// Example: +/// ```rust +/// pub mod foo { +/// pub mod bar { +/// pub trait Bar { .. } +/// +/// pub type Baz = impl Bar; +/// +/// fn f1() -> Baz { .. } +/// } +/// +/// fn f2() -> bar::Baz { .. } +/// } +/// ``` +/// +/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`), +/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`. +/// For the above example, this function returns `true` for `f1` and `false` for `f2`. +pub fn may_define_opaque_type( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + opaque_hir_id: hir::HirId, +) -> bool { + let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + // Named opaque types can be defined by any siblings or children of siblings. + let scope = tcx.hir().get_defining_scope(opaque_hir_id); + // We walk up the node tree until we hit the root or the scope of the opaque type. + while hir_id != scope && hir_id != hir::CRATE_HIR_ID { + hir_id = tcx.hir().get_parent_item(hir_id); + } + // Syntactically, we are allowed to define the concrete type if: + let res = hir_id == scope; + trace!( + "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}", + tcx.hir().find(hir_id), + tcx.hir().get(opaque_hir_id), + res + ); + res +} + +/// Given a set of predicates that apply to an object type, returns +/// the region bounds that the (erased) `Self` type must +/// outlive. Precisely *because* the `Self` type is erased, the +/// parameter `erased_self_ty` must be supplied to indicate what type +/// has been used to represent `Self` in the predicates +/// themselves. This should really be a unique type; `FreshTy(0)` is a +/// popular choice. +/// +/// N.B., in some cases, particularly around higher-ranked bounds, +/// this function returns a kind of conservative approximation. +/// That is, all regions returned by this function are definitely +/// required, but there may be other region bounds that are not +/// returned, as well as requirements like `for<'a> T: 'a`. +/// +/// Requires that trait definitions have been processed so that we can +/// elaborate predicates and walk supertraits. +crate fn required_region_bounds( + tcx: TyCtxt<'tcx>, + erased_self_ty: Ty<'tcx>, + predicates: impl Iterator<Item = ty::Predicate<'tcx>>, +) -> Vec<ty::Region<'tcx>> { + debug!("required_region_bounds(erased_self_ty={:?})", erased_self_ty); + + assert!(!erased_self_ty.has_escaping_bound_vars()); + + traits::elaborate_predicates(tcx, predicates) + .filter_map(|obligation| { + debug!("required_region_bounds(obligation={:?})", obligation); + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Projection(..) + | ty::PredicateAtom::Trait(..) + | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::RegionOutlives(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => None, + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == &erased_self_ty && !r.has_escaping_bound_vars() { + Some(*r) + } else { + None + } + } + } + }) + .collect() +} diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs new file mode 100644 index 00000000000..fa3d0241998 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -0,0 +1,881 @@ +//! Support code for rustdoc and external tools. +//! You really don't want to be using this unless you need to. + +use super::*; + +use crate::infer::region_constraints::{Constraint, RegionConstraintData}; +use crate::infer::InferCtxt; +use rustc_middle::ty::fold::TypeFolder; +use rustc_middle::ty::{Region, RegionVid}; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + +use std::collections::hash_map::Entry; +use std::collections::VecDeque; + +// FIXME(twk): this is obviously not nice to duplicate like that +#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] +pub enum RegionTarget<'tcx> { + Region(Region<'tcx>), + RegionVid(RegionVid), +} + +#[derive(Default, Debug, Clone)] +pub struct RegionDeps<'tcx> { + larger: FxHashSet<RegionTarget<'tcx>>, + smaller: FxHashSet<RegionTarget<'tcx>>, +} + +pub enum AutoTraitResult<A> { + ExplicitImpl, + PositiveImpl(A), + NegativeImpl, +} + +impl<A> AutoTraitResult<A> { + fn is_auto(&self) -> bool { + match *self { + AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, + _ => false, + } + } +} + +pub struct AutoTraitInfo<'cx> { + pub full_user_env: ty::ParamEnv<'cx>, + pub region_data: RegionConstraintData<'cx>, + pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>, +} + +pub struct AutoTraitFinder<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> AutoTraitFinder<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + AutoTraitFinder { tcx } + } + + /// Makes a best effort to determine whether and under which conditions an auto trait is + /// implemented for a type. For example, if you have + /// + /// ``` + /// struct Foo<T> { data: Box<T> } + /// ``` + /// + /// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type). + /// The analysis attempts to account for custom impls as well as other complex cases. This + /// result is intended for use by rustdoc and other such consumers. + /// + /// (Note that due to the coinductive nature of Send, the full and correct result is actually + /// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field + /// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send. + /// But this is often not the best way to present to the user.) + /// + /// Warning: The API should be considered highly unstable, and it may be refactored or removed + /// in the future. + pub fn find_auto_trait_generics<A>( + &self, + ty: Ty<'tcx>, + orig_env: ty::ParamEnv<'tcx>, + trait_did: DefId, + auto_trait_callback: impl Fn(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A, + ) -> AutoTraitResult<A> { + let tcx = self.tcx; + + let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]) }; + + let trait_pred = ty::Binder::bind(trait_ref); + + let bail_out = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::with_negative(&infcx, true); + let result = selcx.select(&Obligation::new( + ObligationCause::dummy(), + orig_env, + trait_pred.to_poly_trait_predicate(), + )); + + match result { + Ok(Some(ImplSource::ImplSourceUserDefined(_))) => { + debug!( + "find_auto_trait_generics({:?}): \ + manual impl found, bailing out", + trait_ref + ); + true + } + _ => false, + } + }); + + // If an explicit impl exists, it always takes priority over an auto impl + if bail_out { + return AutoTraitResult::ExplicitImpl; + } + + tcx.infer_ctxt().enter(|infcx| { + let mut fresh_preds = FxHashSet::default(); + + // Due to the way projections are handled by SelectionContext, we need to run + // evaluate_predicates twice: once on the original param env, and once on the result of + // the first evaluate_predicates call. + // + // The problem is this: most of rustc, including SelectionContext and traits::project, + // are designed to work with a concrete usage of a type (e.g., Vec<u8> + // fn<T>() { Vec<T> }. This information will generally never change - given + // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'. + // If we're unable to prove that 'T' implements a particular trait, we're done - + // there's nothing left to do but error out. + // + // However, synthesizing an auto trait impl works differently. Here, we start out with + // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing + // with - and progressively discover the conditions we need to fulfill for it to + // implement a certain auto trait. This ends up breaking two assumptions made by trait + // selection and projection: + // + // * We can always cache the result of a particular trait selection for the lifetime of + // an InfCtxt + // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T: + // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' + // + // We fix the first assumption by manually clearing out all of the InferCtxt's caches + // in between calls to SelectionContext.select. This allows us to keep all of the + // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift + // them between calls. + // + // We fix the second assumption by reprocessing the result of our first call to + // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first + // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, + // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing + // SelectionContext to return it back to us. + + let (new_env, user_env) = match self.evaluate_predicates( + &infcx, + trait_did, + ty, + orig_env, + orig_env, + &mut fresh_preds, + false, + ) { + Some(e) => e, + None => return AutoTraitResult::NegativeImpl, + }; + + let (full_env, full_user_env) = self + .evaluate_predicates( + &infcx, + trait_did, + ty, + new_env, + user_env, + &mut fresh_preds, + true, + ) + .unwrap_or_else(|| { + panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env) + }); + + debug!( + "find_auto_trait_generics({:?}): fulfilling \ + with {:?}", + trait_ref, full_env + ); + infcx.clear_caches(); + + // At this point, we already have all of the bounds we need. FulfillmentContext is used + // to store all of the necessary region/lifetime bounds in the InferContext, as well as + // an additional sanity check. + let mut fulfill = FulfillmentContext::new(); + fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); + fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { + panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e) + }); + + let body_id_map: FxHashMap<_, _> = infcx + .inner + .borrow() + .region_obligations() + .iter() + .map(|&(id, _)| (id, vec![])) + .collect(); + + infcx.process_registered_region_obligations(&body_id_map, None, full_env); + + let region_data = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .region_constraint_data() + .clone(); + + let vid_to_region = self.map_vid_to_region(®ion_data); + + let info = AutoTraitInfo { full_user_env, region_data, vid_to_region }; + + AutoTraitResult::PositiveImpl(auto_trait_callback(&infcx, info)) + }) + } +} + +impl AutoTraitFinder<'tcx> { + /// The core logic responsible for computing the bounds for our synthesized impl. + /// + /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like + /// `FulfillmentContext`, we recursively select the nested obligations of predicates we + /// encounter. However, whenever we encounter an `UnimplementedError` involving a type + /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular + /// type implements an auto trait, Unimplemented errors tell us what conditions need to be met. + /// + /// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key + /// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete + /// user code. According, it considers all possible ways that a `Predicate` could be met, which + /// isn't always what we want for a synthesized impl. For example, given the predicate `T: + /// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T: + /// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`, + /// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up. + /// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl + /// like this: + /// + /// impl<T> Send for Foo<T> where T: IntoIterator + /// + /// While it might be technically true that Foo implements Send where `T: IntoIterator`, + /// the bound is overly restrictive - it's really only necessary that `T: Iterator`. + /// + /// For this reason, `evaluate_predicates` handles predicates with type variables specially. + /// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately + /// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later + /// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator` + /// needs to hold. + /// + /// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever + /// constructed once for a given type. As part of the construction process, the `ParamEnv` will + /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the + /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our + /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or + /// else `SelectionContext` will choke on the missing predicates. However, this should never + /// show up in the final synthesized generics: we don't want our generated docs page to contain + /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a + /// separate `user_env`, which only holds the predicates that will actually be displayed to the + /// user. + fn evaluate_predicates( + &self, + infcx: &InferCtxt<'_, 'tcx>, + trait_did: DefId, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + user_env: ty::ParamEnv<'tcx>, + fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, + only_projections: bool, + ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> { + let tcx = infcx.tcx; + + // Don't try to proess any nested obligations involving predicates + // that are already in the `ParamEnv` (modulo regions): we already + // know that they must hold. + for predicate in param_env.caller_bounds() { + fresh_preds.insert(self.clean_pred(infcx, predicate)); + } + + let mut select = SelectionContext::with_negative(&infcx, true); + + let mut already_visited = FxHashSet::default(); + let mut predicates = VecDeque::new(); + predicates.push_back(ty::Binder::bind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_did, + substs: infcx.tcx.mk_substs_trait(ty, &[]), + }, + })); + + let computed_preds = param_env.caller_bounds().iter(); + let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds().iter().collect(); + + let mut new_env = param_env; + let dummy_cause = ObligationCause::dummy(); + + while let Some(pred) = predicates.pop_front() { + infcx.clear_caches(); + + if !already_visited.insert(pred) { + continue; + } + + // Call `infcx.resolve_vars_if_possible` to see if we can + // get rid of any inference variables. + let obligation = infcx.resolve_vars_if_possible(&Obligation::new( + dummy_cause.clone(), + new_env, + pred, + )); + let result = select.select(&obligation); + + match &result { + &Ok(Some(ref impl_source)) => { + // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), + // we immediately bail out, since it's impossible for us to continue. + + if let ImplSource::ImplSourceUserDefined(ImplSourceUserDefinedData { + impl_def_id, + .. + }) = impl_source + { + // Blame 'tidy' for the weird bracket placement. + if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative { + debug!( + "evaluate_nested_obligations: found explicit negative impl\ + {:?}, bailing out", + impl_def_id + ); + return None; + } + } + + let obligations = impl_source.clone().nested_obligations().into_iter(); + + if !self.evaluate_nested_obligations( + ty, + obligations, + &mut user_computed_preds, + fresh_preds, + &mut predicates, + &mut select, + only_projections, + ) { + return None; + } + } + &Ok(None) => {} + &Err(SelectionError::Unimplemented) => { + if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { + already_visited.remove(&pred); + self.add_user_pred( + &mut user_computed_preds, + pred.without_const().to_predicate(self.tcx), + ); + predicates.push_back(pred); + } else { + debug!( + "evaluate_nested_obligations: `Unimplemented` found, bailing: \ + {:?} {:?} {:?}", + ty, + pred, + pred.skip_binder().trait_ref.substs + ); + return None; + } + } + _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), + }; + + let normalized_preds = elaborate_predicates( + tcx, + computed_preds.clone().chain(user_computed_preds.iter().cloned()), + ) + .map(|o| o.predicate); + new_env = + ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None); + } + + let final_user_env = ty::ParamEnv::new( + tcx.mk_predicates(user_computed_preds.into_iter()), + user_env.reveal(), + None, + ); + debug!( + "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ + '{:?}'", + ty, trait_did, new_env, final_user_env + ); + + Some((new_env, final_user_env)) + } + + /// This method is designed to work around the following issue: + /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`, + /// progressively building a `ParamEnv` based on the results we get. + /// However, our usage of `SelectionContext` differs from its normal use within the compiler, + /// in that we capture and re-reprocess predicates from `Unimplemented` errors. + /// + /// This can lead to a corner case when dealing with region parameters. + /// During our selection loop in `evaluate_predicates`, we might end up with + /// two trait predicates that differ only in their region parameters: + /// one containing a HRTB lifetime parameter, and one containing a 'normal' + /// lifetime parameter. For example: + /// + /// T as MyTrait<'a> + /// T as MyTrait<'static> + /// + /// If we put both of these predicates in our computed `ParamEnv`, we'll + /// confuse `SelectionContext`, since it will (correctly) view both as being applicable. + /// + /// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB + /// Our end goal is to generate a user-visible description of the conditions + /// under which a type implements an auto trait. A trait predicate involving + /// a HRTB means that the type needs to work with any choice of lifetime, + /// not just one specific lifetime (e.g., `'static`). + fn add_user_pred( + &self, + user_computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>, + new_pred: ty::Predicate<'tcx>, + ) { + let mut should_add_new = true; + user_computed_preds.retain(|&old_pred| { + if let ( + ty::PredicateAtom::Trait(new_trait, _), + ty::PredicateAtom::Trait(old_trait, _), + ) = (new_pred.skip_binders(), old_pred.skip_binders()) + { + if new_trait.def_id() == old_trait.def_id() { + let new_substs = new_trait.trait_ref.substs; + let old_substs = old_trait.trait_ref.substs; + + if !new_substs.types().eq(old_substs.types()) { + // We can't compare lifetimes if the types are different, + // so skip checking `old_pred`. + return true; + } + + for (new_region, old_region) in new_substs.regions().zip(old_substs.regions()) { + match (new_region, old_region) { + // If both predicates have an `ReLateBound` (a HRTB) in the + // same spot, we do nothing. + ( + ty::RegionKind::ReLateBound(_, _), + ty::RegionKind::ReLateBound(_, _), + ) => {} + + (ty::RegionKind::ReLateBound(_, _), _) + | (_, ty::RegionKind::ReVar(_)) => { + // One of these is true: + // The new predicate has a HRTB in a spot where the old + // predicate does not (if they both had a HRTB, the previous + // match arm would have executed). A HRBT is a 'stricter' + // bound than anything else, so we want to keep the newer + // predicate (with the HRBT) in place of the old predicate. + // + // OR + // + // The old predicate has a region variable where the new + // predicate has some other kind of region. An region + // variable isn't something we can actually display to a user, + // so we choose their new predicate (which doesn't have a region + // variable). + // + // In both cases, we want to remove the old predicate, + // from `user_computed_preds`, and replace it with the new + // one. Having both the old and the new + // predicate in a `ParamEnv` would confuse `SelectionContext`. + // + // We're currently in the predicate passed to 'retain', + // so we return `false` to remove the old predicate from + // `user_computed_preds`. + return false; + } + (_, ty::RegionKind::ReLateBound(_, _)) + | (ty::RegionKind::ReVar(_), _) => { + // This is the opposite situation as the previous arm. + // One of these is true: + // + // The old predicate has a HRTB lifetime in a place where the + // new predicate does not. + // + // OR + // + // The new predicate has a region variable where the old + // predicate has some other type of region. + // + // We want to leave the old + // predicate in `user_computed_preds`, and skip adding + // new_pred to `user_computed_params`. + should_add_new = false + } + _ => {} + } + } + } + } + true + }); + + if should_add_new { + user_computed_preds.insert(new_pred); + } + } + + /// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s + /// to each other, we match `ty::RegionVid`s to `ty::Region`s. + fn map_vid_to_region<'cx>( + &self, + regions: &RegionConstraintData<'cx>, + ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> { + let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default(); + let mut finished_map = FxHashMap::default(); + + for constraint in regions.constraints.keys() { + match constraint { + &Constraint::VarSubVar(r1, r2) => { + { + let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(r2)); + } + + let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default(); + deps2.smaller.insert(RegionTarget::RegionVid(r1)); + } + &Constraint::RegSubVar(region, vid) => { + { + let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(vid)); + } + + let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default(); + deps2.smaller.insert(RegionTarget::Region(region)); + } + &Constraint::VarSubReg(vid, region) => { + finished_map.insert(vid, region); + } + &Constraint::RegSubReg(r1, r2) => { + { + let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default(); + deps1.larger.insert(RegionTarget::Region(r2)); + } + + let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default(); + deps2.smaller.insert(RegionTarget::Region(r1)); + } + } + } + + while !vid_map.is_empty() { + let target = *vid_map.keys().next().expect("Keys somehow empty"); + let deps = vid_map.remove(&target).expect("Entry somehow missing"); + + for smaller in deps.smaller.iter() { + for larger in deps.larger.iter() { + match (smaller, larger) { + (&RegionTarget::Region(_), &RegionTarget::Region(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + (&RegionTarget::RegionVid(v1), &RegionTarget::Region(r1)) => { + finished_map.insert(v1, r1); + } + (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => { + // Do nothing; we don't care about regions that are smaller than vids. + } + (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + } + } + } + } + finished_map + } + + fn is_param_no_infer(&self, substs: SubstsRef<'_>) -> bool { + self.is_of_param(substs.type_at(0)) && !substs.types().any(|t| t.has_infer_types()) + } + + pub fn is_of_param(&self, ty: Ty<'_>) -> bool { + match ty.kind { + ty::Param(_) => true, + ty::Projection(p) => self.is_of_param(p.self_ty()), + _ => false, + } + } + + fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { + match p.ty().skip_binder().kind { + ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, + _ => false, + } + } + + fn evaluate_nested_obligations( + &self, + ty: Ty<'_>, + nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>, + computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>, + fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, + predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>, + select: &mut SelectionContext<'_, 'tcx>, + only_projections: bool, + ) -> bool { + let dummy_cause = ObligationCause::dummy(); + + for obligation in nested { + let is_new_pred = + fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate)); + + // Resolve any inference variables that we can, to help selection succeed + let predicate = select.infcx().resolve_vars_if_possible(&obligation.predicate); + + // We only add a predicate as a user-displayable bound if + // it involves a generic parameter, and doesn't contain + // any inference variables. + // + // Displaying a bound involving a concrete type (instead of a generic + // parameter) would be pointless, since it's always true + // (e.g. u8: Copy) + // Displaying an inference variable is impossible, since they're + // an internal compiler detail without a defined visual representation + // + // We check this by calling is_of_param on the relevant types + // from the various possible predicates + + match predicate.skip_binders() { + ty::PredicateAtom::Trait(p, _) => { + if self.is_param_no_infer(p.trait_ref.substs) + && !only_projections + && is_new_pred + { + self.add_user_pred(computed_preds, predicate); + } + predicates.push_back(ty::Binder::bind(p)); + } + ty::PredicateAtom::Projection(p) => { + let p = ty::Binder::bind(p); + debug!( + "evaluate_nested_obligations: examining projection predicate {:?}", + predicate + ); + + // As described above, we only want to display + // bounds which include a generic parameter but don't include + // an inference variable. + // Additionally, we check if we've seen this predicate before, + // to avoid rendering duplicate bounds to the user. + if self.is_param_no_infer(p.skip_binder().projection_ty.substs) + && !p.ty().skip_binder().has_infer_types() + && is_new_pred + { + debug!( + "evaluate_nested_obligations: adding projection predicate\ + to computed_preds: {:?}", + predicate + ); + + // Under unusual circumstances, we can end up with a self-refeential + // projection predicate. For example: + // <T as MyType>::Value == <T as MyType>::Value + // Not only is displaying this to the user pointless, + // having it in the ParamEnv will cause an issue if we try to call + // poly_project_and_unify_type on the predicate, since this kind of + // predicate will normally never end up in a ParamEnv. + // + // For these reasons, we ignore these weird predicates, + // ensuring that we're able to properly synthesize an auto trait impl + if self.is_self_referential_projection(p) { + debug!( + "evaluate_nested_obligations: encountered a projection + predicate equating a type with itself! Skipping" + ); + } else { + self.add_user_pred(computed_preds, predicate); + } + } + + // There are three possible cases when we project a predicate: + // + // 1. We encounter an error. This means that it's impossible for + // our current type to implement the auto trait - there's bound + // that we could add to our ParamEnv that would 'fix' this kind + // of error, as it's not caused by an unimplemented type. + // + // 2. We successfully project the predicate (Ok(Some(_))), generating + // some subobligations. We then process these subobligations + // like any other generated sub-obligations. + // + // 3. We receive an 'ambiguous' result (Ok(None)) + // If we were actually trying to compile a crate, + // we would need to re-process this obligation later. + // However, all we care about is finding out what bounds + // are needed for our type to implement a particular auto trait. + // We've already added this obligation to our computed ParamEnv + // above (if it was necessary). Therefore, we don't need + // to do any further processing of the obligation. + // + // Note that we *must* try to project *all* projection predicates + // we encounter, even ones without inference variable. + // This ensures that we detect any projection errors, + // which indicate that our type can *never* implement the given + // auto trait. In that case, we will generate an explicit negative + // impl (e.g. 'impl !Send for MyType'). However, we don't + // try to process any of the generated subobligations - + // they contain no new information, since we already know + // that our type implements the projected-through trait, + // and can lead to weird region issues. + // + // Normally, we'll generate a negative impl as a result of encountering + // a type with an explicit negative impl of an auto trait + // (for example, raw pointers have !Send and !Sync impls) + // However, through some **interesting** manipulations of the type + // system, it's actually possible to write a type that never + // implements an auto trait due to a projection error, not a normal + // negative impl error. To properly handle this case, we need + // to ensure that we catch any potential projection errors, + // and turn them into an explicit negative impl for our type. + debug!("Projecting and unifying projection predicate {:?}", predicate); + + match project::poly_project_and_unify_type(select, &obligation.with(p)) { + Err(e) => { + debug!( + "evaluate_nested_obligations: Unable to unify predicate \ + '{:?}' '{:?}', bailing out", + ty, e + ); + return false; + } + Ok(Err(project::InProgress)) => { + debug!("evaluate_nested_obligations: recursive projection predicate"); + return false; + } + Ok(Ok(Some(v))) => { + // We only care about sub-obligations + // when we started out trying to unify + // some inference variables. See the comment above + // for more infomration + if p.ty().skip_binder().has_infer_types() { + if !self.evaluate_nested_obligations( + ty, + v.into_iter(), + computed_preds, + fresh_preds, + predicates, + select, + only_projections, + ) { + return false; + } + } + } + Ok(Ok(None)) => { + // It's ok not to make progress when have no inference variables - + // in that case, we were only performing unifcation to check if an + // error occurred (which would indicate that it's impossible for our + // type to implement the auto trait). + // However, we should always make progress (either by generating + // subobligations or getting an error) when we started off with + // inference variables + if p.ty().skip_binder().has_infer_types() { + panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) + } + } + } + } + ty::PredicateAtom::RegionOutlives(binder) => { + let binder = ty::Binder::bind(binder); + if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { + return false; + } + } + ty::PredicateAtom::TypeOutlives(binder) => { + let binder = ty::Binder::bind(binder); + match ( + binder.no_bound_vars(), + binder.map_bound_ref(|pred| pred.0).no_bound_vars(), + ) { + (None, Some(t_a)) => { + select.infcx().register_region_obligation_with_cause( + t_a, + select.infcx().tcx.lifetimes.re_static, + &dummy_cause, + ); + } + (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { + select.infcx().register_region_obligation_with_cause( + t_a, + r_b, + &dummy_cause, + ); + } + _ => {} + }; + } + ty::PredicateAtom::ConstEquate(c1, c2) => { + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { + match select.infcx().const_eval_resolve( + obligation.param_env, + def, + substs, + promoted, + Some(obligation.cause.span), + ) { + Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty)), + Err(err) => Err(err), + } + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match select + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => (), + Err(_) => return false, + } + } + _ => return false, + } + } + _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate), + }; + } + true + } + + pub fn clean_pred( + &self, + infcx: &InferCtxt<'_, 'tcx>, + p: ty::Predicate<'tcx>, + ) -> ty::Predicate<'tcx> { + infcx.freshen(p) + } +} + +// Replaces all ReVars in a type with ty::Region's, using the provided map +pub struct RegionReplacer<'a, 'tcx> { + vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>, + tcx: TyCtxt<'tcx>, +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + (match r { + &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), + _ => None, + }) + .unwrap_or_else(|| r.super_fold_with(self)) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs new file mode 100644 index 00000000000..0097097707f --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -0,0 +1,267 @@ +//! Defines a Chalk-based `TraitEngine` + +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::query::NoSolution; +use crate::traits::{ + ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode, + ObligationCause, PredicateObligation, SelectionError, TraitEngine, +}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub struct FulfillmentContext<'tcx> { + obligations: FxIndexSet<PredicateObligation<'tcx>>, +} + +impl FulfillmentContext<'tcx> { + crate fn new() -> Self { + FulfillmentContext { obligations: FxIndexSet::default() } + } +} + +fn environment<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> &'tcx ty::List<ChalkEnvironmentClause<'tcx>> { + use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; + use rustc_middle::ty::subst::GenericArgKind; + + debug!("environment(def_id = {:?})", def_id); + + // The environment of an impl Trait type is its defining function's environment. + if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { + return environment(tcx, parent); + } + + // Compute the bounds on `Self` and the type parameters. + let ty::InstantiatedPredicates { predicates, .. } = + tcx.predicates_of(def_id).instantiate_identity(tcx); + + let clauses = predicates.into_iter().map(ChalkEnvironmentClause::Predicate); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let node = tcx.hir().get(hir_id); + + enum NodeKind { + TraitImpl, + InherentImpl, + Fn, + Other, + }; + + let node_kind = match node { + Node::TraitItem(item) => match item.kind { + TraitItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::ImplItem(item) => match item.kind { + ImplItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::Item(item) => match item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl, + ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl, + ItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::ForeignItem(item) => match item.kind { + ForeignItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + // FIXME: closures? + _ => NodeKind::Other, + }; + + // FIXME(eddyb) isn't the unordered nature of this a hazard? + let mut inputs = FxIndexSet::default(); + + match node_kind { + // In a trait impl, we assume that the header trait ref and all its + // constituents are well-formed. + NodeKind::TraitImpl => { + let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); + + // FIXME(chalk): this has problems because of late-bound regions + //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); + inputs.extend(trait_ref.substs.iter()); + } + + // In an inherent impl, we assume that the receiver type and all its + // constituents are well-formed. + NodeKind::InherentImpl => { + let self_ty = tcx.type_of(def_id); + inputs.extend(self_ty.walk()); + } + + // In an fn, we assume that the arguments and all their constituents are + // well-formed. + NodeKind::Fn => { + let fn_sig = tcx.fn_sig(def_id); + let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); + + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + } + + NodeKind::Other => (), + } + let input_clauses = inputs.into_iter().filter_map(|arg| { + match arg.unpack() { + GenericArgKind::Type(ty) => Some(ChalkEnvironmentClause::TypeFromEnv(ty)), + + // FIXME(eddyb) no WF conditions from lifetimes? + GenericArgKind::Lifetime(_) => None, + + // FIXME(eddyb) support const generics in Chalk + GenericArgKind::Const(_) => None, + } + }); + + tcx.mk_chalk_environment_clause_list(clauses.chain(input_clauses)) +} + +/// We need to wrap a `ty::Predicate` in an elaborated environment *before* we +/// canonicalize. This is due to the fact that we insert extra clauses into the +/// environment for all input types (`FromEnv`). +fn in_environment( + infcx: &InferCtxt<'_, 'tcx>, + obligation: &PredicateObligation<'tcx>, +) -> ChalkEnvironmentAndGoal<'tcx> { + assert!(!infcx.is_in_snapshot()); + let obligation = infcx.resolve_vars_if_possible(obligation); + + let environment = match obligation.param_env.def_id { + Some(def_id) => environment(infcx.tcx, def_id), + None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(), + // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl + // and ui/generics/generic-static-methods + //_ => bug!("non-empty `ParamEnv` with no def-id"), + _ => ty::List::empty(), + }; + + ChalkEnvironmentAndGoal { environment, goal: obligation.predicate } +} + +impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { + fn normalize_projection_type( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + _param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + _cause: ObligationCause<'tcx>, + ) -> Ty<'tcx> { + infcx.tcx.mk_ty(ty::Projection(projection_ty)) + } + + fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) { + assert!(!infcx.is_in_snapshot()); + let obligation = infcx.resolve_vars_if_possible(&obligation); + + self.obligations.insert(obligation); + } + + fn select_all_or_error( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + self.select_where_possible(infcx)?; + + if self.obligations.is_empty() { + Ok(()) + } else { + let errors = self + .obligations + .iter() + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + points_at_arg_span: false, + }) + .collect(); + Err(errors) + } + } + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + let mut errors = Vec::new(); + let mut next_round = FxIndexSet::default(); + let mut making_progress; + + loop { + making_progress = false; + + // We iterate over all obligations, and record if we are able + // to unambiguously prove at least one obligation. + for obligation in self.obligations.drain(..) { + let goal_in_environment = in_environment(infcx, &obligation); + let mut orig_values = OriginalQueryValues::default(); + let canonical_goal = + infcx.canonicalize_query(&goal_in_environment, &mut orig_values); + + match infcx.tcx.evaluate_goal(canonical_goal) { + Ok(response) => { + if response.is_proven() { + making_progress = true; + + match infcx.instantiate_query_response_and_region_obligations( + &obligation.cause, + obligation.param_env, + &orig_values, + &response, + ) { + Ok(infer_ok) => next_round.extend( + infer_ok.obligations.into_iter().map(|obligation| { + assert!(!infcx.is_in_snapshot()); + infcx.resolve_vars_if_possible(&obligation) + }), + ), + + Err(_err) => errors.push(FulfillmentError { + obligation, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + points_at_arg_span: false, + }), + } + } else { + // Ambiguous: retry at next round. + next_round.insert(obligation); + } + } + + Err(NoSolution) => errors.push(FulfillmentError { + obligation, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + points_at_arg_span: false, + }), + } + } + next_round = std::mem::replace(&mut self.obligations, next_round); + + if !making_progress { + break; + } + } + + if errors.is_empty() { Ok(()) } else { Err(errors) } + } + + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { + self.obligations.iter().cloned().collect() + } +} diff --git a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs new file mode 100644 index 00000000000..dd7ea55cc10 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs @@ -0,0 +1,126 @@ +// This file contains various trait resolution methods used by codegen. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::traits::{ + FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, + Unimplemented, +}; +use rustc_errors::ErrorReported; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, TyCtxt}; + +/// Attempts to resolve an obligation to a `ImplSource`. The result is +/// a shallow `ImplSource` resolution, meaning that we do not +/// (necessarily) resolve all nested obligations on the impl. Note +/// that type check should guarantee to us that all nested +/// obligations *could be* resolved if we wanted to. +/// Assumes that this is run after the entire crate has been successfully type-checked. +pub fn codegen_fulfill_obligation<'tcx>( + ty: TyCtxt<'tcx>, + (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), +) -> Result<ImplSource<'tcx, ()>, ErrorReported> { + // Remove any references to regions; this helps improve caching. + let trait_ref = ty.erase_regions(&trait_ref); + + debug!( + "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", + (param_env, trait_ref), + trait_ref.def_id() + ); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + ty.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = + Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!( + "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ + overflow or prior type error", + trait_ref + ), + ); + return Err(ErrorReported); + } + Err(Unimplemented) => { + // This can trigger when we probe for the source of a `'static` lifetime requirement + // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!( + "Encountered error `Unimplemented` selecting `{:?}` during codegen", + trait_ref + ), + ); + return Err(ErrorReported); + } + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let impl_source = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source); + + info!("Cache miss: {:?} => {:?}", trait_ref, impl_source); + Ok(impl_source) + }) +} + +// # Global Cache + +/// 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<T>( + 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(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/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs new file mode 100644 index 00000000000..b06cf4411d0 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -0,0 +1,577 @@ +//! See Rustc Dev Guide chapters on [trait-resolution] and [trait-specialization] for more info on +//! how this works. +//! +//! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html +//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html + +use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt}; +use crate::traits::select::IntercrateAmbiguityCause; +use crate::traits::SkipLeakCheck; +use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::symbol::sym; +use rustc_span::DUMMY_SP; +use std::iter; + +/// Whether we do the orphan check relative to this crate or +/// to some remote crate. +#[derive(Copy, Clone, Debug)] +enum InCrate { + Local, + Remote, +} + +#[derive(Debug, Copy, Clone)] +pub enum Conflict { + Upstream, + Downstream, +} + +pub struct OverlapResult<'tcx> { + pub impl_header: ty::ImplHeader<'tcx>, + pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, + + /// `true` if the overlap might've been permitted before the shift + /// to universes. + pub involves_placeholder: bool, +} + +pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) { + err.note( + "this behavior recently changed as a result of a bug fix; \ + see rust-lang/rust#56105 for details", + ); +} + +/// If there are types that satisfy both impls, invokes `on_overlap` +/// with a suitably-freshened `ImplHeader` with those types +/// substituted. Otherwise, invokes `no_overlap`. +pub fn overlapping_impls<F1, F2, R>( + tcx: TyCtxt<'_>, + impl1_def_id: DefId, + impl2_def_id: DefId, + skip_leak_check: SkipLeakCheck, + on_overlap: F1, + no_overlap: F2, +) -> R +where + F1: FnOnce(OverlapResult<'_>) -> R, + F2: FnOnce() -> R, +{ + debug!( + "overlapping_impls(\ + impl1_def_id={:?}, \ + impl2_def_id={:?})", + impl1_def_id, impl2_def_id, + ); + + let overlaps = tcx.infer_ctxt().enter(|infcx| { + let selcx = &mut SelectionContext::intercrate(&infcx); + overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some() + }); + + if !overlaps { + return no_overlap(); + } + + // In the case where we detect an error, run the check again, but + // this time tracking intercrate ambuiguity causes for better + // diagnostics. (These take time and can lead to false errors.) + tcx.infer_ctxt().enter(|infcx| { + let selcx = &mut SelectionContext::intercrate(&infcx); + selcx.enable_tracking_intercrate_ambiguity_causes(); + on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap()) + }) +} + +fn with_fresh_ty_vars<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: DefId, +) -> ty::ImplHeader<'tcx> { + let tcx = selcx.tcx(); + let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); + + let header = ty::ImplHeader { + impl_def_id, + self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs), + trait_ref: tcx.impl_trait_ref(impl_def_id).subst(tcx, impl_substs), + predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates, + }; + + let Normalized { value: mut header, obligations } = + traits::normalize(selcx, param_env, ObligationCause::dummy(), &header); + + header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); + header +} + +/// Can both impl `a` and impl `b` be satisfied by a common type (including +/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls. +fn overlap<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + skip_leak_check: SkipLeakCheck, + a_def_id: DefId, + b_def_id: DefId, +) -> Option<OverlapResult<'tcx>> { + debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); + + selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { + overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot) + }) +} + +fn overlap_within_probe( + selcx: &mut SelectionContext<'cx, 'tcx>, + skip_leak_check: SkipLeakCheck, + a_def_id: DefId, + b_def_id: DefId, + snapshot: &CombinedSnapshot<'_, 'tcx>, +) -> Option<OverlapResult<'tcx>> { + // For the purposes of this check, we don't bring any placeholder + // types into scope; instead, we replace the generic types with + // fresh type variables, and hence we do our evaluations in an + // empty environment. + let param_env = ty::ParamEnv::empty(); + + let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id); + let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id); + + debug!("overlap: a_impl_header={:?}", a_impl_header); + debug!("overlap: b_impl_header={:?}", b_impl_header); + + // Do `a` and `b` unify? If not, no overlap. + let obligations = match selcx + .infcx() + .at(&ObligationCause::dummy(), param_env) + .eq_impl_headers(&a_impl_header, &b_impl_header) + { + Ok(InferOk { obligations, value: () }) => obligations, + Err(_) => { + return None; + } + }; + + debug!("overlap: unification check succeeded"); + + // Are any of the obligations unsatisfiable? If so, no overlap. + let infcx = selcx.infcx(); + let opt_failing_obligation = a_impl_header + .predicates + .iter() + .chain(&b_impl_header.predicates) + .map(|p| infcx.resolve_vars_if_possible(p)) + .map(|p| Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: p, + }) + .chain(obligations) + .find(|o| !selcx.predicate_may_hold_fatal(o)); + // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported + // to the canonical trait query form, `infcx.predicate_may_hold`, once + // the new system supports intercrate mode (which coherence needs). + + if let Some(failing_obligation) = opt_failing_obligation { + debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); + return None; + } + + if !skip_leak_check.is_yes() { + if let Err(_) = infcx.leak_check(true, snapshot) { + debug!("overlap: leak check failed"); + return None; + } + } + + let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header); + let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); + debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); + + let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { + Some(true) => true, + _ => false, + }; + + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) +} + +pub fn trait_ref_is_knowable<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, +) -> Option<Conflict> { + debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); + if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() { + // A downstream or cousin crate is allowed to implement some + // substitution of this trait-ref. + return Some(Conflict::Downstream); + } + + if trait_ref_is_local_or_fundamental(tcx, trait_ref) { + // This is a local or fundamental trait, so future-compatibility + // is no concern. We know that downstream/cousin crates are not + // allowed to implement a substitution of this trait ref, which + // means impls could only come from dependencies of this crate, + // which we already know about. + return None; + } + + // This is a remote non-fundamental trait, so if another crate + // can be the "final owner" of a substitution of this trait-ref, + // they are allowed to implement it future-compatibly. + // + // However, if we are a final owner, then nobody else can be, + // and if we are an intermediate owner, then we don't care + // about future-compatibility, which means that we're OK if + // we are an owner. + if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() { + debug!("trait_ref_is_knowable: orphan check passed"); + None + } else { + debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned"); + Some(Conflict::Upstream) + } +} + +pub fn trait_ref_is_local_or_fundamental<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, +) -> bool { + trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) +} + +pub enum OrphanCheckErr<'tcx> { + NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>), + UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>), +} + +/// Checks the coherence orphan rules. `impl_def_id` should be the +/// `DefId` of a trait impl. To pass, either the trait must be local, or else +/// two conditions must be satisfied: +/// +/// 1. All type parameters in `Self` must be "covered" by some local type constructor. +/// 2. Some local type must appear in `Self`. +pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> { + debug!("orphan_check({:?})", impl_def_id); + + // We only except this routine to be invoked on implementations + // of a trait, not inherent implementations. + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + debug!("orphan_check: trait_ref={:?}", trait_ref); + + // If the *trait* is local to the crate, ok. + if trait_ref.def_id.is_local() { + debug!("trait {:?} is local to current crate", trait_ref.def_id); + return Ok(()); + } + + orphan_check_trait_ref(tcx, trait_ref, InCrate::Local) +} + +/// Checks whether a trait-ref is potentially implementable by a crate. +/// +/// The current rule is that a trait-ref orphan checks in a crate C: +/// +/// 1. Order the parameters in the trait-ref in subst order - Self first, +/// others linearly (e.g., `<U as Foo<V, W>>` is U < V < W). +/// 2. Of these type parameters, there is at least one type parameter +/// in which, walking the type as a tree, you can reach a type local +/// to C where all types in-between are fundamental types. Call the +/// first such parameter the "local key parameter". +/// - e.g., `Box<LocalType>` is OK, because you can visit LocalType +/// going through `Box`, which is fundamental. +/// - similarly, `FundamentalPair<Vec<()>, Box<LocalType>>` is OK for +/// the same reason. +/// - but (knowing that `Vec<T>` is non-fundamental, and assuming it's +/// not local), `Vec<LocalType>` is bad, because `Vec<->` is between +/// the local type and the type parameter. +/// 3. Before this local type, no generic type parameter of the impl must +/// be reachable through fundamental types. +/// - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental. +/// - while `impl<T> Trait<LocalType for Box<T>` results in an error, as `T` is +/// reachable through the fundamental type `Box`. +/// 4. Every type in the local key parameter not known in C, going +/// through the parameter's type tree, must appear only as a subtree of +/// a type local to C, with only fundamental types between the type +/// local to C and the local key parameter. +/// - e.g., `Vec<LocalType<T>>>` (or equivalently `Box<Vec<LocalType<T>>>`) +/// is bad, because the only local type with `T` as a subtree is +/// `LocalType<T>`, and `Vec<->` is between it and the type parameter. +/// - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because +/// the second occurrence of `T` is not a subtree of *any* local type. +/// - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of +/// `LocalType<Vec<T>>`, which is local and has no types between it and +/// the type parameter. +/// +/// The orphan rules actually serve several different purposes: +/// +/// 1. They enable link-safety - i.e., 2 mutually-unknowing crates (where +/// every type local to one crate is unknown in the other) can't implement +/// the same trait-ref. This follows because it can be seen that no such +/// type can orphan-check in 2 such crates. +/// +/// To check that a local impl follows the orphan rules, we check it in +/// InCrate::Local mode, using type parameters for the "generic" types. +/// +/// 2. They ground negative reasoning for coherence. If a user wants to +/// write both a conditional blanket impl and a specific impl, we need to +/// make sure they do not overlap. For example, if we write +/// ``` +/// impl<T> IntoIterator for Vec<T> +/// impl<T: Iterator> IntoIterator for T +/// ``` +/// We need to be able to prove that `Vec<$0>: !Iterator` for every type $0. +/// We can observe that this holds in the current crate, but we need to make +/// sure this will also hold in all unknown crates (both "independent" crates, +/// which we need for link-safety, and also child crates, because we don't want +/// child crates to get error for impl conflicts in a *dependency*). +/// +/// For that, we only allow negative reasoning if, for every assignment to the +/// inference variables, every unknown crate would get an orphan error if they +/// try to implement this trait-ref. To check for this, we use InCrate::Remote +/// mode. That is sound because we already know all the impls from known crates. +/// +/// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can +/// add "non-blanket" impls without breaking negative reasoning in dependent +/// crates. This is the "rebalancing coherence" (RFC 1023) restriction. +/// +/// For that, we only a allow crate to perform negative reasoning on +/// non-local-non-`#[fundamental]` only if there's a local key parameter as per (2). +/// +/// Because we never perform negative reasoning generically (coherence does +/// not involve type parameters), this can be interpreted as doing the full +/// orphan check (using InCrate::Local mode), substituting non-local known +/// types for all inference variables. +/// +/// This allows for crates to future-compatibly add impls as long as they +/// can't apply to types with a key parameter in a child crate - applying +/// the rules, this basically means that every type parameter in the impl +/// must appear behind a non-fundamental type (because this is not a +/// type-system requirement, crate owners might also go for "semantic +/// future-compatibility" involving things such as sealed traits, but +/// the above requirement is sufficient, and is necessary in "open world" +/// cases). +/// +/// Note that this function is never called for types that have both type +/// parameters and inference variables. +fn orphan_check_trait_ref<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + in_crate: InCrate, +) -> Result<(), OrphanCheckErr<'tcx>> { + debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); + + if trait_ref.needs_infer() && trait_ref.needs_subst() { + bug!( + "can't orphan check a trait ref with both params and inference variables {:?}", + trait_ref + ); + } + + // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only + // if at least one of the following is true: + // + // - Trait is a local trait + // (already checked in orphan_check prior to calling this function) + // - All of + // - At least one of the types T0..=Tn must be a local type. + // Let Ti be the first such type. + // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) + // + fn uncover_fundamental_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + in_crate: InCrate, + ) -> Vec<Ty<'tcx>> { + // FIXME: this is currently somewhat overly complicated, + // but fixing this requires a more complicated refactor. + if !contained_non_local_types(tcx, ty, in_crate).is_empty() { + if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) { + return inner_tys + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .collect(); + } + } + + vec![ty] + } + + let mut non_local_spans = vec![]; + for (i, input_ty) in trait_ref + .substs + .types() + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .enumerate() + { + debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); + let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate); + if non_local_tys.is_empty() { + debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); + return Ok(()); + } else if let ty::Param(_) = input_ty.kind { + debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); + let local_type = trait_ref + .substs + .types() + .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) + .find(|ty| ty_is_local_constructor(ty, in_crate)); + + debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); + + return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type)); + } + + for input_ty in non_local_tys { + non_local_spans.push((input_ty, i == 0)); + } + } + // If we exit above loop, never found a local type. + debug!("orphan_check_trait_ref: no local type"); + Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) +} + +/// Returns a list of relevant non-local types for `ty`. +/// +/// This is just `ty` itself unless `ty` is `#[fundamental]`, +/// in which case we recursively look into this type. +/// +/// If `ty` is local itself, this method returns an empty `Vec`. +/// +/// # Examples +/// +/// - `u32` is not local, so this returns `[u32]`. +/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`. +/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`. +/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local. +fn contained_non_local_types(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> { + if ty_is_local_constructor(ty, in_crate) { + Vec::new() + } else { + match fundamental_ty_inner_tys(tcx, ty) { + Some(inner_tys) => { + inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect() + } + None => vec![ty], + } + } +} + +/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the +/// type parameters of the ADT, or `T`, respectively. For non-fundamental +/// types, returns `None`. +fn fundamental_ty_inner_tys( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option<impl Iterator<Item = Ty<'tcx>>> { + let (first_ty, rest_tys) = match ty.kind { + ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), + ty::Adt(def, substs) if def.is_fundamental() => { + let mut types = substs.types(); + + // FIXME(eddyb) actually validate `#[fundamental]` up-front. + match types.next() { + None => { + tcx.sess.span_err( + tcx.def_span(def.did), + "`#[fundamental]` requires at least one type parameter", + ); + + return None; + } + + Some(first_ty) => (first_ty, types), + } + } + _ => return None, + }; + + Some(iter::once(first_ty).chain(rest_tys)) +} + +fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { + match in_crate { + // The type is local to *this* crate - it will not be + // local in any other crate. + InCrate::Remote => false, + InCrate::Local => def_id.is_local(), + } +} + +fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { + debug!("ty_is_local_constructor({:?})", ty); + + match ty.kind { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Str + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::Never + | ty::Tuple(..) + | ty::Param(..) + | ty::Projection(..) => false, + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate { + InCrate::Local => false, + // The inference variable might be unified with a local + // type in that remote crate. + InCrate::Remote => true, + }, + + ty::Adt(def, _) => def_id_is_local(def.did, in_crate), + ty::Foreign(did) => def_id_is_local(did, in_crate), + ty::Opaque(..) => { + // This merits some explanation. + // Normally, opaque types are not involed when performing + // coherence checking, since it is illegal to directly + // implement a trait on an opaque type. However, we might + // end up looking at an opaque type during coherence checking + // if an opaque type gets used within another type (e.g. as + // a type parameter). This requires us to decide whether or + // not an opaque type should be considered 'local' or not. + // + // We choose to treat all opaque types as non-local, even + // those that appear within the same crate. This seems + // somewhat surprising at first, but makes sense when + // you consider that opaque types are supposed to hide + // the underlying type *within the same crate*. When an + // opaque type is used from outside the module + // where it is declared, it should be impossible to observe + // anything about it other than the traits that it implements. + // + // The alternative would be to look at the underlying type + // to determine whether or not the opaque type itself should + // be considered local. However, this could make it a breaking change + // to switch the underlying ('defining') type from a local type + // to a remote type. This would violate the rule that opaque + // types should be completely opaque apart from the traits + // that they implement, so we don't use this behavior. + false + } + + ty::Dynamic(ref tt, ..) => { + if let Some(principal) = tt.principal() { + def_id_is_local(principal.def_id(), in_crate) + } else { + false + } + } + + ty::Error(_) => true, + + ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { + bug!("ty_is_local invoked on unexpected type: {:?}", ty) + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs new file mode 100644 index 00000000000..4d477886979 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -0,0 +1,18 @@ +use rustc_middle::ty::TyCtxt; + +use super::TraitEngine; +use super::{ChalkFulfillmentContext, FulfillmentContext}; + +pub trait TraitEngineExt<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Box<Self>; +} + +impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Box<Self> { + if tcx.sess.opts.debugging_opts.chalk { + Box::new(ChalkFulfillmentContext::new()) + } else { + Box::new(FulfillmentContext::new()) + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs new file mode 100644 index 00000000000..28542d4b12e --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -0,0 +1,1949 @@ +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_data_structures::fx::FxHashMap; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::Node; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::fold::TypeFolder; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{ + self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, + TypeFoldable, WithConstness, +}; +use rustc_session::DiagnosticMessageId; +use rustc_span::symbol::{kw, sym}; +use rustc_span::{ExpnKind, MultiSpan, 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<hir::BodyId>, + fallback_has_occurred: bool, + ); + + fn report_overflow_error<T>( + &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<'_>) -> Option<(Span, Vec<ArgKind>)>; + + /// 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<Span>, + expected_args: Vec<ArgKind>, + found_args: Vec<ArgKind>, + 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<hir::BodyId>, + fallback_has_occurred: bool, + ) { + #[derive(Debug)] + struct ErrorDescriptor<'tcx> { + predicate: ty::Predicate<'tcx>, + index: Option<usize>, // 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); + } + + // 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<T>( + &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.skip_binders() { + ty::PredicateAtom::Trait(trait_predicate, _) => { + let trait_predicate = ty::Binder::bind(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 = self.tcx.get_diagnostic_item(sym::from_trait) + == Some(trait_ref.def_id()); + let is_unsize = + { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() }; + let (message, note) = if is_try && is_from { + ( + Some(format!( + "`?` couldn't convert the error to `{}`", + trait_ref.skip_binder().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(tcx), + post_message, + )) + ); + + if is_try && is_from { + let none_error = self + .tcx + .get_diagnostic_item(sym::none_error) + .map(|def_id| tcx.type_of(def_id)); + let should_convert_option_to_result = + Some(trait_ref.skip_binder().substs.type_at(1)) == none_error; + let should_convert_result_to_option = + Some(trait_ref.self_ty().skip_binder()) == none_error; + if should_convert_option_to_result { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider converting the `Option<T>` into a `Result<T, _>` \ + using `Option::ok_or` or `Option::ok_or_else`", + ".ok_or_else(|| /* error value */)".to_string(), + Applicability::HasPlaceholders, + ); + } else if should_convert_result_to_option { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider converting the `Result<T, _>` into an `Option<T>` \ + using `Result::ok`", + ".ok()".to_string(), + Applicability::MachineApplicable, + ); + } + if let Some(ret_span) = self.return_type_span(obligation) { + err.span_label( + ret_span, + &format!( + "expected `{}` because of this", + trait_ref.skip_binder().self_ty() + ), + ); + } + } + + 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.skip_binder().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()); + if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) { + // When the self type is a type param We don't need to "the trait + // `std::marker::Sized` is not implemented for `T`" as we will point + // at the type param with a label to suggest constraining it. + 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 body = 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, + }) + }); + + let enclosing_scope_span = + tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); + + err.span_label(enclosing_scope_span, s.as_str()); + } + + self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); + 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 Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { + self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + } + + if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { + err.emit(); + return; + } + + if is_unsize { + // If the obligation failed due to a missing implementation of the + // `Unsize` trait, give a pointer to why that might be the case + err.note( + "all implementations of `Unsize` are provided \ + automatically by the compiler, see \ + <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \ + for more information", + ); + } + + let is_fn_trait = [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] + .contains(&Some(trait_ref.def_id())); + let is_target_feature_fn = + if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { + !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + } else { + false + }; + if is_fn_trait && is_target_feature_fn { + err.note( + "`#[target_feature]` functions do not implement the `Fn` traits", + ); + } + + // 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); + } + // Changing mutability doesn't make a difference to whether we have + // an `Unsize` impl (Fixes ICE in #71036) + if !is_unsize { + 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.with(predicate.without_const().to_predicate(tcx)); + 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 \ + <https://github.com/rust-lang/rust/issues/48950> \ + for more information). Consider whether you meant to use \ + the type `()` here instead.", + ); + } + } + + err + } + + ty::PredicateAtom::Subtype(predicate) => { + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) + } + + ty::PredicateAtom::RegionOutlives(predicate) => { + let predicate = ty::Binder::bind(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::PredicateAtom::Projection(..) | ty::PredicateAtom::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::PredicateAtom::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::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => { + let found_kind = self.closure_kind(closure_substs).unwrap(); + let closure_span = + self.tcx.sess.source_map().guess_head_span( + self.tcx.hir().span_if_local(closure_def_id).unwrap(), + ); + let hir_id = + self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + 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(typeck_results) = self.in_progress_typeck_results { + let typeck_results = typeck_results.borrow(); + match (found_kind, typeck_results.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::PredicateAtom::WellFormed(ty) => { + if !self.tcx.sess.opts.debugging_opts.chalk { + // 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); + } else { + // FIXME: we'll need a better message which takes into account + // which bounds actually failed to hold. + self.tcx.sess.struct_span_err( + span, + &format!("the type `{}` is not well-formed (chalk)", ty), + ) + } + } + + ty::PredicateAtom::ConstEvaluatable(..) => { + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-evaluatable requirement gave wrong error: `{:?}`", + obligation + ) + } + + ty::PredicateAtom::ConstEquate(..) => { + // Errors for `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-equate 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 = match found_trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + 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().guess_head_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| { + let node = self.tcx.hir().get_if_local(did)?; + let (found_span, found) = self.get_fn_like_arguments(node)?; + Some((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(ErrorReported)) => { + // FIXME(eddyb) remove this once `ErrorReported` becomes a proof token. + self.tcx.sess.delay_span_bug(span, "`ErrorReported` without an error"); + return; + } + + // Already reported in the query, but only as a lint. + // This shouldn't actually happen for constants used in types, modulo + // bugs. The `delay_span_bug` here ensures it won't be ignored. + ConstEvalFailure(ErrorHandled::Linted) => { + self.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint"); + 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<'_>) -> Option<(Span, Vec<ArgKind>)> { + let sm = self.tcx.sess.source_map(); + let hir = self.tcx.hir(); + Some(match node { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), + .. + }) => ( + sm.guess_head_span(span), + hir.body(id) + .params + .iter() + .map(|arg| { + if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = + *arg.pat + { + Some(ArgKind::Tuple( + Some(span), + args.iter() + .map(|pat| { + sm.span_to_snippet(pat.span) + .ok() + .map(|snippet| (snippet, "_".to_owned())) + }) + .collect::<Option<Vec<_>>>()?, + )) + } else { + let name = sm.span_to_snippet(arg.pat.span).ok()?; + Some(ArgKind::Arg(name, "_".to_owned())) + } + }) + .collect::<Option<Vec<ArgKind>>>()?, + ), + Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) + | Node::ImplItem(&hir::ImplItem { + span, + kind: hir::ImplItemKind::Fn(ref sig, _), + .. + }) + | Node::TraitItem(&hir::TraitItem { + span, + kind: hir::TraitItemKind::Fn(ref sig, _), + .. + }) => ( + sm.guess_head_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::<Vec<ArgKind>>(), + ), + Node::Ctor(ref variant_data) => { + let span = variant_data.ctor_hir_id().map(|id| hir.span(id)).unwrap_or(DUMMY_SP); + let span = sm.guess_head_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<Span>, + expected_args: Vec<ArgKind>, + found_args: Vec<ArgKind>, + 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_verbose( + pipe_span, + &format!( + "consider changing the closure to take and ignore the expected argument{}", + pluralize!(expected_args.len()) + ), + 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::<Vec<String>>() + .join(", "); + err.span_suggestion_verbose( + 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::<Vec<String>>() + .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::<Vec<String>>() + .join(", ") + ) + } else { + String::new() + }, + ); + err.span_suggestion_verbose( + 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<hir::BodyId>, + 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<ty::TraitRef<'tcx>>; + + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec<ty::TraitRef<'tcx>>, + err: &mut DiagnosticBuilder<'_>, + ); + + /// Gets the parent trait chain start + fn get_parent_trait_ref( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(String, Option<Span>)>; + + /// 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>, + ); + + /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the + /// `trait_ref`. + /// + /// For this to work, `new_self_ty` must have no escaping bound variables. + fn mk_trait_obligation_with_new_self_ty( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + new_self_ty: Ty<'tcx>, + ) -> PredicateObligation<'tcx>; + + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option<hir::BodyId>, + ); + + fn predicate_can_apply( + &self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>, + ) -> bool; + + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'tcx>, + obligation: &PredicateObligation<'tcx>, + ); + + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut DiagnosticBuilder<'tcx>, + 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; + } + + // FIXME: It should be possible to deal with `ForAll` in a cleaner way. + let (cond, error) = match (cond.skip_binders(), error.skip_binders()) { + (ty::PredicateAtom::Trait(..), ty::PredicateAtom::Trait(error, _)) => { + (cond, ty::Binder::bind(error)) + } + _ => { + // FIXME: make this work in other cases too. + return false; + } + }; + + for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { + if let ty::PredicateAtom::Trait(implication, _) = obligation.predicate.skip_binders() { + let error = error.to_poly_trait_ref(); + let implication = ty::Binder::bind(implication.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<hir::BodyId>, + 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(); + } + FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => { + self.report_mismatched_consts( + &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::PredicateAtom::Projection(data) = predicate.skip_binders() { + let mut selcx = SelectionContext::new(self); + let (data, _) = self.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + &ty::Binder::bind(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<u32> { + 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, + } + } + + 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<ty::TraitRef<'tcx>> { + 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 + .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.map(|def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect(), + } + } + + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec<ty::TraitRef<'tcx>>, + 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::<Vec<String>>(); + + // 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<Span>)> { + 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.skip_binder().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_trait_obligation_with_new_self_ty( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + new_self_ty: Ty<'tcx>, + ) -> PredicateObligation<'tcx> { + assert!(!new_self_ty.has_escaping_bound_vars()); + + let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef { + substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]), + ..*tr + }); + + Obligation::new( + ObligationCause::dummy(), + param_env, + trait_ref.without_const().to_predicate(self.tcx), + ) + } + + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option<hir::BodyId>, + ) { + // 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.skip_binders() { + ty::PredicateAtom::Trait(data, _) => { + let trait_ref = ty::Binder::bind(data.trait_ref); + let self_ty = trait_ref.skip_binder().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 "<generic + // #0> 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 satisfy `{}`", 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.iter().any(|p| p.name != kw::SelfUpper) + && !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]>::<T>` + // ... + // LL | const fn const_val<T: Sized>() -> usize { + // | - required by this bound in `Tt::const_val` + // | + // = note: cannot satisfy `_: Tt` + + err.span_suggestion_verbose( + span.shrink_to_hi(), + &format!( + "consider specifying the type argument{} in the function call", + pluralize!(generics.params.len()), + ), + format!( + "::<{}>", + generics + .params + .iter() + .map(|p| p.name.to_string()) + .collect::<Vec<String>>() + .join(", ") + ), + Applicability::HasPlaceholders, + ); + } + } + err + } + + ty::PredicateAtom::WellFormed(arg) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if arg.references_error() || self.tcx.sess.has_errors() { + return; + } + + match arg.unpack() { + GenericArgKind::Lifetime(lt) => { + span_bug!(span, "unexpected well formed predicate: {:?}", lt) + } + GenericArgKind::Type(ty) => { + self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) + } + GenericArgKind::Const(ct) => { + self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) + } + } + } + + ty::PredicateAtom::Subtype(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; + // 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::PredicateAtom::Projection(data) => { + let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); + let self_ty = trait_ref.skip_binder().self_ty(); + let ty = data.ty; + if predicate.references_error() { + return; + } + if self_ty.needs_infer() && ty.needs_infer() { + // We do this for the `foo.collect()?` case to produce a suggestion. + let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); + err.note(&format!("cannot satisfy `{}`", predicate)); + err + } else { + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ); + err.span_label(span, &format!("cannot satisfy `{}`", predicate)); + err + } + } + + _ => { + if self.tcx.sess.has_errors() { + return; + } + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ); + err.span_label(span, &format!("cannot satisfy `{}`", 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>, 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(selcx.tcx()), + ); + + self.predicate_may_hold(&obligation) + }) + } + + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'tcx>, + 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<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) { + let (pred, item_def_id, span) = + match (obligation.predicate.skip_binders(), obligation.cause.code.peel_derives()) { + ( + ty::PredicateAtom::Trait(pred, _), + &ObligationCauseCode::BindingObligation(item_def_id, span), + ) => (pred, item_def_id, span), + _ => return, + }; + + let node = match ( + self.tcx.hir().get_if_local(item_def_id), + Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + ) { + (Some(node), true) => node, + _ => return, + }; + let generics = match node.generics() { + Some(generics) => generics, + None => return, + }; + for param in generics.params { + if param.span != span + || param.bounds.iter().any(|bound| { + bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id()) + == self.tcx.lang_items().sized_trait() + }) + { + continue; + } + match node { + hir::Node::Item( + item + @ + hir::Item { + kind: + hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..), + .. + }, + ) => { + // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a + // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);` + // is not. + let mut visitor = FindTypeParam { + param: param.name.ident().name, + invalid_spans: vec![], + nested: false, + }; + visitor.visit_item(item); + if !visitor.invalid_spans.is_empty() { + let mut multispan: MultiSpan = param.span.into(); + multispan.push_span_label( + param.span, + format!("this could be changed to `{}: ?Sized`...", param.name.ident()), + ); + for sp in visitor.invalid_spans { + multispan.push_span_label( + sp, + format!( + "...if indirection was used here: `Box<{}>`", + param.name.ident(), + ), + ); + } + err.span_help( + multispan, + &format!( + "you could relax the implicit `Sized` bound on `{T}` if it were \ + used through indirection like `&{T}` or `Box<{T}>`", + T = param.name.ident(), + ), + ); + return; + } + } + _ => {} + } + let (span, separator) = match param.bounds { + [] => (span.shrink_to_hi(), ":"), + [.., bound] => (bound.span().shrink_to_hi(), " +"), + }; + err.span_suggestion_verbose( + 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 + } +} + +/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting +/// `param: ?Sized` would be a valid constraint. +struct FindTypeParam { + param: rustc_span::Symbol, + invalid_spans: Vec<Span>, + nested: bool, +} + +impl<'v> Visitor<'v> for FindTypeParam { + type Map = rustc_hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + // We collect the spans of all uses of the "bare" type param, like in `field: T` or + // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be + // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` + // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases + // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors + // in that case should make what happened clear enough. + match ty.kind { + hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {} + hir::TyKind::Path(hir::QPath::Resolved(None, path)) + if path.segments.len() == 1 && path.segments[0].ident.name == self.param => + { + if !self.nested { + self.invalid_spans.push(ty.span); + } + } + hir::TyKind::Path(_) => { + let prev = self.nested; + self.nested = true; + hir::intravisit::walk_ty(self, ty); + self.nested = prev; + } + _ => { + hir::intravisit::walk_ty(self, ty); + } + } + } +} + +pub fn recursive_type_with_infinite_size_error( + tcx: TyCtxt<'tcx>, + type_def_id: DefId, + spans: Vec<Span>, +) { + assert!(type_def_id.is_local()); + let span = tcx.hir().span_if_local(type_def_id).unwrap(); + let span = tcx.sess.source_map().guess_head_span(span); + let path = tcx.def_path_str(type_def_id); + let mut err = + struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path); + err.span_label(span, "recursive type has infinite size"); + for &span in &spans { + err.span_label(span, "recursive without indirection"); + } + let msg = format!( + "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable", + path, + ); + if spans.len() <= 4 { + err.multipart_suggestion( + &msg, + spans + .iter() + .flat_map(|&span| { + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ] + .into_iter() + }) + .collect(), + Applicability::HasPlaceholders, + ); + } else { + err.help(&msg); + } + err.emit(); +} + +/// 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<Span>, 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<Span>) -> ArgKind { + match t.kind { + ty::Tuple(ref tys) => ArgKind::Tuple( + span, + tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(), + ), + _ => ArgKind::Arg("_".to_owned(), t.to_string()), + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs new file mode 100644 index 00000000000..d2b9f84af33 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -0,0 +1,237 @@ +use super::{ + ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation, +}; +use crate::infer::InferCtxt; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, GenericParamDefKind}; +use rustc_span::symbol::sym; + +use super::InferCtxtPrivExt; + +crate trait InferCtxtExt<'tcx> { + /*private*/ + fn impl_similar_to( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) -> Option<DefId>; + + /*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>, + obligation: &PredicateObligation<'tcx>, + ) -> Option<DefId> { + let tcx = self.tcx; + let param_env = obligation.param_env; + let trait_ref = tcx.erase_late_bound_regions(&trait_ref); + let trait_self_ty = trait_ref.self_ty(); + + let mut self_match_impls = vec![]; + let mut fuzzy_match_impls = vec![]; + + self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { + let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); + let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs); + + let impl_self_ty = impl_trait_ref.self_ty(); + + if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) { + self_match_impls.push(def_id); + + if trait_ref + .substs + .types() + .skip(1) + .zip(impl_trait_ref.substs.types().skip(1)) + .all(|(u, v)| self.fuzzy_match_tys(u, v)) + { + fuzzy_match_impls.push(def_id); + } + } + }); + + let impl_def_id = if self_match_impls.len() == 1 { + self_match_impls[0] + } else if fuzzy_match_impls.len() == 1 { + fuzzy_match_impls[0] + } else { + return None; + }; + + tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id) + } + + /// Used to set on_unimplemented's `ItemContext` + /// to be the enclosing (async) block/function/closure + fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { + let hir = &self.tcx.hir(); + let node = hir.find(hir_id)?; + match &node { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { + self.describe_generator(*body_id).or_else(|| { + Some(match sig.header { + hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function", + _ => "a function", + }) + }) + } + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), + .. + }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")), + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, body_id), + .. + }) => self.describe_generator(*body_id).or_else(|| { + Some(match sig.header { + hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method", + _ => "a method", + }) + }), + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), + .. + }) => self.describe_generator(*body_id).or_else(|| { + Some(if gen_movability.is_some() { "an async closure" } else { "a closure" }) + }), + hir::Node::Expr(hir::Expr { .. }) => { + let parent_hid = hir.get_parent_node(hir_id); + if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None } + } + _ => None, + } + } + + fn on_unimplemented_note( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) -> OnUnimplementedNote { + let def_id = + self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id()); + let trait_ref = trait_ref.skip_binder(); + + let mut flags = vec![]; + flags.push(( + sym::ItemContext, + self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), + )); + + match obligation.cause.code { + ObligationCauseCode::BuiltinDerivedObligation(..) + | ObligationCauseCode::ImplDerivedObligation(..) + | ObligationCauseCode::DerivedObligation(..) => {} + _ => { + // this is a "direct", user-specified, rather than derived, + // obligation. + flags.push((sym::direct, None)); + } + } + + if let ObligationCauseCode::ItemObligation(item) + | ObligationCauseCode::BindingObligation(item, _) = obligation.cause.code + { + // FIXME: maybe also have some way of handling methods + // from other traits? That would require name resolution, + // which we might want to be some sort of hygienic. + // + // Currently I'm leaving it for what I need for `try`. + if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { + let method = self.tcx.item_name(item); + flags.push((sym::from_method, None)); + flags.push((sym::from_method, Some(method.to_string()))); + } + } + if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) { + flags.push((sym::parent_trait, Some(t))); + } + + if let Some(k) = obligation.cause.span.desugaring_kind() { + flags.push((sym::from_desugaring, None)); + flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); + } + let generics = self.tcx.generics_of(def_id); + let self_ty = trait_ref.self_ty(); + // This is also included through the generics list as `Self`, + // but the parser won't allow you to use it + flags.push((sym::_Self, Some(self_ty.to_string()))); + if let Some(def) = self_ty.ty_adt_def() { + // We also want to be able to select self's original + // signature with no type arguments resolved + flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string()))); + } + + for param in generics.params.iter() { + let value = match param.kind { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { + trait_ref.substs[param.index as usize].to_string() + } + GenericParamDefKind::Lifetime => continue, + }; + let name = param.name; + flags.push((name, Some(value))); + } + + if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { + flags.push((sym::crate_local, None)); + } + + // Allow targeting all integers using `{integral}`, even if the exact type was resolved + if self_ty.is_integral() { + flags.push((sym::_Self, Some("{integral}".to_owned()))); + } + + if let ty::Array(aty, len) = self_ty.kind { + flags.push((sym::_Self, Some("[]".to_owned()))); + flags.push((sym::_Self, Some(format!("[{}]", aty)))); + if let Some(def) = aty.ty_adt_def() { + // We also want to be able to select the array's type's original + // signature with no type arguments resolved + flags.push(( + sym::_Self, + Some(format!("[{}]", self.tcx.type_of(def.did).to_string())), + )); + let tcx = self.tcx; + if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) { + flags.push(( + sym::_Self, + Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)), + )); + } else { + flags.push(( + sym::_Self, + Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())), + )); + } + } + } + if let ty::Dynamic(traits, _) = self_ty.kind { + for t in traits.skip_binder() { + if let ty::ExistentialPredicate::Trait(trait_ref) = t { + flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) + } + } + } + + if let Ok(Some(command)) = + OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) + { + command.evaluate(self.tcx, trait_ref, &flags[..]) + } else { + OnUnimplementedNote::default() + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs new file mode 100644 index 00000000000..138293c9533 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -0,0 +1,2231 @@ +use super::{ + EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionContext, +}; + +use crate::autoderef::Autoderef; +use crate::infer::InferCtxt; +use crate::traits::normalize_projection_type; + +use rustc_data_structures::stack::ensure_sufficient_stack; +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; +use rustc_hir::intravisit::Visitor; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; +use rustc_middle::ty::{ + self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, + TyCtxt, TypeFoldable, WithConstness, +}; +use rustc_middle::ty::{TypeAndMut, TypeckResults}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{MultiSpan, Span, DUMMY_SP}; +use std::fmt; + +use super::InferCtxtPrivExt; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; + +#[derive(Debug)] +pub enum GeneratorInteriorOrUpvar { + // span of interior type + Interior(Span), + // span of upvar + Upvar(Span), +} + +// This trait is public to expose the diagnostics methods to clippy. +pub trait InferCtxtExt<'tcx> { + fn suggest_restricting_param_bound( + &self, + err: &mut DiagnosticBuilder<'_>, + trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, + ); + + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + points_at_arg: bool, + ); + + fn get_closure_name( + &self, + def_id: DefId, + err: &mut DiagnosticBuilder<'_>, + msg: &str, + ) -> Option<String>; + + fn suggest_fn_call( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + points_at_arg: bool, + ); + + fn suggest_add_reference_to_arg( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + points_at_arg: bool, + has_custom_message: bool, + ) -> bool; + + fn suggest_remove_reference( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + ); + + fn suggest_change_mut( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + points_at_arg: bool, + ); + + fn suggest_semicolon_removal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + span: Span, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + ); + + fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>; + + fn suggest_impl_trait( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + ) -> bool; + + fn point_at_returns_when_relevant( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ); + + fn report_closure_arg_mismatch( + &self, + span: Span, + found_span: Option<Span>, + 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<'_>, + interior_or_upvar_span: GeneratorInteriorOrUpvar, + interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>, + inner_generator_body: Option<&hir::Body<'tcx>>, + outer_generator: Option<DefId>, + trait_ref: ty::TraitRef<'tcx>, + target_ty: Ty<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + obligation: &PredicateObligation<'tcx>, + next_code: Option<&ObligationCauseCode<'tcx>>, + ); + + fn note_obligation_cause_code<T>( + &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<'_>); + + /// Suggest to await before try: future? => future.await? + fn suggest_await_before_try( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + span: Span, + ); +} + +fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { + ( + generics.where_clause.tail_span_for_suggestion(), + format!( + "{} {}", + if !generics.where_clause.predicates.is_empty() { "," } else { " where" }, + pred, + ), + ) +} + +/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but +/// it can also be an `impl Trait` param that needs to be decomposed to a type +/// param for cleaner code. +fn suggest_restriction( + tcx: TyCtxt<'tcx>, + generics: &hir::Generics<'tcx>, + msg: &str, + err: &mut DiagnosticBuilder<'_>, + fn_sig: Option<&hir::FnSig<'_>>, + projection: Option<&ty::ProjectionTy<'_>>, + trait_ref: ty::PolyTraitRef<'tcx>, + super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, +) { + // When we are dealing with a trait, `super_traits` will be `Some`: + // Given `trait T: A + B + C {}` + // - ^^^^^^^^^ GenericBounds + // | + // &Ident + let span = generics.where_clause.span_for_predicates_or_empty_place(); + if span.from_expansion() || span.desugaring_kind().is_some() { + return; + } + // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... + if let Some((bound_str, fn_sig)) = + fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind { + // Shenanigans to get the `Trait` from the `impl Trait`. + ty::Param(param) => { + // `fn foo(t: impl Trait)` + // ^^^^^ get this string + param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig)) + } + _ => None, + }) + { + // We know we have an `impl Trait` that doesn't satisfy a required projection. + + // Find all of the ocurrences of `impl Trait` for `Trait` in the function arguments' + // types. There should be at least one, but there might be *more* than one. In that + // case we could just ignore it and try to identify which one needs the restriction, + // but instead we choose to suggest replacing all instances of `impl Trait` with `T` + // where `T: Trait`. + let mut ty_spans = vec![]; + let impl_trait_str = format!("impl {}", bound_str); + for input in fn_sig.decl.inputs { + if let hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { segments: [segment], .. }, + )) = input.kind + { + if segment.ident.as_str() == impl_trait_str.as_str() { + // `fn foo(t: impl Trait)` + // ^^^^^^^^^^ get this to suggest `T` instead + + // There might be more than one `impl Trait`. + ty_spans.push(input.span); + } + } + } + + let type_param_name = generics.params.next_type_param_name(Some(&bound_str)); + // The type param `T: Trait` we will suggest to introduce. + let type_param = format!("{}: {}", type_param_name, bound_str); + + // FIXME: modify the `trait_ref` instead of string shenanigans. + // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`. + let pred = trait_ref.without_const().to_predicate(tcx).to_string(); + let pred = pred.replace(&impl_trait_str, &type_param_name); + let mut sugg = vec![ + match generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) + .last() + { + // `fn foo(t: impl Trait)` + // ^ suggest `<T: Trait>` here + None => (generics.span, format!("<{}>", type_param)), + // `fn foo<A>(t: impl Trait)` + // ^^^ suggest `<A, T: Trait>` here + Some(param) => ( + param.bounds_span().unwrap_or(param.span).shrink_to_hi(), + format!(", {}", type_param), + ), + }, + // `fn foo(t: impl Trait)` + // ^ suggest `where <T as Trait>::A: Bound` + predicate_constraint(generics, pred), + ]; + sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string()))); + + // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`. + // FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest + // `fn foo(t: impl Trait<A: Bound>)` instead. + err.multipart_suggestion( + "introduce a type parameter with a trait bound instead of using `impl Trait`", + sugg, + Applicability::MaybeIncorrect, + ); + } else { + // Trivial case: `T` needs an extra bound: `T: Bound`. + let (sp, suggestion) = match super_traits { + None => predicate_constraint( + generics, + trait_ref.without_const().to_predicate(tcx).to_string(), + ), + Some((ident, bounds)) => match bounds { + [.., bound] => ( + bound.span().shrink_to_hi(), + format!(" + {}", trait_ref.print_only_trait_path().to_string()), + ), + [] => ( + ident.span.shrink_to_hi(), + format!(": {}", trait_ref.print_only_trait_path().to_string()), + ), + }, + }; + + err.span_suggestion_verbose( + sp, + &format!("consider further restricting {}", msg), + suggestion, + Applicability::MachineApplicable, + ); + } +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { + fn suggest_restricting_param_bound( + &self, + mut err: &mut DiagnosticBuilder<'_>, + trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, + ) { + let self_ty = trait_ref.skip_binder().self_ty(); + let (param_ty, projection) = match &self_ty.kind { + ty::Param(_) => (true, None), + ty::Projection(projection) => (false, Some(projection)), + _ => return, + }; + + // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we + // don't suggest `T: Sized + ?Sized`. + let mut hir_id = body_id; + while let Some(node) = self.tcx.hir().find(hir_id) { + match node { + hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Trait(_, _, generics, bounds, _), + .. + }) if self_ty == self.tcx.types.self_param => { + assert!(param_ty); + // Restricting `Self` for a single method. + suggest_restriction( + self.tcx, + &generics, + "`Self`", + err, + None, + projection, + trait_ref, + Some((ident, bounds)), + ); + return; + } + + hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Fn(..), + .. + }) if self_ty == self.tcx.types.self_param => { + assert!(param_ty); + // Restricting `Self` for a single method. + suggest_restriction( + self.tcx, &generics, "`Self`", err, None, projection, trait_ref, None, + ); + return; + } + + hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Fn(fn_sig, ..), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + generics, + kind: hir::ImplItemKind::Fn(fn_sig, ..), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(fn_sig, generics, _), .. + }) if projection.is_some() => { + // Missing restriction on associated type of type parameter (unmet projection). + suggest_restriction( + self.tcx, + &generics, + "the associated type", + err, + Some(fn_sig), + projection, + trait_ref, + None, + ); + return; + } + hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Trait(_, _, generics, _, _) + | hir::ItemKind::Impl { generics, .. }, + .. + }) if projection.is_some() => { + // Missing restriction on associated type of type parameter (unmet projection). + suggest_restriction( + self.tcx, + &generics, + "the associated type", + err, + None, + projection, + trait_ref, + None, + ); + return; + } + + hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Struct(_, generics) + | hir::ItemKind::Enum(_, generics) + | hir::ItemKind::Union(_, generics) + | hir::ItemKind::Trait(_, _, generics, ..) + | hir::ItemKind::Impl { generics, .. } + | hir::ItemKind::Fn(_, generics, _) + | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::TraitAlias(generics, _) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { generics, .. }) + | hir::Node::ImplItem(hir::ImplItem { generics, .. }) + if param_ty => + { + // Missing generic type parameter bound. + let param_name = self_ty.to_string(); + let constraint = trait_ref.print_only_trait_path().to_string(); + if suggest_constraining_type_param( + self.tcx, + generics, + &mut err, + ¶m_name, + &constraint, + Some(trait_ref.def_id()), + ) { + return; + } + } + + hir::Node::Crate(..) => return, + + _ => {} + } + + hir_id = self.tcx.hir().get_parent_item(hir_id); + } + } + + /// When after several dereferencing, the reference satisfies the trait + /// binding. This function provides dereference suggestion for this + /// specific situation. + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + points_at_arg: bool, + ) { + // It only make sense when suggesting dereferences for arguments + if !points_at_arg { + return; + } + let param_env = obligation.param_env; + let body_id = obligation.cause.body_id; + let span = obligation.cause.span; + let real_trait_ref = match &obligation.cause.code { + ObligationCauseCode::ImplDerivedObligation(cause) + | ObligationCauseCode::DerivedObligation(cause) + | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref, + _ => trait_ref, + }; + let real_ty = match real_trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + if let ty::Ref(region, base_ty, mutbl) = real_ty.kind { + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + if let Some(steps) = autoderef.find_map(|(ty, steps)| { + // Re-add the `&` + let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty); + Some(steps).filter(|_| self.predicate_may_hold(&obligation)) + }) { + if steps > 0 { + if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { + // Don't care about `&mut` because `DerefMut` is used less + // often and user will not expect autoderef happens. + if src.starts_with('&') && !src.starts_with("&mut ") { + let derefs = "*".repeat(steps); + err.span_suggestion( + span, + "consider adding dereference here", + format!("&{}{}", derefs, &src[1..]), + Applicability::MachineApplicable, + ); + } + } + } + } + } + } + + /// 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. + fn get_closure_name( + &self, + def_id: DefId, + err: &mut DiagnosticBuilder<'_>, + msg: &str, + ) -> Option<String> { + let get_name = + |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind<'_>| -> Option<String> { + // Get the local name of this closure. This can be inaccurate because + // of the possibility of reassignment, but this should be good enough. + match &kind { + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { + Some(format!("{}", name)) + } + _ => { + err.note(&msg); + None + } + } + }; + + let hir = self.tcx.hir(); + let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); + let parent_node = hir.get_parent_node(hir_id); + match hir.find(parent_node) { + Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { + get_name(err, &local.pat.kind) + } + // Different to previous arm because one is `&hir::Local` and the other + // is `P<hir::Local>`. + Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind), + _ => None, + } + } + + /// 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`. + fn suggest_fn_call( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + points_at_arg: bool, + ) { + let self_ty = match trait_ref.self_ty().no_bound_vars() { + None => return, + Some(ty) => ty, + }; + + let (def_id, output_ty, callable) = match self_ty.kind { + ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"), + ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), + _ => return, + }; + let msg = format!("use parentheses to call the {}", callable); + + // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound + // variables, so bail out if we have any. + let output_ty = match output_ty.no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + let new_obligation = + self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_ref, output_ty); + + match self.evaluate_obligation(&new_obligation) { + Ok( + EvaluationResult::EvaluatedToOk + | EvaluationResult::EvaluatedToOkModuloRegions + | EvaluationResult::EvaluatedToAmbig, + ) => {} + _ => return, + } + let hir = self.tcx.hir(); + // Get the name of the callable and the arguments to be used in the suggestion. + let (snippet, sugg) = match hir.get_if_local(def_id) { + Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_, decl, _, span, ..), + .. + })) => { + err.span_label(*span, "consider calling this closure"); + let name = match self.get_closure_name(def_id, err, &msg) { + Some(name) => name, + None => return, + }; + let args = decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", "); + let sugg = format!("({})", args); + (format!("{}{}", name, sugg), sugg) + } + Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Fn(.., body_id), + .. + })) => { + err.span_label(ident.span, "consider calling this function"); + let body = hir.body(*body_id); + let args = body + .params + .iter() + .map(|arg| match &arg.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + // FIXME: provide a better suggestion when encountering `SelfLower`, it + // should suggest a method call. + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }) + .collect::<Vec<_>>() + .join(", "); + let sugg = format!("({})", args); + (format!("{}{}", ident, sugg), sugg) + } + _ => return, + }; + if points_at_arg { + // When the obligation error has been ensured to have been caused by + // an argument, the `obligation.cause.span` points at the expression + // of the argument, so we can provide a suggestion. This is signaled + // by `points_at_arg`. Otherwise, we give a more general note. + err.span_suggestion_verbose( + obligation.cause.span.shrink_to_hi(), + &msg, + sugg, + Applicability::HasPlaceholders, + ); + } else { + err.help(&format!("{}: `{}`", msg, snippet)); + } + } + + fn suggest_add_reference_to_arg( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + points_at_arg: bool, + has_custom_message: bool, + ) -> bool { + if !points_at_arg { + return false; + } + + let span = obligation.cause.span; + let param_env = obligation.param_env; + let trait_ref = trait_ref.skip_binder(); + + if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code { + // Try to apply the original trait binding obligation by borrowing. + let self_ty = trait_ref.self_ty(); + let found = self_ty.to_string(); + let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); + let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); + let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + new_trait_ref.without_const().to_predicate(self.tcx), + ); + + if self.predicate_must_hold_modulo_regions(&new_obligation) { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + // We have a very specific type of error, where just borrowing this argument + // might solve the problem. In cases like this, the important part is the + // original type obligation, not the last one that failed, which is arbitrary. + // Because of this, we modify the error to refer to the original obligation and + // return early in the caller. + + let msg = format!( + "the trait bound `{}: {}` is not satisfied", + found, + obligation.parent_trait_ref.skip_binder().print_only_trait_path(), + ); + if has_custom_message { + err.note(&msg); + } else { + err.message = vec![(msg, Style::NoStyle)]; + } + if snippet.starts_with('&') { + // This is already a literal borrow and the obligation is failing + // somewhere else in the obligation chain. Do not suggest non-sense. + return false; + } + err.span_label( + span, + &format!( + "expected an implementor of trait `{}`", + obligation.parent_trait_ref.skip_binder().print_only_trait_path(), + ), + ); + + // This if is to prevent a special edge-case + if !span.from_expansion() { + // We don't want a borrowing suggestion on the fields in structs, + // ``` + // struct Foo { + // the_foos: Vec<Foo> + // } + // ``` + + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } + return true; + } + } + } + false + } + + /// 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. + fn suggest_remove_reference( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + ) { + let span = obligation.cause.span; + + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let refs_number = + snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); + if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { + // Do not suggest removal of borrow from type arguments. + return; + } + + let mut suggested_ty = match trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + for refs_remaining in 0..refs_number { + if let ty::Ref(_, inner_ty, _) = suggested_ty.kind { + suggested_ty = inner_ty; + + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_ref, + suggested_ty, + ); + + if self.predicate_may_hold(&new_obligation) { + let sp = self + .tcx + .sess + .source_map() + .span_take_while(span, |c| c.is_whitespace() || *c == '&'); + + let remove_refs = refs_remaining + 1; + + let msg = if remove_refs == 1 { + "consider removing the leading `&`-reference".to_string() + } else { + format!("consider removing {} leading `&`-references", remove_refs) + }; + + err.span_suggestion_short( + sp, + &msg, + String::new(), + Applicability::MachineApplicable, + ); + break; + } + } else { + break; + } + } + } + } + + /// Check if the trait bound is implemented for a different mutability and note it in the + /// final error. + fn suggest_change_mut( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + points_at_arg: bool, + ) { + let span = obligation.cause.span; + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let refs_number = + snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); + if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { + // Do not suggest removal of borrow from type arguments. + return; + } + let trait_ref = self.resolve_vars_if_possible(trait_ref); + if trait_ref.has_infer_types_or_consts() { + // Do not ICE while trying to find if a reborrow would succeed on a trait with + // unresolved bindings. + return; + } + + if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { + if region.is_late_bound() || t_type.has_escaping_bound_vars() { + // Avoid debug assertion in `mk_obligation_for_def_id`. + // + // If the self type has escaping bound vars then it's not + // going to be the type of an expression, so the suggestion + // probably won't apply anyway. + return; + } + + let suggested_ty = match mutability { + hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type), + hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type), + }; + + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + &trait_ref, + suggested_ty, + ); + let suggested_ty_would_satisfy_obligation = self + .evaluate_obligation_no_overflow(&new_obligation) + .must_apply_modulo_regions(); + if suggested_ty_would_satisfy_obligation { + let sp = self + .tcx + .sess + .source_map() + .span_take_while(span, |c| c.is_whitespace() || *c == '&'); + if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 { + err.span_suggestion_verbose( + sp, + "consider changing this borrow's mutability", + "&mut ".to_string(), + Applicability::MachineApplicable, + ); + } else { + err.note(&format!( + "`{}` is implemented for `{:?}`, but not for `{:?}`", + trait_ref.print_only_trait_path(), + suggested_ty, + trait_ref.skip_binder().self_ty(), + )); + } + } + } + } + } + + fn suggest_semicolon_removal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + span: Span, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + ) { + let is_empty_tuple = + |ty: ty::Binder<Ty<'_>>| ty.skip_binder().kind == ty::Tuple(ty::List::empty()); + + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node(obligation.cause.body_id); + let node = hir.find(parent_node); + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(sig, _, body_id), .. + })) = node + { + let body = hir.body(*body_id); + if let hir::ExprKind::Block(blk, _) = &body.value.kind { + if sig.decl.output.span().overlaps(span) + && blk.expr.is_none() + && is_empty_tuple(trait_ref.self_ty()) + { + // FIXME(estebank): When encountering a method with a trait + // bound not satisfied in the return type with a body that has + // no return, suggest removal of semicolon on last statement. + // Once that is added, close #54771. + if let Some(ref stmt) = blk.stmts.last() { + let sp = self.tcx.sess.source_map().end_point(stmt.span); + err.span_label(sp, "consider removing this semicolon"); + } + } + } + } + } + + fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node(obligation.cause.body_id); + let sig = match hir.find(parent_node) { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) => sig, + _ => return None, + }; + + if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { Some(ret_ty.span) } else { None } + } + + /// 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. + fn suggest_impl_trait( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + ) -> bool { + match obligation.cause.code.peel_derives() { + // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. + ObligationCauseCode::SizedReturnType => {} + _ => return false, + } + + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node(obligation.cause.body_id); + let node = hir.find(parent_node); + let (sig, body_id) = if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(sig, _, body_id), + .. + })) = node + { + (sig, body_id) + } else { + return false; + }; + let body = hir.body(*body_id); + let trait_ref = self.resolve_vars_if_possible(trait_ref); + let ty = trait_ref.skip_binder().self_ty(); + let is_object_safe = match ty.kind { + ty::Dynamic(predicates, _) => { + // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. + predicates + .principal_def_id() + .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) + } + // We only want to suggest `impl Trait` to `dyn Trait`s. + // For example, `fn foo() -> str` needs to be filtered out. + _ => return false, + }; + + let ret_ty = if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { + ret_ty + } else { + return false; + }; + + // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for + // cases like `fn foo() -> (dyn Trait, i32) {}`. + // Recursively look for `TraitObject` types and if there's only one, use that span to + // suggest `impl Trait`. + + // Visit to make sure there's a single `return` type to suggest `impl Trait`, + // otherwise suggest using `Box<dyn Trait>` or an enum. + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(&body); + + let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); + + let mut ret_types = visitor + .returns + .iter() + .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) + .map(|ty| self.resolve_vars_if_possible(&ty)); + let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold( + (None, true, true), + |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool), + ty| { + let ty = self.resolve_vars_if_possible(&ty); + same &= + !matches!(ty.kind, ty::Error(_)) + && last_ty.map_or(true, |last_ty| { + // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes + // *after* in the dependency graph. + match (&ty.kind, &last_ty.kind) { + (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) + | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) + | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) + | ( + Infer(InferTy::FreshFloatTy(_)), + Infer(InferTy::FreshFloatTy(_)), + ) => true, + _ => ty == last_ty, + } + }); + (Some(ty), same, only_never_return && matches!(ty.kind, ty::Never)) + }, + ); + let all_returns_conform_to_trait = + if let Some(ty_ret_ty) = typeck_results.node_type_opt(ret_ty.hir_id) { + match ty_ret_ty.kind { + ty::Dynamic(predicates, _) => { + let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id); + let param_env = ty::ParamEnv::empty(); + only_never_return + || ret_types.all(|returned_ty| { + predicates.iter().all(|predicate| { + let pred = predicate.with_self_ty(self.tcx, returned_ty); + let obl = Obligation::new(cause.clone(), param_env, pred); + self.predicate_may_hold(&obl) + }) + }) + } + _ => false, + } + } else { + true + }; + + let sm = self.tcx.sess.source_map(); + let snippet = if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = ( + // Verify that we're dealing with a return `dyn Trait` + ret_ty.span.overlaps(span), + &ret_ty.kind, + sm.span_to_snippet(ret_ty.span), + // If any of the return types does not conform to the trait, then we can't + // suggest `impl Trait` nor trait objects: it is a type mismatch error. + all_returns_conform_to_trait, + ) { + snippet + } else { + return false; + }; + err.code(error_code!(E0746)); + err.set_primary_message("return type cannot have an unboxed trait object"); + err.children.clear(); + let impl_trait_msg = "for information on `impl Trait`, see \ + <https://doc.rust-lang.org/book/ch10-02-traits.html\ + #returning-types-that-implement-traits>"; + let trait_obj_msg = "for information on trait objects, see \ + <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ + #using-trait-objects-that-allow-for-values-of-different-types>"; + let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); + let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] }; + if only_never_return { + // No return paths, probably using `panic!()` or similar. + // Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`. + suggest_trait_object_return_type_alternatives( + err, + ret_ty.span, + trait_obj, + is_object_safe, + ); + } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) { + // Suggest `-> impl Trait`. + err.span_suggestion( + ret_ty.span, + &format!( + "use `impl {1}` as the return type, as all return paths are of type `{}`, \ + which implements `{1}`", + last_ty, trait_obj, + ), + format!("impl {}", trait_obj), + Applicability::MachineApplicable, + ); + err.note(impl_trait_msg); + } else { + if is_object_safe { + // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`. + // Get all the return values and collect their span and suggestion. + if let Some(mut suggestions) = visitor + .returns + .iter() + .map(|expr| { + let snip = sm.span_to_snippet(expr.span).ok()?; + Some((expr.span, format!("Box::new({})", snip))) + }) + .collect::<Option<Vec<_>>>() + { + // Add the suggestion for the return type. + suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj))); + err.multipart_suggestion( + "return a boxed trait object instead", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } else { + // This is currently not possible to trigger because E0038 takes precedence, but + // leave it in for completeness in case anything changes in an earlier stage. + err.note(&format!( + "if trait `{}` was object safe, you could return a trait object", + trait_obj, + )); + } + err.note(trait_obj_msg); + err.note(&format!( + "if all the returned values were of the same type you could use `impl {}` as the \ + return type", + trait_obj, + )); + err.note(impl_trait_msg); + err.note("you can create a new `enum` with a variant for each returned type"); + } + true + } + + fn point_at_returns_when_relevant( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + match obligation.cause.code.peel_derives() { + ObligationCauseCode::SizedReturnType => {} + _ => return, + } + + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node(obligation.cause.body_id); + let node = hir.find(parent_node); + if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = + node + { + let body = hir.body(*body_id); + // Point at all the `return`s in the function as they have failed trait bounds. + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(&body); + let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); + for expr in &visitor.returns { + if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { + let ty = self.resolve_vars_if_possible(&returned_ty); + err.span_label(expr.span, &format!("this returned value is of type `{}`", ty)); + } + } + } + } + + fn report_closure_arg_mismatch( + &self, + span: Span, + found_span: Option<Span>, + expected_ref: ty::PolyTraitRef<'tcx>, + found: ty::PolyTraitRef<'tcx>, + ) -> DiagnosticBuilder<'tcx> { + crate fn build_fn_sig_string<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + ) -> String { + let inputs = trait_ref.substs.type_at(1); + let sig = if let ty::Tuple(inputs) = inputs.kind { + tcx.mk_fn_sig( + inputs.iter().map(|k| k.expect_ty()), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + false, + hir::Unsafety::Normal, + ::rustc_target::spec::abi::Abi::Rust, + ) + } else { + tcx.mk_fn_sig( + ::std::iter::once(inputs), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + false, + hir::Unsafety::Normal, + ::rustc_target::spec::abi::Abi::Rust, + ) + }; + ty::Binder::bind(sig).to_string() + } + + let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0631, + "type mismatch in {} arguments", + if argument_is_closure { "closure" } else { "function" } + ); + + let found_str = format!( + "expected signature of `{}`", + build_fn_sig_string(self.tcx, found.skip_binder()) + ); + err.span_label(span, found_str); + + let found_span = found_span.unwrap_or(span); + let expected_str = format!( + "found signature of `{}`", + build_fn_sig_string(self.tcx, expected_ref.skip_binder()) + ); + err.span_label(found_span, expected_str); + + err + } + + fn suggest_fully_qualified_path( + &self, + err: &mut DiagnosticBuilder<'_>, + def_id: DefId, + span: Span, + trait_ref: DefId, + ) { + if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) { + if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { + err.note(&format!( + "{}s cannot be accessed directly on a `trait`, they can only be \ + accessed through a specific `impl`", + assoc_item.kind.as_def_kind().descr(def_id) + )); + err.span_suggestion( + span, + "use the fully qualified path to an implementation", + format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident), + Applicability::HasPlaceholders, + ); + } + } + } + + /// Adds an async-await specific note to the diagnostic when the future does not implement + /// an auto trait because of a captured type. + /// + /// ```text + /// note: future does not implement `Qux` as this value is used across an await + /// --> $DIR/issue-64130-3-other.rs:17:5 + /// | + /// LL | let x = Foo; + /// | - has type `Foo` + /// LL | baz().await; + /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + /// LL | } + /// | - `x` is later dropped here + /// ``` + /// + /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic + /// is "replaced" with a different message and a more specific error. + /// + /// ```text + /// error: future cannot be sent between threads safely + /// --> $DIR/issue-64130-2-send.rs:21:5 + /// | + /// LL | fn is_send<T: Send>(t: T) { } + /// | ---- required by this bound in `is_send` + /// ... + /// LL | is_send(bar()); + /// | ^^^^^^^ future returned by `bar` is not send + /// | + /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not + /// implemented for `Foo` + /// note: future is not send as this value is used across an await + /// --> $DIR/issue-64130-2-send.rs:15:5 + /// | + /// LL | let x = Foo; + /// | - has type `Foo` + /// LL | baz().await; + /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later + /// LL | } + /// | - `x` is later dropped here + /// ``` + /// + /// Returns `true` if an async-await specific note was added to the diagnostic. + fn maybe_note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + debug!( + "maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \ + obligation.cause.span={:?}", + obligation.predicate, obligation.cause.span + ); + let hir = self.tcx.hir(); + + // Attempt to detect an async-await error by looking at the obligation causes, looking + // for a generator to be present. + // + // When a future does not implement a trait because of a captured type in one of the + // generators somewhere in the call stack, then the result is a chain of obligations. + // + // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that + // future is passed as an argument to a function C which requires a `Send` type, then the + // chain looks something like this: + // + // - `BuiltinDerivedObligation` with a generator witness (B) + // - `BuiltinDerivedObligation` with a generator (B) + // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) + // - `BuiltinDerivedObligation` with a generator witness (A) + // - `BuiltinDerivedObligation` with a generator (A) + // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) + // - `BindingObligation` with `impl_send (Send requirement) + // + // The first obligation in the chain is the most useful and has the generator that captured + // the type. The last generator (`outer_generator` below) has information about where the + // bound was introduced. At least one generator should be present for this diagnostic to be + // modified. + let (mut trait_ref, mut target_ty) = match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(p, _) => (Some(p.trait_ref), Some(p.self_ty())), + _ => (None, None), + }; + let mut generator = None; + let mut outer_generator = None; + let mut next_code = Some(&obligation.cause.code); + while let Some(code) = next_code { + debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); + match code { + ObligationCauseCode::DerivedObligation(derived_obligation) + | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) + | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { + let ty = derived_obligation.parent_trait_ref.skip_binder().self_ty(); + debug!( + "maybe_note_obligation_cause_for_async_await: \ + parent_trait_ref={:?} self_ty.kind={:?}", + derived_obligation.parent_trait_ref, ty.kind + ); + + match ty.kind { + ty::Generator(did, ..) => { + generator = generator.or(Some(did)); + outer_generator = Some(did); + } + ty::GeneratorWitness(..) => {} + _ if generator.is_none() => { + trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder()); + target_ty = Some(ty); + } + _ => {} + } + + next_code = Some(derived_obligation.parent_code.as_ref()); + } + _ => break, + } + } + + // Only continue if a generator was found. + debug!( + "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \ + target_ty={:?}", + generator, trait_ref, target_ty + ); + let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) { + (Some(generator_did), Some(trait_ref), Some(target_ty)) => { + (generator_did, trait_ref, target_ty) + } + _ => return false, + }; + + let span = self.tcx.def_span(generator_did); + + // Do not ICE on closure typeck (#66868). + if !generator_did.is_local() { + return false; + } + + // Get the typeck results from the infcx if the generator is the function we are + // currently type-checking; otherwise, get them by performing a query. + // This is needed to avoid cycles. + let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()); + let generator_did_root = self.tcx.closure_base_def_id(generator_did); + debug!( + "maybe_note_obligation_cause_for_async_await: generator_did={:?} \ + generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}", + generator_did, + generator_did_root, + in_progress_typeck_results.as_ref().map(|t| t.hir_owner), + span + ); + let query_typeck_results; + let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results { + Some(t) if t.hir_owner.to_def_id() == generator_did_root => t, + _ => { + query_typeck_results = self.tcx.typeck(generator_did.expect_local()); + &query_typeck_results + } + }; + + let generator_body = generator_did + .as_local() + .map(|def_id| hir.local_def_id_to_hir_id(def_id)) + .and_then(|hir_id| hir.maybe_body_owned_by(hir_id)) + .map(|body_id| hir.body(body_id)); + let mut visitor = AwaitsVisitor::default(); + if let Some(body) = generator_body { + visitor.visit_body(body); + } + debug!("maybe_note_obligation_cause_for_async_await: awaits = {:?}", visitor.awaits); + + // Look for a type inside the generator interior that matches the target type to get + // a span. + let target_ty_erased = self.tcx.erase_regions(&target_ty); + let ty_matches = |ty| -> bool { + // Careful: the regions for types that appear in the + // generator interior are not generally known, so we + // want to erase them when comparing (and anyway, + // `Send` and other bounds are generally unaffected by + // the choice of region). When erasing regions, we + // also have to erase late-bound regions. This is + // because the types that appear in the generator + // interior generally contain "bound regions" to + // represent regions that are part of the suspended + // generator frame. Bound regions are preserved by + // `erase_regions` and so we must also call + // `erase_late_bound_regions`. + let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty)); + let ty_erased = self.tcx.erase_regions(&ty_erased); + let eq = ty::TyS::same_type(ty_erased, target_ty_erased); + debug!( + "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ + target_ty_erased={:?} eq={:?}", + ty_erased, target_ty_erased, eq + ); + eq + }; + + let mut interior_or_upvar_span = None; + let mut interior_extra_info = None; + + if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) { + interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| { + let upvar_ty = typeck_results.node_type(*upvar_id); + let upvar_ty = self.resolve_vars_if_possible(&upvar_ty); + if ty_matches(&upvar_ty) { + Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) + } else { + None + } + }); + }; + + typeck_results + .generator_interior_types + .iter() + .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty)) + .map(|cause| { + // Check to see if any awaited expressions have the target type. + let from_awaited_ty = visitor + .awaits + .into_iter() + .map(|id| hir.expect_expr(id)) + .find(|await_expr| { + let ty = typeck_results.expr_ty_adjusted(&await_expr); + debug!( + "maybe_note_obligation_cause_for_async_await: await_expr={:?}", + await_expr + ); + ty_matches(ty) + }) + .map(|expr| expr.span); + let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = + cause; + + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); + interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); + }); + + debug!( + "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \ + generator_interior_types={:?}", + interior_or_upvar_span, typeck_results.generator_interior_types + ); + if let Some(interior_or_upvar_span) = interior_or_upvar_span { + self.note_obligation_cause_for_async_await( + err, + interior_or_upvar_span, + interior_extra_info, + generator_body, + outer_generator, + trait_ref, + target_ty, + typeck_results, + obligation, + next_code, + ); + true + } else { + false + } + } + + /// Unconditionally adds the diagnostic note described in + /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. + fn note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + interior_or_upvar_span: GeneratorInteriorOrUpvar, + interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>, + inner_generator_body: Option<&hir::Body<'tcx>>, + outer_generator: Option<DefId>, + trait_ref: ty::TraitRef<'tcx>, + target_ty: Ty<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + obligation: &PredicateObligation<'tcx>, + next_code: Option<&ObligationCauseCode<'tcx>>, + ) { + let source_map = self.tcx.sess.source_map(); + + let is_async = inner_generator_body + .and_then(|body| body.generator_kind()) + .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..))) + .unwrap_or(false); + let (await_or_yield, an_await_or_yield) = + if is_async { ("await", "an await") } else { ("yield", "a yield") }; + let future_or_generator = if is_async { "future" } else { "generator" }; + + // Special case the primary error message when send or sync is the trait that was + // not implemented. + let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); + let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); + let hir = self.tcx.hir(); + let trait_explanation = if is_send || is_sync { + let (trait_name, trait_verb) = + if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; + + err.clear_code(); + err.set_primary_message(format!( + "{} cannot be {} between threads safely", + future_or_generator, trait_verb + )); + + let original_span = err.span.primary_span().unwrap(); + let mut span = MultiSpan::from_span(original_span); + + let message = outer_generator + .and_then(|generator_did| { + Some(match self.tcx.generator_kind(generator_did).unwrap() { + GeneratorKind::Gen => format!("generator is not {}", trait_name), + GeneratorKind::Async(AsyncGeneratorKind::Fn) => self + .tcx + .parent(generator_did) + .and_then(|parent_did| parent_did.as_local()) + .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .map(|name| { + format!("future returned by `{}` is not {}", name, trait_name) + })?, + GeneratorKind::Async(AsyncGeneratorKind::Block) => { + format!("future created by async block is not {}", trait_name) + } + GeneratorKind::Async(AsyncGeneratorKind::Closure) => { + format!("future created by async closure is not {}", trait_name) + } + }) + }) + .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name)); + + span.push_span_label(original_span, message); + err.set_span(span); + + format!("is not {}", trait_name) + } else { + format!("does not implement `{}`", trait_ref.print_only_trait_path()) + }; + + let mut explain_yield = |interior_span: Span, + yield_span: Span, + scope_span: Option<Span>| { + let mut span = MultiSpan::from_span(yield_span); + if let Ok(snippet) = source_map.span_to_snippet(interior_span) { + span.push_span_label( + yield_span, + format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), + ); + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + span.push_span_label( + source_map.end_point(scope_span), + format!("`{}` is later dropped here", snippet), + ); + } + } + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + }; + match interior_or_upvar_span { + GeneratorInteriorOrUpvar::Interior(interior_span) => { + if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { + if let Some(await_span) = from_awaited_ty { + // The type causing this obligation is one being awaited at await_span. + let mut span = MultiSpan::from_span(await_span); + span.push_span_label( + await_span, + format!( + "await occurs here on type `{}`, which {}", + target_ty, trait_explanation + ), + ); + err.span_note( + span, + &format!( + "future {not_trait} as it awaits another future which {not_trait}", + not_trait = trait_explanation + ), + ); + } else { + // Look at the last interior type to get a span for the `.await`. + debug!( + "note_obligation_cause_for_async_await generator_interior_types: {:#?}", + typeck_results.generator_interior_types + ); + explain_yield(interior_span, yield_span, scope_span); + } + + if let Some(expr_id) = expr { + let expr = hir.expect_expr(expr_id); + debug!("target_ty evaluated from {:?}", expr); + + let parent = hir.get_parent_node(expr_id); + if let Some(hir::Node::Expr(e)) = hir.find(parent) { + let parent_span = hir.span(parent); + let parent_did = parent.owner.to_def_id(); + // ```rust + // impl T { + // fn foo(&self) -> i32 {} + // } + // T.foo(); + // ^^^^^^^ a temporary `&T` created inside this method call due to `&self` + // ``` + // + let is_region_borrow = typeck_results + .expr_adjustments(expr) + .iter() + .any(|adj| adj.is_region_borrow()); + + // ```rust + // struct Foo(*const u8); + // bar(Foo(std::ptr::null())).await; + // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor. + // ``` + debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did)); + let is_raw_borrow_inside_fn_like_call = + match self.tcx.def_kind(parent_did) { + DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(), + _ => false, + }; + + if (typeck_results.is_method_call(e) && is_region_borrow) + || is_raw_borrow_inside_fn_like_call + { + err.span_help( + parent_span, + "consider moving this into a `let` \ + binding to create a shorter lived borrow", + ); + } + } + } + } + } + GeneratorInteriorOrUpvar::Upvar(upvar_span) => { + let mut span = MultiSpan::from_span(upvar_span); + span.push_span_label( + upvar_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note(span, &format!("captured value {}", trait_explanation)); + } + } + + // Add a note for the item obligation that remains - normally a note pointing to the + // bound that introduced the obligation (e.g. `T: Send`). + debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); + self.note_obligation_cause_code( + err, + &obligation.predicate, + next_code.unwrap(), + &mut Vec::new(), + ); + } + + fn note_obligation_cause_code<T>( + &self, + err: &mut DiagnosticBuilder<'_>, + predicate: &T, + cause_code: &ObligationCauseCode<'tcx>, + obligated_types: &mut Vec<&ty::TyS<'tcx>>, + ) where + T: fmt::Display, + { + let tcx = self.tcx; + match *cause_code { + ObligationCauseCode::ExprAssignable + | ObligationCauseCode::MatchExpressionArm { .. } + | ObligationCauseCode::Pattern { .. } + | ObligationCauseCode::IfExpression { .. } + | ObligationCauseCode::IfExpressionWithNoElse + | ObligationCauseCode::MainFunctionType + | ObligationCauseCode::StartFunctionType + | ObligationCauseCode::IntrinsicType + | ObligationCauseCode::MethodReceiver + | ObligationCauseCode::ReturnNoExpression + | ObligationCauseCode::UnifyReceiver(..) + | ObligationCauseCode::MiscObligation => {} + ObligationCauseCode::SliceOrArrayElem => { + err.note("slice and array elements must have `Sized` type"); + } + ObligationCauseCode::TupleElem => { + err.note("only the last element of a tuple may have a dynamically sized type"); + } + ObligationCauseCode::ProjectionWf(data) => { + err.note(&format!("required so that the projection `{}` is well-formed", data,)); + } + ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { + err.note(&format!( + "required so that reference `{}` does not outlive its referent", + ref_ty, + )); + } + ObligationCauseCode::ObjectTypeBound(object_ty, region) => { + err.note(&format!( + "required so that the lifetime bound of `{}` for `{}` is satisfied", + region, object_ty, + )); + } + ObligationCauseCode::ItemObligation(item_def_id) => { + let item_name = tcx.def_path_str(item_def_id); + let msg = format!("required by `{}`", item_name); + if let Some(sp) = tcx.hir().span_if_local(item_def_id) { + let sp = tcx.sess.source_map().guess_head_span(sp); + err.span_label(sp, &msg); + } else { + err.note(&msg); + } + } + ObligationCauseCode::BindingObligation(item_def_id, span) => { + let item_name = tcx.def_path_str(item_def_id); + let msg = format!("required by this bound in `{}`", item_name); + if let Some(ident) = tcx.opt_item_name(item_def_id) { + let sm = tcx.sess.source_map(); + let same_line = + match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) { + (Ok(l), Ok(r)) => l.line == r.line, + _ => true, + }; + if !ident.span.overlaps(span) && !same_line { + err.span_label(ident.span, "required by a bound in this"); + } + } + if span != DUMMY_SP { + err.span_label(span, &msg); + } else { + err.note(&msg); + } + } + ObligationCauseCode::ObjectCastObligation(object_ty) => { + err.note(&format!( + "required for the cast to the object type `{}`", + self.ty_to_string(object_ty) + )); + } + ObligationCauseCode::Coercion { source: _, target } => { + err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); + } + ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => { + err.note( + "the `Copy` trait is required because the repeated element will be copied", + ); + if suggest_const_in_array_repeat_expressions { + err.note( + "this array initializer can be evaluated at compile-time, see issue \ + #49147 <https://github.com/rust-lang/rust/issues/49147> \ + for more information", + ); + if tcx.sess.opts.unstable_features.is_nightly_build() { + err.help( + "add `#![feature(const_in_array_repeat_expressions)]` to the \ + crate attributes to enable", + ); + } + } + } + ObligationCauseCode::VariableType(hir_id) => { + let parent_node = self.tcx.hir().get_parent_node(hir_id); + match self.tcx.hir().find(parent_node) { + Some(Node::Local(hir::Local { + init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }), + .. + })) => { + // 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. + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider borrowing here", + "&".to_owned(), + Applicability::MachineApplicable, + ); + err.note("all local variables must have a statically known size"); + } + Some(Node::Param(param)) => { + err.span_suggestion_verbose( + param.ty_span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed types \ + always have a known size", + "&".to_owned(), + Applicability::MachineApplicable, + ); + } + _ => { + err.note("all local variables must have a statically known size"); + } + } + if !self.tcx.features().unsized_locals { + err.help("unsized locals are gated as an unstable feature"); + } + } + ObligationCauseCode::SizedArgumentType(sp) => { + if let Some(span) = sp { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed types \ + always have a known size", + "&".to_string(), + Applicability::MachineApplicable, + ); + } else { + err.note("all function arguments must have a statically known size"); + } + if tcx.sess.opts.unstable_features.is_nightly_build() + && !self.tcx.features().unsized_locals + { + err.help("unsized locals are gated as an unstable feature"); + } + } + ObligationCauseCode::SizedReturnType => { + err.note("the return type of a function must have a statically known size"); + } + ObligationCauseCode::SizedYieldType => { + err.note("the yield type of a generator must have a statically known size"); + } + ObligationCauseCode::AssignmentLhsSized => { + err.note("the left-hand-side of an assignment must have a statically known size"); + } + ObligationCauseCode::TupleInitializerSized => { + err.note("tuples must have a statically known size to be initialized"); + } + ObligationCauseCode::StructInitializerSized => { + err.note("structs must have a statically known size to be initialized"); + } + ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => { + match *item { + AdtKind::Struct => { + if last { + err.note( + "the last field of a packed struct may only have a \ + dynamically sized type if it does not need drop to be run", + ); + } else { + err.note( + "only the last field of a struct may have a dynamically sized type", + ); + } + } + AdtKind::Union => { + err.note("no field of a union may have a dynamically sized type"); + } + AdtKind::Enum => { + err.note("no field of an enum variant may have a dynamically sized type"); + } + } + err.help("change the field's type to have a statically known size"); + err.span_suggestion( + span.shrink_to_lo(), + "borrowed types always have a statically known size", + "&".to_string(), + Applicability::MachineApplicable, + ); + err.multipart_suggestion( + "the `Box` type always has a statically known size and allocates its contents \ + in the heap", + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } + ObligationCauseCode::ConstSized => { + err.note("constant expressions must have a statically known size"); + } + ObligationCauseCode::InlineAsmSized => { + err.note("all inline asm arguments must have a statically known size"); + } + ObligationCauseCode::ConstPatternStructural => { + err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); + } + ObligationCauseCode::SharedStatic => { + err.note("shared static variables must have a type that implements `Sync`"); + } + ObligationCauseCode::BuiltinDerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let ty = parent_trait_ref.skip_binder().self_ty(); + err.note(&format!("required because it appears within the type `{}`", ty)); + obligated_types.push(ty); + + let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + if !self.is_recursive_obligation(obligated_types, &data.parent_code) { + // #74711: avoid a stack overflow + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + &parent_predicate, + &data.parent_code, + obligated_types, + ) + }); + } + } + ObligationCauseCode::ImplDerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + err.note(&format!( + "required because of the requirements on the impl of `{}` for `{}`", + parent_trait_ref.print_only_trait_path(), + parent_trait_ref.skip_binder().self_ty() + )); + let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + // #74711: avoid a stack overflow + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + &parent_predicate, + &data.parent_code, + obligated_types, + ) + }); + } + ObligationCauseCode::DerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); + let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); + // #74711: avoid a stack overflow + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + &parent_predicate, + &data.parent_code, + obligated_types, + ) + }); + } + ObligationCauseCode::CompareImplMethodObligation { .. } => { + err.note(&format!( + "the requirement `{}` appears on the impl method \ + but not on the corresponding trait method", + predicate + )); + } + ObligationCauseCode::CompareImplTypeObligation { .. } => { + err.note(&format!( + "the requirement `{}` appears on the associated impl type \ + but not on the corresponding associated trait type", + predicate + )); + } + ObligationCauseCode::CompareImplConstObligation => { + err.note(&format!( + "the requirement `{}` appears on the associated impl constant \ + but not on the corresponding associated trait constant", + predicate + )); + } + ObligationCauseCode::ReturnType + | ObligationCauseCode::ReturnValue(_) + | ObligationCauseCode::BlockTailExpression(_) => (), + ObligationCauseCode::TrivialBound => { + err.help("see issue #48214"); + if tcx.sess.opts.unstable_features.is_nightly_build() { + err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable"); + } + } + } + } + + fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { + let current_limit = self.tcx.sess.recursion_limit(); + let suggested_limit = current_limit * 2; + err.help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, self.tcx.crate_name, + )); + } + + fn suggest_await_before_try( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + span: Span, + ) { + debug!( + "suggest_await_before_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", + obligation, + span, + trait_ref, + trait_ref.self_ty() + ); + let body_hir_id = obligation.cause.body_id; + let item_id = self.tcx.hir().get_parent_node(body_hir_id); + + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { + let body = self.tcx.hir().body(body_id); + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + + let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + + // Do not check on infer_types to avoid panic in evaluate_obligation. + if self_ty.has_infer_types() { + return; + } + let self_ty = self.tcx.erase_regions(&self_ty); + + let impls_future = self.tcx.type_implements_trait(( + future_trait, + self_ty.skip_binder(), + ty::List::empty(), + obligation.param_env, + )); + + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + // `<T as Future>::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self.tcx.mk_substs_trait( + trait_ref.self_ty().skip_binder(), + self.fresh_substs_for_item(span, item_def_id), + ), + // `Future::Output` + item_def_id, + }; + + let mut selcx = SelectionContext::new(self); + + let mut obligations = vec![]; + let normalized_ty = normalize_projection_type( + &mut selcx, + obligation.param_env, + projection_ty, + obligation.cause.clone(), + 0, + &mut obligations, + ); + + debug!( + "suggest_await_before_try: normalized_projection_type {:?}", + self.resolve_vars_if_possible(&normalized_ty) + ); + let try_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_ref, + normalized_ty, + ); + debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); + if self.predicate_may_hold(&try_obligation) && impls_future { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + if snippet.ends_with('?') { + err.span_suggestion( + span, + "consider using `.await` here", + format!("{}.await?", snippet.trim_end_matches('?')), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + } +} + +/// Collect all the returned expressions within the input expression. +/// Used to point at the return spans when we want to suggest some change to them. +#[derive(Default)] +pub struct ReturnsVisitor<'v> { + pub returns: Vec<&'v hir::Expr<'v>>, + in_block_tail: bool, +} + +impl<'v> Visitor<'v> for ReturnsVisitor<'v> { + type Map = hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + // Visit every expression to detect `return` paths, either through the function's tail + // expression or `return` statements. We walk all nodes to find `return` statements, but + // we only care about tail expressions when `in_block_tail` is `true`, which means that + // they're in the return path of the function body. + match ex.kind { + hir::ExprKind::Ret(Some(ex)) => { + self.returns.push(ex); + } + hir::ExprKind::Block(block, _) if self.in_block_tail => { + self.in_block_tail = false; + for stmt in block.stmts { + hir::intravisit::walk_stmt(self, stmt); + } + self.in_block_tail = true; + if let Some(expr) = block.expr { + self.visit_expr(expr); + } + } + hir::ExprKind::Match(_, arms, _) if self.in_block_tail => { + for arm in arms { + self.visit_expr(arm.body); + } + } + // We need to walk to find `return`s in the entire body. + _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex), + _ => self.returns.push(ex), + } + } + + fn visit_body(&mut self, body: &'v hir::Body<'v>) { + assert!(!self.in_block_tail); + if body.generator_kind().is_none() { + if let hir::ExprKind::Block(block, None) = body.value.kind { + if block.expr.is_some() { + self.in_block_tail = true; + } + } + } + hir::intravisit::walk_body(self, body); + } +} + +/// Collect all the awaited expressions within the input expression. +#[derive(Default)] +struct AwaitsVisitor { + awaits: Vec<hir::HirId>, +} + +impl<'v> Visitor<'v> for AwaitsVisitor { + type Map = hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind { + self.awaits.push(id) + } + hir::intravisit::walk_expr(self, ex) + } +} + +pub trait NextTypeParamName { + fn next_type_param_name(&self, name: Option<&str>) -> String; +} + +impl NextTypeParamName for &[hir::GenericParam<'_>] { + fn next_type_param_name(&self, name: Option<&str>) -> String { + // This is the list of possible parameter names that we might suggest. + let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase()); + let name = name.as_deref(); + let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"]; + let used_names = self + .iter() + .filter_map(|p| match p.name { + hir::ParamName::Plain(ident) => Some(ident.name), + _ => None, + }) + .collect::<Vec<_>>(); + + possible_names + .iter() + .find(|n| !used_names.contains(&Symbol::intern(n))) + .unwrap_or(&"ParamName") + .to_string() + } +} + +fn suggest_trait_object_return_type_alternatives( + err: &mut DiagnosticBuilder<'_>, + ret_ty: Span, + trait_obj: &str, + is_object_safe: bool, +) { + err.span_suggestion( + ret_ty, + "use some type `T` that is `T: Sized` as the return type if all return paths have the \ + same type", + "T".to_string(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion( + ret_ty, + &format!( + "use `impl {}` as the return type if all return paths have the same type but you \ + want to expose only the trait in the signature", + trait_obj, + ), + format!("impl {}", trait_obj), + Applicability::MaybeIncorrect, + ); + if is_object_safe { + err.span_suggestion( + ret_ty, + &format!( + "use a boxed trait object if all return paths implement trait `{}`", + trait_obj, + ), + format!("Box<dyn {}>", trait_obj), + Applicability::MaybeIncorrect, + ); + } +} diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs new file mode 100644 index 00000000000..a5c6dc042ab --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -0,0 +1,668 @@ +use crate::infer::{InferCtxt, TyOrConstInferVar}; +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_errors::ErrorReported; +use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; +use std::marker::PhantomData; + +use super::project; +use super::select::SelectionContext; +use super::wf; +use super::CodeAmbiguity; +use super::CodeProjectionError; +use super::CodeSelectionError; +use super::{ConstEvalFailure, Unimplemented}; +use super::{FulfillmentError, FulfillmentErrorCode}; +use super::{ObligationCause, PredicateObligation}; + +use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::project::PolyProjectionObligation; +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 + /// or fails. + type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>; + + fn as_cache_key(&self) -> Self::CacheKey { + self.obligation.param_env.and(self.obligation.predicate) + } +} + +/// The fulfillment context is used to drive trait resolution. It +/// consists of a list of obligations that must be (eventually) +/// satisfied. The job is to track which are satisfied, which yielded +/// errors, and which are still pending. At any point, users can call +/// `select_where_possible`, and the fulfillment context will try to do +/// selection, retaining only those obligations that remain +/// ambiguous. This may be helpful in pushing type inference +/// along. Once all type inference constraints have been generated, the +/// method `select_all_or_error` can be used to report any remaining +/// ambiguous cases as errors. +pub struct FulfillmentContext<'tcx> { + // A list of all obligations that have been registered with this + // fulfillment context. + predicates: ObligationForest<PendingPredicateObligation<'tcx>>, + // Should this fulfillment context register type-lives-for-region + // obligations on its parent infcx? In some cases, region + // obligations are either already known to hold (normalization) or + // hopefully verifed elsewhere (type-impls-bound), and therefore + // should not be checked. + // + // Note that if we are normalizing a type that we already + // know is well-formed, there should be no harm setting this + // to true - all the region variables should be determinable + // using the RFC 447 rules, which don't depend on + // type-lives-for-region constraints, and because the type + // is well-formed, the constraints should hold. + register_region_obligations: bool, + // Is it OK to register obligations into this infcx inside + // an infcx snapshot? + // + // The "primary fulfillment" in many cases in typeck lives + // outside of any snapshot, so any use of it inside a snapshot + // will lead to trouble and therefore is checked against, but + // other fulfillment contexts sometimes do live inside of + // a snapshot (they don't *straddle* a snapshot, so there + // is no trouble there). + usable_in_snapshot: bool, +} + +#[derive(Clone, Debug)] +pub struct PendingPredicateObligation<'tcx> { + pub obligation: PredicateObligation<'tcx>, + // This is far more often read than modified, meaning that we + // should mostly optimize for reading speed, while modifying is not as relevant. + // + // For whatever reason using a boxed slice is slower than using a `Vec` here. + pub stalled_on: Vec<TyOrConstInferVar<'tcx>>, +} + +// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PendingPredicateObligation<'_>, 64); + +impl<'a, 'tcx> FulfillmentContext<'tcx> { + /// Creates a new fulfillment context. + pub fn new() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + register_region_obligations: true, + usable_in_snapshot: false, + } + } + + pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + register_region_obligations: true, + usable_in_snapshot: true, + } + } + + pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + register_region_obligations: false, + usable_in_snapshot: false, + } + } + + /// Attempts to select obligations using `selcx`. + fn select( + &mut self, + selcx: &mut SelectionContext<'a, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + debug!("select(obligation-forest-size={})", self.predicates.len()); + + let mut errors = Vec::new(); + + loop { + debug!("select: starting another iteration"); + + // Process pending obligations. + let outcome = self.predicates.process_obligations( + &mut FulfillProcessor { + selcx, + register_region_obligations: self.register_region_obligations, + }, + DoCompleted::No, + ); + debug!("select: outcome={:#?}", outcome); + + // FIXME: if we kept the original cache key, we could mark projection + // obligations as complete for the projection cache here. + + errors.extend(outcome.errors.into_iter().map(to_fulfillment_error)); + + // If nothing new was added, no need to keep looping. + if outcome.stalled { + break; + } + } + + debug!( + "select({} predicates remaining, {} errors) done", + self.predicates.len(), + errors.len() + ); + + if errors.is_empty() { Ok(()) } else { Err(errors) } + } +} + +impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { + /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `<SomeType as SomeTrait>::X == $0`. When the + /// inference engine runs, it will attempt to find an impl of + /// `SomeTrait` or a where-clause that lets us unify `$0` with + /// something concrete. If this fails, we'll unify `$0` with + /// `projection_ty` again. + fn normalize_projection_type( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + ) -> Ty<'tcx> { + debug!("normalize_projection_type(projection_ty={:?})", projection_ty); + + debug_assert!(!projection_ty.has_escaping_bound_vars()); + + // FIXME(#20304) -- cache + + let mut selcx = SelectionContext::new(infcx); + let mut obligations = vec![]; + let normalized_ty = project::normalize_projection_type( + &mut selcx, + param_env, + projection_ty, + cause, + 0, + &mut obligations, + ); + self.register_predicate_obligations(infcx, obligations); + + debug!("normalize_projection_type: result={:?}", normalized_ty); + + normalized_ty + } + + fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) { + // this helps to reduce duplicate errors, as well as making + // debug output much nicer to read and so on. + let obligation = infcx.resolve_vars_if_possible(&obligation); + + debug!("register_predicate_obligation(obligation={:?})", obligation); + + assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); + + self.predicates + .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); + } + + fn select_all_or_error( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + self.select_where_possible(infcx)?; + + let errors: Vec<_> = self + .predicates + .to_errors(CodeAmbiguity) + .into_iter() + .map(to_fulfillment_error) + .collect(); + if errors.is_empty() { Ok(()) } else { Err(errors) } + } + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec<FulfillmentError<'tcx>>> { + let mut selcx = SelectionContext::new(infcx); + self.select(&mut selcx) + } + + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { + self.predicates.map_pending_obligations(|o| o.obligation.clone()) + } +} + +struct FulfillProcessor<'a, 'b, 'tcx> { + selcx: &'a mut SelectionContext<'b, 'tcx>, + register_region_obligations: bool, +} + +fn mk_pending(os: Vec<PredicateObligation<'tcx>>) -> Vec<PendingPredicateObligation<'tcx>> { + os.into_iter() + .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) + .collect() +} + +impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { + type Obligation = PendingPredicateObligation<'tcx>; + type Error = FulfillmentErrorCode<'tcx>; + + /// Processes a predicate obligation and returns either: + /// - `Changed(v)` if the predicate is true, presuming that `v` are also true + /// - `Unchanged` if we don't have enough info to be sure + /// - `Error(e)` if the predicate does not hold + /// + /// This is always inlined, despite its size, because it has a single + /// callsite and it is called *very* frequently. + #[inline(always)] + fn process_obligation( + &mut self, + pending_obligation: &mut Self::Obligation, + ) -> ProcessResult<Self::Obligation, Self::Error> { + // If we were stalled on some unresolved variables, first check whether + // any of them have been resolved; if not, don't bother doing more work + // yet. + let change = match pending_obligation.stalled_on.len() { + // Match arms are in order of frequency, which matters because this + // code is so hot. 1 and 0 dominate; 2+ is fairly rare. + 1 => { + let infer_var = pending_obligation.stalled_on[0]; + self.selcx.infcx().ty_or_const_infer_var_changed(infer_var) + } + 0 => { + // In this case we haven't changed, but wish to make a change. + true + } + _ => { + // This `for` loop was once a call to `all()`, but this lower-level + // form was a perf win. See #64545 for details. + (|| { + for &infer_var in &pending_obligation.stalled_on { + if self.selcx.infcx().ty_or_const_infer_var_changed(infer_var) { + return true; + } + } + false + })() + } + }; + + if !change { + debug!( + "process_predicate: pending obligation {:?} still stalled on {:?}", + self.selcx.infcx().resolve_vars_if_possible(&pending_obligation.obligation), + pending_obligation.stalled_on + ); + return ProcessResult::Unchanged; + } + + // This part of the code is much colder. + + pending_obligation.stalled_on.truncate(0); + + let obligation = &mut pending_obligation.obligation; + + if obligation.predicate.has_infer_types_or_consts() { + obligation.predicate = + self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); + } + + debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + + let infcx = self.selcx.infcx(); + + match obligation.predicate.kind() { + ty::PredicateKind::ForAll(binder) => match binder.skip_binder() { + // Evaluation will discard candidates using the leak check. + // This means we need to pass it the bound version of our + // predicate. + ty::PredicateAtom::Trait(trait_ref, _constness) => { + let trait_obligation = obligation.with(Binder::bind(trait_ref)); + + self.process_trait_obligation( + obligation, + trait_obligation, + &mut pending_obligation.stalled_on, + ) + } + ty::PredicateAtom::Projection(data) => { + let project_obligation = obligation.with(Binder::bind(data)); + + self.process_projection_obligation( + project_obligation, + &mut pending_obligation.stalled_on, + ) + } + ty::PredicateAtom::RegionOutlives(_) + | ty::PredicateAtom::TypeOutlives(_) + | ty::PredicateAtom::WellFormed(_) + | ty::PredicateAtom::ObjectSafe(_) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::Subtype(_) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => { + let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder); + ProcessResult::Changed(mk_pending(vec![ + obligation.with(pred.to_predicate(self.selcx.tcx())), + ])) + } + }, + &ty::PredicateKind::Atom(atom) => match atom { + ty::PredicateAtom::Trait(ref data, _) => { + let trait_obligation = obligation.with(Binder::dummy(*data)); + + self.process_trait_obligation( + obligation, + trait_obligation, + &mut pending_obligation.stalled_on, + ) + } + + ty::PredicateAtom::RegionOutlives(data) => { + match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) { + Ok(()) => ProcessResult::Changed(vec![]), + Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), + } + } + + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => { + if self.register_region_obligations { + self.selcx.infcx().register_region_obligation_with_cause( + t_a, + r_b, + &obligation.cause, + ); + } + ProcessResult::Changed(vec![]) + } + + ty::PredicateAtom::Projection(ref data) => { + let project_obligation = obligation.with(Binder::dummy(*data)); + + self.process_projection_obligation( + project_obligation, + &mut pending_obligation.stalled_on, + ) + } + + ty::PredicateAtom::ObjectSafe(trait_def_id) => { + if !self.selcx.tcx().is_object_safe(trait_def_id) { + ProcessResult::Error(CodeSelectionError(Unimplemented)) + } else { + ProcessResult::Changed(vec![]) + } + } + + ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { + match self.selcx.infcx().closure_kind(closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + ProcessResult::Changed(vec![]) + } else { + ProcessResult::Error(CodeSelectionError(Unimplemented)) + } + } + None => ProcessResult::Unchanged, + } + } + + ty::PredicateAtom::WellFormed(arg) => { + match wf::obligations( + self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + arg, + obligation.cause.span, + ) { + None => { + pending_obligation.stalled_on = + vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()]; + ProcessResult::Unchanged + } + Some(os) => ProcessResult::Changed(mk_pending(os)), + } + } + + ty::PredicateAtom::Subtype(subtype) => { + match self.selcx.infcx().subtype_predicate( + &obligation.cause, + obligation.param_env, + Binder::dummy(subtype), + ) { + None => { + // None means that both are unresolved. + pending_obligation.stalled_on = vec![ + TyOrConstInferVar::maybe_from_ty(subtype.a).unwrap(), + TyOrConstInferVar::maybe_from_ty(subtype.b).unwrap(), + ]; + ProcessResult::Unchanged + } + Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Some(Err(err)) => { + let expected_found = + ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b); + ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( + expected_found, + err, + )) + } + } + } + + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { + match self.selcx.infcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + None, + Some(obligation.cause.span), + ) { + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), + } + } + + ty::PredicateAtom::ConstEquate(c1, c2) => { + debug!("equating consts: c1={:?} c2={:?}", c1, c2); + + let stalled_on = &mut pending_obligation.stalled_on; + + let mut evaluate = |c: &'tcx Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { + match self.selcx.infcx().const_eval_resolve( + obligation.param_env, + def, + substs, + promoted, + Some(obligation.cause.span), + ) { + Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)), + Err(ErrorHandled::TooGeneric) => { + stalled_on.append( + &mut substs + .types() + .filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)) + .collect(), + ); + Err(ErrorHandled::TooGeneric) + } + Err(err) => Err(err), + } + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self + .selcx + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => ProcessResult::Error( + FulfillmentErrorCode::CodeConstEquateError( + ExpectedFound::new(true, c1, c2), + err, + ), + ), + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => { + ProcessResult::Error(CodeSelectionError(ConstEvalFailure( + ErrorHandled::Reported(ErrorReported), + ))) + } + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { + span_bug!( + obligation.cause.span(self.selcx.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ) + } + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + ProcessResult::Unchanged + } + } + } + }, + } + } + + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) where + I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, + { + if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { + debug!("process_child_obligations: coinductive match"); + } else { + let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); + self.selcx.infcx().report_overflow_error_cycle(&cycle); + } + } +} + +impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { + fn process_trait_obligation( + &mut self, + obligation: &PredicateObligation<'tcx>, + trait_obligation: TraitObligation<'tcx>, + stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { + let infcx = self.selcx.infcx(); + if obligation.predicate.is_global() { + // no type variables present, can use evaluation for better caching. + // FIXME: consider caching errors too. + if infcx.predicate_must_hold_considering_regions(obligation) { + debug!( + "selecting trait `{:?}` at depth {} evaluated to holds", + obligation.predicate, obligation.recursion_depth + ); + return ProcessResult::Changed(vec![]); + } + } + + match self.selcx.select(&trait_obligation) { + Ok(Some(impl_source)) => { + debug!( + "selecting trait `{:?}` at depth {} yielded Ok(Some)", + trait_obligation.predicate, obligation.recursion_depth + ); + ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) + } + Ok(None) => { + debug!( + "selecting trait `{:?}` at depth {} yielded Ok(None)", + trait_obligation.predicate, obligation.recursion_depth + ); + + // This is a bit subtle: for the most part, the + // only reason we can fail to make progress on + // trait selection is because we don't have enough + // information about the types in the trait. + *stalled_on = trait_ref_infer_vars( + self.selcx, + trait_obligation.predicate.map_bound(|pred| pred.trait_ref), + ); + + debug!( + "process_predicate: pending obligation {:?} now stalled on {:?}", + infcx.resolve_vars_if_possible(obligation), + stalled_on + ); + + ProcessResult::Unchanged + } + Err(selection_err) => { + info!( + "selecting trait `{:?}` at depth {} yielded Err", + trait_obligation.predicate, obligation.recursion_depth + ); + + ProcessResult::Error(CodeSelectionError(selection_err)) + } + } + } + + fn process_projection_obligation( + &mut self, + project_obligation: PolyProjectionObligation<'tcx>, + stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { + let tcx = self.selcx.tcx(); + match project::poly_project_and_unify_type(self.selcx, &project_obligation) { + Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), + Ok(Ok(None)) => { + *stalled_on = trait_ref_infer_vars( + self.selcx, + project_obligation.predicate.to_poly_trait_ref(self.selcx.tcx()), + ); + ProcessResult::Unchanged + } + // Let the caller handle the recursion + Ok(Err(project::InProgress)) => ProcessResult::Changed(mk_pending(vec![ + project_obligation.with(project_obligation.predicate.to_predicate(tcx)), + ])), + Err(e) => ProcessResult::Error(CodeProjectionError(e)), + } + } +} + +/// Returns the set of inference variables contained in a trait ref. +fn trait_ref_infer_vars<'a, 'tcx>( + selcx: &mut SelectionContext<'a, 'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, +) -> Vec<TyOrConstInferVar<'tcx>> { + selcx + .infcx() + .resolve_vars_if_possible(&trait_ref) + .skip_binder() + .substs + .iter() + // FIXME(eddyb) try using `skip_current_subtree` to skip everything that + // doesn't contain inference variables, not just the outermost level. + .filter(|arg| arg.has_infer_types_or_consts()) + .flat_map(|arg| arg.walk()) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg) + .collect() +} + +fn to_fulfillment_error<'tcx>( + error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>, +) -> FulfillmentError<'tcx> { + let obligation = error.backtrace.into_iter().next().unwrap().obligation; + FulfillmentError::new(obligation, error.error) +} diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs new file mode 100644 index 00000000000..61567aeb57c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -0,0 +1,74 @@ +//! Miscellaneous type-system utilities that are too small to deserve their own modules. + +use crate::infer::InferCtxtExt as _; +use crate::traits::{self, ObligationCause}; + +use rustc_hir as hir; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; + +use crate::traits::error_reporting::InferCtxtExt; + +#[derive(Clone)] +pub enum CopyImplementationError<'tcx> { + InfrigingFields(Vec<&'tcx ty::FieldDef>), + NotAnAdt, + HasDestructor, +} + +pub fn can_type_implement_copy( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_type: Ty<'tcx>, +) -> Result<(), CopyImplementationError<'tcx>> { + // FIXME: (@jroesch) float this code up + tcx.infer_ctxt().enter(|infcx| { + let (adt, substs) = match self_type.kind { + // These types used to have a builtin impl. + // Now libcore provides that impl. + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), + + ty::Adt(adt, substs) => (adt, substs), + + _ => return Err(CopyImplementationError::NotAnAdt), + }; + + let mut infringing = Vec::new(); + for variant in &adt.variants { + for field in &variant.fields { + let ty = field.ty(tcx, substs); + if ty.references_error() { + continue; + } + let span = tcx.def_span(field.did); + let cause = ObligationCause::dummy_with_span(span); + let ctx = traits::FulfillmentContext::new(); + match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { + Ok(ty) => { + if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { + infringing.push(field); + } + } + Err(errors) => { + infcx.report_fulfillment_errors(&errors, None, false); + } + }; + } + } + if !infringing.is_empty() { + return Err(CopyImplementationError::InfrigingFields(infringing)); + } + if adt.has_dtor(tcx) { + return Err(CopyImplementationError::HasDestructor); + } + + Ok(()) + }) +} diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs new file mode 100644 index 00000000000..fe406e88c52 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -0,0 +1,563 @@ +//! 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; +mod chalk_fulfill; +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, RegionckMode, TyCtxtInferExt}; +use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_errors::ErrorReported; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::{ + self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness, +}; +use rustc_span::Span; + +use std::fmt::Debug; + +pub use self::FulfillmentErrorCode::*; +pub use self::ImplSource::*; +pub use self::ObligationCauseCode::*; +pub use self::SelectionError::*; + +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}; +pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; +pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; +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::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_item_is_final, predicate_for_trait_def, upcast_choices, +}; +pub use self::util::{ + supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, +}; + +pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; + +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>, +) -> impl Iterator<Item = PredicateObligation<'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::CRATE_HIR_ID), + recursion_depth: 0, + predicate: trait_ref.without_const().to_predicate(infcx.tcx), + }; + + 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::CRATE_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<ty::Predicate<'tcx>>, +) -> Result<Vec<ty::Predicate<'tcx>>, 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); + + // 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, + &outlives_env, + RegionckMode::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.needs_infer() { + tcx.sess.delay_span_bug(span, "encountered inference variables after `fully_resolve`"); + 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().into_iter()) + .map(|obligation| obligation.predicate) + .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.skip_binders() { + ty::PredicateAtom::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<T, Vec<FulfillmentError<'tcx>>> +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 true, 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 impossible_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: Vec<ty::Predicate<'tcx>>, +) -> bool { + debug!("impossible_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_err() + }); + debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result); + result +} + +fn subst_and_check_impossible_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + key: (DefId, SubstsRef<'tcx>), +) -> bool { + debug!("subst_and_check_impossible_predicates(key={:?})", key); + + let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; + predicates.retain(|predicate| !predicate.needs_subst()); + let result = impossible_predicates(tcx, predicates); + + debug!("subst_and_check_impossible_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::Fn); + + // 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 impossible_predicates(tcx, predicates.predicates) { + debug!("vtable_methods: predicates do not hold"); + return None; + } + + Some((def_id, substs)) + }) + })) +} + +/// Check whether a `ty` implements given trait(trait_def_id). +/// +/// NOTE: Always return `false` for a type which needs inference. +fn type_implements_trait<'tcx>( + tcx: TyCtxt<'tcx>, + key: ( + DefId, // trait_def_id, + Ty<'tcx>, // type + SubstsRef<'tcx>, + ParamEnv<'tcx>, + ), +) -> bool { + let (trait_def_id, ty, params, param_env) = key; + + debug!( + "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}", + trait_def_id, ty, params, param_env + ); + + let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; + + let obligation = Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: trait_ref.without_const().to_predicate(tcx), + }; + tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) +} + +pub fn provide(providers: &mut ty::query::Providers) { + object_safety::provide(providers); + structural_match::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, + type_implements_trait, + subst_and_check_impossible_predicates, + ..*providers + }; +} diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs new file mode 100644 index 00000000000..c003e4f8068 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -0,0 +1,789 @@ +//! "Object safety" refers to the ability for a trait to be converted +//! to an object. In general, traits may only be converted to an +//! object if all of their methods meet certain criteria. In particular, +//! they must: +//! +//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version +//! that doesn't contain the vtable; +//! - not reference the erased type `Self` except for in this receiver; +//! - not have generic type parameters. + +use super::elaborate_predicates; + +use crate::infer::TyCtxtInferExt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{self, Obligation, ObligationCause}; +use rustc_errors::{Applicability, FatalError}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness}; +use rustc_middle::ty::{Predicate, ToPredicate}; +use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; +use rustc_span::symbol::Symbol; +use rustc_span::Span; +use smallvec::SmallVec; + +use std::iter; + +pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; + +/// Returns the object safety violations that affect +/// astconv -- currently, `Self` in supertraits. This is needed +/// because `object_safety_violations` can't be used during +/// type collection. +pub fn astconv_object_safety_violations( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> Vec<ObjectSafetyViolation> { + debug_assert!(tcx.generics_of(trait_def_id).has_self); + let violations = traits::supertrait_def_ids(tcx, trait_def_id) + .map(|def_id| predicates_reference_self(tcx, def_id, true)) + .filter(|spans| !spans.is_empty()) + .map(ObjectSafetyViolation::SupertraitSelf) + .collect(); + + debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations); + + violations +} + +fn object_safety_violations( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, +) -> &'tcx [ObjectSafetyViolation] { + debug_assert!(tcx.generics_of(trait_def_id).has_self); + debug!("object_safety_violations: {:?}", trait_def_id); + + tcx.arena.alloc_from_iter( + traits::supertrait_def_ids(tcx, trait_def_id) + .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)), + ) +} + +/// We say a method is *vtable safe* if it can be invoked on a trait +/// object. Note that object-safe traits can have some +/// non-vtable-safe methods, so long as they require `Self: Sized` or +/// otherwise ensure that they cannot be used when `Self = Trait`. +pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool { + debug_assert!(tcx.generics_of(trait_def_id).has_self); + debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); + // Any method that has a `Self: Sized` bound cannot be called. + if generics_require_sized_self(tcx, method.def_id) { + return false; + } + + match virtual_call_violation_for_method(tcx, trait_def_id, method) { + None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, + Some(_) => false, + } +} + +fn object_safety_violations_for_trait( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> Vec<ObjectSafetyViolation> { + // Check methods for violations. + let mut violations: Vec<_> = tcx + .associated_items(trait_def_id) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Fn) + .filter_map(|item| { + object_safety_violation_for_method(tcx, trait_def_id, &item) + .map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span)) + }) + .filter(|violation| { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation + { + // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. + // It's also hard to get a use site span, so we use the method definition span. + tcx.struct_span_lint_hir( + WHERE_CLAUSES_OBJECT_SAFETY, + hir::CRATE_HIR_ID, + *span, + |lint| { + let mut err = lint.build(&format!( + "the trait `{}` cannot be made into an object", + tcx.def_path_str(trait_def_id) + )); + let node = tcx.hir().get_if_local(trait_def_id); + let msg = if let Some(hir::Node::Item(item)) = node { + err.span_label( + item.ident.span, + "this trait cannot be made into an object...", + ); + format!("...because {}", violation.error_msg()) + } else { + format!( + "the trait cannot be made into an object because {}", + violation.error_msg() + ) + }; + err.span_label(*span, &msg); + match (node, violation.solution()) { + (Some(_), Some((note, None))) => { + err.help(¬e); + } + (Some(_), Some((note, Some((sugg, span))))) => { + err.span_suggestion( + span, + ¬e, + sugg, + Applicability::MachineApplicable, + ); + } + // Only provide the help if its a local trait, otherwise it's not actionable. + _ => {} + } + err.emit(); + }, + ); + false + } else { + true + } + }) + .collect(); + + // Check the trait itself. + if trait_has_sized_self(tcx, trait_def_id) { + // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. + let spans = get_sized_bounds(tcx, trait_def_id); + violations.push(ObjectSafetyViolation::SizedSelf(spans)); + } + let spans = predicates_reference_self(tcx, trait_def_id, false); + if !spans.is_empty() { + violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); + } + + violations.extend( + tcx.associated_items(trait_def_id) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Const) + .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), + ); + + debug!( + "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, violations + ); + + violations +} + +fn sized_trait_bound_spans<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: hir::GenericBounds<'tcx>, +) -> impl 'tcx + Iterator<Item = Span> { + bounds.iter().filter_map(move |b| match b { + hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) + if trait_has_sized_self( + tcx, + trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), + ) => + { + // Fetch spans for supertraits that are `Sized`: `trait T: Super` + Some(trait_ref.span) + } + _ => None, + }) +} + +fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { + tcx.hir() + .get_if_local(trait_def_id) + .and_then(|node| match node { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(.., generics, bounds, _), + .. + }) => Some( + generics + .where_clause + .predicates + .iter() + .filter_map(|pred| { + match pred { + hir::WherePredicate::BoundPredicate(pred) + if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id => + { + // Fetch spans for trait bounds that are Sized: + // `trait T where Self: Pred` + Some(sized_trait_bound_spans(tcx, pred.bounds)) + } + _ => None, + } + }) + .flatten() + // Fetch spans for supertraits that are `Sized`: `trait T: Super`. + .chain(sized_trait_bound_spans(tcx, bounds)) + .collect::<SmallVec<[Span; 1]>>(), + ), + _ => None, + }) + .unwrap_or_else(SmallVec::new) +} + +fn predicates_reference_self( + tcx: TyCtxt<'_>, + trait_def_id: DefId, + supertraits_only: bool, +) -> SmallVec<[Span; 1]> { + let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); + let predicates = if supertraits_only { + tcx.super_predicates_of(trait_def_id) + } else { + tcx.predicates_of(trait_def_id) + }; + let self_ty = tcx.types.self_param; + let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into()); + predicates + .predicates + .iter() + .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) + .filter_map(|(predicate, &sp)| { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(ref data, _) => { + // In the case of a trait predicate, we can skip the "self" type. + if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } + } + ty::PredicateAtom::Projection(ref data) => { + // And similarly for projections. This should be redundant with + // the previous check because any projection should have a + // matching `Trait` predicate with the same inputs, but we do + // the check to be safe. + // + // Note that we *do* allow projection *outputs* to contain + // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`), + // we just require the user to specify *both* outputs + // in the object type (i.e., `dyn Foo<Output=(), Result=()>`). + // + // This is ALT2 in issue #56288, see that for discussion of the + // possible alternatives. + if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) { + Some(sp) + } else { + None + } + } + ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::TypeOutlives(..) + | ty::PredicateAtom::RegionOutlives(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => None, + } + }) + .collect() +} + +fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + generics_require_sized_self(tcx, trait_def_id) +} + +fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let sized_def_id = match tcx.lang_items().sized_trait() { + Some(def_id) => def_id, + None => { + return false; /* No Sized trait, can't require it! */ + } + }; + + // Search for a predicate like `Self : Sized` amongst the trait bounds. + let predicates = tcx.predicates_of(def_id); + let predicates = predicates.instantiate_identity(tcx).predicates; + elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(ref trait_pred, _) => { + trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) + } + ty::PredicateAtom::Projection(..) + | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::RegionOutlives(..) + | ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::TypeOutlives(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => false, + } + }) +} + +/// Returns `Some(_)` if this method makes the containing trait not object safe. +fn object_safety_violation_for_method( + tcx: TyCtxt<'_>, + trait_def_id: DefId, + method: &ty::AssocItem, +) -> Option<(MethodViolationCode, Span)> { + debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); + // Any method that has a `Self : Sized` requisite is otherwise + // exempt from the regulations. + if generics_require_sized_self(tcx, method.def_id) { + return None; + } + + let violation = virtual_call_violation_for_method(tcx, trait_def_id, method); + // Get an accurate span depending on the violation. + violation.map(|v| { + let node = tcx.hir().get_if_local(method.def_id); + let span = match (v, node) { + (MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node + .fn_decl() + .and_then(|decl| decl.inputs.get(arg + 1)) + .map_or(method.ident.span, |arg| arg.span), + (MethodViolationCode::UndispatchableReceiver, Some(node)) => node + .fn_decl() + .and_then(|decl| decl.inputs.get(0)) + .map_or(method.ident.span, |arg| arg.span), + (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + node.fn_decl().map_or(method.ident.span, |decl| decl.output.span()) + } + _ => method.ident.span, + }; + (v, span) + }) +} + +/// Returns `Some(_)` if this method cannot be called on a trait +/// object; this does not necessarily imply that the enclosing trait +/// is not object safe, because the method might have a where clause +/// `Self:Sized`. +fn virtual_call_violation_for_method<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + method: &ty::AssocItem, +) -> Option<MethodViolationCode> { + // The method's first parameter must be named `self` + if !method.fn_has_self_parameter { + // We'll attempt to provide a structured suggestion for `Self: Sized`. + let sugg = + tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map( + |generics| match generics.where_clause.predicates { + [] => (" where Self: Sized", generics.where_clause.span), + [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()), + }, + ); + return Some(MethodViolationCode::StaticMethod(sugg)); + } + + let sig = tcx.fn_sig(method.def_id); + + for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { + if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { + return Some(MethodViolationCode::ReferencesSelfInput(i)); + } + } + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) { + return Some(MethodViolationCode::ReferencesSelfOutput); + } + + // We can't monomorphize things like `fn foo<A>(...)`. + let own_counts = tcx.generics_of(method.def_id).own_counts(); + if own_counts.types + own_counts.consts != 0 { + return Some(MethodViolationCode::Generic); + } + + if tcx + .predicates_of(method.def_id) + .predicates + .iter() + // A trait object can't claim to live more than the concrete type, + // so outlives predicates will always hold. + .cloned() + .filter(|(p, _)| p.to_opt_type_outlives().is_none()) + .collect::<Vec<_>>() + // Do a shallow visit so that `contains_illegal_self_type_reference` + // may apply it's custom visiting. + .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t)) + { + return Some(MethodViolationCode::WhereClauseReferencesSelf); + } + + let receiver_ty = + tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); + + // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. + // However, this is already considered object-safe. We allow it as a special case here. + // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows + // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. + if receiver_ty != tcx.types.self_param { + if !receiver_is_dispatchable(tcx, method, receiver_ty) { + return Some(MethodViolationCode::UndispatchableReceiver); + } else { + // Do sanity check to make sure the receiver actually has the layout of a pointer. + + use rustc_target::abi::Abi; + + let param_env = tcx.param_env(method.def_id); + + let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) => &layout.abi, + Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty), + } + }; + + // e.g., `Rc<()>` + let unit_receiver_ty = + receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); + + match abi_of_ty(unit_receiver_ty) { + &Abi::Scalar(..) => (), + abi => { + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!( + "receiver when `Self = ()` should have a Scalar ABI; found {:?}", + abi + ), + ); + } + } + + let trait_object_ty = + object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic)); + + // e.g., `Rc<dyn Trait>` + let trait_object_receiver = + receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); + + match abi_of_ty(trait_object_receiver) { + &Abi::ScalarPair(..) => (), + abi => { + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!( + "receiver when `Self = {}` should have a ScalarPair ABI; \ + found {:?}", + trait_object_ty, abi + ), + ); + } + } + } + } + + None +} + +/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. +/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`. +fn receiver_for_self_ty<'tcx>( + tcx: TyCtxt<'tcx>, + receiver_ty: Ty<'tcx>, + self_ty: Ty<'tcx>, + method_def_id: DefId, +) -> Ty<'tcx> { + debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); + let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { + if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } + }); + + let result = receiver_ty.subst(tcx, substs); + debug!( + "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", + receiver_ty, self_ty, method_def_id, result + ); + result +} + +/// Creates the object type for the current trait. For example, +/// if the current trait is `Deref`, then this will be +/// `dyn Deref<Target = Self::Target> + 'static`. +fn object_ty_for_trait<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + lifetime: ty::Region<'tcx>, +) -> Ty<'tcx> { + debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); + + let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); + + let trait_predicate = + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + + let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) + .flat_map(|super_trait_ref| { + tcx.associated_items(super_trait_ref.def_id()) + .in_definition_order() + .map(move |item| (super_trait_ref, item)) + }) + .filter(|(_, item)| item.kind == ty::AssocKind::Type) + .collect::<Vec<_>>(); + + // existential predicates need to be in a specific order + associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id)); + + let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { + // We *can* get bound lifetimes here in cases like + // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. + // + // binder moved to (*)... + let super_trait_ref = super_trait_ref.skip_binder(); + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), + item_def_id: item.def_id, + substs: super_trait_ref.substs, + }) + }); + + let existential_predicates = + tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); + + let object_ty = tcx.mk_dynamic( + // (*) ... binder re-introduced here + ty::Binder::bind(existential_predicates), + lifetime, + ); + + debug!("object_ty_for_trait: object_ty=`{}`", object_ty); + + object_ty +} + +/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a +/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type +/// in the following way: +/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`, +/// - require the following bound: +/// +/// ``` +/// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]> +/// ``` +/// +/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" +/// (substitution notation). +/// +/// Some examples of receiver types and their required obligation: +/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, +/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`, +/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`. +/// +/// The only case where the receiver is not dispatchable, but is still a valid receiver +/// type (just not object-safe), is when there is more than one level of pointer indirection. +/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there +/// is no way, or at least no inexpensive way, to coerce the receiver from the version where +/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type +/// contained by the trait object, because the object that needs to be coerced is behind +/// a pointer. +/// +/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result +/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch +/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561). +/// Instead, we fudge a little by introducing a new type parameter `U` such that +/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. +/// Written as a chalk-style query: +/// +/// forall (U: Trait + ?Sized) { +/// if (Self: Unsize<U>) { +/// Receiver: DispatchFromDyn<Receiver[Self => U]> +/// } +/// } +/// +/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` +/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>` +/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>` +// +// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this +// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like +// `self: Wrapper<Self>`. +#[allow(dead_code)] +fn receiver_is_dispatchable<'tcx>( + tcx: TyCtxt<'tcx>, + method: &ty::AssocItem, + receiver_ty: Ty<'tcx>, +) -> bool { + debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); + + let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait()); + let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { + (u, cu) + } else { + debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); + return false; + }; + + // the type `U` in the query + // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. + // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can + // replace this with `dyn Trait` + let unsized_self_ty: Ty<'tcx> = + tcx.mk_ty_param(u32::MAX, Symbol::intern("RustaceansAreAwesome")); + + // `Receiver[Self => U]` + let unsized_receiver_ty = + receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id); + + // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds + // `U: ?Sized` is already implied here + let param_env = { + let param_env = tcx.param_env(method.def_id); + + // Self: Unsize<U> + let unsize_predicate = ty::TraitRef { + def_id: unsize_did, + substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), + } + .without_const() + .to_predicate(tcx); + + // U: Trait<Arg1, ..., ArgN> + let trait_predicate = { + let substs = + InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| { + if param.index == 0 { + unsized_self_ty.into() + } else { + tcx.mk_param_from_def(param) + } + }); + + ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx) + }; + + let caller_bounds: Vec<Predicate<'tcx>> = param_env + .caller_bounds() + .iter() + .chain(iter::once(unsize_predicate)) + .chain(iter::once(trait_predicate)) + .collect(); + + ty::ParamEnv::new( + tcx.intern_predicates(&caller_bounds), + param_env.reveal(), + param_env.def_id, + ) + }; + + // Receiver: DispatchFromDyn<Receiver[Self => U]> + let obligation = { + let predicate = ty::TraitRef { + def_id: dispatch_from_dyn_did, + substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), + } + .without_const() + .to_predicate(tcx); + + Obligation::new(ObligationCause::dummy(), param_env, predicate) + }; + + tcx.infer_ctxt().enter(|ref infcx| { + // the receiver is dispatchable iff the obligation holds + infcx.predicate_must_hold_modulo_regions(&obligation) + }) +} + +fn contains_illegal_self_type_reference<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + ty: Ty<'tcx>, +) -> bool { + // This is somewhat subtle. In general, we want to forbid + // references to `Self` in the argument and return types, + // since the value of `Self` is erased. However, there is one + // exception: it is ok to reference `Self` in order to access + // an associated type of the current trait, since we retain + // the value of those associated types in the object type + // itself. + // + // ```rust + // trait SuperTrait { + // type X; + // } + // + // trait Trait : SuperTrait { + // type Y; + // fn foo(&self, x: Self) // bad + // fn foo(&self) -> Self // bad + // fn foo(&self) -> Option<Self> // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> <Self as Trait>::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> <Self as SuperTrait>::X // OK + // } + // ``` + // + // However, it is not as simple as allowing `Self` in a projected + // type, because there are illegal ways to use `Self` as well: + // + // ```rust + // trait Trait : SuperTrait { + // ... + // fn foo(&self) -> <Self as SomeOtherTrait>::X; + // } + // ``` + // + // Here we will not have the type of `X` recorded in the + // object type, and we cannot resolve `Self as SomeOtherTrait` + // without knowing what `Self` is. + + struct IllegalSelfTypeVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + trait_def_id: DefId, + supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>, + } + + impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Param(_) => t == self.self_ty, + ty::Projection(ref data) => { + // This is a projected type `<Foo as SomeTrait>::X`. + + // Compute supertraits of current trait lazily. + if self.supertraits.is_none() { + let trait_ref = + ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect()); + } + + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx)); + let is_supertrait_of_current_trait = + self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); + + if is_supertrait_of_current_trait { + false // do not walk contained types, do not report error, do collect $200 + } else { + t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error + } + } + _ => t.super_visit_with(self), // walk contained types, if any + } + } + + fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool { + // FIXME(#72219) Look into the unevaluated constants for object safety violations. + // Do not walk substitutions of unevaluated consts, as they contain `Self`, even + // though the const expression doesn't necessary use it. Currently type variables + // inside array length expressions are forbidden, so they can't break the above + // rules. + false + } + } + + ty.visit_with(&mut IllegalSelfTypeVisitor { + tcx, + self_ty: tcx.types.self_param, + trait_def_id, + supertraits: None, + }) +} + +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { object_safety_violations, ..*providers }; +} diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs new file mode 100644 index 00000000000..75822eadb2a --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -0,0 +1,385 @@ +use rustc_ast::{MetaItem, NestedMetaItem}; +use rustc_attr as attr; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{struct_span_err, ErrorReported}; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_parse_format::{ParseMode, Parser, Piece, Position}; +use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::Span; + +#[derive(Clone, Debug)] +pub struct OnUnimplementedFormatString(Symbol); + +#[derive(Debug)] +pub struct OnUnimplementedDirective { + pub condition: Option<MetaItem>, + pub subcommands: Vec<OnUnimplementedDirective>, + pub message: Option<OnUnimplementedFormatString>, + pub label: Option<OnUnimplementedFormatString>, + pub note: Option<OnUnimplementedFormatString>, + pub enclosing_scope: Option<OnUnimplementedFormatString>, +} + +#[derive(Default)] +pub struct OnUnimplementedNote { + pub message: Option<String>, + pub label: Option<String>, + pub note: Option<String>, + pub enclosing_scope: Option<String>, +} + +fn parse_error( + tcx: TyCtxt<'_>, + span: Span, + message: &str, + label: &str, + note: Option<&str>, +) -> ErrorReported { + let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message); + diag.span_label(span, label); + if let Some(note) = note { + diag.note(note); + } + diag.emit(); + ErrorReported +} + +impl<'tcx> OnUnimplementedDirective { + fn parse( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + items: &[NestedMetaItem], + span: Span, + is_root: bool, + ) -> Result<Self, ErrorReported> { + let mut errored = false; + let mut item_iter = items.iter(); + + let condition = if is_root { + None + } else { + let cond = item_iter + .next() + .ok_or_else(|| { + parse_error( + tcx, + span, + "empty `on`-clause in `#[rustc_on_unimplemented]`", + "empty on-clause here", + None, + ) + })? + .meta_item() + .ok_or_else(|| { + parse_error( + tcx, + span, + "invalid `on`-clause in `#[rustc_on_unimplemented]`", + "invalid on-clause here", + None, + ) + })?; + attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true); + Some(cond.clone()) + }; + + let mut message = None; + let mut label = None; + let mut note = None; + let mut enclosing_scope = None; + let mut subcommands = vec![]; + + let parse_value = |value_str| { + OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) + }; + + for item in item_iter { + if item.has_name(sym::message) && message.is_none() { + if let Some(message_) = item.value_str() { + message = parse_value(message_)?; + continue; + } + } else if item.has_name(sym::label) && label.is_none() { + if let Some(label_) = item.value_str() { + label = parse_value(label_)?; + continue; + } + } else if item.has_name(sym::note) && note.is_none() { + if let Some(note_) = item.value_str() { + note = parse_value(note_)?; + continue; + } + } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() { + if let Some(enclosing_scope_) = item.value_str() { + enclosing_scope = parse_value(enclosing_scope_)?; + continue; + } + } else if item.has_name(sym::on) + && is_root + && message.is_none() + && label.is_none() + && note.is_none() + { + if let Some(items) = item.meta_item_list() { + if let Ok(subcommand) = + Self::parse(tcx, trait_def_id, &items, item.span(), false) + { + subcommands.push(subcommand); + } else { + errored = true; + } + continue; + } + } + + // nothing found + parse_error( + tcx, + item.span(), + "this attribute must have a valid value", + "expected value here", + Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#), + ); + } + + if errored { + Err(ErrorReported) + } else { + Ok(OnUnimplementedDirective { + condition, + subcommands, + message, + label, + note, + enclosing_scope, + }) + } + } + + pub fn of_item( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + impl_def_id: DefId, + ) -> Result<Option<Self>, ErrorReported> { + let attrs = tcx.get_attrs(impl_def_id); + + let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) { + item + } else { + return Ok(None); + }; + + let result = if let Some(items) = attr.meta_item_list() { + Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some) + } else if let Some(value) = attr.value_str() { + Ok(Some(OnUnimplementedDirective { + condition: None, + message: None, + subcommands: vec![], + label: Some(OnUnimplementedFormatString::try_parse( + tcx, + trait_def_id, + value, + attr.span, + )?), + note: None, + enclosing_scope: None, + })) + } else { + return Err(ErrorReported); + }; + debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result); + result + } + + pub fn evaluate( + &self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + options: &[(Symbol, Option<String>)], + ) -> OnUnimplementedNote { + let mut message = None; + let mut label = None; + let mut note = None; + let mut enclosing_scope = None; + info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); + + for command in self.subcommands.iter().chain(Some(self)).rev() { + if let Some(ref condition) = command.condition { + if !attr::eval_condition( + condition, + &tcx.sess.parse_sess, + Some(tcx.features()), + &mut |c| { + c.ident().map_or(false, |ident| { + options.contains(&(ident.name, c.value_str().map(|s| s.to_string()))) + }) + }, + ) { + debug!("evaluate: skipping {:?} due to condition", command); + continue; + } + } + debug!("evaluate: {:?} succeeded", command); + if let Some(ref message_) = command.message { + message = Some(message_.clone()); + } + + if let Some(ref label_) = command.label { + label = Some(label_.clone()); + } + + if let Some(ref note_) = command.note { + note = Some(note_.clone()); + } + + if let Some(ref enclosing_scope_) = command.enclosing_scope { + enclosing_scope = Some(enclosing_scope_.clone()); + } + } + + let options: FxHashMap<Symbol, String> = + options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect(); + OnUnimplementedNote { + label: label.map(|l| l.format(tcx, trait_ref, &options)), + message: message.map(|m| m.format(tcx, trait_ref, &options)), + note: note.map(|n| n.format(tcx, trait_ref, &options)), + enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)), + } + } +} + +impl<'tcx> OnUnimplementedFormatString { + fn try_parse( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + from: Symbol, + err_sp: Span, + ) -> Result<Self, ErrorReported> { + let result = OnUnimplementedFormatString(from); + result.verify(tcx, trait_def_id, err_sp)?; + Ok(result) + } + + fn verify( + &self, + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + span: Span, + ) -> Result<(), ErrorReported> { + let name = tcx.item_name(trait_def_id); + let generics = tcx.generics_of(trait_def_id); + let s = self.0.as_str(); + let parser = Parser::new(&s, None, None, false, ParseMode::Format); + let mut result = Ok(()); + for token in parser { + match token { + Piece::String(_) => (), // Normal string, no need to check it + Piece::NextArgument(a) => match a.position { + // `{Self}` is allowed + Position::ArgumentNamed(s) if s == kw::SelfUpper => (), + // `{ThisTraitsName}` is allowed + Position::ArgumentNamed(s) if s == name => (), + // `{from_method}` is allowed + Position::ArgumentNamed(s) if s == sym::from_method => (), + // `{from_desugaring}` is allowed + Position::ArgumentNamed(s) if s == sym::from_desugaring => (), + // `{ItemContext}` is allowed + Position::ArgumentNamed(s) if s == sym::ItemContext => (), + // So is `{A}` if A is a type parameter + Position::ArgumentNamed(s) => { + match generics.params.iter().find(|param| param.name == s) { + Some(_) => (), + None => { + struct_span_err!( + tcx.sess, + span, + E0230, + "there is no parameter `{}` on trait `{}`", + s, + name + ) + .emit(); + result = Err(ErrorReported); + } + } + } + // `{:1}` and `{}` are not to be used + Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => { + struct_span_err!( + tcx.sess, + span, + E0231, + "only named substitution parameters are allowed" + ) + .emit(); + result = Err(ErrorReported); + } + }, + } + } + + result + } + + pub fn format( + &self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + options: &FxHashMap<Symbol, String>, + ) -> String { + let name = tcx.item_name(trait_ref.def_id); + let trait_str = tcx.def_path_str(trait_ref.def_id); + let generics = tcx.generics_of(trait_ref.def_id); + let generic_map = generics + .params + .iter() + .filter_map(|param| { + let value = match param.kind { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { + trait_ref.substs[param.index as usize].to_string() + } + GenericParamDefKind::Lifetime => return None, + }; + let name = param.name; + Some((name, value)) + }) + .collect::<FxHashMap<Symbol, String>>(); + let empty_string = String::new(); + + let s = self.0.as_str(); + let parser = Parser::new(&s, None, None, false, ParseMode::Format); + let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string); + parser + .map(|p| match p { + Piece::String(s) => s, + Piece::NextArgument(a) => match a.position { + Position::ArgumentNamed(s) => match generic_map.get(&s) { + Some(val) => val, + None if s == name => &trait_str, + None => { + if let Some(val) = options.get(&s) { + val + } else if s == sym::from_desugaring || s == sym::from_method { + // don't break messages using these two arguments incorrectly + &empty_string + } else if s == sym::ItemContext { + &item_context + } else { + bug!( + "broken on_unimplemented {:?} for {:?}: \ + no argument matching {:?}", + self.0, + trait_ref, + s + ) + } + } + }, + _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0), + }, + }) + .collect() + } +} diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs new file mode 100644 index 00000000000..c788e4f5c90 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -0,0 +1,1581 @@ +//! 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::{ + ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, + ImplSourceGeneratorData, ImplSourceUserDefinedData, +}; +use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; + +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; +use crate::traits::error_reporting::InferCtxtExt; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::ErrorReported; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_span::symbol::sym; +use rustc_span::DUMMY_SP; + +pub use rustc_middle::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>>; + +pub(super) struct InProgress; + +/// When attempting to resolve `<T as TraitRef>::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 <<A as Trait>::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<...> <T as Trait>::U == V +/// +/// If successful, this may result in additional obligations. Also returns +/// the projection cache key used to track these additional obligations. +/// +/// ## Returns +/// +/// - `Err(_)`: the projection can be normalized, but is not equal to the +/// expected type. +/// - `Ok(Err(InProgress))`: this is called recursively while normalizing +/// the same projection. +/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity +/// (resolving some inference variables in the projection may fix this). +/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to +/// the given obligations. If the projection cannot be normalized because +/// the required trait bound doesn't hold this returned with `obligations` +/// being a predicate that cannot be proven. +pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &PolyProjectionObligation<'tcx>, +) -> Result< + Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, + MismatchedProjectionTypes<'tcx>, +> { + debug!("poly_project_and_unify_type(obligation={:?})", obligation); + + let infcx = selcx.infcx(); + infcx.commit_if_ok(|_snapshot| { + let (placeholder_predicate, _) = + infcx.replace_bound_vars_with_placeholders(&obligation.predicate); + + let placeholder_obligation = obligation.with(placeholder_predicate); + let result = project_and_unify_type(selcx, &placeholder_obligation)?; + Ok(result) + }) +} + +/// Evaluates constraints of the form: +/// +/// <T as Trait>::U == V +/// +/// If successful, this may result in additional obligations. +/// +/// See [poly_project_and_unify_type] for an explanation of the return value. +fn project_and_unify_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionObligation<'tcx>, +) -> Result< + Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, + 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, + ) { + Ok(Some(n)) => n, + Ok(None) => return Ok(Ok(None)), + Err(InProgress) => return Ok(Err(InProgress)), + }; + + 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(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<PredicateObligation<'tcx>>, +) -> 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<PredicateObligation<'tcx>>, +) -> 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 = ensure_sufficient_stack(|| 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<PredicateObligation<'tcx>>, + 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<PredicateObligation<'tcx>>, + ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { + AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } + } + + fn fold<T: TypeFoldable<'tcx>>(&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(<T as Foo<&'a>>::A) + // + // Instead of normalizing `<T as Foo<&'a>>::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) => { + // 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(); + if !recursion_limit.value_within_limit(self.depth) { + let obligation = Obligation::with_depth( + self.cause.clone(), + recursion_limit.0, + 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 i32)`), 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> { + if self.selcx.tcx().lazy_normalization() { + constant + } else { + let constant = constant.super_fold_with(self); + constant.eval(self.selcx.tcx(), self.param_env) + } + } +} + +/// The guts of `normalize`: normalize a specific projection like `<T +/// as Trait>::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 `<T as Trait>::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<PredicateObligation<'tcx>>, +) -> Ty<'tcx> { + opt_normalize_projection_type( + selcx, + param_env, + projection_ty, + cause.clone(), + depth, + obligations, + ) + .ok() + .flatten() + .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(tcx)); + obligations.push(obligation); + ty_var + }) +} + +/// The guts of `normalize`: normalize a specific projection like `<T +/// as Trait>::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<NormalizedTy<'tcx>>`, 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<PredicateObligation<'tcx>>, +) -> Result<Option<Ty<'tcx>>, InProgress> { + 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<U=Foo>` + // 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 Ok(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. + + debug!( + "opt_normalize_projection_type: \ + found cache entry: in-progress" + ); + + return Err(InProgress); + } + 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 Ok(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 Ok(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); + Ok(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`. + Ok(Some(result.value)) + } + Err(ProjectionTyError::TooManyCandidates) => { + debug!( + "opt_normalize_projection_type: \ + too many candidates" + ); + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); + Ok(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); + Ok(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.skip_binders() { + // We found a `T: Foo<X = U>` 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<X = ?1>` and `?1: Bar<X = + // ?0>`). + ty::PredicateAtom::Projection(data) => { + infcx.unresolved_type_vars(&ty::Binder::bind(data.ty)).is_some() + } + + // We are only interested in `T: Foo<X = U>` 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 `<T as +/// Trait>::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(infcx.tcx), + } +} + +/// If we are projecting `<T as Trait>::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 `<MyType<$0> +/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as +/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// `<MyType<[type error]> 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(selcx.tcx()), + }; + 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<PredicateObligation<'tcx>>, +} + +impl<'tcx> Progress<'tcx> { + fn error(tcx: TyCtxt<'tcx>) -> Self { + Progress { ty: tcx.ty_error(), obligations: vec![] } + } + + fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> 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<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { + debug!("project(obligation={:?})", obligation); + + if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { + 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(), + ); +} + +/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find +/// that the definition of `Foo` has some clues: +/// +/// ``` +/// trait Foo { +/// type FooT : Bar<BarT=i32> +/// } +/// ``` +/// +/// 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. + // If so, extract what we know from the trait and try to come up with a good answer. + let bounds = match obligation_trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, 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, + }; + + assemble_candidates_from_predicates( + selcx, + obligation, + obligation_trait_ref, + candidate_set, + ProjectionTyCandidate::TraitDef, + bounds.iter(), + ) +} + +fn assemble_candidates_from_predicates<'cx, 'tcx>( + 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: impl Iterator<Item = ty::Predicate<'tcx>>, +) { + 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::PredicateAtom::Projection(data) = predicate.skip_binders() { + let data = ty::Binder::bind(data); + 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 `<T as TraitRef<...>>::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 impl_source = match selcx.select(&trait_obligation) { + Ok(Some(impl_source)) => impl_source, + 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 &impl_source { + super::ImplSourceClosure(_) + | super::ImplSourceGenerator(_) + | super::ImplSourceFnPointer(_) + | super::ImplSourceObject(_) + | super::ImplSourceTraitAlias(_) => { + debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); + true + } + super::ImplSourceUserDefined(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) + .map_err(|ErrorReported| ())?; + + if node_item.is_final() { + // Non-specializable items are always projectable. + true + } else { + // 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. + 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.still_further_specializable() + } else { + 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::ImplSourceDiscriminantKind(..) => { + // While `DiscriminantKind` is automatically implemented for every type, + // the concrete discriminant may not be known yet. + // + // Any type with multiple potential discriminant types is therefore not eligible. + let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); + + match self_ty.kind { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Foreign(_) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Never + | ty::Tuple(..) + // Integers and floats always have `u8` as their discriminant. + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + + ty::Projection(..) + | ty::Opaque(..) + | ty::Param(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) + | ty::Error(_) => false, + } + } + super::ImplSourceParam(..) => { + // This case tell us nothing about the value of an + // associated type. Consider: + // + // ``` + // trait SomeTrait { type Foo; } + // fn foo<T:SomeTrait>(...) { } + // ``` + // + // If the user writes `<T as SomeTrait>::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<T:SomeTrait<Foo=usize>>(...) { ... } + // ``` + // + // Doesn't the `T : Sometrait<Foo=usize>` 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::ImplSourceAutoImpl(..) | super::ImplSourceBuiltin(..) => { + // These traits have no associated types. + selcx.tcx().sess.delay_span_bug( + obligation.cause.span, + &format!("Cannot project an associated type from `{:?}`", impl_source), + ); + return Err(()); + } + }; + + if eligible { + if candidate_set.push_candidate(ProjectionTyCandidate::Select(impl_source)) { + 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); + + let mut progress = match candidate { + ProjectionTyCandidate::ParamEnv(poly_projection) + | ProjectionTyCandidate::TraitDef(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection) + } + + ProjectionTyCandidate::Select(impl_source) => { + confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source) + } + }; + // When checking for cycle during evaluation, we compare predicates with + // "syntactic" equality. Since normalization generally introduces a type + // with new region variables, we need to resolve them to existing variables + // when possible for this to work. See `auto-trait-projection-recursion.rs` + // for a case where this matters. + if progress.ty.has_infer_regions() { + progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty); + } + progress +} + +fn confirm_select_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, + impl_source: Selection<'tcx>, +) -> Progress<'tcx> { + match impl_source { + super::ImplSourceUserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + super::ImplSourceGenerator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSourceClosure(data) => confirm_closure_candidate(selcx, obligation, data), + super::ImplSourceFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::ImplSourceDiscriminantKind(data) => { + confirm_discriminant_kind_candidate(selcx, obligation, data) + } + super::ImplSourceObject(_) => { + confirm_object_candidate(selcx, obligation, obligation_trait_ref) + } + super::ImplSourceAutoImpl(..) + | super::ImplSourceParam(..) + | super::ImplSourceBuiltin(..) + | super::ImplSourceTraitAlias(..) => + // we don't create Select candidates with this kind of resolution + { + span_bug!( + obligation.cause.span, + "Cannot project an associated type from `{:?}`", + impl_source + ) + } + } +} + +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(selcx.tcx())); + 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(|o| match o.predicate.skip_binders() { + ty::PredicateAtom::Projection(data) + if data.projection_ty.item_def_id == obligation.predicate.item_def_id => + { + Some(ty::Binder::bind(data)) + } + _ => 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>, + impl_source: ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let gen_sig = impl_source.substs.as_generator().poly_sig(); + 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.require_lang_item(LangItem::Generator, None); + + 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(impl_source.nested) + .with_addl_obligations(obligations) +} + +fn confirm_discriminant_kind_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + _: ImplSourceDiscriminantKindData, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + + let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); + let substs = tcx.mk_substs([self_ty.into()].iter()); + + let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id }, + ty: self_ty.discriminant_ty(tcx), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate)) +} + +fn confirm_fn_pointer_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let fn_type = selcx.infcx().shallow_resolve(fn_pointer_impl_source.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_impl_source.nested) + .with_addl_obligations(obligations) +} + +fn confirm_closure_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + impl_source: ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let closure_sig = impl_source.substs.as_closure().sig(); + 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(impl_source.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); + + let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); + let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); + + 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 { + substs: trait_ref.substs, + item_def_id: fn_once_output_def_id, + }, + 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); + let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); + Progress { ty: err, obligations: vec![] } + } + } +} + +fn confirm_impl_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + + let ImplSourceUserDefinedData { impl_def_id, substs, nested } = impl_impl_source; + 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 = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) { + Ok(assoc_ty) => assoc_ty, + Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested }, + }; + + 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.ty_error(), obligations: nested }; + } + // If we're trying to normalize `<Vec<u32> as X>::A<S>` using + //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then: + // + // * `obligation.predicate.substs` is `[Vec<u32>, S]` + // * `substs` is `[u32]` + // * `substs` ends up as `[u32, S]` + 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.defining_node); + let ty = tcx.type_of(assoc_ty.item.def_id); + if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { + let err = tcx.ty_error_with_message( + DUMMY_SP, + "impl item and trait item have different parameter counts", + ); + Progress { ty: 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, +) -> Result<specialization_graph::LeafDef, ErrorReported> { + 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 TraitDef::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) + && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) + { + return Ok(specialization_graph::LeafDef { + item: *item, + defining_node: impl_node, + finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) }, + }); + } + } + + let ancestors = trait_def.ancestors(tcx, impl_def_id)?; + if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) { + Ok(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<Self>; +} + +impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> { + fn from_poly_projection_predicate( + selcx: &mut SelectionContext<'cx, 'tcx>, + predicate: ty::PolyProjectionPredicate<'tcx>, + ) -> Option<Self> { + 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/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs new file mode 100644 index 00000000000..d07c95270e0 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -0,0 +1,139 @@ +use crate::infer::at::At; +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferOk; + +use rustc_middle::ty::subst::GenericArg; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub use rustc_middle::traits::query::{DropckOutlivesResult, DtorckConstraint}; + +pub trait AtExt<'tcx> { + fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>>; +} + +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 + /// destructor might access. This is used during regionck to + /// impose "outlives" constraints on any lifetimes referenced + /// within. + /// + /// The rules here are given by the "dropck" RFCs, notably [#1238] + /// and [#1327]. This is a fixed-point computation, where we + /// explore all the data that will be dropped (transitively) when + /// a value of type `ty` is dropped. For each type T that will be + /// dropped and which has a destructor, we must assume that all + /// the types/regions of T are live during the destructor, unless + /// they are marked with a special attribute (`#[may_dangle]`). + /// + /// [#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 + fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> { + debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,); + + // Quick check: there are a number of cases that we know do not require + // any destructor. + let tcx = self.infcx.tcx; + if trivial_dropck_outlives(tcx, ty) { + return InferOk { value: vec![], obligations: vec![] }; + } + + let mut orig_values = OriginalQueryValues::default(); + let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); + let span = self.cause.span; + debug!("c_ty = {:?}", c_ty); + if let Ok(result) = &tcx.dropck_outlives(c_ty) { + if result.is_proven() { + if let Ok(InferOk { value, obligations }) = + self.infcx.instantiate_query_response_and_region_obligations( + self.cause, + self.param_env, + &orig_values, + result, + ) + { + let ty = self.infcx.resolve_vars_if_possible(&ty); + let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); + return InferOk { value: kinds, obligations }; + } + } + } + + // Errors and ambiuity in dropck occur in two cases: + // - unresolved inference variables at the end of typeck + // - non well-formed types where projections cannot be resolved + // Either of these should have created an error before. + tcx.sess.delay_span_bug(span, "dtorck encountered internal error"); + + InferOk { value: vec![], obligations: vec![] } + } +} + +/// This returns true if the type `ty` is "trivial" for +/// dropck-outlives -- that is, if it doesn't require any types to +/// outlive. This is similar but not *quite* the same as the +/// `needs_drop` test in the compiler already -- that is, for every +/// type T for which this function return true, needs-drop would +/// return `false`. But the reverse does not hold: in particular, +/// `needs_drop` returns false for `PhantomData`, but it is not +/// trivial for dropck-outlives. +/// +/// Note also that `needs_drop` requires a "global" type (i.e., one +/// with erased regions), but this function does not. +pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind { + // None of these types have a destructor and hence they do not + // require anything in particular to outlive the dtor's + // execution. + ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) + | ty::Bool + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Never + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Char + | ty::GeneratorWitness(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::Str + | ty::Foreign(..) + | ty::Error(_) => true, + + // [T; N] and [T] have same properties as T. + ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), + + // (T1..Tn) and closures have same properties as T1..Tn -- + // check if *any* of those are trivial. + ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), + ty::Closure(_, ref substs) => { + substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t)) + } + + ty::Adt(def, _) => { + if Some(def.did) == tcx.lang_items().manually_drop() { + // `ManuallyDrop` never has a dtor. + true + } else { + // Other types might. Moreover, PhantomData doesn't + // have a dtor, but it is considered to own its + // content, so it is non-trivial. Unions can have `impl Drop`, + // and hence are non-trivial as well. + false + } + } + + // The following *might* require a destructor: needs deeper inspection. + ty::Dynamic(..) + | ty::Projection(..) + | ty::Param(_) + | ty::Opaque(..) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Bound(..) + | ty::Generator(..) => false, + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs new file mode 100644 index 00000000000..0569f6217da --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -0,0 +1,97 @@ +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::{ + EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode, +}; + +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<EvaluationResult, OverflowError>; + + // 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`. + fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { + self.evaluate_obligation_no_overflow(obligation).may_apply() + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + /// + /// This version may conservatively fail when outlives obligations + /// are required. + fn predicate_must_hold_considering_regions( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions() + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + /// + /// This version ignores all outlives constraints. + 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. + fn evaluate_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + let mut _orig_values = OriginalQueryValues::default(); + let c_pred = self + .canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values); + // Run canonical query. If overflow occurs, rerun from scratch but this time + // in standard trait query mode so that overflow is handled appropriately + // within `SelectionContext`. + self.tcx.evaluate_obligation(c_pred) + } + + // 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. + fn evaluate_obligation_no_overflow( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> EvaluationResult { + match self.evaluate_obligation(obligation) { + Ok(result) => result, + Err(OverflowError) => { + let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); + selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| { + span_bug!( + obligation.cause.span, + "Overflow should be caught earlier in standard query mode: {:?}, {:?}", + obligation, + r, + ) + }) + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs b/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs new file mode 100644 index 00000000000..3c0ebec9335 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs @@ -0,0 +1,3 @@ +pub use rustc_middle::traits::query::{ + CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult, +}; diff --git a/compiler/rustc_trait_selection/src/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs new file mode 100644 index 00000000000..01f4f09e238 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/mod.rs @@ -0,0 +1,15 @@ +//! Experimental types for the trait query interface. The methods +//! defined in this module are all based on **canonicalization**, +//! which makes a canonical query by replacing unbound inference +//! variables and regions, so that results can be reused more broadly. +//! The providers for the queries defined here can be found in +//! `librustc_traits`. + +pub mod dropck_outlives; +pub mod evaluate_obligation; +pub mod method_autoderef; +pub mod normalize; +pub mod outlives_bounds; +pub mod type_op; + +pub use rustc_middle::traits::query::*; diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs new file mode 100644 index 00000000000..93652329305 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -0,0 +1,207 @@ +//! Code for the 'normalization' query. This consists of a wrapper +//! which folds deeply, invoking the underlying +//! `normalize_projection_ty` query when it encounters projections. + +use crate::infer::at::At; +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_infer::traits::Normalized; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +use super::NoSolution; + +pub use rustc_middle::traits::query::NormalizationResult; + +pub trait AtExt<'tcx> { + fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, 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 + /// `normalize_erasing_regions`, which is more efficient. + /// + /// If the normalization succeeds and is unambiguous, returns back + /// the normalized value along with various outlives relations (in + /// the form of obligations that must be discharged). + /// + /// N.B., this will *eventually* be the main means of + /// 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". + fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution> + where + T: TypeFoldable<'tcx>, + { + debug!( + "normalize::<{}>(value={:?}, param_env={:?})", + ::std::any::type_name::<T>(), + value, + self.param_env, + ); + if !value.has_projections() { + return Ok(Normalized { value: value.clone(), obligations: vec![] }); + } + + let mut normalizer = QueryNormalizer { + infcx: self.infcx, + cause: self.cause, + param_env: self.param_env, + obligations: vec![], + error: false, + anon_depth: 0, + }; + + let result = value.fold_with(&mut normalizer); + debug!( + "normalize::<{}>: result={:?} with {} obligations", + ::std::any::type_name::<T>(), + result, + normalizer.obligations.len(), + ); + debug!( + "normalize::<{}>: obligations={:?}", + ::std::any::type_name::<T>(), + normalizer.obligations, + ); + if normalizer.error { + Err(NoSolution) + } else { + Ok(Normalized { value: result, obligations: normalizer.obligations }) + } + } +} + +struct QueryNormalizer<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + cause: &'cx ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + obligations: Vec<PredicateObligation<'tcx>>, + error: bool, + anon_depth: usize, +} + +impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_projections() { + return ty; + } + + let ty = ty.super_fold_with(self); + match ty.kind { + ty::Opaque(def_id, substs) => { + // 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(); + if !recursion_limit.value_within_limit(self.anon_depth) { + let obligation = Obligation::with_depth( + self.cause.clone(), + recursion_limit.0, + self.param_env, + ty, + ); + self.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.anon_depth += 1; + if concrete_ty == ty { + bug!( + "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ + concrete_ty: {:#?}, ty: {:#?}", + generic_ty, + substs, + concrete_ty, + ty + ); + } + let folded_ty = ensure_sufficient_stack(|| self.fold_ty(concrete_ty)); + self.anon_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 i32)`), 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 tcx = self.infcx.tcx; + + let mut orig_values = OriginalQueryValues::default(); + // HACK(matthewjasper) `'static` is special-cased in selection, + // so we cannot canonicalize it. + let c_data = self + .infcx + .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values); + debug!("QueryNormalizer: c_data = {:#?}", c_data); + debug!("QueryNormalizer: orig_values = {:#?}", orig_values); + match tcx.normalize_projection_ty(c_data) { + Ok(result) => { + // We don't expect ambiguity. + if result.is_ambiguous() { + self.error = true; + return ty; + } + + match self.infcx.instantiate_query_response_and_region_obligations( + self.cause, + self.param_env, + &orig_values, + &result, + ) { + Ok(InferOk { value: result, obligations }) => { + debug!("QueryNormalizer: result = {:#?}", result); + debug!("QueryNormalizer: obligations = {:#?}", obligations); + self.obligations.extend(obligations); + result.normalized_ty + } + + Err(_) => { + self.error = true; + ty + } + } + } + + Err(NoSolution) => { + self.error = true; + ty + } + } + } + + _ => ty, + } + } + + fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + let constant = constant.super_fold_with(self); + constant.eval(self.infcx.tcx, self.param_env) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs new file mode 100644 index 00000000000..a42409515db --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs @@ -0,0 +1,95 @@ +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::query::NoSolution; +use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine}; +use rustc_hir as hir; +use rustc_infer::traits::TraitEngineExt as _; +use rustc_middle::ty::{self, Ty}; +use rustc_span::source_map::Span; + +pub use rustc_middle::traits::query::OutlivesBound; + +pub trait InferCtxtExt<'tcx> { + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec<OutlivesBound<'tcx>>; +} + +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 + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// + /// fn foo<'a,T>(x: &'a T) + /// + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. + /// + /// # Parameters + /// + /// - `param_env`, the where-clauses in scope + /// - `body_id`, the body-id to use when normalizing assoc types. + /// Note that this may cause outlives obligations to be injected + /// into the inference context with this body-id. + /// - `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. + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec<OutlivesBound<'tcx>> { + debug!("implied_outlives_bounds(ty = {:?})", ty); + + let mut orig_values = OriginalQueryValues::default(); + let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); + let result = match self.tcx.implied_outlives_bounds(key) { + Ok(r) => r, + Err(NoSolution) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve all obligations", + ); + return vec![]; + } + }; + assert!(result.value.is_proven()); + + let result = self.instantiate_query_response_and_region_obligations( + &ObligationCause::misc(span, body_id), + param_env, + &orig_values, + &result, + ); + debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); + let result = match result { + Ok(v) => v, + Err(_) => { + self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate"); + return vec![]; + } + }; + + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = FulfillmentContext::new(); + fulfill_cx.register_predicate_obligations(self, result.obligations); + if fulfill_cx.select_all_or_error(self).is_err() { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation", + ); + } + + result.value + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs new file mode 100644 index 00000000000..86b015767f0 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -0,0 +1,23 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::Fallible; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; + +pub use rustc_middle::traits::query::type_op::AscribeUserType; + +impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { + type QueryResponse = (); + + fn try_fast_path( + _tcx: TyCtxt<'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option<Self::QueryResponse> { + None + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { + tcx.type_op_ascribe_user_type(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs new file mode 100644 index 00000000000..915e8ae4a7a --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -0,0 +1,108 @@ +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::query::Fallible; +use std::fmt; + +use crate::infer::canonical::query_response; +use crate::infer::canonical::QueryRegionConstraints; +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; + +pub struct CustomTypeOp<F, G> { + closure: F, + description: G, +} + +impl<F, G> CustomTypeOp<F, G> { + pub fn new<'tcx, R>(closure: F, description: G) -> Self + where + F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>, + G: Fn() -> String, + { + CustomTypeOp { closure, description } + } +} + +impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> +where + F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>, + G: Fn() -> String, +{ + type Output = R; + + /// Processes the operation and all resulting obligations, + /// returning the final result along with any region constraints + /// (they will be given over to the NLL region solver). + fn fully_perform( + self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { + if cfg!(debug_assertions) { + info!("fully_perform({:?})", self); + } + + scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?)) + } +} + +impl<F, G> fmt::Debug for CustomTypeOp<F, G> +where + G: Fn() -> String, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", (self.description)()) + } +} + +/// Executes `op` and then scrapes out all the "old style" region +/// constraints that result, creating query-region-constraints. +fn scrape_region_constraints<'tcx, R>( + infcx: &InferCtxt<'_, 'tcx>, + op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, +) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> { + let mut fulfill_cx = TraitEngine::new(infcx.tcx); + let dummy_body_id = ObligationCause::dummy().body_id; + + // During NLL, we expect that nobody will register region + // obligations **except** as part of a custom type op (and, at the + // end of each custom type op, we scrape out the region + // obligations that resulted). So this vector should be empty on + // entry. + let pre_obligations = infcx.take_registered_region_obligations(); + assert!( + pre_obligations.is_empty(), + "scrape_region_constraints: incoming region obligations = {:#?}", + pre_obligations, + ); + + let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; + debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); + fulfill_cx.register_predicate_obligations(infcx, obligations); + if let Err(e) = fulfill_cx.select_all_or_error(infcx) { + infcx.tcx.sess.diagnostic().delay_span_bug( + DUMMY_SP, + &format!("errors selecting obligation during MIR typeck: {:?}", e), + ); + } + + let region_obligations = infcx.take_registered_region_obligations(); + + let region_constraint_data = infcx.take_and_reset_region_constraints(); + + let region_constraints = query_response::make_query_region_constraints( + infcx.tcx, + region_obligations + .iter() + .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) + .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)), + ®ion_constraint_data, + ); + + if region_constraints.is_empty() { + Ok((value, None)) + } else { + Ok((value, Some(Rc::new(region_constraints)))) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs new file mode 100644 index 00000000000..490114aacd1 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs @@ -0,0 +1,23 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::Fallible; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; + +pub use rustc_middle::traits::query::type_op::Eq; + +impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { + type QueryResponse = (); + + fn try_fast_path( + _tcx: TyCtxt<'tcx>, + key: &ParamEnvAnd<'tcx, Eq<'tcx>>, + ) -> Option<Self::QueryResponse> { + if key.value.a == key.value.b { Some(()) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { + tcx.type_op_eq(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs new file mode 100644 index 00000000000..cf7f0a553c7 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -0,0 +1,41 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::outlives_bounds::OutlivesBound; +use crate::traits::query::Fallible; +use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] +pub struct ImpliedOutlivesBounds<'tcx> { + pub ty: Ty<'tcx>, +} + +impl<'tcx> ImpliedOutlivesBounds<'tcx> { + pub fn new(ty: Ty<'tcx>) -> Self { + ImpliedOutlivesBounds { ty } + } +} + +impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { + type QueryResponse = Vec<OutlivesBound<'tcx>>; + + fn try_fast_path( + _tcx: TyCtxt<'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option<Self::QueryResponse> { + None + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { + // FIXME this `unchecked_map` is only necessary because the + // query is defined as taking a `ParamEnvAnd<Ty>`; it should + // take a `ImpliedOutlivesBounds` instead + let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| { + let ImpliedOutlivesBounds { ty } = value; + param_env.and(ty) + }); + + tcx.implied_outlives_bounds(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs new file mode 100644 index 00000000000..ed6c6d0cc0a --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -0,0 +1,136 @@ +use crate::infer::canonical::{ + Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints, +}; +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::query::Fallible; +use crate::traits::ObligationCause; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use std::fmt; +use std::rc::Rc; + +pub mod ascribe_user_type; +pub mod custom; +pub mod eq; +pub mod implied_outlives_bounds; +pub mod normalize; +pub mod outlives; +pub mod prove_predicate; +use self::prove_predicate::ProvePredicate; +pub mod subtype; + +pub use rustc_middle::traits::query::type_op::*; + +/// "Type ops" are used in NLL to perform some particular action and +/// extract out the resulting region constraints (or an error if it +/// cannot be completed). +pub trait TypeOp<'tcx>: Sized + fmt::Debug { + type Output; + + /// Processes the operation and all resulting obligations, + /// returning the final result along with any region constraints + /// (they will be given over to the NLL region solver). + fn fully_perform( + self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>; +} + +/// "Query type ops" are type ops that are implemented using a +/// [canonical query][c]. The `Self` type here contains the kernel of +/// information needed to do the operation -- `TypeOp` is actually +/// implemented for `ParamEnvAnd<Self>`, since we always need to bring +/// along a parameter environment as well. For query type-ops, we will +/// first canonicalize the key and then invoke the query on the tcx, +/// which produces the resulting query region constraints. +/// +/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html +pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { + type QueryResponse: TypeFoldable<'tcx>; + + /// Give query the option for a simple fast path that never + /// actually hits the tcx cache lookup etc. Return `Some(r)` with + /// a final result or `None` to do the full path. + fn try_fast_path( + tcx: TyCtxt<'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option<Self::QueryResponse>; + + /// Performs the actual query with the canonicalized key -- the + /// real work happens here. This method is not given an `infcx` + /// because it shouldn't need one -- and if it had access to one, + /// it might do things like invoke `sub_regions`, which would be + /// bad, because it would create subregion relationships that are + /// not captured in the return value. + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>; + + fn fully_perform_into( + query_key: ParamEnvAnd<'tcx, Self>, + infcx: &InferCtxt<'_, 'tcx>, + output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, + ) -> Fallible<Self::QueryResponse> { + if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { + return Ok(result); + } + + // FIXME(#33684) -- We need to use + // `canonicalize_hr_query_hack` here because of things + // like the subtype query, which go awry around + // `'static` otherwise. + let mut canonical_var_values = OriginalQueryValues::default(); + let canonical_self = + infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); + let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; + + let param_env = query_key.param_env; + + let InferOk { value, obligations } = infcx + .instantiate_nll_query_response_and_region_obligations( + &ObligationCause::dummy(), + param_env, + &canonical_var_values, + canonical_result, + output_query_region_constraints, + )?; + + // Typically, instantiating NLL query results does not + // create obligations. However, in some cases there + // are unresolved type variables, and unify them *can* + // create obligations. In that case, we have to go + // fulfill them. We do this via a (recursive) query. + for obligation in obligations { + let () = ProvePredicate::fully_perform_into( + obligation.param_env.and(ProvePredicate::new(obligation.predicate)), + infcx, + output_query_region_constraints, + )?; + } + + Ok(value) + } +} + +impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q> +where + Q: QueryTypeOp<'tcx>, +{ + type Output = Q::QueryResponse; + + fn fully_perform( + self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { + let mut region_constraints = QueryRegionConstraints::default(); + let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?; + + // Promote the final query-region-constraints into a + // (optional) ref-counted vector: + let opt_qrc = + if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; + + Ok((r, opt_qrc)) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs new file mode 100644 index 00000000000..729b66ac21c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -0,0 +1,68 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::Fallible; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; +use std::fmt; + +pub use rustc_middle::traits::query::type_op::Normalize; + +impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T> +where + T: Normalizable<'tcx> + 'tcx, +{ + type QueryResponse = T; + + fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> { + if !key.value.value.has_projections() { Some(key.value.value) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { + T::type_op_method(tcx, canonicalized) + } +} + +pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>; +} + +impl Normalizable<'tcx> for Ty<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { + tcx.type_op_normalize_ty(canonicalized) + } +} + +impl Normalizable<'tcx> for ty::Predicate<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { + tcx.type_op_normalize_predicate(canonicalized) + } +} + +impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { + tcx.type_op_normalize_poly_fn_sig(canonicalized) + } +} + +impl Normalizable<'tcx> for ty::FnSig<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { + tcx.type_op_normalize_fn_sig(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs new file mode 100644 index 00000000000..5a27e57860e --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -0,0 +1,55 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; +use crate::traits::query::Fallible; +use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] +pub struct DropckOutlives<'tcx> { + dropped_ty: Ty<'tcx>, +} + +impl<'tcx> DropckOutlives<'tcx> { + pub fn new(dropped_ty: Ty<'tcx>) -> Self { + DropckOutlives { dropped_ty } + } +} + +impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { + type QueryResponse = DropckOutlivesResult<'tcx>; + + fn try_fast_path( + tcx: TyCtxt<'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option<Self::QueryResponse> { + if trivial_dropck_outlives(tcx, key.value.dropped_ty) { + Some(DropckOutlivesResult::default()) + } else { + None + } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { + // Subtle: note that we are not invoking + // `infcx.at(...).dropck_outlives(...)` here, but rather the + // underlying `dropck_outlives` query. This same underlying + // query is also used by the + // `infcx.at(...).dropck_outlives(...)` fn. Avoiding the + // wrapper means we don't need an infcx in this code, which is + // good because the interface doesn't give us one (so that we + // know we are not registering any subregion relations or + // other things). + + // FIXME convert to the type expected by the `dropck_outlives` + // query. This should eventually be fixed by changing the + // *underlying query*. + let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| { + let DropckOutlives { dropped_ty } = value; + param_env.and(dropped_ty) + }); + + tcx.dropck_outlives(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs new file mode 100644 index 00000000000..93ddcb68554 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -0,0 +1,37 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::Fallible; +use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; + +pub use rustc_middle::traits::query::type_op::ProvePredicate; + +impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { + type QueryResponse = (); + + fn try_fast_path( + tcx: TyCtxt<'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option<Self::QueryResponse> { + // Proving Sized, very often on "obviously sized" types like + // `&T`, accounts for about 60% percentage of the predicates + // we have to prove. No need to canonicalize and all that for + // such cases. + if let ty::PredicateAtom::Trait(trait_ref, _) = key.value.predicate.skip_binders() { + if let Some(sized_def_id) = tcx.lang_items().sized_trait() { + if trait_ref.def_id() == sized_def_id { + if trait_ref.self_ty().is_trivially_sized(tcx) { + return Some(()); + } + } + } + } + + None + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { + tcx.type_op_prove_predicate(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs new file mode 100644 index 00000000000..57290b66914 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs @@ -0,0 +1,20 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::Fallible; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; + +pub use rustc_middle::traits::query::type_op::Subtype; + +impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { + type QueryResponse = (); + + fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> { + if key.value.sub == key.value.sup { Some(()) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { + tcx.type_op_subtype(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs new file mode 100644 index 00000000000..1d5441b8eff --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -0,0 +1,635 @@ +//! Candidate assembly. +//! +//! The selection process begins by examining all in-scope impls, +//! caller obligations, and so forth and assembling a list of +//! candidates. See the [rustc dev guide] for more details. +//! +//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly +use rustc_hir as hir; +use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_middle::ty::{self, TypeFoldable}; +use rustc_target::spec::abi::Abi; + +use crate::traits::{util, SelectionResult}; + +use super::BuiltinImplConditions; +use super::SelectionCandidate::{self, *}; +use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack}; + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub(super) fn candidate_from_obligation<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + // Watch out for overflow. This intentionally bypasses (and does + // not update) the cache. + self.check_recursion_limit(&stack.obligation, &stack.obligation)?; + + // Check the cache. Note that we freshen the trait-ref + // separately rather than using `stack.fresh_trait_ref` -- + // this is because we want the unbound variables to be + // replaced with fresh types starting from index 0. + let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate); + debug!( + "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", + cache_fresh_trait_pred, stack + ); + debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); + + if let Some(c) = + self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) + { + debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); + return c; + } + + // If no match, compute result and insert into cache. + // + // FIXME(nikomatsakis) -- this cache is not taking into + // account cycles that may have occurred in forming the + // candidate. I don't know of any specific problems that + // result but it seems awfully suspicious. + let (candidate, dep_node) = + self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); + + debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); + self.insert_candidate_cache( + stack.obligation.param_env, + cache_fresh_trait_pred, + dep_node, + candidate.clone(), + ); + candidate + } + + pub(super) fn assemble_candidates<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> { + let TraitObligationStack { obligation, .. } = *stack; + let obligation = &Obligation { + param_env: obligation.param_env, + cause: obligation.cause.clone(), + recursion_depth: obligation.recursion_depth, + predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), + }; + + if obligation.predicate.skip_binder().self_ty().is_ty_var() { + // Self is a type variable (e.g., `_: AsRef<str>`). + // + // This is somewhat problematic, as the current scheme can't really + // handle it turning to be a projection. This does end up as truly + // ambiguous in most cases anyway. + // + // Take the fast path out - this also improves + // performance by preventing assemble_candidates_from_impls from + // matching every impl for this trait. + return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); + } + + let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + + self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?; + + // Other bounds. Consider both in-scope bounds from fn decl + // and applicable impls. There is a certain set of precedence rules here. + let def_id = obligation.predicate.def_id(); + let lang_items = self.tcx().lang_items(); + + if lang_items.copy_trait() == Some(def_id) { + debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); + + // User-defined copy impls are permitted, but only for + // structs and enums. + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + + // For other types, we'll use the builtin rules. + let copy_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; + } else if lang_items.discriminant_kind_trait() == Some(def_id) { + // `DiscriminantKind` is automatically implemented for every type. + candidates.vec.push(DiscriminantKindCandidate); + } else if lang_items.sized_trait() == Some(def_id) { + // Sized is never implementable by end-users, it is + // always automatically computed. + let sized_conditions = self.sized_conditions(obligation); + self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; + } else if lang_items.unsize_trait() == Some(def_id) { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else { + if lang_items.clone_trait() == Some(def_id) { + // Same builtin conditions as `Copy`, i.e., every type which has builtin support + // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` + // types have builtin support for `Clone`. + let clone_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; + } + + self.assemble_generator_candidates(obligation, &mut candidates)?; + self.assemble_closure_candidates(obligation, &mut candidates)?; + self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + self.assemble_candidates_from_object_ty(obligation, &mut candidates); + } + + self.assemble_candidates_from_projected_tys(obligation, &mut candidates); + self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; + // Auto implementations have lower priority, so we only + // consider triggering a default if there is no other impl that can apply. + if candidates.vec.is_empty() { + self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?; + } + debug!("candidate list size: {}", candidates.vec.len()); + Ok(candidates) + } + + fn assemble_candidates_from_projected_tys( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + debug!("assemble_candidates_for_projected_tys({:?})", obligation); + + // Before we go into the whole placeholder thing, just + // quickly check if the self-type is a projection at all. + match obligation.predicate.skip_binder().trait_ref.self_ty().kind { + ty::Projection(_) | ty::Opaque(..) => {} + ty::Infer(ty::TyVar(_)) => { + span_bug!( + obligation.cause.span, + "Self=_ should have been handled by assemble_candidates" + ); + } + _ => return, + } + + let result = self + .infcx + .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); + + if result { + candidates.vec.push(ProjectionCandidate); + } + } + + /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller + /// supplied to find out whether it is listed among them. + /// + /// Never affects the inference environment. + fn assemble_candidates_from_caller_bounds<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); + + let all_bounds = stack + .obligation + .param_env + .caller_bounds() + .iter() + .filter_map(|o| o.to_opt_poly_trait_ref()); + + // Micro-optimization: filter out predicates relating to different traits. + let matching_bounds = + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + + // Keep only those bounds which may apply, and propagate overflow if it occurs. + let mut param_candidates = vec![]; + for bound in matching_bounds { + let wc = self.evaluate_where_clause(stack, bound)?; + if wc.may_apply() { + param_candidates.push(ParamCandidate(bound)); + } + } + + candidates.vec.extend(param_candidates); + + Ok(()) + } + + fn assemble_generator_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { + return Ok(()); + } + + // Okay to skip binder because the substs on generator types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = obligation.self_ty().skip_binder(); + match self_ty.kind { + ty::Generator(..) => { + debug!( + "assemble_generator_candidates: self_ty={:?} obligation={:?}", + self_ty, obligation + ); + + candidates.vec.push(GeneratorCandidate); + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_generator_candidates: ambiguous self-type"); + candidates.ambiguous = true; + } + _ => {} + } + + Ok(()) + } + + /// Checks for the artificial impl that the compiler will create for an obligation like `X : + /// FnMut<..>` where `X` is a closure type. + /// + /// Note: the type parameters on a closure candidate are modeled as *output* type + /// parameters and hence do not affect whether this trait is a match or not. They will be + /// unified during the confirmation step. + fn assemble_closure_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) { + Some(k) => k, + None => { + return Ok(()); + } + }; + + // Okay to skip binder because the substs on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters + match obligation.self_ty().skip_binder().kind { + ty::Closure(_, closure_substs) => { + debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); + match self.infcx.closure_kind(closure_substs) { + Some(closure_kind) => { + debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); + if closure_kind.extends(kind) { + candidates.vec.push(ClosureCandidate); + } + } + None => { + debug!("assemble_unboxed_candidates: closure_kind not yet known"); + candidates.vec.push(ClosureCandidate); + } + } + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); + candidates.ambiguous = true; + } + _ => {} + } + + Ok(()) + } + + /// Implements one of the `Fn()` family for a fn pointer. + fn assemble_fn_pointer_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // We provide impl of all fn traits for fn pointers. + if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() { + return Ok(()); + } + + // Okay to skip binder because what we are inspecting doesn't involve bound regions. + let self_ty = obligation.self_ty().skip_binder(); + match self_ty.kind { + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_fn_pointer_candidates: ambiguous self-type"); + candidates.ambiguous = true; // Could wind up being a fn() type. + } + // Provide an impl, but only for suitable `fn` pointers. + ty::FnPtr(_) => { + if let ty::FnSig { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } = self_ty.fn_sig(self.tcx()).skip_binder() + { + candidates.vec.push(FnPointerCandidate); + } + } + // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). + ty::FnDef(def_id, _) => { + if let ty::FnSig { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } = self_ty.fn_sig(self.tcx()).skip_binder() + { + if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { + candidates.vec.push(FnPointerCandidate); + } + } + } + _ => {} + } + + Ok(()) + } + + /// Searches for impls that might apply to `obligation`. + fn assemble_candidates_from_impls( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + + // Essentially any user-written impl will match with an error type, + // so creating `ImplCandidates` isn't useful. However, we might + // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized) + // This helps us avoid overflow: see issue #72839 + // Since compilation is already guaranteed to fail, this is just + // to try to show the 'nicest' possible errors to the user. + if obligation.references_error() { + return Ok(()); + } + + self.tcx().for_each_relevant_impl( + obligation.predicate.def_id(), + obligation.predicate.skip_binder().trait_ref.self_ty(), + |impl_def_id| { + self.infcx.probe(|_| { + if let Ok(_substs) = self.match_impl(impl_def_id, obligation) { + candidates.vec.push(ImplCandidate(impl_def_id)); + } + }); + }, + ); + + Ok(()) + } + + fn assemble_candidates_from_auto_impls( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // Okay to skip binder here because the tests we do below do not involve bound regions. + let self_ty = obligation.self_ty().skip_binder(); + debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); + + let def_id = obligation.predicate.def_id(); + + if self.tcx().trait_is_auto(def_id) { + match self_ty.kind { + ty::Dynamic(..) => { + // For object types, we don't know what the closed + // over types are. This means we conservatively + // say nothing; a candidate may be added by + // `assemble_candidates_from_object_ty`. + } + ty::Foreign(..) => { + // Since the contents of foreign types is unknown, + // we don't add any `..` impl. Default traits could + // still be provided by a manual implementation for + // this trait and type. + } + ty::Param(..) | ty::Projection(..) => { + // In these cases, we don't know what the actual + // type is. Therefore, we cannot break it down + // into its constituent types. So we don't + // consider the `..` impl but instead just add no + // candidates: this means that typeck will only + // succeed if there is another reason to believe + // that this obligation holds. That could be a + // where-clause or, in the case of an object type, + // it could be that the object type lists the + // trait (e.g., `Foo+Send : Send`). See + // `compile-fail/typeck-default-trait-impl-send-param.rs` + // for an example of a test case that exercises + // this path. + } + ty::Infer(ty::TyVar(_)) => { + // The auto impl might apply; we don't know. + candidates.ambiguous = true; + } + ty::Generator(_, _, movability) + if self.tcx().lang_items().unpin_trait() == Some(def_id) => + { + match movability { + hir::Movability::Static => { + // Immovable generators are never `Unpin`, so + // suppress the normal auto-impl candidate for it. + } + hir::Movability::Movable => { + // Movable generators are always `Unpin`, so add an + // unconditional builtin candidate. + candidates.vec.push(BuiltinCandidate { has_nested: false }); + } + } + } + + _ => candidates.vec.push(AutoImplCandidate(def_id)), + } + } + + Ok(()) + } + + /// Searches for impls that might apply to `obligation`. + fn assemble_candidates_from_object_ty( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + debug!( + "assemble_candidates_from_object_ty(self_ty={:?})", + obligation.self_ty().skip_binder() + ); + + self.infcx.probe(|_snapshot| { + // The code below doesn't care about regions, and the + // self-ty here doesn't escape this probe, so just erase + // any LBR. + let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); + let poly_trait_ref = match self_ty.kind { + ty::Dynamic(ref data, ..) => { + if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { + debug!( + "assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate" + ); + candidates.vec.push(BuiltinObjectCandidate); + return; + } + + if let Some(principal) = data.principal() { + if !self.infcx.tcx.features().object_safe_for_dispatch { + principal.with_self_ty(self.tcx(), self_ty) + } else if self.tcx().is_object_safe(principal.def_id()) { + principal.with_self_ty(self.tcx(), self_ty) + } else { + return; + } + } else { + // Only auto trait bounds exist. + return; + } + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type + return; + } + _ => return, + }; + + debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); + + // Count only those upcast versions that match the trait-ref + // we are looking for. Specifically, do not only check for the + // correct trait, but also the correct type parameters. + // For example, we may be trying to upcast `Foo` to `Bar<i32>`, + // but `Foo` is declared as `trait Foo: Bar<u32>`. + let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) + .filter(|upcast_trait_ref| { + self.infcx + .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok()) + }) + .count(); + + if upcast_trait_refs > 1 { + // Can be upcast in many ways; need more type information. + candidates.ambiguous = true; + } else if upcast_trait_refs == 1 { + candidates.vec.push(ObjectCandidate); + } + }) + } + + /// Searches for unsizing that might apply to `obligation`. + fn assemble_candidates_for_unsizing( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + // We currently never consider higher-ranked obligations e.g. + // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not + // because they are a priori invalid, and we could potentially add support + // for them later, it's just that there isn't really a strong need for it. + // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>` + // impl, and those are generally applied to concrete types. + // + // That said, one might try to write a fn with a where clause like + // for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>> + // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. + // Still, you'd be more likely to write that where clause as + // T: Trait + // so it seems ok if we (conservatively) fail to accept that `Unsize` + // obligation above. Should be possible to extend this in the future. + let source = match obligation.self_ty().no_bound_vars() { + Some(t) => t, + None => { + // Don't add any candidates if there are bound regions. + return; + } + }; + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + + debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); + + let may_apply = match (&source.kind, &target.kind) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + // Upcasts permit two things: + // + // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` + // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b` + // + // Note that neither of these changes requires any + // change at runtime. Eventually this will be + // generalized. + // + // We always upcast when we can because of reason + // #2 (region bounds). + data_a.principal_def_id() == data_b.principal_def_id() + && data_b + .auto_traits() + // All of a's auto traits need to be in b's auto traits. + .all(|b| data_a.auto_traits().any(|a| a == b)) + } + + // `T` -> `Trait` + (_, &ty::Dynamic(..)) => true, + + // Ambiguous handling is below `T` -> `Trait`, because inference + // variables can still implement `Unsize<Trait>` and nested + // obligations will have the final say (likely deferred). + (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => { + debug!("assemble_candidates_for_unsizing: ambiguous"); + candidates.ambiguous = true; + false + } + + // `[T; n]` -> `[T]` + (&ty::Array(..), &ty::Slice(_)) => true, + + // `Struct<T>` -> `Struct<U>` + (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => { + def_id_a == def_id_b + } + + // `(.., T)` -> `(.., U)` + (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(), + + _ => false, + }; + + if may_apply { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + + fn assemble_candidates_for_trait_alias( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // Okay to skip binder here because the tests we do below do not involve bound regions. + let self_ty = obligation.self_ty().skip_binder(); + debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); + + let def_id = obligation.predicate.def_id(); + + if self.tcx().is_trait_alias(def_id) { + candidates.vec.push(TraitAliasCandidate(def_id)); + } + + Ok(()) + } + + /// Assembles the trait which are built-in to the language itself: + /// `Copy`, `Clone` and `Sized`. + fn assemble_builtin_bound_candidates( + &mut self, + conditions: BuiltinImplConditions<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + match conditions { + BuiltinImplConditions::Where(nested) => { + debug!("builtin_bound: nested={:?}", nested); + candidates + .vec + .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); + } + BuiltinImplConditions::None => {} + BuiltinImplConditions::Ambiguous => { + debug!("assemble_builtin_bound_candidates: ambiguous builtin"); + candidates.ambiguous = true; + } + } + + Ok(()) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs new file mode 100644 index 00000000000..3d6eb845136 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -0,0 +1,810 @@ +//! Confirmation. +//! +//! Confirmation unifies the output type parameters of the trait +//! with the values found in the obligation, possibly yielding a +//! type error. See the [rustc dev guide] for more details. +//! +//! [rustc dev guide]: +//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::lang_items::LangItem; +use rustc_index::bit_set::GrowableBitSet; +use rustc_infer::infer::InferOk; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; +use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness}; +use rustc_span::def_id::DefId; + +use crate::traits::project::{self, normalize_with_depth}; +use crate::traits::select::TraitObligationExt; +use crate::traits::util; +use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::Normalized; +use crate::traits::OutputTypeParameterMismatch; +use crate::traits::Selection; +use crate::traits::TraitNotObjectSafe; +use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; +use crate::traits::{ + ImplSourceAutoImpl, ImplSourceBuiltin, ImplSourceClosure, ImplSourceDiscriminantKind, + ImplSourceFnPointer, ImplSourceGenerator, ImplSourceObject, ImplSourceParam, + ImplSourceTraitAlias, ImplSourceUserDefined, +}; +use crate::traits::{ + ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, + ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, + ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData, +}; +use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation}; +use crate::traits::{Obligation, ObligationCause}; +use crate::traits::{SelectionError, Unimplemented}; + +use super::BuiltinImplConditions; +use super::SelectionCandidate::{self, *}; +use super::SelectionContext; + +use std::iter; + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub(super) fn confirm_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + candidate: SelectionCandidate<'tcx>, + ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { + debug!("confirm_candidate({:?}, {:?})", obligation, candidate); + + match candidate { + BuiltinCandidate { has_nested } => { + let data = self.confirm_builtin_candidate(obligation, has_nested); + Ok(ImplSourceBuiltin(data)) + } + + ParamCandidate(param) => { + let obligations = self.confirm_param_candidate(obligation, param); + Ok(ImplSourceParam(obligations)) + } + + ImplCandidate(impl_def_id) => { + Ok(ImplSourceUserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) + } + + AutoImplCandidate(trait_def_id) => { + let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); + Ok(ImplSourceAutoImpl(data)) + } + + ProjectionCandidate => { + self.confirm_projection_candidate(obligation); + Ok(ImplSourceParam(Vec::new())) + } + + ClosureCandidate => { + let vtable_closure = self.confirm_closure_candidate(obligation)?; + Ok(ImplSourceClosure(vtable_closure)) + } + + GeneratorCandidate => { + let vtable_generator = self.confirm_generator_candidate(obligation)?; + Ok(ImplSourceGenerator(vtable_generator)) + } + + FnPointerCandidate => { + let data = self.confirm_fn_pointer_candidate(obligation)?; + Ok(ImplSourceFnPointer(data)) + } + + DiscriminantKindCandidate => { + Ok(ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData)) + } + + TraitAliasCandidate(alias_def_id) => { + let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); + Ok(ImplSourceTraitAlias(data)) + } + + ObjectCandidate => { + let data = self.confirm_object_candidate(obligation); + Ok(ImplSourceObject(data)) + } + + BuiltinObjectCandidate => { + // This indicates something like `Trait + Send: Send`. In this case, we know that + // this holds because that's what the object type is telling us, and there's really + // no additional obligations to prove and no types in particular to unify, etc. + Ok(ImplSourceParam(Vec::new())) + } + + BuiltinUnsizeCandidate => { + let data = self.confirm_builtin_unsize_candidate(obligation)?; + Ok(ImplSourceBuiltin(data)) + } + } + } + + fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { + self.infcx.commit_unconditionally(|_| { + let result = self.match_projection_obligation_against_definition_bounds(obligation); + assert!(result); + }) + } + + fn confirm_param_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + param: ty::PolyTraitRef<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + debug!("confirm_param_candidate({:?},{:?})", obligation, param); + + // During evaluation, we already checked that this + // where-clause trait-ref could be unified with the obligation + // trait-ref. Repeat that unification now without any + // transactional boundary; it should not fail. + match self.match_where_clause_trait_ref(obligation, param) { + Ok(obligations) => obligations, + Err(()) => { + bug!( + "Where clause `{:?}` was applicable to `{:?}` but now is not", + param, + obligation + ); + } + } + } + + fn confirm_builtin_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + has_nested: bool, + ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> { + debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); + + let lang_items = self.tcx().lang_items(); + let obligations = if has_nested { + let trait_def = obligation.predicate.def_id(); + let conditions = if Some(trait_def) == lang_items.sized_trait() { + self.sized_conditions(obligation) + } else if Some(trait_def) == lang_items.copy_trait() { + self.copy_clone_conditions(obligation) + } else if Some(trait_def) == lang_items.clone_trait() { + self.copy_clone_conditions(obligation) + } else { + bug!("unexpected builtin trait {:?}", trait_def) + }; + let nested = match conditions { + BuiltinImplConditions::Where(nested) => nested, + _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation), + }; + + let cause = obligation.derived_cause(BuiltinDerivedObligation); + ensure_sufficient_stack(|| { + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) + }) + } else { + vec![] + }; + + debug!("confirm_builtin_candidate: obligations={:?}", obligations); + + ImplSourceBuiltinData { nested: obligations } + } + + /// This handles the case where a `auto trait Foo` impl is being used. + /// The idea is that the impl applies to `X : Foo` if the following conditions are met: + /// + /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds + /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. + fn confirm_auto_impl_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { + debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); + + let types = obligation.predicate.map_bound(|inner| { + let self_ty = self.infcx.shallow_resolve(inner.self_ty()); + self.constituent_types_for_ty(self_ty) + }); + self.vtable_auto_impl(obligation, trait_def_id, types) + } + + /// See `confirm_auto_impl_candidate`. + fn vtable_auto_impl( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + nested: ty::Binder<Vec<Ty<'tcx>>>, + ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { + debug!("vtable_auto_impl: nested={:?}", nested); + ensure_sufficient_stack(|| { + let cause = obligation.derived_cause(BuiltinDerivedObligation); + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def_id, + nested, + ); + + let trait_obligations: Vec<PredicateObligation<'_>> = + self.infcx.commit_unconditionally(|_| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, _) = + self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); + let cause = obligation.derived_cause(ImplDerivedObligation); + self.impl_or_trait_obligations( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + ) + }); + + // Adds the predicates from the trait. Note that this contains a `Self: Trait` + // predicate as usual. It won't have any effect since auto traits are coinductive. + obligations.extend(trait_obligations); + + debug!("vtable_auto_impl: obligations={:?}", obligations); + + ImplSourceAutoImplData { trait_def_id, nested: obligations } + }) + } + + fn confirm_impl_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: DefId, + ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); + + // First, create the substitutions by matching the impl again, + // this time not in a probe. + self.infcx.commit_unconditionally(|_| { + let substs = self.rematch_impl(impl_def_id, obligation); + debug!("confirm_impl_candidate: substs={:?}", substs); + let cause = obligation.derived_cause(ImplDerivedObligation); + ensure_sufficient_stack(|| { + self.vtable_impl( + impl_def_id, + substs, + cause, + obligation.recursion_depth + 1, + obligation.param_env, + ) + }) + }) + } + + fn vtable_impl( + &mut self, + impl_def_id: DefId, + mut substs: Normalized<'tcx, SubstsRef<'tcx>>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + debug!( + "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", + impl_def_id, substs, recursion_depth, + ); + + let mut impl_obligations = self.impl_or_trait_obligations( + cause, + recursion_depth, + param_env, + impl_def_id, + &substs.value, + ); + + debug!( + "vtable_impl: impl_def_id={:?} impl_obligations={:?}", + impl_def_id, impl_obligations + ); + + // Because of RFC447, the impl-trait-ref and obligations + // are sufficient to determine the impl substs, without + // relying on projections in the impl-trait-ref. + // + // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` + impl_obligations.append(&mut substs.obligations); + + ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations } + } + + fn confirm_object_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> { + debug!("confirm_object_candidate({:?})", obligation); + + // FIXME(nmatsakis) skipping binder here seems wrong -- we should + // probably flatten the binder from the obligation and the binder + // from the object. Have to try to make a broken test case that + // results. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let poly_trait_ref = match self_ty.kind { + ty::Dynamic(ref data, ..) => data + .principal() + .unwrap_or_else(|| { + span_bug!(obligation.cause.span, "object candidate with no principal") + }) + .with_self_ty(self.tcx(), self_ty), + _ => span_bug!(obligation.cause.span, "object candidate with non-object"), + }; + + let mut upcast_trait_ref = None; + let mut nested = vec![]; + let vtable_base; + + { + let tcx = self.tcx(); + + // We want to find the first supertrait in the list of + // supertraits that we can unify with, and do that + // unification. We know that there is exactly one in the list + // where we can unify, because otherwise select would have + // reported an ambiguity. (When we do find a match, also + // record it for later.) + let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| { + match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) { + Ok(obligations) => { + upcast_trait_ref = Some(t); + nested.extend(obligations); + false + } + Err(_) => true, + } + }); + + // Additionally, for each of the non-matching predicates that + // we pass over, we sum up the set of number of vtable + // entries, so that we can compute the offset for the selected + // trait. + vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); + } + + ImplSourceObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } + } + + fn confirm_fn_pointer_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> + { + debug!("confirm_fn_pointer_candidate({:?})", obligation); + + // Okay to skip binder; it is reintroduced below. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let sig = self_ty.fn_sig(self.tcx()); + let trait_ref = closure_trait_ref_and_return_type( + self.tcx(), + obligation.predicate.def_id(), + self_ty, + sig, + util::TupleArgumentsFlag::Yes, + ) + .map_bound(|(trait_ref, _)| trait_ref); + + let Normalized { value: trait_ref, obligations } = ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ) + }); + + self.confirm_poly_trait_refs( + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref, + )?; + Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested: obligations }) + } + + fn confirm_trait_alias_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + alias_def_id: DefId, + ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> { + debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); + + self.infcx.commit_unconditionally(|_| { + let (predicate, _) = + self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + let trait_ref = predicate.trait_ref; + let trait_def_id = trait_ref.def_id; + let substs = trait_ref.substs; + + let trait_obligations = self.impl_or_trait_obligations( + obligation.cause.clone(), + obligation.recursion_depth, + obligation.param_env, + trait_def_id, + &substs, + ); + + debug!( + "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", + trait_def_id, trait_obligations + ); + + ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations } + }) + } + + fn confirm_generator_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result<ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> + { + // Okay to skip binder because the substs on generator types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let (generator_def_id, substs) = match self_ty.kind { + ty::Generator(id, substs, _) => (id, substs), + _ => bug!("closure candidate for non-closure {:?}", obligation), + }; + + debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); + + let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); + let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ) + }); + + debug!( + "confirm_generator_candidate(generator_def_id={:?}, \ + trait_ref={:?}, obligations={:?})", + generator_def_id, trait_ref, obligations + ); + + obligations.extend(self.confirm_poly_trait_refs( + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref, + )?); + + Ok(ImplSourceGeneratorData { generator_def_id, substs, nested: obligations }) + } + + fn confirm_closure_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { + debug!("confirm_closure_candidate({:?})", obligation); + + let kind = self + .tcx() + .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) + .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); + + // Okay to skip binder because the substs on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let (closure_def_id, substs) = match self_ty.kind { + ty::Closure(id, substs) => (id, substs), + _ => bug!("closure candidate for non-closure {:?}", obligation), + }; + + let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); + let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ) + }); + + debug!( + "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", + closure_def_id, trait_ref, obligations + ); + + obligations.extend(self.confirm_poly_trait_refs( + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref, + )?); + + // FIXME: Chalk + + if !self.tcx().sess.opts.debugging_opts.chalk { + obligations.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + ty::PredicateAtom::ClosureKind(closure_def_id, substs, kind) + .to_predicate(self.tcx()), + )); + } + + Ok(ImplSourceClosureData { closure_def_id, substs, nested: obligations }) + } + + /// In the case of closure types and fn pointers, + /// we currently treat the input type parameters on the trait as + /// outputs. This means that when we have a match we have only + /// considered the self type, so we have to go back and make sure + /// to relate the argument types too. This is kind of wrong, but + /// since we control the full set of impls, also not that wrong, + /// and it DOES yield better error messages (since we don't report + /// errors as if there is no applicable impl, but rather report + /// errors are about mismatched argument types. + /// + /// Here is an example. Imagine we have a closure expression + /// and we desugared it so that the type of the expression is + /// `Closure`, and `Closure` expects `i32` as argument. Then it + /// is "as if" the compiler generated this impl: + /// + /// impl Fn(i32) for Closure { ... } + /// + /// Now imagine our obligation is `Closure: Fn(usize)`. So far + /// we have matched the self type `Closure`. At this point we'll + /// compare the `i32` to `usize` and generate an error. + /// + /// Note that this checking occurs *after* the impl has selected, + /// because these output type parameters should not affect the + /// selection of the impl. Therefore, if there is a mismatch, we + /// report an error to the user. + fn confirm_poly_trait_refs( + &mut self, + obligation_cause: ObligationCause<'tcx>, + obligation_param_env: ty::ParamEnv<'tcx>, + obligation_trait_ref: ty::PolyTraitRef<'tcx>, + expected_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + self.infcx + .at(&obligation_cause, obligation_param_env) + .sup(obligation_trait_ref, expected_trait_ref) + .map(|InferOk { obligations, .. }| obligations) + .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } + + fn confirm_builtin_unsize_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + let tcx = self.tcx(); + + // `assemble_candidates_for_unsizing` should ensure there are no late-bound + // regions here. See the comment there for more details. + let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + let target = self.infcx.shallow_resolve(target); + + debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); + + let mut nested = vec![]; + match (&source.kind, &target.kind) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + // See `assemble_candidates_for_unsizing` for more info. + let existential_predicates = data_a.map_bound(|data_a| { + let iter = data_a + .principal() + .map(ty::ExistentialPredicate::Trait) + .into_iter() + .chain(data_a.projection_bounds().map(ty::ExistentialPredicate::Projection)) + .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); + tcx.mk_existential_predicates(iter) + }); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + + // Require that the traits involved in this upcast are **equal**; + // only the **lifetime bound** is changed. + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .sup(target, source_trait) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + + // Register one obligation for 'a: 'b. + let cause = ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target), + ); + let outlives = ty::OutlivesPredicate(r_a, r_b); + nested.push(Obligation::with_depth( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + ty::Binder::bind(outlives).to_predicate(tcx), + )); + } + + // `T` -> `Trait` + (_, &ty::Dynamic(ref data, r)) => { + let mut object_dids = data.auto_traits().chain(data.principal_def_id()); + if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { + return Err(TraitNotObjectSafe(did)); + } + + let cause = ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target), + ); + + let predicate_to_obligation = |predicate| { + Obligation::with_depth( + cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate, + ) + }; + + // Create obligations: + // - Casting `T` to `Trait` + // - For all the various builtin bounds attached to the object cast. (In other + // words, if the object type is `Foo + Send`, this would create an obligation for + // the `Send` check.) + // - Projection predicates + nested.extend( + data.iter().map(|predicate| { + predicate_to_obligation(predicate.with_self_ty(tcx, source)) + }), + ); + + // We can only make objects from sized types. + let tr = ty::TraitRef::new( + tcx.require_lang_item(LangItem::Sized, None), + tcx.mk_substs_trait(source, &[]), + ); + nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); + + // If the type is `Foo + 'a`, ensure that the type + // being cast to `Foo + 'a` outlives `'a`: + let outlives = ty::OutlivesPredicate(source, r); + nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate(tcx))); + } + + // `[T; n]` -> `[T]` + (&ty::Array(a, _), &ty::Slice(b)) => { + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(b, a) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + } + + // `Struct<T>` -> `Struct<U>` + (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { + let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { + GenericArgKind::Type(ty) => match ty.kind { + ty::Param(p) => Some(p.index), + _ => None, + }, + + // Lifetimes aren't allowed to change during unsizing. + GenericArgKind::Lifetime(_) => None, + + GenericArgKind::Const(ct) => match ct.val { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, + }; + + // The last field of the structure has to exist and contain type/const parameters. + let (tail_field, prefix_fields) = + def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; + let tail_field_ty = tcx.type_of(tail_field.did); + + let mut unsizing_params = GrowableBitSet::new_empty(); + let mut found = false; + for arg in tail_field_ty.walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); + found = true; + } + } + if !found { + return Err(Unimplemented); + } + + // Ensure none of the other fields mention the parameters used + // in unsizing. + // FIXME(eddyb) cache this (including computing `unsizing_params`) + // by putting it in a query; it would only need the `DefId` as it + // looks at declared field types, not anything substituted. + for field in prefix_fields { + for arg in tcx.type_of(field.did).walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + if unsizing_params.contains(i) { + return Err(Unimplemented); + } + } + } + } + + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`. + let source_tail = tail_field_ty.subst(tcx, substs_a); + let target_tail = tail_field_ty.subst(tcx, substs_b); + + // Check that the source struct with the target's + // unsizing parameters is equal to the target. + let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, k)| { + if unsizing_params.contains(i as u32) { substs_b[i] } else { k } + })); + let new_struct = tcx.mk_adt(def, substs); + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, new_struct) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + + // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. + nested.push(predicate_for_trait_def( + tcx, + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + source_tail, + &[target_tail.into()], + )); + } + + // `(.., T)` -> `(.., U)` + (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { + assert_eq!(tys_a.len(), tys_b.len()); + + // The last field of the tuple has to exist. + let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?; + let &b_last = tys_b.last().unwrap(); + + // Check that the source tuple with the target's + // last element is equal to the target. + let new_tuple = tcx.mk_tup( + a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())), + ); + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, new_tuple) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + + // Construct the nested `T: Unsize<U>` predicate. + nested.push(ensure_sufficient_stack(|| { + predicate_for_trait_def( + tcx, + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + a_last.expect_ty(), + &[b_last], + ) + })); + } + + _ => bug!(), + }; + + Ok(ImplSourceBuiltinData { nested }) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs new file mode 100644 index 00000000000..82f476b463d --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -0,0 +1,2436 @@ +//! Candidate selection. 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#selection + +use self::EvaluationResult::*; +use self::SelectionCandidate::*; + +use super::coherence::{self, Conflict}; +use super::project; +use super::project::normalize_with_depth_to; +use super::util; +use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::wf; +use super::DerivedObligationCause; +use super::Obligation; +use super::ObligationCauseCode; +use super::Selection; +use super::SelectionResult; +use super::TraitQueryMode; +use super::{Normalized, ProjectionCacheKey}; +use super::{ObligationCause, PredicateObligation, TraitObligation}; +use super::{Overflow, SelectionError, Unimplemented}; + +use crate::infer::{InferCtxt, InferOk, TypeFreshener}; +use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::ProjectionCacheKeyExt; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::ErrorReported; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::fast_reject; +use rustc_middle::ty::relate::TypeRelation; +use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; +use rustc_middle::ty::{ + self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; +use rustc_span::symbol::sym; + +use std::cell::{Cell, RefCell}; +use std::cmp; +use std::fmt::{self, Display}; +use std::iter; +use std::rc::Rc; + +pub use rustc_middle::traits::select::*; + +mod candidate_assembly; +mod confirmation; + +#[derive(Clone, Debug)] +pub enum IntercrateAmbiguityCause { + DownstreamCrate { trait_desc: String, self_desc: Option<String> }, + UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> }, + 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(), + } + } +} + +pub struct SelectionContext<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + + /// Freshener used specifically for entries on the obligation + /// stack. This ensures that all entries on the stack at one time + /// will have the same set of placeholder entries, which is + /// important for checking for trait bounds that recursively + /// require themselves. + freshener: TypeFreshener<'cx, 'tcx>, + + /// If `true`, indicates that the evaluation should be conservative + /// and consider the possibility of types outside this crate. + /// This comes up primarily when resolving ambiguity. Imagine + /// there is some trait reference `$0: Bar` where `$0` is an + /// inference variable. If `intercrate` is true, then we can never + /// say for sure that this reference is not implemented, even if + /// there are *no impls at all for `Bar`*, because `$0` could be + /// bound to some type that in a downstream crate that implements + /// `Bar`. This is the suitable mode for coherence. Elsewhere, + /// though, we set this to false, because we are only interested + /// in types that the user could actually have written --- in + /// other words, we consider `$0: Bar` to be unimplemented if + /// there is no type that the user could *actually name* that + /// would satisfy it. This avoids crippling inference, basically. + intercrate: bool, + + intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>, + + /// Controls whether or not to filter out negative impls when selecting. + /// This is used in librustdoc to distinguish between the lack of an impl + /// and a negative impl + allow_negative_impls: bool, + + /// The mode that trait queries run in, which informs our error handling + /// policy. In essence, canonicalized queries need their errors propagated + /// rather than immediately reported because we do not have accurate spans. + query_mode: TraitQueryMode, +} + +// A stack that walks back up the stack frame. +struct TraitObligationStack<'prev, 'tcx> { + obligation: &'prev TraitObligation<'tcx>, + + /// The trait ref from `obligation` but "freshened" with the + /// selection-context's freshener. Used to check for recursion. + fresh_trait_ref: ty::PolyTraitRef<'tcx>, + + /// Starts out equal to `depth` -- if, during evaluation, we + /// encounter a cycle, then we will set this flag to the minimum + /// depth of that cycle for all participants in the cycle. These + /// participants will then forego caching their results. This is + /// not the most efficient solution, but it addresses #60010. The + /// problem we are trying to prevent: + /// + /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait` + /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok) + /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok) + /// + /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` + /// is `EvaluatedToOk`; this is because they were only considered + /// ok on the premise that if `A: AutoTrait` held, but we indeed + /// encountered a problem (later on) with `A: AutoTrait. So we + /// currently set a flag on the stack node for `B: AutoTrait` (as + /// well as the second instance of `A: AutoTrait`) to suppress + /// caching. + /// + /// This is a simple, targeted fix. A more-performant fix requires + /// deeper changes, but would permit more caching: we could + /// basically defer caching until we have fully evaluated the + /// tree, and then cache the entire tree at once. In any case, the + /// performance impact here shouldn't be so horrible: every time + /// this is hit, we do cache at least one trait, so we only + /// evaluate each member of a cycle up to N times, where N is the + /// length of the cycle. This means the performance impact is + /// bounded and we shouldn't have any terrible worst-cases. + reached_depth: Cell<usize>, + + previous: TraitObligationStackList<'prev, 'tcx>, + + /// The number of parent frames plus one (thus, the topmost frame has depth 1). + depth: usize, + + /// The depth-first number of this node in the search graph -- a + /// pre-order index. Basically, a freshly incremented counter. + dfn: usize, +} + +struct SelectionCandidateSet<'tcx> { + // A list of candidates that definitely apply to the current + // obligation (meaning: types unify). + vec: Vec<SelectionCandidate<'tcx>>, + + // If `true`, then there were candidates that might or might + // not have applied, but we couldn't tell. This occurs when some + // of the input types are type variables, in which case there are + // various "builtin" rules that might or might not trigger. + ambiguous: bool, +} + +#[derive(PartialEq, Eq, Debug, Clone)] +struct EvaluatedCandidate<'tcx> { + candidate: SelectionCandidate<'tcx>, + evaluation: EvaluationResult, +} + +/// When does the builtin impl for `T: Trait` apply? +enum BuiltinImplConditions<'tcx> { + /// The impl is conditional on `T1, T2, ...: Trait`. + Where(ty::Binder<Vec<Ty<'tcx>>>), + /// There is no built-in impl. There may be some other + /// candidate (a where-clause or user-defined impl). + None, + /// It is unknown whether there is an impl. + Ambiguous, +} + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: false, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: true, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_negative( + infcx: &'cx InferCtxt<'cx, 'tcx>, + allow_negative_impls: bool, + ) -> SelectionContext<'cx, 'tcx> { + debug!("with_negative({:?})", allow_negative_impls); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: false, + intercrate_ambiguity_causes: None, + allow_negative_impls, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_query_mode( + infcx: &'cx InferCtxt<'cx, 'tcx>, + query_mode: TraitQueryMode, + ) -> SelectionContext<'cx, 'tcx> { + debug!("with_query_mode({:?})", query_mode); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: false, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode, + } + } + + /// Enables tracking of intercrate ambiguity causes. These are + /// used in coherence to give improved diagnostics. We don't do + /// this until we detect a coherence error because it can lead to + /// false overflow results (#47139) and because it costs + /// computation time. + pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { + assert!(self.intercrate); + assert!(self.intercrate_ambiguity_causes.is_none()); + self.intercrate_ambiguity_causes = Some(vec![]); + debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); + } + + /// Gets the intercrate ambiguity causes collected since tracking + /// was enabled and disables tracking at the same time. If + /// tracking is not enabled, just returns an empty vector. + pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> { + assert!(self.intercrate); + self.intercrate_ambiguity_causes.take().unwrap_or(vec![]) + } + + pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + pub fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + /////////////////////////////////////////////////////////////////////////// + // Selection + // + // The selection phase tries to identify *how* an obligation will + // be resolved. For example, it will identify which impl or + // parameter bound is to be used. The process can be inconclusive + // if the self type in the obligation is not fully inferred. Selection + // can result in an error in one of two ways: + // + // 1. If no applicable impl or parameter bound can be found. + // 2. If the output type parameters in the obligation do not match + // those specified by the impl/bound. For example, if the obligation + // is `Vec<Foo>: Iterable<Bar>`, but the impl specifies + // `impl<T> Iterable<T> for Vec<T>`, than an error would result. + + /// Attempts to satisfy the obligation. If successful, this will affect the surrounding + /// type environment by performing unification. + pub fn select( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, Selection<'tcx>> { + debug!("select({:?})", obligation); + debug_assert!(!obligation.predicate.has_escaping_bound_vars()); + + let pec = &ProvisionalEvaluationCache::default(); + let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation); + + let candidate = match self.candidate_from_obligation(&stack) { + Err(SelectionError::Overflow) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow); + } + Err(e) => { + return Err(e); + } + Ok(None) => { + return Ok(None); + } + Ok(Some(candidate)) => candidate, + }; + + match self.confirm_candidate(obligation, candidate) { + Err(SelectionError::Overflow) => { + assert!(self.query_mode == TraitQueryMode::Canonical); + Err(SelectionError::Overflow) + } + Err(e) => Err(e), + Ok(candidate) => Ok(Some(candidate)), + } + } + + /////////////////////////////////////////////////////////////////////////// + // EVALUATION + // + // Tests whether an obligation can be selected or whether an impl + // can be applied to particular types. It skips the "confirmation" + // step and hence completely ignores output type parameters. + // + // The result is "true" if the obligation *may* hold and "false" if + // we can be sure it does not. + + /// Evaluates whether the obligation `obligation` can be satisfied (by any means). + pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { + debug!("predicate_may_hold_fatal({:?})", obligation); + + // This fatal query is a stopgap that should only be used in standard mode, + // where we do not expect overflow to be propagated. + assert!(self.query_mode == TraitQueryMode::Standard); + + self.evaluate_root_obligation(obligation) + .expect("Overflow should be caught earlier in standard query mode") + .may_apply() + } + + /// Evaluates whether the obligation `obligation` can be satisfied + /// and returns an `EvaluationResult`. This is meant for the + /// *initial* call. + pub fn evaluate_root_obligation( + &mut self, + obligation: &PredicateObligation<'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + self.evaluation_probe(|this| { + this.evaluate_predicate_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + obligation.clone(), + ) + }) + } + + fn evaluation_probe( + &mut self, + op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>, + ) -> Result<EvaluationResult, OverflowError> { + self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> { + let result = op(self)?; + + match self.infcx.leak_check(true, snapshot) { + Ok(()) => {} + Err(_) => return Ok(EvaluatedToErr), + } + + match self.infcx.region_constraints_added_in_snapshot(snapshot) { + None => Ok(result), + Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), + } + }) + } + + /// Evaluates the predicates in `predicates` recursively. Note that + /// this applies projections in the predicates, and therefore + /// is run within an inference probe. + fn evaluate_predicates_recursively<'o, I>( + &mut self, + stack: TraitObligationStackList<'o, 'tcx>, + predicates: I, + ) -> Result<EvaluationResult, OverflowError> + where + I: IntoIterator<Item = PredicateObligation<'tcx>>, + { + let mut result = EvaluatedToOk; + for obligation in predicates { + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); + if let EvaluatedToErr = eval { + // fast-path - EvaluatedToErr is the top of the lattice, + // so we don't need to look on the other predicates. + return Ok(EvaluatedToErr); + } else { + result = cmp::max(result, eval); + } + } + Ok(result) + } + + fn evaluate_predicate_recursively<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + debug!( + "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})", + previous_stack.head(), + obligation + ); + + // `previous_stack` stores a `TraitObligation`, while `obligation` is + // a `PredicateObligation`. These are distinct types, so we can't + // use any `Option` combinator method that would force them to be + // the same. + match previous_stack.head() { + Some(h) => self.check_recursion_limit(&obligation, h.obligation)?, + None => self.check_recursion_limit(&obligation, &obligation)?, + } + + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(t, _) => { + let t = ty::Binder::bind(t); + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(t); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } + + ty::PredicateAtom::Subtype(p) => { + let p = ty::Binder::bind(p); + // Does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { + Some(Ok(InferOk { mut obligations, .. })) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively( + previous_stack, + obligations.into_iter(), + ) + } + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), + } + } + + ty::PredicateAtom::WellFormed(arg) => match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + arg, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + } + None => Ok(EvaluatedToAmbig), + }, + + ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) + } + + ty::PredicateAtom::ObjectSafe(trait_def_id) => { + if self.tcx().is_object_safe(trait_def_id) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } + } + + ty::PredicateAtom::Projection(data) => { + let data = ty::Binder::bind(data); + let project_obligation = obligation.with(data); + match project::poly_project_and_unify_type(self, &project_obligation) { + Ok(Ok(Some(mut subobligations))) => { + self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); + let result = self.evaluate_predicates_recursively( + previous_stack, + subobligations.into_iter(), + ); + if let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate(self, data) + { + self.infcx.inner.borrow_mut().projection_cache().complete(key); + } + result + } + Ok(Ok(None)) => Ok(EvaluatedToAmbig), + // EvaluatedToRecur might also be acceptable here, but use + // Unknown for now because it means that we won't dismiss a + // selection candidate solely because it has a projection + // cycle. This is closest to the previous behavior of + // immediately erroring. + Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), + Err(_) => Ok(EvaluatedToErr), + } + } + + ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { + match self.infcx.closure_kind(closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } + } + None => Ok(EvaluatedToAmbig), + } + } + + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { + match self.tcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + None, + None, + ) { + Ok(_) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), + } + } + + ty::PredicateAtom::ConstEquate(c1, c2) => { + debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); + + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { + self.infcx + .const_eval_resolve( + obligation.param_env, + def, + substs, + promoted, + Some(obligation.cause.span), + ) + .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( + obligation.cause.span(self.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ), + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + Ok(EvaluatedToAmbig) + } + } + } + } + } + + fn evaluate_trait_predicate_recursively<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + mut obligation: TraitObligation<'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + debug!("evaluate_trait_predicate_recursively({:?})", obligation); + + if !self.intercrate + && obligation.is_global() + && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) + { + // If a param env has no global bounds, global obligations do not + // depend on its particular value in order to work, so we can clear + // out the param env and get better caching. + debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); + obligation.param_env = obligation.param_env.without_caller_bounds(); + } + + let stack = self.push_stack(previous_stack, &obligation); + let fresh_trait_ref = stack.fresh_trait_ref; + if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { + debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + return Ok(result); + } + + if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { + debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + stack.update_reached_depth(stack.cache().current_reached_depth()); + return Ok(result); + } + + // Check if this is a match for something already on the + // stack. If so, we don't want to insert the result into the + // main cache (it is cycle dependent) nor the provisional + // cache (which is meant for things that have completed but + // for a "backedge" -- this result *is* the backedge). + if let Some(cycle_result) = self.check_evaluation_cycle(&stack) { + return Ok(cycle_result); + } + + let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let result = result?; + + if !result.must_apply_modulo_regions() { + stack.cache().on_failure(stack.dfn); + } + + let reached_depth = stack.reached_depth.get(); + if reached_depth >= stack.depth { + debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); + self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); + + stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| { + self.insert_evaluation_cache( + obligation.param_env, + fresh_trait_ref, + dep_node, + provisional_result.max(result), + ); + }); + } else { + debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result); + debug!( + "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ + is a cycle participant (at depth {}, reached depth {})", + fresh_trait_ref, stack.depth, reached_depth, + ); + + stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result); + } + + Ok(result) + } + + /// If there is any previous entry on the stack that precisely + /// matches this obligation, then we can assume that the + /// obligation is satisfied for now (still all other conditions + /// must be met of course). One obvious case this comes up is + /// marker traits like `Send`. Think of a linked list: + /// + /// struct List<T> { data: T, next: Option<Box<List<T>>> } + /// + /// `Box<List<T>>` will be `Send` if `T` is `Send` and + /// `Option<Box<List<T>>>` is `Send`, and in turn + /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is + /// `Send`. + /// + /// Note that we do this comparison using the `fresh_trait_ref` + /// fields. Because these have all been freshened using + /// `self.freshener`, we can be sure that (a) this will not + /// affect the inferencer state and (b) that if we see two + /// fresh regions with the same index, they refer to the same + /// unbound type variable. + fn check_evaluation_cycle( + &mut self, + stack: &TraitObligationStack<'_, 'tcx>, + ) -> Option<EvaluationResult> { + if let Some(cycle_depth) = stack + .iter() + .skip(1) // Skip top-most frame. + .find(|prev| { + stack.obligation.param_env == prev.obligation.param_env + && stack.fresh_trait_ref == prev.fresh_trait_ref + }) + .map(|stack| stack.depth) + { + debug!( + "evaluate_stack({:?}) --> recursive at depth {}", + stack.fresh_trait_ref, cycle_depth, + ); + + // If we have a stack like `A B C D E A`, where the top of + // the stack is the final `A`, then this will iterate over + // `A, E, D, C, B` -- i.e., all the participants apart + // from the cycle head. We mark them as participating in a + // cycle. This suppresses caching for those nodes. See + // `in_cycle` field for more details. + stack.update_reached_depth(cycle_depth); + + // Subtle: when checking for a coinductive cycle, we do + // not compare using the "freshened trait refs" (which + // have erased regions) but rather the fully explicit + // trait refs. This is important because it's only a cycle + // if the regions match exactly. + let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); + let tcx = self.tcx(); + let cycle = + cycle.map(|stack| stack.obligation.predicate.without_const().to_predicate(tcx)); + if self.coinductive_match(cycle) { + debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); + Some(EvaluatedToOk) + } else { + debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); + Some(EvaluatedToRecur) + } + } else { + None + } + } + + fn evaluate_stack<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + // In intercrate mode, whenever any of the generics are unbound, + // there can always be an impl. Even if there are no impls in + // this crate, perhaps the type would be unified with + // something from another crate that does provide an impl. + // + // In intra mode, we must still be conservative. The reason is + // that we want to avoid cycles. Imagine an impl like: + // + // impl<T:Eq> Eq for Vec<T> + // + // and a trait reference like `$0 : Eq` where `$0` is an + // unbound variable. When we evaluate this trait-reference, we + // will unify `$0` with `Vec<$1>` (for some fresh variable + // `$1`), on the condition that `$1 : Eq`. We will then wind + // up with many candidates (since that are other `Eq` impls + // that apply) and try to winnow things down. This results in + // a recursive evaluation that `$1 : Eq` -- as you can + // imagine, this is just where we started. To avoid that, we + // check for unbound variables and return an ambiguous (hence possible) + // match if we've seen this trait before. + // + // This suffices to allow chains like `FnMut` implemented in + // terms of `Fn` etc, but we could probably make this more + // precise still. + let unbound_input_types = + stack.fresh_trait_ref.skip_binder().substs.types().any(|ty| ty.is_fresh()); + // This check was an imperfect workaround for a bug in the old + // intercrate mode; it should be removed when that goes away. + if unbound_input_types && self.intercrate { + debug!( + "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", + stack.fresh_trait_ref + ); + // Heuristics: show the diagnostics when there are no candidates in crate. + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + if let Ok(candidate_set) = self.assemble_candidates(stack) { + if !candidate_set.ambiguous && candidate_set.vec.is_empty() { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let cause = IntercrateAmbiguityCause::DownstreamCrate { + trait_desc: trait_ref.print_only_trait_path().to_string(), + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } + } + } + return Ok(EvaluatedToAmbig); + } + if unbound_input_types + && stack.iter().skip(1).any(|prev| { + stack.obligation.param_env == prev.obligation.param_env + && self.match_fresh_trait_refs( + stack.fresh_trait_ref, + prev.fresh_trait_ref, + prev.obligation.param_env, + ) + }) + { + debug!( + "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", + stack.fresh_trait_ref + ); + return Ok(EvaluatedToUnknown); + } + + match self.candidate_from_obligation(stack) { + Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Ok(None) => Ok(EvaluatedToAmbig), + Err(Overflow) => Err(OverflowError), + Err(..) => Ok(EvaluatedToErr), + } + } + + /// For defaulted traits, we use a co-inductive strategy to solve, so + /// that recursion is ok. This routine returns `true` if the top of the + /// stack (`cycle[0]`): + /// + /// - is a defaulted trait, + /// - it also appears in the backtrace at some position `X`, + /// - all the predicates at positions `X..` between `X` and the top are + /// also defaulted traits. + pub fn coinductive_match<I>(&mut self, cycle: I) -> bool + where + I: Iterator<Item = ty::Predicate<'tcx>>, + { + let mut cycle = cycle; + cycle.all(|predicate| self.coinductive_predicate(predicate)) + } + + fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { + let result = match predicate.skip_binders() { + ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), + _ => false, + }; + debug!("coinductive_predicate({:?}) = {:?}", predicate, result); + result + } + + /// Further evaluates `candidate` to decide whether all type parameters match and whether nested + /// obligations are met. Returns whether `candidate` remains viable after this further + /// scrutiny. + fn evaluate_candidate<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidate: &SelectionCandidate<'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + debug!( + "evaluate_candidate: depth={} candidate={:?}", + stack.obligation.recursion_depth, candidate + ); + let result = self.evaluation_probe(|this| { + let candidate = (*candidate).clone(); + match this.confirm_candidate(stack.obligation, candidate) { + Ok(selection) => this.evaluate_predicates_recursively( + stack.list(), + selection.nested_obligations().into_iter(), + ), + Err(..) => Ok(EvaluatedToErr), + } + })?; + debug!( + "evaluate_candidate: depth={} result={:?}", + stack.obligation.recursion_depth, result + ); + Ok(result) + } + + fn check_evaluation_cache( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Option<EvaluationResult> { + let tcx = self.tcx(); + if self.can_use_global_caches(param_env) { + if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) { + return Some(res); + } + } + self.infcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) + } + + fn insert_evaluation_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + dep_node: DepNodeIndex, + result: EvaluationResult, + ) { + // Avoid caching results that depend on more than just the trait-ref + // - the stack can create recursion. + if result.is_stack_dependent() { + return; + } + + if self.can_use_global_caches(param_env) { + if !trait_ref.needs_infer() { + debug!( + "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", + trait_ref, result, + ); + // This may overwrite the cache with the same value + // FIXME: Due to #50507 this overwrites the different values + // This should be changed to use HashMapExt::insert_same + // when that is fixed + self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result); + return; + } + } + + debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); + self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result); + } + + /// For various reasons, it's possible for a subobligation + /// to have a *lower* recursion_depth than the obligation used to create it. + /// Projection sub-obligations may be returned from the projection cache, + /// which results in obligations with an 'old' `recursion_depth`. + /// Additionally, methods like `wf::obligations` and + /// `InferCtxt.subtype_predicate` produce subobligations without + /// taking in a 'parent' depth, causing the generated subobligations + /// to have a `recursion_depth` of `0`. + /// + /// To ensure that obligation_depth never decreasees, we force all subobligations + /// to have at least the depth of the original obligation. + fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>( + &self, + it: I, + min_depth: usize, + ) { + it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); + } + + /// Checks that the recursion limit has not been exceeded. + /// + /// The weird return type of this function allows it to be used with the `try` (`?`) + /// operator within certain functions. + fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>( + &self, + obligation: &Obligation<'tcx, T>, + error_obligation: &Obligation<'tcx, V>, + ) -> Result<(), OverflowError> { + if !self.infcx.tcx.sess.recursion_limit().value_within_limit(obligation.recursion_depth) { + match self.query_mode { + TraitQueryMode::Standard => { + self.infcx().report_overflow_error(error_obligation, true); + } + TraitQueryMode::Canonical => { + return Err(OverflowError); + } + } + } + Ok(()) + } + + fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex) + where + OP: FnOnce(&mut Self) -> R, + { + let (result, dep_node) = + self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.read_index(dep_node); + (result, dep_node) + } + + // Treat negative impls as unimplemented, and reservation impls as ambiguity. + fn filter_negative_and_reservation_impls( + &mut self, + candidate: SelectionCandidate<'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let ImplCandidate(def_id) = candidate { + let tcx = self.tcx(); + match tcx.impl_polarity(def_id) { + ty::ImplPolarity::Negative if !self.allow_negative_impls => { + return Err(Unimplemented); + } + ty::ImplPolarity::Reservation => { + if let Some(intercrate_ambiguity_clauses) = + &mut self.intercrate_ambiguity_causes + { + let attrs = tcx.get_attrs(def_id); + let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl); + let value = attr.and_then(|a| a.value_str()); + if let Some(value) = value { + debug!( + "filter_negative_and_reservation_impls: \ + reservation impl ambiguity on {:?}", + def_id + ); + intercrate_ambiguity_clauses.push( + IntercrateAmbiguityCause::ReservationImpl { + message: value.to_string(), + }, + ); + } + } + return Ok(None); + } + _ => {} + }; + } + Ok(Some(candidate)) + } + + fn candidate_from_obligation_no_cache<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let Some(conflict) = self.is_knowable(stack) { + debug!("coherence stage: not knowable"); + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + // Heuristics: show the diagnostics when there are no candidates in crate. + if let Ok(candidate_set) = self.assemble_candidates(stack) { + let mut no_candidates_apply = true; + + for c in candidate_set.vec.iter() { + if self.evaluate_candidate(stack, &c)?.may_apply() { + no_candidates_apply = false; + break; + } + } + + if !candidate_set.ambiguous && no_candidates_apply { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let trait_desc = trait_ref.print_only_trait_path().to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } + } + } + return Ok(None); + } + + let candidate_set = self.assemble_candidates(stack)?; + + if candidate_set.ambiguous { + debug!("candidate set contains ambig"); + return Ok(None); + } + + let mut candidates = candidate_set.vec; + + debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + // At this point, we know that each of the entries in the + // candidate set is *individually* applicable. Now we have to + // figure out if they contain mutual incompatibilities. This + // frequently arises if we have an unconstrained input type -- + // for example, we are looking for `$0: Eq` where `$0` is some + // unconstrained type variable. In that case, we'll get a + // candidate which assumes $0 == int, one that assumes `$0 == + // usize`, etc. This spells an ambiguity. + + // If there is more than one candidate, first winnow them down + // by considering extra conditions (nested obligations and so + // forth). We don't winnow if there is exactly one + // candidate. This is a relatively minor distinction but it + // can lead to better inference and error-reporting. An + // example would be if there was an impl: + // + // impl<T:Clone> Vec<T> { fn push_clone(...) { ... } } + // + // and we were to see some code `foo.push_clone()` where `boo` + // is a `Vec<Bar>` and `Bar` does not implement `Clone`. If + // we were to winnow, we'd wind up with zero candidates. + // Instead, we select the right impl now but report "`Bar` does + // not implement `Clone`". + if candidates.len() == 1 { + return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); + } + + // Winnow, but record the exact outcome of evaluation, which + // is needed for specialization. Propagate overflow if it occurs. + let mut candidates = candidates + .into_iter() + .map(|c| match self.evaluate_candidate(stack, &c) { + Ok(eval) if eval.may_apply() => { + Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) + } + Ok(_) => Ok(None), + Err(OverflowError) => Err(Overflow), + }) + .flat_map(Result::transpose) + .collect::<Result<Vec<_>, _>>()?; + + debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + let needs_infer = stack.obligation.predicate.needs_infer(); + + // If there are STILL multiple candidates, we can further + // reduce the list by dropping duplicates -- including + // resolving specializations. + if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { + self.candidate_should_be_dropped_in_favor_of( + &candidates[i], + &candidates[j], + needs_infer, + ) + }); + if is_dup { + debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + candidates.swap_remove(i); + } else { + debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } + } + } + } + + // If there are *NO* candidates, then there are no impls -- + // that we know of, anyway. Note that in the case where there + // are unbound type variables within the obligation, it might + // be the case that you could still satisfy the obligation + // from another crate by instantiating the type variables with + // a type from another crate that does have an impl. This case + // is checked for in `evaluate_stack` (and hence users + // who might care about this case, like coherence, should use + // that function). + if candidates.is_empty() { + // If there's an error type, 'downgrade' our result from + // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid + // emitting additional spurious errors, since we're guaranteed + // to have emitted at least one. + if stack.obligation.references_error() { + debug!("no results for error type, treating as ambiguous"); + return Ok(None); + } + return Err(Unimplemented); + } + + // Just one candidate left. + self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) + } + + fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> { + debug!("is_knowable(intercrate={:?})", self.intercrate); + + if !self.intercrate { + return None; + } + + let obligation = &stack.obligation; + let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + + // Okay to skip binder because of the nature of the + // trait-ref-is-knowable check, which does not care about + // bound regions. + let trait_ref = predicate.skip_binder().trait_ref; + + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + } + + /// Returns `true` if the global caches can be used. + /// Do note that if the type itself is not in the + /// global tcx, the local caches will be used. + fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { + // If there are any inference variables in the `ParamEnv`, then we + // always use a cache local to this particular scope. Otherwise, we + // switch to a global cache. + if param_env.needs_infer() { + return false; + } + + // Avoid using the master cache during coherence and just rely + // on the local cache. This effectively disables caching + // during coherence. It is really just a simplification to + // avoid us having to fear that coherence results "pollute" + // the master cache. Since coherence executes pretty quickly, + // it's not worth going to more trouble to increase the + // hit-rate, I don't think. + if self.intercrate { + return false; + } + + // Otherwise, we can use the global cache. + true + } + + fn check_candidate_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { + let tcx = self.tcx(); + let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; + if self.can_use_global_caches(param_env) { + if let Some(res) = tcx.selection_cache.get(¶m_env.and(*trait_ref), tcx) { + return Some(res); + } + } + self.infcx.selection_cache.get(¶m_env.and(*trait_ref), tcx) + } + + /// Determines whether can we safely cache the result + /// of selecting an obligation. This is almost always `true`, + /// except when dealing with certain `ParamCandidate`s. + /// + /// Ordinarily, a `ParamCandidate` will contain no inference variables, + /// since it was usually produced directly from a `DefId`. However, + /// certain cases (currently only librustdoc's blanket impl finder), + /// a `ParamEnv` may be explicitly constructed with inference types. + /// When this is the case, we do *not* want to cache the resulting selection + /// candidate. This is due to the fact that it might not always be possible + /// to equate the obligation's trait ref and the candidate's trait ref, + /// if more constraints end up getting added to an inference variable. + /// + /// Because of this, we always want to re-run the full selection + /// process for our obligation the next time we see it, since + /// we might end up picking a different `SelectionCandidate` (or none at all). + fn can_cache_candidate( + &self, + result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, + ) -> bool { + match result { + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), + _ => true, + } + } + + fn insert_candidate_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + dep_node: DepNodeIndex, + candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, + ) { + let tcx = self.tcx(); + let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; + + if !self.can_cache_candidate(&candidate) { + debug!( + "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ + candidate is not cacheable", + trait_ref, candidate + ); + return; + } + + if self.can_use_global_caches(param_env) { + if let Err(Overflow) = candidate { + // Don't cache overflow globally; we only produce this in certain modes. + } else if !trait_ref.needs_infer() { + if !candidate.needs_infer() { + debug!( + "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", + trait_ref, candidate, + ); + // This may overwrite the cache with the same value. + tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate); + return; + } + } + } + + debug!( + "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", + trait_ref, candidate, + ); + self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate); + } + + fn match_projection_obligation_against_definition_bounds( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> bool { + let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let (placeholder_trait_predicate, _) = + self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); + debug!( + "match_projection_obligation_against_definition_bounds: \ + placeholder_trait_predicate={:?}", + placeholder_trait_predicate, + ); + + let tcx = self.infcx.tcx; + let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), + _ => { + span_bug!( + obligation.cause.span, + "match_projection_obligation_against_definition_bounds() called \ + but self-ty is not a projection: {:?}", + placeholder_trait_predicate.trait_ref.self_ty() + ); + } + }; + + let matching_bound = predicates.iter().find_map(|bound| { + if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() { + let bound = ty::Binder::bind(pred.trait_ref); + if self.infcx.probe(|_| { + self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref) + }) { + return Some(bound); + } + } + None + }); + + debug!( + "match_projection_obligation_against_definition_bounds: \ + matching_bound={:?}", + matching_bound + ); + match matching_bound { + None => false, + Some(bound) => { + // Repeat the successful match, if any, this time outside of a probe. + let result = + self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref); + + assert!(result); + true + } + } + } + + fn match_projection( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_bound: ty::PolyTraitRef<'tcx>, + placeholder_trait_ref: ty::TraitRef<'tcx>, + ) -> bool { + debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) + .is_ok() + } + + fn evaluate_where_clause<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result<EvaluationResult, OverflowError> { + self.evaluation_probe(|this| { + match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + Ok(obligations) => { + this.evaluate_predicates_recursively(stack.list(), obligations.into_iter()) + } + Err(()) => Ok(EvaluatedToErr), + } + }) + } + + /////////////////////////////////////////////////////////////////////////// + // WINNOW + // + // Winnowing is the process of attempting to resolve ambiguity by + // probing further. During the winnowing process, we unify all + // type variables and then we also attempt to evaluate recursive + // bounds to see if they are satisfied. + + /// Returns `true` if `victim` should be dropped in favor of + /// `other`. Generally speaking we will drop duplicate + /// candidates and prefer where-clause candidates. + /// + /// See the comment for "SelectionCandidate" for more details. + fn candidate_should_be_dropped_in_favor_of( + &mut self, + victim: &EvaluatedCandidate<'tcx>, + other: &EvaluatedCandidate<'tcx>, + needs_infer: bool, + ) -> bool { + if victim.candidate == other.candidate { + return true; + } + + // Check if a bound would previously have been removed when normalizing + // the param_env so that it can be given the lowest priority. See + // #50825 for the motivation for this. + let is_global = + |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); + + // (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate` + // to anything else. + // + // This is a fix for #53123 and prevents winnowing from accidentally extending the + // lifetime of a variable. + match other.candidate { + // (*) + BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true, + ParamCandidate(ref cand) => match victim.candidate { + AutoImplCandidate(..) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates" + ); + } + // (*) + BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false, + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) => { + // Global bounds from the where clause should be ignored + // here (see issue #50825). Otherwise, we have a where + // clause so don't go around looking for impls. + !is_global(cand) + } + ObjectCandidate | ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + !is_global(cand) + } + ParamCandidate(..) => false, + }, + ObjectCandidate | ProjectionCandidate => match victim.candidate { + AutoImplCandidate(..) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates" + ); + } + // (*) + BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false, + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) => true, + ObjectCandidate | ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + true + } + ParamCandidate(ref cand) => is_global(cand), + }, + ImplCandidate(other_def) => { + // See if we can toss out `victim` based on specialization. + // This requires us to know *for sure* that the `other` impl applies + // i.e., `EvaluatedToOk`. + if other.evaluation.must_apply_modulo_regions() { + match victim.candidate { + ImplCandidate(victim_def) => { + let tcx = self.tcx(); + if tcx.specializes((other_def, victim_def)) { + return true; + } + return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { + Some(ty::ImplOverlapKind::Permitted { marker: true }) => { + // Subtle: If the predicate we are evaluating has inference + // variables, do *not* allow discarding candidates due to + // marker trait impls. + // + // Without this restriction, we could end up accidentally + // constrainting inference variables based on an arbitrarily + // chosen trait impl. + // + // Imagine we have the following code: + // + // ```rust + // #[marker] trait MyTrait {} + // impl MyTrait for u8 {} + // impl MyTrait for bool {} + // ``` + // + // And we are evaluating the predicate `<_#0t as MyTrait>`. + // + // During selection, we will end up with one candidate for each + // impl of `MyTrait`. If we were to discard one impl in favor + // of the other, we would be left with one candidate, causing + // us to "successfully" select the predicate, unifying + // _#0t with (for example) `u8`. + // + // However, we have no reason to believe that this unification + // is correct - we've essentially just picked an arbitrary + // *possibility* for _#0t, and required that this be the *only* + // possibility. + // + // Eventually, we will either: + // 1) Unify all inference variables in the predicate through + // some other means (e.g. type-checking of a function). We will + // then be in a position to drop marker trait candidates + // without constraining inference variables (since there are + // none left to constrin) + // 2) Be left with some unconstrained inference variables. We + // will then correctly report an inference error, since the + // existence of multiple marker trait impls tells us nothing + // about which one should actually apply. + !needs_infer + } + Some(_) => true, + None => false, + }; + } + ParamCandidate(ref cand) => { + // Prefer the impl to a global where clause candidate. + return is_global(cand); + } + _ => (), + } + } + + false + } + ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { has_nested: true } => { + match victim.candidate { + ParamCandidate(ref cand) => { + // Prefer these to a global where-clause bound + // (see issue #50825). + is_global(cand) && other.evaluation.must_apply_modulo_regions() + } + _ => false, + } + } + _ => false, + } + } + + fn sized_conditions( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> BuiltinImplConditions<'tcx> { + use self::BuiltinImplConditions::{Ambiguous, None, Where}; + + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + + match self_ty.kind { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Error(_) => { + // safe for everything + Where(ty::Binder::dummy(Vec::new())) + } + + ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, + + ty::Tuple(tys) => { + Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect())) + } + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(self.tcx()); + // (*) binder moved here + Where(ty::Binder::bind( + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(), + )) + } + + ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, + ty::Infer(ty::TyVar(_)) => Ambiguous, + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } + } + } + + fn copy_clone_conditions( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> BuiltinImplConditions<'tcx> { + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + + use self::BuiltinImplConditions::{Ambiguous, None, Where}; + + match self_ty.kind { + ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())), + + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, hir::Mutability::Not) => { + // Implementations provided in libcore + None + } + + ty::Dynamic(..) + | ty::Str + | ty::Slice(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Foreign(..) + | ty::Ref(_, _, hir::Mutability::Mut) => None, + + ty::Array(element_ty, _) => { + // (*) binder moved here + Where(ty::Binder::bind(vec![element_ty])) + } + + ty::Tuple(tys) => { + // (*) binder moved here + Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect())) + } + + ty::Closure(_, substs) => { + // (*) binder moved here + Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect())) + } + + ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { + // Fallback to whatever user-defined impls exist in this case. + None + } + + ty::Infer(ty::TyVar(_)) => { + // Unbound type variable. Might or might not have + // applicable impls and so forth, depending on what + // those type variables wind up being bound to. + Ambiguous + } + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } + } + } + + /// For default impls, we need to break apart a type into its + /// "constituent types" -- meaning, the types that it contains. + /// + /// Here are some (simple) examples: + /// + /// ``` + /// (i32, u32) -> [i32, u32] + /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] + /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32] + /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32] + /// ``` + fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> { + match t.kind { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => Vec::new(), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Projection(..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("asked to assemble constituent types of unexpected type: {:?}", t); + } + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + vec![element_ty] + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + tys.iter().map(|k| k.expect_ty()).collect() + } + + ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(), + + ty::Generator(_, ref substs, _) => { + let witness = substs.as_generator().witness(); + substs.as_generator().upvar_tys().chain(iter::once(witness)).collect() + } + + ty::GeneratorWitness(types) => { + // This is sound because no regions in the witness can refer to + // the binder outside the witness. So we'll effectivly reuse + // the implicit binder around the witness. + types.skip_binder().to_vec() + } + + // For `PhantomData<T>`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), + + ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), + + ty::Opaque(def_id, substs) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] + } + } + } + + fn collect_predicates_for_types( + &mut self, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + trait_def_id: DefId, + types: ty::Binder<Vec<Ty<'tcx>>>, + ) -> Vec<PredicateObligation<'tcx>> { + // Because the types were potentially derived from + // higher-ranked obligations they may reference late-bound + // regions. For example, `for<'a> Foo<&'a i32> : Copy` would + // yield a type like `for<'a> &'a i32`. In general, we + // maintain the invariant that we never manipulate bound + // regions, so we have to process these bound regions somehow. + // + // The strategy is to: + // + // 1. Instantiate those regions to placeholder regions (e.g., + // `for<'a> &'a i32` becomes `&0 i32`. + // 2. Produce something like `&'0 i32 : Copy` + // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` + + types + .skip_binder() // binder moved -\ + .iter() + .flat_map(|ty| { + let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/ + + self.infcx.commit_unconditionally(|_| { + let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); + let Normalized { value: normalized_ty, mut obligations } = + ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + param_env, + cause.clone(), + recursion_depth, + &placeholder_ty, + ) + }); + let placeholder_obligation = predicate_for_trait_def( + self.tcx(), + param_env, + cause.clone(), + trait_def_id, + recursion_depth, + normalized_ty, + &[], + ); + obligations.push(placeholder_obligation); + obligations + }) + }) + .collect() + } + + /////////////////////////////////////////////////////////////////////////// + // Matching + // + // Matching is a common path used for both evaluation and + // confirmation. It basically unifies types that appear in impls + // and traits. This does affect the surrounding environment; + // therefore, when used during evaluation, match routines must be + // run inside of a `probe()` so that their side-effects are + // contained. + + fn rematch_impl( + &mut self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + ) -> Normalized<'tcx, SubstsRef<'tcx>> { + match self.match_impl(impl_def_id, obligation) { + Ok(substs) => substs, + Err(()) => { + bug!( + "Impl {:?} was matchable against {:?} but now is not", + impl_def_id, + obligation + ); + } + } + } + + fn match_impl( + &mut self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { + let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); + + // Before we create the substitutions and everything, first + // consider a "quick reject". This avoids creating more types + // and so forth that we need to. + if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { + return Err(()); + } + + let (placeholder_obligation, _) = + self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; + + let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); + + let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + + let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = + ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &impl_trait_ref, + ) + }); + + debug!( + "match_impl(impl_def_id={:?}, obligation={:?}, \ + impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})", + impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref + ); + + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(placeholder_obligation_trait_ref, impl_trait_ref) + .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; + nested_obligations.extend(obligations); + + if !self.intercrate + && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation + { + debug!("match_impl: reservation impls only apply in intercrate mode"); + return Err(()); + } + + debug!("match_impl: success impl_substs={:?}", impl_substs); + Ok(Normalized { value: impl_substs, obligations: nested_obligations }) + } + + fn fast_reject_trait_refs( + &mut self, + obligation: &TraitObligation<'_>, + impl_trait_ref: &ty::TraitRef<'_>, + ) -> bool { + // We can avoid creating type variables and doing the full + // substitution if we find that any of the input types, when + // simplified, do not match. + + obligation.predicate.skip_binder().trait_ref.substs.iter().zip(impl_trait_ref.substs).any( + |(obligation_arg, impl_arg)| { + match (obligation_arg.unpack(), impl_arg.unpack()) { + (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => { + let simplified_obligation_ty = + fast_reject::simplify_type(self.tcx(), obligation_ty, true); + let simplified_impl_ty = + fast_reject::simplify_type(self.tcx(), impl_ty, false); + + simplified_obligation_ty.is_some() + && simplified_impl_ty.is_some() + && simplified_obligation_ty != simplified_impl_ty + } + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => { + // Lifetimes can never cause a rejection. + false + } + (GenericArgKind::Const(_), GenericArgKind::Const(_)) => { + // Conservatively ignore consts (i.e. assume they might + // unify later) until we have `fast_reject` support for + // them (if we'll ever need it, even). + false + } + _ => unreachable!(), + } + }, + ) + } + + /// Normalize `where_clause_trait_ref` and try to match it against + /// `obligation`. If successful, return any predicates that + /// result from the normalization. Normalization is necessary + /// because where-clauses are stored in the parameter environment + /// unnormalized. + fn match_where_clause_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { + self.match_poly_trait_ref(obligation, where_clause_trait_ref) + } + + /// Returns `Ok` if `poly_trait_ref` being true implies that the + /// obligation is satisfied. + fn match_poly_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { + debug!( + "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", + obligation, poly_trait_ref + ); + + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) + .map(|InferOk { obligations, .. }| obligations) + .map_err(|_| ()) + } + + /////////////////////////////////////////////////////////////////////////// + // Miscellany + + fn match_fresh_trait_refs( + &self, + previous: ty::PolyTraitRef<'tcx>, + current: ty::PolyTraitRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + let mut matcher = ty::_match::Match::new(self.tcx(), param_env); + matcher.relate(previous, current).is_ok() + } + + fn push_stack<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: &'o TraitObligation<'tcx>, + ) -> TraitObligationStack<'o, 'tcx> { + let fresh_trait_ref = + obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); + + let dfn = previous_stack.cache.next_dfn(); + let depth = previous_stack.depth() + 1; + TraitObligationStack { + obligation, + fresh_trait_ref, + reached_depth: Cell::new(depth), + previous: previous_stack, + dfn, + depth, + } + } + + fn closure_trait_ref_unnormalized( + &mut self, + obligation: &TraitObligation<'tcx>, + substs: SubstsRef<'tcx>, + ) -> ty::PolyTraitRef<'tcx> { + debug!("closure_trait_ref_unnormalized(obligation={:?}, substs={:?})", obligation, substs); + let closure_sig = substs.as_closure().sig(); + + debug!("closure_trait_ref_unnormalized: closure_sig = {:?}", closure_sig); + + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an unboxed closure type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + closure_trait_ref_and_return_type( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + closure_sig, + util::TupleArgumentsFlag::No, + ) + .map_bound(|(trait_ref, _)| trait_ref) + } + + fn generator_trait_ref_unnormalized( + &mut self, + obligation: &TraitObligation<'tcx>, + substs: SubstsRef<'tcx>, + ) -> ty::PolyTraitRef<'tcx> { + let gen_sig = substs.as_generator().poly_sig(); + + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an generator type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + + super::util::generator_trait_ref_and_outputs( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + gen_sig, + ) + .map_bound(|(trait_ref, ..)| trait_ref) + } + + /// Returns the obligations that are implied by instantiating an + /// impl or trait. The obligations are substituted and fully + /// normalized. This is used when confirming an impl or default + /// impl. + fn impl_or_trait_obligations( + &mut self, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, // of impl or trait + substs: SubstsRef<'tcx>, // for impl or trait + ) -> Vec<PredicateObligation<'tcx>> { + debug!("impl_or_trait_obligations(def_id={:?})", def_id); + let tcx = self.tcx(); + + // To allow for one-pass evaluation of the nested obligation, + // each predicate must be preceded by the obligations required + // to normalize it. + // for example, if we have: + // impl<U: Iterator<Item: Copy>, V: Iterator<Item = U>> Foo for V + // the impl will have the following predicates: + // <V as Iterator>::Item = U, + // U: Iterator, U: Sized, + // V: Iterator, V: Sized, + // <U as Iterator>::Item: Copy + // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last + // obligation will normalize to `<$0 as Iterator>::Item = $1` and + // `$1: Copy`, so we must ensure the obligations are emitted in + // that order. + let predicates = tcx.predicates_of(def_id); + assert_eq!(predicates.parent, None); + let mut obligations = Vec::with_capacity(predicates.predicates.len()); + for (predicate, _) in predicates.predicates { + let predicate = normalize_with_depth_to( + self, + param_env, + cause.clone(), + recursion_depth, + &predicate.subst(tcx, substs), + &mut obligations, + ); + obligations.push(Obligation { + cause: cause.clone(), + recursion_depth, + param_env, + predicate, + }); + } + + // We are performing deduplication here to avoid exponential blowups + // (#38528) from happening, but the real cause of the duplication is + // unknown. What we know is that the deduplication avoids exponential + // amount of predicates being propagated when processing deeply nested + // types. + // + // This code is hot enough that it's worth avoiding the allocation + // required for the FxHashSet when possible. Special-casing lengths 0, + // 1 and 2 covers roughly 75-80% of the cases. + if obligations.len() <= 1 { + // No possibility of duplicates. + } else if obligations.len() == 2 { + // Only two elements. Drop the second if they are equal. + if obligations[0] == obligations[1] { + obligations.truncate(1); + } + } else { + // Three or more elements. Use a general deduplication process. + let mut seen = FxHashSet::default(); + obligations.retain(|i| seen.insert(i.clone())); + } + + obligations + } +} + +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)] + fn derived_cause( + &self, + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + /*! + * Creates a cause for obligations that are derived from + * `obligation` by a recursive search (e.g., for a builtin + * bound, or eventually a `auto trait Foo`). If `obligation` + * is itself a derived obligation, this is just a clone, but + * otherwise we create a "derived obligation" cause so as to + * keep track of the original root obligation for error + * reporting. + */ + + let obligation = self; + + // NOTE(flaper87): As of now, it keeps track of the whole error + // chain. Ideally, we should have a way to configure this either + // by using -Z verbose or just a CLI argument. + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: Rc::new(obligation.cause.code.clone()), + }; + let derived_code = variant(derived_cause); + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) + } +} + +impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { + fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { + TraitObligationStackList::with(self) + } + + fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> { + self.previous.cache + } + + fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> { + self.list() + } + + /// Indicates that attempting to evaluate this stack entry + /// required accessing something from the stack at depth `reached_depth`. + fn update_reached_depth(&self, reached_depth: usize) { + assert!( + self.depth > reached_depth, + "invoked `update_reached_depth` with something under this stack: \ + self.depth={} reached_depth={}", + self.depth, + reached_depth, + ); + debug!("update_reached_depth(reached_depth={})", reached_depth); + let mut p = self; + while reached_depth < p.depth { + debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); + p.reached_depth.set(p.reached_depth.get().min(reached_depth)); + p = p.previous.head.unwrap(); + } + } +} + +/// The "provisional evaluation cache" is used to store intermediate cache results +/// when solving auto traits. Auto traits are unusual in that they can support +/// cycles. So, for example, a "proof tree" like this would be ok: +/// +/// - `Foo<T>: Send` :- +/// - `Bar<T>: Send` :- +/// - `Foo<T>: Send` -- cycle, but ok +/// - `Baz<T>: Send` +/// +/// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and +/// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`. +/// For non-auto traits, this cycle would be an error, but for auto traits (because +/// they are coinductive) it is considered ok. +/// +/// However, there is a complication: at the point where we have +/// "proven" `Bar<T>: Send`, we have in fact only proven it +/// *provisionally*. In particular, we proved that `Bar<T>: Send` +/// *under the assumption* that `Foo<T>: Send`. But what if we later +/// find out this assumption is wrong? Specifically, we could +/// encounter some kind of error proving `Baz<T>: Send`. In that case, +/// `Bar<T>: Send` didn't turn out to be true. +/// +/// In Issue #60010, we found a bug in rustc where it would cache +/// these intermediate results. This was fixed in #60444 by disabling +/// *all* caching for things involved in a cycle -- in our example, +/// that would mean we don't cache that `Bar<T>: Send`. But this led +/// to large slowdowns. +/// +/// Specifically, imagine this scenario, where proving `Baz<T>: Send` +/// first requires proving `Bar<T>: Send` (which is true: +/// +/// - `Foo<T>: Send` :- +/// - `Bar<T>: Send` :- +/// - `Foo<T>: Send` -- cycle, but ok +/// - `Baz<T>: Send` +/// - `Bar<T>: Send` -- would be nice for this to be a cache hit! +/// - `*const T: Send` -- but what if we later encounter an error? +/// +/// The *provisional evaluation cache* resolves this issue. It stores +/// cache results that we've proven but which were involved in a cycle +/// in some way. We track the minimal stack depth (i.e., the +/// farthest from the top of the stack) that we are dependent on. +/// The idea is that the cache results within are all valid -- so long as +/// none of the nodes in between the current node and the node at that minimum +/// depth result in an error (in which case the cached results are just thrown away). +/// +/// During evaluation, we consult this provisional cache and rely on +/// it. Accessing a cached value is considered equivalent to accessing +/// a result at `reached_depth`, so it marks the *current* solution as +/// provisional as well. If an error is encountered, we toss out any +/// provisional results added from the subtree that encountered the +/// error. When we pop the node at `reached_depth` from the stack, we +/// can commit all the things that remain in the provisional cache. +struct ProvisionalEvaluationCache<'tcx> { + /// next "depth first number" to issue -- just a counter + dfn: Cell<usize>, + + /// Stores the "coldest" depth (bottom of stack) reached by any of + /// the evaluation entries. The idea here is that all things in the provisional + /// cache are always dependent on *something* that is colder in the stack: + /// therefore, if we add a new entry that is dependent on something *colder still*, + /// we have to modify the depth for all entries at once. + /// + /// Example: + /// + /// Imagine we have a stack `A B C D E` (with `E` being the top of + /// the stack). We cache something with depth 2, which means that + /// it was dependent on C. Then we pop E but go on and process a + /// new node F: A B C D F. Now F adds something to the cache with + /// depth 1, meaning it is dependent on B. Our original cache + /// entry is also dependent on B, because there is a path from E + /// to C and then from C to F and from F to B. + reached_depth: Cell<usize>, + + /// Map from cache key to the provisionally evaluated thing. + /// The cache entries contain the result but also the DFN in which they + /// were added. The DFN is used to clear out values on failure. + /// + /// Imagine we have a stack like: + /// + /// - `A B C` and we add a cache for the result of C (DFN 2) + /// - Then we have a stack `A B D` where `D` has DFN 3 + /// - We try to solve D by evaluating E: `A B D E` (DFN 4) + /// - `E` generates various cache entries which have cyclic dependices on `B` + /// - `A B D E F` and so forth + /// - the DFN of `F` for example would be 5 + /// - then we determine that `E` is in error -- we will then clear + /// all cache values whose DFN is >= 4 -- in this case, that + /// means the cached value for `F`. + map: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ProvisionalEvaluation>>, +} + +/// A cache value for the provisional cache: contains the depth-first +/// number (DFN) and result. +#[derive(Copy, Clone, Debug)] +struct ProvisionalEvaluation { + from_dfn: usize, + result: EvaluationResult, +} + +impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { + fn default() -> Self { + Self { dfn: Cell::new(0), reached_depth: Cell::new(usize::MAX), map: Default::default() } + } +} + +impl<'tcx> ProvisionalEvaluationCache<'tcx> { + /// Get the next DFN in sequence (basically a counter). + fn next_dfn(&self) -> usize { + let result = self.dfn.get(); + self.dfn.set(result + 1); + result + } + + /// Check the provisional cache for any result for + /// `fresh_trait_ref`. If there is a hit, then you must consider + /// it an access to the stack slots at depth + /// `self.current_reached_depth()` and above. + fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> { + debug!( + "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", + fresh_trait_ref, + self.map.borrow().get(&fresh_trait_ref), + self.reached_depth.get(), + ); + Some(self.map.borrow().get(&fresh_trait_ref)?.result) + } + + /// Current value of the `reached_depth` counter -- all the + /// provisional cache entries are dependent on the item at this + /// depth. + fn current_reached_depth(&self) -> usize { + self.reached_depth.get() + } + + /// Insert a provisional result into the cache. The result came + /// from the node with the given DFN. It accessed a minimum depth + /// of `reached_depth` to compute. It evaluated `fresh_trait_ref` + /// and resulted in `result`. + fn insert_provisional( + &self, + from_dfn: usize, + reached_depth: usize, + fresh_trait_ref: ty::PolyTraitRef<'tcx>, + result: EvaluationResult, + ) { + debug!( + "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", + from_dfn, reached_depth, fresh_trait_ref, result, + ); + let r_d = self.reached_depth.get(); + self.reached_depth.set(r_d.min(reached_depth)); + + debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); + + self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); + } + + /// Invoked when the node with dfn `dfn` does not get a successful + /// result. This will clear out any provisional cache entries + /// that were added since `dfn` was created. This is because the + /// provisional entries are things which must assume that the + /// things on the stack at the time of their creation succeeded -- + /// since the failing node is presently at the top of the stack, + /// these provisional entries must either depend on it or some + /// ancestor of it. + fn on_failure(&self, dfn: usize) { + debug!("on_failure(dfn={:?})", dfn,); + self.map.borrow_mut().retain(|key, eval| { + if !eval.from_dfn >= dfn { + debug!("on_failure: removing {:?}", key); + false + } else { + true + } + }); + } + + /// Invoked when the node at depth `depth` completed without + /// depending on anything higher in the stack (if that completion + /// was a failure, then `on_failure` should have been invoked + /// already). The callback `op` will be invoked for each + /// provisional entry that we can now confirm. + fn on_completion( + &self, + depth: usize, + mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), + ) { + debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); + + if self.reached_depth.get() < depth { + debug!("on_completion: did not yet reach depth to complete"); + return; + } + + for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { + debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); + + op(fresh_trait_ref, eval.result); + } + + self.reached_depth.set(usize::MAX); + } +} + +#[derive(Copy, Clone)] +struct TraitObligationStackList<'o, 'tcx> { + cache: &'o ProvisionalEvaluationCache<'tcx>, + head: Option<&'o TraitObligationStack<'o, 'tcx>>, +} + +impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { + fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> { + TraitObligationStackList { cache, head: None } + } + + fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> { + TraitObligationStackList { cache: r.cache(), head: Some(r) } + } + + fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { + self.head + } + + fn depth(&self) -> usize { + if let Some(head) = self.head { head.depth } else { 0 } + } +} + +impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> { + type Item = &'o TraitObligationStack<'o, 'tcx>; + + fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { + match self.head { + Some(o) => { + *self = o.previous; + Some(o) + } + None => None, + } + } +} + +impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TraitObligationStack({:?})", self.obligation) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs new file mode 100644 index 00000000000..4d81a3baa0e --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -0,0 +1,518 @@ +//! Logic and data structures related to impl specialization, explained in +//! greater detail below. +//! +//! At the moment, this implementation support only the simple "chain" rule: +//! If any two impls overlap, one must be a strict subset of the other. +//! +//! See the [rustc dev guide] for a bit more detail on how specialization +//! fits together with the rest of the trait machinery. +//! +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html + +pub mod specialization_graph; +use specialization_graph::GraphExt; + +use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use crate::traits::select::IntercrateAmbiguityCause; +use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::struct_span_err; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; +use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; +use rustc_span::DUMMY_SP; + +use super::util::impl_trait_ref_and_oblig; +use super::{FulfillmentContext, SelectionContext}; + +/// Information pertinent to an overlapping impl error. +#[derive(Debug)] +pub struct OverlapError { + pub with_impl: DefId, + pub trait_desc: String, + pub self_desc: Option<String>, + pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, + pub involves_placeholder: bool, +} + +/// Given a subst for the requested impl, translate it to a subst +/// appropriate for the actual item definition (whether it be in that impl, +/// a parent impl, or the trait). +/// +/// When we have selected one impl, but are actually using item definitions from +/// a parent impl providing a default, we need a way to translate between the +/// type parameters of the two impls. Here the `source_impl` is the one we've +/// selected, and `source_substs` is a substitution of its generics. +/// And `target_node` is the impl/trait we're actually going to get the +/// definition from. The resulting substitution will map from `target_node`'s +/// generics to `source_impl`'s generics as instantiated by `source_subst`. +/// +/// For example, consider the following scenario: +/// +/// ```rust +/// trait Foo { ... } +/// impl<T, U> Foo for (T, U) { ... } // target impl +/// impl<V> Foo for (V, V) { ... } // source impl +/// ``` +/// +/// Suppose we have selected "source impl" with `V` instantiated with `u32`. +/// This function will produce a substitution with `T` and `U` both mapping to `u32`. +/// +/// where-clauses add some trickiness here, because they can be used to "define" +/// an argument indirectly: +/// +/// ```rust +/// impl<'a, I, T: 'a> Iterator for Cloned<I> +/// where I: Iterator<Item = &'a T>, T: Clone +/// ``` +/// +/// In a case like this, the substitution for `T` is determined indirectly, +/// through associated type projection. We deal with such cases by using +/// *fulfillment* to relate the two impls, requiring that all projections are +/// resolved. +pub fn translate_substs<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + source_impl: DefId, + source_substs: SubstsRef<'tcx>, + target_node: specialization_graph::Node, +) -> SubstsRef<'tcx> { + debug!( + "translate_substs({:?}, {:?}, {:?}, {:?})", + param_env, source_impl, source_substs, target_node + ); + let source_trait_ref = + infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs); + + // translate the Self and Param parts of the substitution, since those + // vary across impls + let target_substs = match target_node { + specialization_graph::Node::Impl(target_impl) => { + // no need to translate if we're targeting the impl we started with + if source_impl == target_impl { + return source_substs; + } + + fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else( + |_| { + bug!( + "When translating substitutions for specialization, the expected \ + specialization failed to hold" + ) + }, + ) + } + specialization_graph::Node::Trait(..) => source_trait_ref.substs, + }; + + // directly inherent the method generics, since those do not vary across impls + source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) +} + +/// Is `impl1` a specialization of `impl2`? +/// +/// Specialization is determined by the sets of types to which the impls apply; +/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies +/// to. +pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool { + debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id); + + // The feature gate should prevent introducing new specializations, but not + // taking advantage of upstream ones. + let features = tcx.features(); + let specialization_enabled = features.specialization || features.min_specialization; + if !specialization_enabled && (impl1_def_id.is_local() || impl2_def_id.is_local()) { + return false; + } + + // We determine whether there's a subset relationship by: + // + // - replacing bound vars with placeholders in impl1, + // - assuming the where clauses for impl1, + // - instantiating impl2 with fresh inference variables, + // - unifying, + // - attempting to prove the where clauses for impl2 + // + // The last three steps are encapsulated in `fulfill_implication`. + // + // See RFC 1210 for more details and justification. + + // Currently we do not allow e.g., a negative impl to specialize a positive one + if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { + return false; + } + + // create a parameter environment corresponding to a (placeholder) instantiation of impl1 + let penv = tcx.param_env(impl1_def_id); + let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); + + // Create a infcx, taking the predicates of impl1 as assumptions: + tcx.infer_ctxt().enter(|infcx| { + // Normalize the trait reference. The WF rules ought to ensure + // that this always succeeds. + let impl1_trait_ref = match traits::fully_normalize( + &infcx, + FulfillmentContext::new(), + ObligationCause::dummy(), + penv, + &impl1_trait_ref, + ) { + Ok(impl1_trait_ref) => impl1_trait_ref, + Err(err) => { + bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); + } + }; + + // Attempt to prove that impl2 applies, given all of the above. + fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() + }) +} + +/// Attempt to fulfill all obligations of `target_impl` after unification with +/// `source_trait_ref`. If successful, returns a substitution for *all* the +/// generics of `target_impl`, including both those needed to unify with +/// `source_trait_ref` and those whose identity is determined via a where +/// clause in the impl. +fn fulfill_implication<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + source_trait_ref: ty::TraitRef<'tcx>, + target_impl: DefId, +) -> Result<SubstsRef<'tcx>, ()> { + debug!( + "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", + param_env, source_trait_ref, target_impl + ); + + let selcx = &mut SelectionContext::new(&infcx); + let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); + let (target_trait_ref, obligations) = + impl_trait_ref_and_oblig(selcx, param_env, target_impl, target_substs); + + // do the impls unify? If not, no specialization. + let more_obligations = + match infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref) + { + Ok(InferOk { obligations, .. }) => obligations, + Err(_) => { + debug!( + "fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, target_trait_ref + ); + return Err(()); + } + }; + + // attempt to prove all of the predicates for impl2 given those for impl1 + // (which are packed up in penv) + + infcx.save_and_restore_in_snapshot_flag(|infcx| { + // If we came from `translate_substs`, we already know that the + // predicates for our impl hold (after all, we know that a more + // specialized impl holds, so our impl must hold too), and + // we only want to process the projections to determine the + // the types in our substs using RFC 447, so we can safely + // ignore region obligations, which allows us to avoid threading + // a node-id to assign them with. + // + // If we came from specialization graph construction, then + // we already make a mockery out of the region system, so + // why not ignore them a bit earlier? + let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); + for oblig in obligations.chain(more_obligations) { + fulfill_cx.register_predicate_obligation(&infcx, oblig); + } + match fulfill_cx.select_all_or_error(infcx) { + Err(errors) => { + // no dice! + debug!( + "fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + source_trait_ref, + target_trait_ref, + errors, + param_env.caller_bounds() + ); + Err(()) + } + + Ok(()) => { + debug!( + "fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, target_trait_ref + ); + + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_vars_if_possible(&target_substs)) + } + } + }) +} + +// Query provider for `specialization_graph_of`. +pub(super) fn specialization_graph_provider( + tcx: TyCtxt<'_>, + trait_id: DefId, +) -> specialization_graph::Graph { + let mut sg = specialization_graph::Graph::new(); + + let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect(); + + // The coherence checking implementation seems to rely on impls being + // iterated over (roughly) in definition order, so we are sorting by + // negated `CrateNum` (so remote definitions are visited first) and then + // by a flattened version of the `DefIndex`. + trait_impls + .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index())); + + for impl_def_id in trait_impls { + if let Some(impl_def_id) = impl_def_id.as_local() { + // This is where impl overlap checking happens: + let insert_result = sg.insert(tcx, impl_def_id.to_def_id()); + // Report error if there was one. + let (overlap, used_to_be_allowed) = match insert_result { + Err(overlap) => (Some(overlap), None), + Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)), + Ok(None) => (None, None), + }; + + if let Some(overlap) = overlap { + report_overlap_conflict(tcx, overlap, impl_def_id, used_to_be_allowed, &mut sg); + } + } else { + let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id); + sg.record_impl_from_cstore(tcx, parent, impl_def_id) + } + } + + sg +} + +fn report_overlap_conflict( + tcx: TyCtxt<'_>, + overlap: OverlapError, + impl_def_id: LocalDefId, + used_to_be_allowed: Option<FutureCompatOverlapErrorKind>, + sg: &mut specialization_graph::Graph, +) { + let impl_polarity = tcx.impl_polarity(impl_def_id.to_def_id()); + let other_polarity = tcx.impl_polarity(overlap.with_impl); + match (impl_polarity, other_polarity) { + (ty::ImplPolarity::Negative, ty::ImplPolarity::Positive) => { + report_negative_positive_conflict( + tcx, + &overlap, + impl_def_id, + impl_def_id.to_def_id(), + overlap.with_impl, + sg, + ); + } + + (ty::ImplPolarity::Positive, ty::ImplPolarity::Negative) => { + report_negative_positive_conflict( + tcx, + &overlap, + impl_def_id, + overlap.with_impl, + impl_def_id.to_def_id(), + sg, + ); + } + + _ => { + report_conflicting_impls(tcx, overlap, impl_def_id, used_to_be_allowed, sg); + } + } +} + +fn report_negative_positive_conflict( + tcx: TyCtxt<'_>, + overlap: &OverlapError, + local_impl_def_id: LocalDefId, + negative_impl_def_id: DefId, + positive_impl_def_id: DefId, + sg: &mut specialization_graph::Graph, +) { + let impl_span = tcx + .sess + .source_map() + .guess_head_span(tcx.span_of_impl(local_impl_def_id.to_def_id()).unwrap()); + + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0751, + "found both positive and negative implementation of trait `{}`{}:", + overlap.trait_desc, + overlap.self_desc.clone().map_or(String::new(), |ty| format!(" for type `{}`", ty)) + ); + + match tcx.span_of_impl(negative_impl_def_id) { + Ok(span) => { + err.span_label( + tcx.sess.source_map().guess_head_span(span), + "negative implementation here".to_string(), + ); + } + Err(cname) => { + err.note(&format!("negative implementation in crate `{}`", cname)); + } + } + + match tcx.span_of_impl(positive_impl_def_id) { + Ok(span) => { + err.span_label( + tcx.sess.source_map().guess_head_span(span), + "positive implementation here".to_string(), + ); + } + Err(cname) => { + err.note(&format!("positive implementation in crate `{}`", cname)); + } + } + + sg.has_errored = true; + err.emit(); +} + +fn report_conflicting_impls( + tcx: TyCtxt<'_>, + overlap: OverlapError, + impl_def_id: LocalDefId, + used_to_be_allowed: Option<FutureCompatOverlapErrorKind>, + sg: &mut specialization_graph::Graph, +) { + let impl_span = + tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id.to_def_id()).unwrap()); + + // Work to be done after we've built the DiagnosticBuilder. We have to define it + // now because the struct_lint methods don't return back the DiagnosticBuilder + // that's passed in. + let decorate = |err: LintDiagnosticBuilder<'_>| { + let msg = format!( + "conflicting implementations of trait `{}`{}:{}", + overlap.trait_desc, + overlap.self_desc.clone().map_or(String::new(), |ty| { format!(" for type `{}`", ty) }), + match used_to_be_allowed { + Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)", + _ => "", + } + ); + let mut err = err.build(&msg); + match tcx.span_of_impl(overlap.with_impl) { + Ok(span) => { + err.span_label( + tcx.sess.source_map().guess_head_span(span), + "first implementation here".to_string(), + ); + + err.span_label( + impl_span, + format!( + "conflicting implementation{}", + overlap.self_desc.map_or(String::new(), |ty| format!(" for `{}`", ty)) + ), + ); + } + Err(cname) => { + let msg = match to_pretty_impl_header(tcx, overlap.with_impl) { + Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s), + None => format!("conflicting implementation in crate `{}`", cname), + }; + err.note(&msg); + } + } + + for cause in &overlap.intercrate_ambiguity_causes { + cause.add_intercrate_ambiguity_hint(&mut err); + } + + if overlap.involves_placeholder { + coherence::add_placeholder_note(&mut err); + } + err.emit() + }; + + match used_to_be_allowed { + None => { + sg.has_errored = true; + let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); + decorate(LintDiagnosticBuilder::new(err)); + } + Some(kind) => { + let lint = match kind { + FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS, + FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, + }; + tcx.struct_span_lint_hir( + lint, + tcx.hir().local_def_id_to_hir_id(impl_def_id), + impl_span, + decorate, + ) + } + }; +} + +/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a +/// string. +fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> { + use std::fmt::Write; + + let trait_ref = tcx.impl_trait_ref(impl_def_id)?; + let mut w = "impl".to_owned(); + + let substs = InternalSubsts::identity_for_item(tcx, impl_def_id); + + // FIXME: Currently only handles ?Sized. + // Needs to support ?Move and ?DynSized when they are implemented. + let mut types_without_default_bounds = FxHashSet::default(); + let sized_trait = tcx.lang_items().sized_trait(); + + if !substs.is_noop() { + types_without_default_bounds.extend(substs.types()); + w.push('<'); + w.push_str( + &substs + .iter() + .map(|k| k.to_string()) + .filter(|k| k != "'_") + .collect::<Vec<_>>() + .join(", "), + ); + w.push('>'); + } + + write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap(); + + // The predicates will contain default bounds like `T: Sized`. We need to + // remove these bounds, and add `T: ?Sized` to any untouched type parameters. + let predicates = tcx.predicates_of(impl_def_id).predicates; + let mut pretty_predicates = + Vec::with_capacity(predicates.len() + types_without_default_bounds.len()); + + for (p, _) in predicates { + if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { + if Some(poly_trait_ref.def_id()) == sized_trait { + types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder()); + continue; + } + } + pretty_predicates.push(p.to_string()); + } + + pretty_predicates + .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty))); + + if !pretty_predicates.is_empty() { + write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); + } + + w.push(';'); + Some(w) +} diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs new file mode 100644 index 00000000000..56b8354d68c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -0,0 +1,379 @@ +use super::OverlapError; + +use crate::traits; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::fast_reject::{self, SimplifiedType}; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; + +pub use rustc_middle::traits::specialization_graph::*; + +#[derive(Copy, Clone, Debug)] +pub enum FutureCompatOverlapErrorKind { + Issue33140, + LeakCheck, +} + +#[derive(Debug)] +pub struct FutureCompatOverlapError { + pub error: OverlapError, + pub kind: FutureCompatOverlapErrorKind, +} + +/// The result of attempting to insert an impl into a group of children. +enum Inserted { + /// The impl was inserted as a new child in this group of children. + BecameNewSibling(Option<FutureCompatOverlapError>), + + /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc. + ReplaceChildren(Vec<DefId>), + + /// The impl is a specialization of an existing child. + ShouldRecurseOn(DefId), +} + +trait ChildrenExt { + fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); + fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); + + fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + simplified_self: Option<SimplifiedType>, + ) -> Result<Inserted, OverlapError>; +} + +impl ChildrenExt for Children { + /// Insert an impl into this set of children without comparing to any existing impls. + fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); + self.nonblanket_impls.entry(st).or_default().push(impl_def_id) + } else { + debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); + self.blanket_impls.push(impl_def_id) + } + } + + /// Removes an impl from this set of children. Used when replacing + /// an impl with a parent. The impl must be present in the list of + /// children already. + fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let vec: &mut Vec<DefId>; + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); + vec = self.nonblanket_impls.get_mut(&st).unwrap(); + } else { + debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); + vec = &mut self.blanket_impls; + } + + let index = vec.iter().position(|d| *d == impl_def_id).unwrap(); + vec.remove(index); + } + + /// Attempt to insert an impl into this set of children, while comparing for + /// specialization relationships. + fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + simplified_self: Option<SimplifiedType>, + ) -> Result<Inserted, OverlapError> { + let mut last_lint = None; + let mut replace_children = Vec::new(); + + debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,); + + let possible_siblings = match simplified_self { + Some(st) => PotentialSiblings::Filtered(filtered_children(self, st)), + None => PotentialSiblings::Unfiltered(iter_children(self)), + }; + + for possible_sibling in possible_siblings { + debug!( + "insert: impl_def_id={:?}, simplified_self={:?}, possible_sibling={:?}", + impl_def_id, simplified_self, possible_sibling, + ); + + let create_overlap_error = |overlap: traits::coherence::OverlapResult<'_>| { + let trait_ref = overlap.impl_header.trait_ref.unwrap(); + let self_ty = trait_ref.self_ty(); + + OverlapError { + with_impl: possible_sibling, + trait_desc: trait_ref.print_only_trait_path().to_string(), + // Only report the `Self` type if it has at least + // some outer concrete shell; otherwise, it's + // not adding much information. + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, + involves_placeholder: overlap.involves_placeholder, + } + }; + + let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>, + last_lint: &mut _| { + // Found overlap, but no specialization; error out or report future-compat warning. + + // Do we *still* get overlap if we disable the future-incompatible modes? + let should_err = traits::overlapping_impls( + tcx, + possible_sibling, + impl_def_id, + traits::SkipLeakCheck::default(), + |_| true, + || false, + ); + + let error = create_overlap_error(overlap); + + if should_err { + Err(error) + } else { + *last_lint = Some(FutureCompatOverlapError { + error, + kind: FutureCompatOverlapErrorKind::LeakCheck, + }); + + Ok((false, false)) + } + }; + + let last_lint_mut = &mut last_lint; + let (le, ge) = traits::overlapping_impls( + tcx, + possible_sibling, + impl_def_id, + traits::SkipLeakCheck::Yes, + |overlap| { + if let Some(overlap_kind) = + tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) + { + match overlap_kind { + ty::ImplOverlapKind::Permitted { marker: _ } => {} + ty::ImplOverlapKind::Issue33140 => { + *last_lint_mut = Some(FutureCompatOverlapError { + error: create_overlap_error(overlap), + kind: FutureCompatOverlapErrorKind::Issue33140, + }); + } + } + + return Ok((false, false)); + } + + let le = tcx.specializes((impl_def_id, possible_sibling)); + let ge = tcx.specializes((possible_sibling, impl_def_id)); + + if le == ge { + report_overlap_error(overlap, last_lint_mut) + } else { + Ok((le, ge)) + } + }, + || Ok((false, false)), + )?; + + if le && !ge { + debug!( + "descending as child of TraitRef {:?}", + tcx.impl_trait_ref(possible_sibling).unwrap() + ); + + // The impl specializes `possible_sibling`. + return Ok(Inserted::ShouldRecurseOn(possible_sibling)); + } else if ge && !le { + debug!( + "placing as parent of TraitRef {:?}", + tcx.impl_trait_ref(possible_sibling).unwrap() + ); + + replace_children.push(possible_sibling); + } else { + // Either there's no overlap, or the overlap was already reported by + // `overlap_error`. + } + } + + if !replace_children.is_empty() { + return Ok(Inserted::ReplaceChildren(replace_children)); + } + + // No overlap with any potential siblings, so add as a new sibling. + debug!("placing as new sibling"); + self.insert_blindly(tcx, impl_def_id); + Ok(Inserted::BecameNewSibling(last_lint)) + } +} + +fn iter_children(children: &mut Children) -> impl Iterator<Item = DefId> + '_ { + let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); + children.blanket_impls.iter().chain(nonblanket).cloned() +} + +fn filtered_children( + children: &mut Children, + st: SimplifiedType, +) -> impl Iterator<Item = DefId> + '_ { + let nonblanket = children.nonblanket_impls.entry(st).or_default().iter(); + children.blanket_impls.iter().chain(nonblanket).cloned() +} + +// A custom iterator used by Children::insert +enum PotentialSiblings<I, J> +where + I: Iterator<Item = DefId>, + J: Iterator<Item = DefId>, +{ + Unfiltered(I), + Filtered(J), +} + +impl<I, J> Iterator for PotentialSiblings<I, J> +where + I: Iterator<Item = DefId>, + J: Iterator<Item = DefId>, +{ + type Item = DefId; + + fn next(&mut self) -> Option<Self::Item> { + match *self { + PotentialSiblings::Unfiltered(ref mut iter) => iter.next(), + PotentialSiblings::Filtered(ref mut iter) => iter.next(), + } + } +} + +pub trait GraphExt { + /// Insert a local impl into the specialization graph. If an existing impl + /// conflicts with it (has overlap, but neither specializes the other), + /// information about the area of overlap is returned in the `Err`. + fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + ) -> Result<Option<FutureCompatOverlapError>, OverlapError>; + + /// Insert cached metadata mapping from a child impl back to its parent. + fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId); +} + +impl GraphExt for Graph { + /// Insert a local impl into the specialization graph. If an existing impl + /// conflicts with it (has overlap, but neither specializes the other), + /// information about the area of overlap is returned in the `Err`. + fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + ) -> Result<Option<FutureCompatOverlapError>, OverlapError> { + assert!(impl_def_id.is_local()); + + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let trait_def_id = trait_ref.def_id; + + debug!( + "insert({:?}): inserting TraitRef {:?} into specialization graph", + impl_def_id, trait_ref + ); + + // If the reference itself contains an earlier error (e.g., due to a + // resolution failure), then we just insert the impl at the top level of + // the graph and claim that there's no overlap (in order to suppress + // bogus errors). + if trait_ref.references_error() { + debug!( + "insert: inserting dummy node for erroneous TraitRef {:?}, \ + impl_def_id={:?}, trait_def_id={:?}", + trait_ref, impl_def_id, trait_def_id + ); + + self.parent.insert(impl_def_id, trait_def_id); + self.children.entry(trait_def_id).or_default().insert_blindly(tcx, impl_def_id); + return Ok(None); + } + + let mut parent = trait_def_id; + let mut last_lint = None; + let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false); + + // Descend the specialization tree, where `parent` is the current parent node. + loop { + use self::Inserted::*; + + let insert_result = + self.children.entry(parent).or_default().insert(tcx, impl_def_id, simplified)?; + + match insert_result { + BecameNewSibling(opt_lint) => { + last_lint = opt_lint; + break; + } + ReplaceChildren(grand_children_to_be) => { + // We currently have + // + // P + // | + // G + // + // and we are inserting the impl N. We want to make it: + // + // P + // | + // N + // | + // G + + // Adjust P's list of children: remove G and then add N. + { + let siblings = self.children.get_mut(&parent).unwrap(); + for &grand_child_to_be in &grand_children_to_be { + siblings.remove_existing(tcx, grand_child_to_be); + } + siblings.insert_blindly(tcx, impl_def_id); + } + + // Set G's parent to N and N's parent to P. + for &grand_child_to_be in &grand_children_to_be { + self.parent.insert(grand_child_to_be, impl_def_id); + } + self.parent.insert(impl_def_id, parent); + + // Add G as N's child. + for &grand_child_to_be in &grand_children_to_be { + self.children + .entry(impl_def_id) + .or_default() + .insert_blindly(tcx, grand_child_to_be); + } + break; + } + ShouldRecurseOn(new_parent) => { + parent = new_parent; + } + } + } + + self.parent.insert(impl_def_id, parent); + Ok(last_lint) + } + + /// Insert cached metadata mapping from a child impl back to its parent. + fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) { + if self.parent.insert(child, parent).is_some() { + bug!( + "When recording an impl from the crate store, information about its parent \ + was already present." + ); + } + + self.children.entry(parent).or_default().insert_blindly(tcx, child); + } +} diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs new file mode 100644 index 00000000000..78186a5e8a5 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -0,0 +1,281 @@ +use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::traits::ObligationCause; +use crate::traits::{self, TraitEngine}; + +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_span::Span; + +#[derive(Debug)] +pub enum NonStructuralMatchTy<'tcx> { + Adt(&'tcx AdtDef), + Param, + Dynamic, + Foreign, + Opaque, + Generator, + Projection, + Closure, +} + +/// This method traverses the structure of `ty`, trying to find an +/// instance of an ADT (i.e. struct or enum) that doesn't implement +/// the structural-match traits, or a generic type parameter +/// (which cannot be determined to be structural-match). +/// +/// The "structure of a type" includes all components that would be +/// considered when doing a pattern match on a constant of that +/// type. +/// +/// * This means this method descends into fields of structs/enums, +/// and also descends into the inner type `T` of `&T` and `&mut T` +/// +/// * The traversal doesn't dereference unsafe pointers (`*const T`, +/// `*mut T`), and it does not visit the type arguments of an +/// instantiated generic like `PhantomData<T>`. +/// +/// The reason we do this search is Rust currently require all ADTs +/// reachable from a constant's type to implement the +/// structural-match traits, which essentially say that +/// the implementation of `PartialEq::eq` behaves *equivalently* to a +/// comparison against the unfolded structure. +/// +/// For more background on why Rust has this requirement, and issues +/// that arose when the requirement was not enforced completely, see +/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. +pub fn search_for_structural_match_violation<'tcx>( + _id: hir::HirId, + span: Span, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option<NonStructuralMatchTy<'tcx>> { + // FIXME: we should instead pass in an `infcx` from the outside. + tcx.infer_ctxt().enter(|infcx| { + let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() }; + ty.visit_with(&mut search); + search.found + }) +} + +/// This method returns true if and only if `adt_ty` itself has been marked as +/// eligible for structural-match: namely, if it implements both +/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by +/// `#[derive(PartialEq)]` and `#[derive(Eq)]`). +/// +/// Note that this does *not* recursively check if the substructure of `adt_ty` +/// implements the traits. +fn type_marked_structural( + infcx: &InferCtxt<'_, 'tcx>, + adt_ty: Ty<'tcx>, + cause: ObligationCause<'tcx>, +) -> bool { + let mut fulfillment_cx = traits::FulfillmentContext::new(); + // require `#[derive(PartialEq)]` + let structural_peq_def_id = + infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); + fulfillment_cx.register_bound( + infcx, + ty::ParamEnv::empty(), + adt_ty, + structural_peq_def_id, + cause.clone(), + ); + // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around + // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) + let structural_teq_def_id = + infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span)); + fulfillment_cx.register_bound( + infcx, + ty::ParamEnv::empty(), + adt_ty, + structural_teq_def_id, + cause, + ); + + // We deliberately skip *reporting* fulfillment errors (via + // `report_fulfillment_errors`), for two reasons: + // + // 1. The error messages would mention `std::marker::StructuralPartialEq` + // (a trait which is solely meant as an implementation detail + // for now), and + // + // 2. We are sometimes doing future-incompatibility lints for + // now, so we do not want unconditional errors here. + fulfillment_cx.select_all_or_error(infcx).is_ok() +} + +/// This implements the traversal over the structure of a given type to try to +/// find instances of ADTs (specifically structs or enums) that do not implement +/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`). +struct Search<'a, 'tcx> { + span: Span, + + infcx: InferCtxt<'a, 'tcx>, + + /// Records first ADT that does not implement a structural-match trait. + found: Option<NonStructuralMatchTy<'tcx>>, + + /// Tracks ADTs previously encountered during search, so that + /// we will not recur on them again. + seen: FxHashSet<hir::def_id::DefId>, +} + +impl Search<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { + adt_ty.is_structural_eq_shallow(self.tcx()) + } +} + +impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + debug!("Search visiting ty: {:?}", ty); + + let (adt_def, substs) = match ty.kind { + ty::Adt(adt_def, substs) => (adt_def, substs), + ty::Param(_) => { + self.found = Some(NonStructuralMatchTy::Param); + return true; // Stop visiting. + } + ty::Dynamic(..) => { + self.found = Some(NonStructuralMatchTy::Dynamic); + return true; // Stop visiting. + } + ty::Foreign(_) => { + self.found = Some(NonStructuralMatchTy::Foreign); + return true; // Stop visiting. + } + ty::Opaque(..) => { + self.found = Some(NonStructuralMatchTy::Opaque); + return true; // Stop visiting. + } + ty::Projection(..) => { + self.found = Some(NonStructuralMatchTy::Projection); + return true; // Stop visiting. + } + ty::Generator(..) | ty::GeneratorWitness(..) => { + self.found = Some(NonStructuralMatchTy::Generator); + return true; // Stop visiting. + } + ty::Closure(..) => { + self.found = Some(NonStructuralMatchTy::Closure); + return true; // Stop visiting. + } + ty::RawPtr(..) => { + // structural-match ignores substructure of + // `*const _`/`*mut _`, so skip `super_visit_with`. + // + // For example, if you have: + // ``` + // struct NonStructural; + // #[derive(PartialEq, Eq)] + // struct T(*const NonStructural); + // const C: T = T(std::ptr::null()); + // ``` + // + // Even though `NonStructural` does not implement `PartialEq`, + // structural equality on `T` does not recur into the raw + // pointer. Therefore, one can still use `C` in a pattern. + + // (But still tell the caller to continue search.) + return false; + } + ty::FnDef(..) | ty::FnPtr(..) => { + // Types of formals and return in `fn(_) -> _` are also irrelevant; + // so we do not recur into them via `super_visit_with` + // + // (But still tell the caller to continue search.) + return false; + } + ty::Array(_, n) + if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => + { + // rust-lang/rust#62336: ignore type of contents + // for empty array. + // + // (But still tell the caller to continue search.) + return false; + } + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { + // These primitive types are always structural match. + // + // `Never` is kind of special here, but as it is not inhabitable, this should be fine. + // + // (But still tell the caller to continue search.) + return false; + } + + ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { + // First check all contained types and then tell the caller to continue searching. + ty.super_visit_with(self); + return false; + } + ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { + bug!("unexpected type during structural-match checking: {:?}", ty); + } + ty::Error(_) => { + self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); + // We still want to check other types after encountering an error, + // as this may still emit relevant errors. + // + // So we continue searching here. + return false; + } + }; + + if !self.seen.insert(adt_def.did) { + debug!("Search already seen adt_def: {:?}", adt_def); + // Let caller continue its search. + return false; + } + + if !self.type_marked_structural(ty) { + debug!("Search found ty: {:?}", ty); + self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); + return true; // Halt visiting! + } + + // structural-match does not care about the + // instantiation of the generics in an ADT (it + // instead looks directly at its fields outside + // this match), so we skip super_visit_with. + // + // (Must not recur on substs for `PhantomData<T>` cf + // rust-lang/rust#55028 and rust-lang/rust#55837; but also + // want to skip substs when only uses of generic are + // behind unsafe pointers `*const T`/`*mut T`.) + + // even though we skip super_visit_with, we must recur on + // fields of ADT. + let tcx = self.tcx(); + for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { + let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); + debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); + + if ty.visit_with(self) { + // found an ADT without structural-match; halt visiting! + assert!(self.found.is_some()); + return true; + } + } + + // Even though we do not want to recur on substs, we do + // want our caller to continue its own search. + false + } +} + +pub fn provide(providers: &mut Providers) { + providers.has_structural_eq_impls = |tcx, ty| { + tcx.infer_ctxt().enter(|infcx| { + let cause = ObligationCause::dummy(); + type_marked_structural(&infcx, ty, cause) + }) + }; +} diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs new file mode 100644 index 00000000000..f626bb0b7e3 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -0,0 +1,363 @@ +use rustc_errors::DiagnosticBuilder; +use rustc_span::Span; +use smallvec::smallvec; +use smallvec::SmallVec; + +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; + +use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; +pub use rustc_infer::traits::util::*; + +/////////////////////////////////////////////////////////////////////////// +// `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<TraitAliasExpansionInfo<'tcx>>, +} + +/// 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)); + } + } + if self.top().1 != self.bottom().1 { + // When the trait object is in a return type these two spans match, we don't want + // redundant labels. + 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 Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>, +) -> TraitAliasExpander<'tcx> { + let items: Vec<_> = + trait_refs.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(tcx); + + 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(tcx)) == 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<usize>) { + (self.stack.len(), None) + } + + fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> { + 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<DefId>, + visited: FxHashSet<DefId>, +} + +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<DefId> { + 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 +/////////////////////////////////////////////////////////////////////////// + +/// 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>, impl Iterator<Item = PredicateObligation<'tcx>>) { + 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 = impl_obligations + .chain(normalization_obligations1.into_iter()) + .chain(normalization_obligations2.into_iter()); + + (impl_trait_ref, impl_obligations) +} + +pub fn predicates_for_generics<'tcx>( + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + generic_bounds: ty::InstantiatedPredicates<'tcx>, +) -> impl Iterator<Item = PredicateObligation<'tcx>> { + debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); + + generic_bounds.predicates.into_iter().map(move |predicate| Obligation { + cause: cause.clone(), + recursion_depth, + param_env, + predicate, + }) +} + +pub fn predicate_for_trait_ref<'tcx>( + tcx: TyCtxt<'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(tcx), + } +} + +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(tcx, 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<ty::PolyTraitRef<'tcx>> { + 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::Fn { + 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<N>( + tcx: TyCtxt<'tcx>, + object: &super::ImplSourceObjectData<'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, as those aren't stored in the vtable. + 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::Fn); + return entries; + } + if trait_item.kind == ty::AssocKind::Fn { + 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_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { + assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final() +} + +pub enum TupleArgumentsFlag { + Yes, + No, +} diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs new file mode 100644 index 00000000000..0ac3c6ffe62 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -0,0 +1,710 @@ +use crate::infer::InferCtxt; +use crate::opaque_types::required_region_bounds; +use crate::traits; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; +use rustc_span::Span; +use std::rc::Rc; + +/// Returns the set of obligations needed to make `arg` well-formed. +/// If `arg` contains unresolved inference variables, this may include +/// further WF obligations. However, if `arg` IS an unresolved +/// inference variable, returns `None`, because we are not able to +/// make any progress at all. This is to prevent "livelock" where we +/// say "$0 is WF if $0 is WF". +pub fn obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + arg: GenericArg<'tcx>, + span: Span, +) -> Option<Vec<traits::PredicateObligation<'tcx>>> { + // Handle the "livelock" case (see comment above) by bailing out if necessary. + let arg = match arg.unpack() { + GenericArgKind::Type(ty) => { + match ty.kind { + ty::Infer(ty::TyVar(_)) => { + let resolved_ty = infcx.shallow_resolve(ty); + if resolved_ty == ty { + // No progress, bail out to prevent "livelock". + return None; + } + + resolved_ty + } + _ => ty, + } + .into() + } + GenericArgKind::Const(ct) => { + match ct.val { + ty::ConstKind::Infer(infer) => { + let resolved = infcx.shallow_resolve(infer); + if resolved == infer { + // No progress. + return None; + } + + infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty }) + } + _ => ct, + } + .into() + } + // There is nothing we have to do for lifetimes. + GenericArgKind::Lifetime(..) => return Some(Vec::new()), + }; + + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; + wf.compute(arg); + debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); + + let result = wf.normalize(); + debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result); + Some(result) +} + +/// Returns the obligations that make this trait reference +/// well-formed. For example, if there is a trait `Set` defined like +/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF +/// if `Bar: Eq`. +pub fn trait_obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + trait_ref: &ty::TraitRef<'tcx>, + span: Span, + item: Option<&'tcx hir::Item<'tcx>>, +) -> Vec<traits::PredicateObligation<'tcx>> { + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item }; + wf.compute_trait_ref(trait_ref, Elaborate::All); + wf.normalize() +} + +pub fn predicate_obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + predicate: ty::Predicate<'tcx>, + span: Span, +) -> Vec<traits::PredicateObligation<'tcx>> { + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; + + // It's ok to skip the binder here because wf code is prepared for it + match predicate.skip_binders() { + ty::PredicateAtom::Trait(t, _) => { + wf.compute_trait_ref(&t.trait_ref, Elaborate::None); + } + ty::PredicateAtom::RegionOutlives(..) => {} + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { + wf.compute(ty.into()); + } + ty::PredicateAtom::Projection(t) => { + wf.compute_projection(t.projection_ty); + wf.compute(t.ty.into()); + } + ty::PredicateAtom::WellFormed(arg) => { + wf.compute(arg); + } + ty::PredicateAtom::ObjectSafe(_) => {} + ty::PredicateAtom::ClosureKind(..) => {} + ty::PredicateAtom::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { + wf.compute(a.into()); + wf.compute(b.into()); + } + ty::PredicateAtom::ConstEvaluatable(def, substs) => { + let obligations = wf.nominal_obligations(def.did, substs); + wf.out.extend(obligations); + + for arg in substs.iter() { + wf.compute(arg); + } + } + ty::PredicateAtom::ConstEquate(c1, c2) => { + wf.compute(c1.into()); + wf.compute(c2.into()); + } + } + + wf.normalize() +} + +struct WfPredicates<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + span: Span, + out: Vec<traits::PredicateObligation<'tcx>>, + item: Option<&'tcx hir::Item<'tcx>>, +} + +/// Controls whether we "elaborate" supertraits and so forth on the WF +/// predicates. This is a kind of hack to address #43784. The +/// underlying problem in that issue was a trait structure like: +/// +/// ``` +/// trait Foo: Copy { } +/// trait Bar: Foo { } +/// impl<T: Bar> Foo for T { } +/// impl<T> Bar for T { } +/// ``` +/// +/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but +/// we decide that this is true because `T: Bar` is in the +/// where-clauses (and we can elaborate that to include `T: +/// Copy`). This wouldn't be a problem, except that when we check the +/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` +/// impl. And so nowhere did we check that `T: Copy` holds! +/// +/// To resolve this, we elaborate the WF requirements that must be +/// proven when checking impls. This means that (e.g.) the `impl Bar +/// for T` will be forced to prove not only that `T: Foo` but also `T: +/// Copy` (which it won't be able to do, because there is no `Copy` +/// impl for `T`). +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +enum Elaborate { + All, + None, +} + +fn extend_cause_with_original_assoc_item_obligation<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + item: Option<&hir::Item<'tcx>>, + cause: &mut traits::ObligationCause<'tcx>, + pred: &ty::Predicate<'tcx>, + mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>, +) { + debug!( + "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", + trait_ref, item, cause, pred + ); + let items = match item { + Some(hir::Item { kind: hir::ItemKind::Impl { items, .. }, .. }) => items, + _ => return, + }; + let fix_span = + |impl_item_ref: &hir::ImplItemRef<'_>| match tcx.hir().impl_item(impl_item_ref.id).kind { + hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span, + _ => impl_item_ref.span, + }; + + // It is fine to skip the binder as we don't care about regions here. + match pred.skip_binders() { + ty::PredicateAtom::Projection(proj) => { + // The obligation comes not from the current `impl` nor the `trait` being implemented, + // but rather from a "second order" obligation, where an associated type has a + // projection coming from another associated type. See + // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and + // `traits-assoc-type-in-supertrait-bad.rs`. + if let ty::Projection(projection_ty) = proj.ty.kind { + let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); + if let Some(impl_item_span) = + items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) + { + cause.make_mut().span = impl_item_span; + } + } + } + ty::PredicateAtom::Trait(pred, _) => { + // An associated item obligation born out of the `trait` failed to be met. An example + // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. + debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); + if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = pred.self_ty().kind { + if let Some(impl_item_span) = trait_assoc_items + .find(|i| i.def_id == item_def_id) + .and_then(|trait_assoc_item| { + items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span) + }) + { + cause.make_mut().span = impl_item_span; + } + } + } + _ => {} + } +} + +impl<'a, 'tcx> WfPredicates<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + traits::ObligationCause::new(self.span, self.body_id, code) + } + + fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> { + let cause = self.cause(traits::MiscObligation); + let infcx = &mut self.infcx; + let param_env = self.param_env; + let mut obligations = Vec::with_capacity(self.out.len()); + for pred in &self.out { + assert!(!pred.has_escaping_bound_vars()); + let mut selcx = traits::SelectionContext::new(infcx); + let i = obligations.len(); + let value = + traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations); + obligations.insert(i, value); + } + obligations + } + + /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. + fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { + let tcx = self.infcx.tcx; + let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); + + debug!("compute_trait_ref obligations {:?}", obligations); + let cause = self.cause(traits::MiscObligation); + let param_env = self.param_env; + + let item = self.item; + + let extend = |obligation: traits::PredicateObligation<'tcx>| { + let mut cause = cause.clone(); + if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() { + let derived_cause = traits::DerivedObligationCause { + parent_trait_ref, + parent_code: Rc::new(obligation.cause.code.clone()), + }; + cause.make_mut().code = + traits::ObligationCauseCode::DerivedObligation(derived_cause); + } + extend_cause_with_original_assoc_item_obligation( + tcx, + trait_ref, + item, + &mut cause, + &obligation.predicate, + tcx.associated_items(trait_ref.def_id).in_definition_order(), + ); + traits::Obligation::new(cause, param_env, obligation.predicate) + }; + + if let Elaborate::All = elaborate { + let implied_obligations = traits::util::elaborate_obligations(tcx, obligations); + let implied_obligations = implied_obligations.map(extend); + self.out.extend(implied_obligations); + } else { + self.out.extend(obligations); + } + + let tcx = self.tcx(); + self.out.extend( + trait_ref + .substs + .iter() + .enumerate() + .filter(|(_, arg)| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) + .filter(|(_, arg)| !arg.has_escaping_bound_vars()) + .map(|(i, arg)| { + let mut new_cause = cause.clone(); + // The first subst is the self ty - use the correct span for it. + if i == 0 { + if let Some(hir::ItemKind::Impl { self_ty, .. }) = item.map(|i| &i.kind) { + new_cause.make_mut().span = self_ty.span; + } + } + traits::Obligation::new( + new_cause, + param_env, + ty::PredicateAtom::WellFormed(arg).to_predicate(tcx), + ) + }), + ); + } + + /// Pushes the obligations required for `trait_ref::Item` to be WF + /// into `self.out`. + fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { + // A projection is well-formed if (a) the trait ref itself is + // WF and (b) the trait-ref holds. (It may also be + // normalizable and be WF that way.) + let trait_ref = data.trait_ref(self.infcx.tcx); + self.compute_trait_ref(&trait_ref, Elaborate::None); + + if !data.has_escaping_bound_vars() { + let predicate = trait_ref.without_const().to_predicate(self.infcx.tcx); + let cause = self.cause(traits::ProjectionWf(data)); + self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); + } + } + + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { + if !subty.has_escaping_bound_vars() { + let cause = self.cause(cause); + let trait_ref = ty::TraitRef { + def_id: self.infcx.tcx.require_lang_item(LangItem::Sized, None), + substs: self.infcx.tcx.mk_substs_trait(subty, &[]), + }; + self.out.push(traits::Obligation::new( + cause, + self.param_env, + trait_ref.without_const().to_predicate(self.infcx.tcx), + )); + } + } + + /// Pushes all the predicates needed to validate that `ty` is WF into `out`. + fn compute(&mut self, arg: GenericArg<'tcx>) { + let mut walker = arg.walk(); + let param_env = self.param_env; + while let Some(arg) = walker.next() { + let ty = match arg.unpack() { + GenericArgKind::Type(ty) => ty, + + // No WF constraints for lifetimes being present, any outlives + // obligations are handled by the parent (e.g. `ty::Ref`). + GenericArgKind::Lifetime(_) => continue, + + GenericArgKind::Const(constant) => { + match constant.val { + ty::ConstKind::Unevaluated(def, substs, promoted) => { + assert!(promoted.is_none()); + + let obligations = self.nominal_obligations(def.did, substs); + self.out.extend(obligations); + + let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs) + .to_predicate(self.tcx()); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + predicate, + )); + } + ty::ConstKind::Infer(infer) => { + let resolved = self.infcx.shallow_resolve(infer); + // the `InferConst` changed, meaning that we made progress. + if resolved != infer { + let cause = self.cause(traits::MiscObligation); + + let resolved_constant = self.infcx.tcx.mk_const(ty::Const { + val: ty::ConstKind::Infer(resolved), + ..*constant + }); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateAtom::WellFormed(resolved_constant.into()) + .to_predicate(self.tcx()), + )); + } + } + ty::ConstKind::Error(_) + | ty::ConstKind::Param(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Placeholder(..) => { + // These variants are trivially WF, so nothing to do here. + } + ty::ConstKind::Value(..) => { + // FIXME: Enforce that values are structurally-matchable. + } + } + continue; + } + }; + + match ty.kind { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Error(_) + | ty::Str + | ty::GeneratorWitness(..) + | ty::Never + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Foreign(..) => { + // WfScalar, WfParameter, etc + } + + // Can only infer to `ty::Int(_) | ty::Uint(_)`. + ty::Infer(ty::IntVar(_)) => {} + + // Can only infer to `ty::Float(_)`. + ty::Infer(ty::FloatVar(_)) => {} + + ty::Slice(subty) => { + self.require_sized(subty, traits::SliceOrArrayElem); + } + + ty::Array(subty, _) => { + self.require_sized(subty, traits::SliceOrArrayElem); + // Note that we handle the len is implicitly checked while walking `arg`. + } + + ty::Tuple(ref tys) => { + if let Some((_last, rest)) = tys.split_last() { + for elem in rest { + self.require_sized(elem.expect_ty(), traits::TupleElem); + } + } + } + + ty::RawPtr(_) => { + // Simple cases that are WF if their type args are WF. + } + + ty::Projection(data) => { + walker.skip_current_subtree(); // Subtree handled by compute_projection. + self.compute_projection(data); + } + + ty::Adt(def, substs) => { + // WfNominalType + let obligations = self.nominal_obligations(def.did, substs); + self.out.extend(obligations); + } + + ty::FnDef(did, substs) => { + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } + + ty::Ref(r, rty, _) => { + // WfReference + if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { + let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + self.out.push(traits::Obligation::new( + cause, + param_env, + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(rty, r)) + .to_predicate(self.tcx()), + )); + } + } + + ty::Generator(..) => { + // Walk ALL the types in the generator: this will + // include the upvar types as well as the yield + // type. Note that this is mildly distinct from + // the closure case, where we have to be careful + // about the signature of the closure. We don't + // have the problem of implied bounds here since + // generators don't take arguments. + } + + ty::Closure(_, substs) => { + // Only check the upvar types for WF, not the rest + // of the types within. This is needed because we + // capture the signature and it may not be WF + // without the implied bounds. Consider a closure + // like `|x: &'a T|` -- it may be that `T: 'a` is + // not known to hold in the creator's context (and + // indeed the closure may not be invoked by its + // creator, but rather turned to someone who *can* + // verify that). + // + // The special treatment of closures here really + // ought not to be necessary either; the problem + // is related to #25860 -- there is no way for us + // to express a fn type complete with the implied + // bounds that it is assuming. I think in reality + // the WF rules around fn are a bit messed up, and + // that is the rot problem: `fn(&'a T)` should + // probably always be WF, because it should be + // shorthand for something like `where(T: 'a) { + // fn(&'a T) }`, as discussed in #25860. + // + // Note that we are also skipping the generic + // types. This is consistent with the `outlives` + // code, but anyway doesn't matter: within the fn + // body where they are created, the generics will + // always be WF, and outside of that fn body we + // are not directly inspecting closure types + // anyway, except via auto trait matching (which + // only inspects the upvar types). + walker.skip_current_subtree(); // subtree handled below + for upvar_ty in substs.as_closure().upvar_tys() { + // FIXME(eddyb) add the type to `walker` instead of recursing. + self.compute(upvar_ty.into()); + } + } + + ty::FnPtr(_) => { + // let the loop iterate into the argument/return + // types appearing in the fn signature + } + + ty::Opaque(did, substs) => { + // all of the requirements on type parameters + // should've been checked by the instantiation + // of whatever returned this exact `impl Trait`. + + // for named opaque `impl Trait` types we still need to check them + if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() { + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } + } + + ty::Dynamic(data, r) => { + // WfObject + // + // Here, we defer WF checking due to higher-ranked + // regions. This is perhaps not ideal. + self.from_object_ty(ty, data, r); + + // FIXME(#27579) RFC also considers adding trait + // obligations that don't refer to Self and + // checking those + + let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; + + if !defer_to_coercion { + let cause = self.cause(traits::MiscObligation); + let component_traits = data.auto_traits().chain(data.principal_def_id()); + let tcx = self.tcx(); + self.out.extend(component_traits.map(|did| { + traits::Obligation::new( + cause.clone(), + param_env, + ty::PredicateAtom::ObjectSafe(did).to_predicate(tcx), + ) + })); + } + } + + // Inference variables are the complicated case, since we don't + // know what type they are. We do two things: + // + // 1. Check if they have been resolved, and if so proceed with + // THAT type. + // 2. If not, we've at least simplified things (e.g., we went + // from `Vec<$0>: WF` to `$0: WF`), so we can + // register a pending obligation and keep + // moving. (Goal is that an "inductive hypothesis" + // is satisfied to ensure termination.) + // See also the comment on `fn obligations`, describing "livelock" + // prevention, which happens before this can be reached. + ty::Infer(_) => { + let ty = self.infcx.shallow_resolve(ty); + if let ty::Infer(ty::TyVar(_)) = ty.kind { + // Not yet resolved, but we've made progress. + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new( + cause, + param_env, + ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()), + )); + } else { + // Yes, resolved, proceed with the result. + // FIXME(eddyb) add the type to `walker` instead of recursing. + self.compute(ty.into()); + } + } + } + } + } + + fn nominal_obligations( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec<traits::PredicateObligation<'tcx>> { + let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); + predicates + .predicates + .into_iter() + .zip(predicates.spans.into_iter()) + .map(|(pred, span)| { + let cause = self.cause(traits::BindingObligation(def_id, span)); + traits::Obligation::new(cause, self.param_env, pred) + }) + .filter(|pred| !pred.has_escaping_bound_vars()) + .collect() + } + + fn from_object_ty( + &mut self, + ty: Ty<'tcx>, + data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, + region: ty::Region<'tcx>, + ) { + // Imagine a type like this: + // + // trait Foo { } + // trait Bar<'c> : 'c { } + // + // &'b (Foo+'c+Bar<'d>) + // ^ + // + // In this case, the following relationships must hold: + // + // 'b <= 'c + // 'd <= 'c + // + // The first conditions is due to the normal region pointer + // rules, which say that a reference cannot outlive its + // referent. + // + // The final condition may be a bit surprising. In particular, + // you may expect that it would have been `'c <= 'd`, since + // usually lifetimes of outer things are conservative + // approximations for inner things. However, it works somewhat + // differently with trait objects: here the idea is that if the + // user specifies a region bound (`'c`, in this case) it is the + // "master bound" that *implies* that bounds from other traits are + // all met. (Remember that *all bounds* in a type like + // `Foo+Bar+Zed` must be met, not just one, hence if we write + // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and + // 'y.) + // + // Note: in fact we only permit builtin traits, not `Bar<'d>`, I + // am looking forward to the future here. + if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { + let implicit_bounds = object_region_bounds(self.infcx.tcx, data); + + let explicit_bound = region; + + self.out.reserve(implicit_bounds.len()); + for implicit_bound in implicit_bounds { + let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); + let outlives = + ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound)); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + outlives.to_predicate(self.infcx.tcx), + )); + } + } + } +} + +/// Given an object type like `SomeTrait + Send`, computes the lifetime +/// bounds that must hold on the elided self type. These are derived +/// from the declarations of `SomeTrait`, `Send`, and friends -- if +/// they declare `trait SomeTrait : 'static`, for example, then +/// `'static` would appear in the list. The hard work is done by +/// `infer::required_region_bounds`, see that for more information. +pub fn object_region_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, +) -> Vec<ty::Region<'tcx>> { + // Since we don't actually *know* the self type for an object, + // this "open(err)" serves as a kind of dummy standin -- basically + // a placeholder type. + let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); + + let predicates = existential_predicates.iter().filter_map(|predicate| { + if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() { + None + } else { + Some(predicate.with_self_ty(tcx, open_ty)) + } + }); + + required_region_bounds(tcx, open_ty, predicates) +} |
