From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_trait_selection/src/autoderef.rs | 240 ++ compiler/rustc_trait_selection/src/infer.rs | 177 ++ compiler/rustc_trait_selection/src/lib.rs | 40 + .../rustc_trait_selection/src/traits/auto_trait.rs | 903 ++++++ .../src/traits/chalk_fulfill.rs | 163 + .../rustc_trait_selection/src/traits/codegen.rs | 80 + .../rustc_trait_selection/src/traits/coherence.rs | 747 +++++ .../src/traits/const_evaluatable.rs | 308 ++ .../rustc_trait_selection/src/traits/engine.rs | 112 + .../src/traits/error_reporting/mod.rs | 2765 +++++++++++++++++ .../src/traits/error_reporting/on_unimplemented.rs | 272 ++ .../src/traits/error_reporting/suggestions.rs | 3119 ++++++++++++++++++++ .../rustc_trait_selection/src/traits/fulfill.rs | 757 +++++ compiler/rustc_trait_selection/src/traits/misc.rs | 88 + compiler/rustc_trait_selection/src/traits/mod.rs | 863 ++++++ .../src/traits/object_safety.rs | 866 ++++++ .../src/traits/on_unimplemented.rs | 425 +++ .../rustc_trait_selection/src/traits/project.rs | 2150 ++++++++++++++ .../src/traits/query/dropck_outlives.rs | 73 + .../src/traits/query/evaluate_obligation.rs | 118 + .../src/traits/query/method_autoderef.rs | 3 + .../rustc_trait_selection/src/traits/query/mod.rs | 14 + .../src/traits/query/normalize.rs | 354 +++ .../src/traits/query/type_op/ascribe_user_type.rs | 23 + .../src/traits/query/type_op/custom.rs | 117 + .../src/traits/query/type_op/eq.rs | 23 + .../query/type_op/implied_outlives_bounds.rs | 42 + .../src/traits/query/type_op/mod.rs | 168 ++ .../src/traits/query/type_op/normalize.rs | 68 + .../src/traits/query/type_op/outlives.rs | 55 + .../src/traits/query/type_op/prove_predicate.rs | 43 + .../src/traits/query/type_op/subtype.rs | 20 + .../src/traits/relationships.rs | 58 + .../src/traits/select/candidate_assembly.rs | 1009 +++++++ .../src/traits/select/confirmation.rs | 1266 ++++++++ .../rustc_trait_selection/src/traits/select/mod.rs | 2698 +++++++++++++++++ .../src/traits/specialize/mod.rs | 531 ++++ .../src/traits/specialize/specialization_graph.rs | 395 +++ .../src/traits/structural_match.rs | 273 ++ compiler/rustc_trait_selection/src/traits/util.rs | 368 +++ compiler/rustc_trait_selection/src/traits/wf.rs | 888 ++++++ 41 files changed, 22682 insertions(+) create mode 100644 compiler/rustc_trait_selection/src/autoderef.rs create mode 100644 compiler/rustc_trait_selection/src/infer.rs create mode 100644 compiler/rustc_trait_selection/src/lib.rs create mode 100644 compiler/rustc_trait_selection/src/traits/auto_trait.rs create mode 100644 compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs create mode 100644 compiler/rustc_trait_selection/src/traits/codegen.rs create mode 100644 compiler/rustc_trait_selection/src/traits/coherence.rs create mode 100644 compiler/rustc_trait_selection/src/traits/const_evaluatable.rs create mode 100644 compiler/rustc_trait_selection/src/traits/engine.rs create mode 100644 compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs create mode 100644 compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs create mode 100644 compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs create mode 100644 compiler/rustc_trait_selection/src/traits/fulfill.rs create mode 100644 compiler/rustc_trait_selection/src/traits/misc.rs create mode 100644 compiler/rustc_trait_selection/src/traits/mod.rs create mode 100644 compiler/rustc_trait_selection/src/traits/object_safety.rs create mode 100644 compiler/rustc_trait_selection/src/traits/on_unimplemented.rs create mode 100644 compiler/rustc_trait_selection/src/traits/project.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/mod.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/normalize.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs create mode 100644 compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs create mode 100644 compiler/rustc_trait_selection/src/traits/relationships.rs create mode 100644 compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs create mode 100644 compiler/rustc_trait_selection/src/traits/select/confirmation.rs create mode 100644 compiler/rustc_trait_selection/src/traits/select/mod.rs create mode 100644 compiler/rustc_trait_selection/src/traits/specialize/mod.rs create mode 100644 compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs create mode 100644 compiler/rustc_trait_selection/src/traits/structural_match.rs create mode 100644 compiler/rustc_trait_selection/src/traits/util.rs create mode 100644 compiler/rustc_trait_selection/src/traits/wf.rs (limited to 'compiler/rustc_trait_selection/src') diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs new file mode 100644 index 000000000..8b7e8984a --- /dev/null +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -0,0 +1,240 @@ +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}; +use rustc_middle::ty::{ToPredicate, TypeVisitable}; +use rustc_session::Limit; +use rustc_span::def_id::LOCAL_CRATE; +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>, +} + +pub struct Autoderef<'a, 'tcx> { + // Meta infos: + infcx: &'a InferCtxt<'a, 'tcx>, + span: Span, + overloaded_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 { + 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.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>, + overloaded_span: Span, + ) -> Autoderef<'a, 'tcx> { + Autoderef { + infcx, + span, + overloaded_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> { + debug!("overloaded_deref_ty({:?})", ty); + + let tcx = self.infcx.tcx; + + // + 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, + ty::Binder::dummy(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 { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, + cause, + ); + let errors = fulfillcx.select_where_possible(&self.infcx); + if !errors.is_empty() { + // 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", errors); + 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> { + self.state.obligations + } + + pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] { + &self.state.steps + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn overloaded_span(&self) -> Span { + self.overloaded_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 = match tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; + 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 increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + suggested_limit, + tcx.crate_name(LOCAL_CRATE), + )) + .emit(); +} diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs new file mode 100644 index 000000000..9d30374f8 --- /dev/null +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -0,0 +1,177 @@ +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use crate::traits::{self, TraitEngine, TraitEngineExt}; + +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +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::subst::SubstsRef; +use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable}; +use rustc_span::{Span, DUMMY_SP}; + +use std::fmt::Debug; + +pub use rustc_infer::infer::*; + +pub trait InferCtxtExt<'tcx> { + fn type_is_copy_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool; + + fn partially_normalize_associated_types_in( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>; + + /// Check whether a `ty` implements given trait(trait_def_id). + /// The inputs are: + /// + /// - the def-id of the trait + /// - the self type + /// - the *other* type parameters of the trait, excluding the self-type + /// - the parameter environment + /// + /// Invokes `evaluate_obligation`, so in the event that evaluating + /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown) + /// will be returned. + fn type_implements_trait( + &self, + trait_def_id: DefId, + ty: Ty<'tcx>, + params: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> traits::EvaluationResult; +} +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( + &self, + cause: ObligationCause<'tcx>, + 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 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 } + } + + fn type_implements_trait( + &self, + trait_def_id: DefId, + ty: Ty<'tcx>, + params: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> traits::EvaluationResult { + 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: self.tcx.mk_substs_trait(ty, params) }; + + let obligation = traits::Obligation { + cause: traits::ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx), + }; + self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) + } +} + +pub trait InferCtxtBuilderExt<'tcx> { + fn enter_canonical_trait_query( + &mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, + ) -> Fallible> + where + K: TypeFoldable<'tcx>, + R: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'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( + &mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, + ) -> Fallible> + where + K: TypeFoldable<'tcx>, + R: Debug + TypeFoldable<'tcx>, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, + { + self.enter_with_canonical( + DUMMY_SP, + canonical_key, + |ref infcx, key, canonical_inference_vars| { + let mut fulfill_cx = >::new(infcx.tcx); + let value = operation(infcx, &mut *fulfill_cx, key)?; + infcx.make_canonicalized_query_response( + canonical_inference_vars, + value, + &mut *fulfill_cx, + ) + }, + ) + } +} diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs new file mode 100644 index 000000000..282ee632c --- /dev/null +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -0,0 +1,40 @@ +//! This crate 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. + +#![allow(rustc::potential_query_instability)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(box_patterns)] +#![feature(control_flow_enum)] +#![feature(drain_filter)] +#![feature(hash_drain_filter)] +#![feature(label_break_value)] +#![feature(let_chains)] +#![feature(let_else)] +#![feature(if_let_guard)] +#![feature(never_type)] +#![recursion_limit = "512"] // For rustdoc + +#[macro_use] +extern crate rustc_macros; +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[macro_use] +extern crate rustc_data_structures; +#[macro_use] +extern crate tracing; +#[macro_use] +extern crate rustc_middle; +#[macro_use] +extern crate smallvec; + +pub mod autoderef; +pub mod infer; +pub mod traits; 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 000000000..294c81d0b --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -0,0 +1,903 @@ +//! 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 crate::traits::project::ProjectAndUnifyResult; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::{Region, RegionVid, Term}; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + +use std::collections::hash_map::Entry; +use std::collections::VecDeque; +use std::iter; + +// 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>, + smaller: FxHashSet>, +} + +pub enum AutoTraitResult { + ExplicitImpl, + PositiveImpl(A), + NegativeImpl, +} + +#[allow(dead_code)] +impl AutoTraitResult { + fn is_auto(&self) -> bool { + matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl) + } +} + +pub struct AutoTraitInfo<'cx> { + pub full_user_env: ty::ParamEnv<'cx>, + pub region_data: RegionConstraintData<'cx>, + pub vid_to_region: FxHashMap>, +} + +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 { data: Box } + /// ``` + /// + /// then this might return that Foo: 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: Send if Box: 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( + &self, + ty: Ty<'tcx>, + orig_env: ty::ParamEnv<'tcx>, + trait_did: DefId, + mut auto_trait_callback: impl FnMut(AutoTraitInfo<'tcx>) -> A, + ) -> AutoTraitResult { + let tcx = self.tcx; + + let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]) }; + + let trait_pred = ty::Binder::dummy(trait_ref); + + let bail_out = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + let result = selcx.select(&Obligation::new( + ObligationCause::dummy(), + orig_env, + trait_pred.to_poly_trait_predicate(), + )); + + match result { + Ok(Some(ImplSource::UserDefined(_))) => { + debug!( + "find_auto_trait_generics({:?}): \ + manual impl found, bailing out", + trait_ref + ); + return true; + } + _ => {} + } + + let result = selcx.select(&Obligation::new( + ObligationCause::dummy(), + orig_env, + trait_pred.to_poly_trait_predicate_negative_polarity(), + )); + + match result { + Ok(Some(ImplSource::UserDefined(_))) => { + 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 + // fn() { Vec }. This information will generally never change - given + // the 'T' in fn() { ... }, 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 '::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 '::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 Some((new_env, user_env)) = self.evaluate_predicates( + &infcx, + trait_did, + ty, + orig_env, + orig_env, + &mut fresh_preds, + false, + ) else { + 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 = >::new(tcx); + fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); + let errors = fulfill.select_all_or_error(&infcx); + + if !errors.is_empty() { + panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); + } + + infcx.process_registered_region_obligations(&Default::default(), 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(info)) + }) + } +} + +impl<'tcx> 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: + /// ```ignore (illustrative) + /// impl Send for Foo 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`, 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>, + only_projections: bool, + ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> { + let tcx = infcx.tcx; + + // Don't try to process 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::new(&infcx); + + let mut already_visited = FxHashSet::default(); + let mut predicates = VecDeque::new(); + predicates.push_back(ty::Binder::dummy(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_did, + substs: infcx.tcx.mk_substs_trait(ty, &[]), + }, + constness: ty::BoundConstness::NotConst, + // Auto traits are positive + polarity: ty::ImplPolarity::Positive, + })); + + 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::UserDefined(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.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(), + param_env.constness(), + ); + } + + let final_user_env = ty::ParamEnv::new( + tcx.mk_predicates(user_computed_preds.into_iter()), + user_env.reveal(), + user_env.constness(), + ); + 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: + /// ```ignore (illustrative) + /// 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>, + new_pred: ty::Predicate<'tcx>, + ) { + let mut should_add_new = true; + user_computed_preds.retain(|&old_pred| { + if let (ty::PredicateKind::Trait(new_trait), ty::PredicateKind::Trait(old_trait)) = + (new_pred.kind().skip_binder(), old_pred.kind().skip_binder()) + { + 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 + iter::zip(new_substs.regions(), old_substs.regions()) + { + match (*new_region, *old_region) { + // If both predicates have an `ReLateBound` (a HRTB) in the + // same spot, we do nothing. + (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {} + + (ty::ReLateBound(_, _), _) | (_, ty::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::ReLateBound(_, _)) | (ty::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> { + let mut vid_map: FxHashMap, 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 { + if let Term::Ty(ty) = p.term().skip_binder() { + matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty) + } else { + false + } + } + + fn evaluate_nested_obligations( + &self, + ty: Ty<'_>, + nested: impl Iterator>>, + computed_preds: &mut FxHashSet>, + fresh_preds: &mut FxHashSet>, + predicates: &mut VecDeque>, + 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 + + let bound_predicate = predicate.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(p) => { + // Add this to `predicates` so that we end up calling `select` + // with it. If this predicate ends up being unimplemented, + // then `evaluate_predicates` will handle adding it the `ParamEnv` + // if possible. + predicates.push_back(bound_predicate.rebind(p)); + } + ty::PredicateKind::Projection(p) => { + let p = bound_predicate.rebind(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.term().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-referential + // projection predicate. For example: + // ::Value == ::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)) { + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { + debug!( + "evaluate_nested_obligations: Unable to unify predicate \ + '{:?}' '{:?}', bailing out", + ty, e + ); + return false; + } + ProjectAndUnifyResult::Recursive => { + debug!("evaluate_nested_obligations: recursive projection predicate"); + return false; + } + ProjectAndUnifyResult::Holds(v) => { + // We only care about sub-obligations + // when we started out trying to unify + // some inference variables. See the comment above + // for more information + if p.term().skip_binder().has_infer_types() { + if !self.evaluate_nested_obligations( + ty, + v.into_iter(), + computed_preds, + fresh_preds, + predicates, + select, + only_projections, + ) { + return false; + } + } + } + ProjectAndUnifyResult::FailedNormalization => { + // It's ok not to make progress when have no inference variables - + // in that case, we were only performing unification 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.term().skip_binder().has_infer_types() { + panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) + } + } + } + } + ty::PredicateKind::RegionOutlives(binder) => { + let binder = bound_predicate.rebind(binder); + select.infcx().region_outlives_predicate(&dummy_cause, binder) + } + ty::PredicateKind::TypeOutlives(binder) => { + let binder = bound_predicate.rebind(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::PredicateKind::ConstEquate(c1, c2) => { + let evaluate = |c: ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { + match select.infcx().const_eval_resolve( + obligation.param_env, + unevaluated, + Some(obligation.cause.span), + ) { + Ok(Some(valtree)) => { + Ok(ty::Const::from_value(select.tcx(), valtree, c.ty())) + } + Ok(None) => { + let tcx = self.tcx; + let def_id = unevaluated.def.did; + let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit(); + + Err(ErrorHandled::Reported(reported)) + } + 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, + } + } + // There's not really much we can do with these predicates - + // we start out with a `ParamEnv` with no inference variables, + // and these don't correspond to adding any new bounds to + // the `ParamEnv`. + ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} + }; + } + 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>, + 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 000000000..9ef7ac9a8 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -0,0 +1,163 @@ +//! Defines a Chalk-based `TraitEngine` + +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::query::NoSolution; +use crate::traits::{ + ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, + PredicateObligation, SelectionError, TraitEngine, +}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; + +pub struct FulfillmentContext<'tcx> { + obligations: FxIndexSet>, + + relationships: FxHashMap, +} + +impl FulfillmentContext<'_> { + pub(crate) fn new() -> Self { + FulfillmentContext { + obligations: FxIndexSet::default(), + relationships: FxHashMap::default(), + } + } +} + +impl<'tcx> 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); + + super::relationships::update(self, infcx, &obligation); + + self.obligations.insert(obligation); + } + + fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec> { + { + let errors = self.select_where_possible(infcx); + + if !errors.is_empty() { + return errors; + } + } + + // any remaining obligations are errors + self.obligations + .iter() + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation.clone(), + }) + .collect() + } + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Vec> { + assert!(!infcx.is_in_snapshot()); + + 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 obligation = infcx.resolve_vars_if_possible(obligation); + let environment = obligation.param_env.caller_bounds(); + let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; + let mut orig_values = OriginalQueryValues::default(); + if goal.references_error() { + continue; + } + + let canonical_goal = + infcx.canonicalize_query_preserving_universes(goal, &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: obligation.clone(), + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation, + }), + } + } else { + // Ambiguous: retry at next round. + next_round.insert(obligation); + } + } + + Err(NoSolution) => errors.push(FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation, + }), + } + } + next_round = std::mem::replace(&mut self.obligations, next_round); + + if !making_progress { + break; + } + } + + errors + } + + fn pending_obligations(&self) -> Vec> { + self.obligations.iter().cloned().collect() + } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } +} diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs new file mode 100644 index 000000000..c0700748c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -0,0 +1,80 @@ +// 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::{DefiningAnchor, TyCtxtInferExt}; +use crate::traits::{ + ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, + Unimplemented, +}; +use rustc_middle::traits::CodegenObligationError; +use rustc_middle::ty::{self, TyCtxt}; + +/// Attempts to resolve an obligation to an `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. +/// +/// This also expects that `trait_ref` is fully normalized. +#[instrument(level = "debug", skip(tcx))] +pub fn codegen_fulfill_obligation<'tcx>( + tcx: TyCtxt<'tcx>, + (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), +) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { + // We expect the input to be fully normalized. + debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let mut infcx_builder = + tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); + infcx_builder.enter(|infcx| { + //~^ HACK `Bubble` is required for + // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs + 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) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) + } + }; + + debug!(?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 = >::new(tcx); + let impl_source = selection.map(|predicate| { + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + return Err(CodegenObligationError::FulfillmentError); + } + + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); + + // Opaque types may have gotten their hidden types constrained, but we can ignore them safely + // as they will get constrained elsewhere, too. + // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + debug!("Cache miss: {trait_ref:?} => {impl_source:?}"); + Ok(&*tcx.arena.alloc(impl_source)) + }) +} 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 000000000..1c8cdf4ca --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -0,0 +1,747 @@ +//! 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::outlives::env::OutlivesEnvironment; +use crate::infer::{CombinedSnapshot, InferOk}; +use crate::traits::select::IntercrateAmbiguityCause; +use crate::traits::util::impl_subject_and_oblig; +use crate::traits::SkipLeakCheck; +use crate::traits::{ + self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, + PredicateObligations, SelectionContext, TraitEngineExt, +}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::Diagnostic; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::{util, TraitEngine}; +use rustc_middle::traits::specialization_graph::OverlapMode; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor}; +use rustc_span::symbol::sym; +use rustc_span::DUMMY_SP; +use std::fmt::Debug; +use std::iter; +use std::ops::ControlFlow; + +/// 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: FxIndexSet, + + /// `true` if the overlap might've been permitted before the shift + /// to universes. + pub involves_placeholder: bool, +} + +pub fn add_placeholder_note(err: &mut Diagnostic) { + 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`. +#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")] +pub fn overlapping_impls( + tcx: TyCtxt<'_>, + impl1_def_id: DefId, + impl2_def_id: DefId, + skip_leak_check: SkipLeakCheck, + overlap_mode: OverlapMode, + on_overlap: F1, + no_overlap: F2, +) -> R +where + F1: FnOnce(OverlapResult<'_>) -> R, + F2: FnOnce() -> R, +{ + // Before doing expensive operations like entering an inference context, do + // a quick check via fast_reject to tell if the impl headers could possibly + // unify. + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }; + let impl1_ref = tcx.impl_trait_ref(impl1_def_id); + let impl2_ref = tcx.impl_trait_ref(impl2_def_id); + let may_overlap = match (impl1_ref, impl2_ref) { + (Some(a), Some(b)) => iter::zip(a.substs, b.substs) + .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)), + (None, None) => { + let self_ty1 = tcx.type_of(impl1_def_id); + let self_ty2 = tcx.type_of(impl2_def_id); + drcx.types_may_unify(self_ty1, self_ty2) + } + _ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"), + }; + + if !may_overlap { + // Some types involved are definitely different, so the impls couldn't possibly overlap. + debug!("overlapping_impls: fast_reject early-exit"); + return no_overlap(); + } + + let overlaps = tcx.infer_ctxt().enter(|infcx| { + let selcx = &mut SelectionContext::intercrate(&infcx); + overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some() + }); + + if !overlaps { + return no_overlap(); + } + + // In the case where we detect an error, run the check again, but + // this time tracking intercrate ambiguity 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, overlap_mode).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.bound_type_of(impl_def_id).subst(tcx, impl_substs), + trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.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, + impl1_def_id: DefId, + impl2_def_id: DefId, + overlap_mode: OverlapMode, +) -> Option> { + debug!( + "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})", + impl1_def_id, impl2_def_id, overlap_mode + ); + + selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { + overlap_within_probe(selcx, impl1_def_id, impl2_def_id, overlap_mode, snapshot) + }) +} + +fn overlap_within_probe<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + impl1_def_id: DefId, + impl2_def_id: DefId, + overlap_mode: OverlapMode, + snapshot: &CombinedSnapshot<'_, 'tcx>, +) -> Option> { + let infcx = selcx.infcx(); + + if overlap_mode.use_negative_impl() { + if negative_impl(selcx, impl1_def_id, impl2_def_id) + || negative_impl(selcx, impl2_def_id, impl1_def_id) + { + return None; + } + } + + // 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 impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); + let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); + + let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?; + debug!("overlap: unification check succeeded"); + + if overlap_mode.use_implicit_negative() { + if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) { + return None; + } + } + + // We disable the leak when when creating the `snapshot` by using + // `infcx.probe_maybe_disable_leak_check`. + if infcx.leak_check(true, snapshot).is_err() { + debug!("overlap: leak check failed"); + return None; + } + + let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); + debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); + + let involves_placeholder = + matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true)); + + let impl_header = selcx.infcx().resolve_vars_if_possible(impl1_header); + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) +} + +fn equate_impl_headers<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + impl1_header: &ty::ImplHeader<'tcx>, + impl2_header: &ty::ImplHeader<'tcx>, +) -> Option> { + // Do `a` and `b` unify? If not, no overlap. + debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header); + selcx + .infcx() + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .eq_impl_headers(impl1_header, impl2_header) + .map(|infer_ok| infer_ok.obligations) + .ok() +} + +/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including +/// where-clauses) If so, return false, otherwise return true, they are disjoint. +fn implicit_negative<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl1_header: &ty::ImplHeader<'tcx>, + impl2_header: ty::ImplHeader<'tcx>, + obligations: PredicateObligations<'tcx>, +) -> bool { + // There's no overlap if obligations are unsatisfiable or if the obligation negated is + // satisfied. + // + // For example, given these two impl headers: + // + // `impl<'a> From<&'a str> for Box` + // `impl From for Box where E: Error` + // + // So we have: + // + // `Box: From<&'?a str>` + // `Box: From` + // + // After equating the two headers: + // + // `Box = Box` + // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`. + // + // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't + // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because + // at some point an impl for `&'?a str: Error` could be added. + debug!( + "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})", + impl1_header, impl2_header, obligations + ); + let infcx = selcx.infcx(); + let opt_failing_obligation = impl1_header + .predicates + .iter() + .copied() + .chain(impl2_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)); + + if let Some(failing_obligation) = opt_failing_obligation { + debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); + true + } else { + false + } +} + +/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including +/// where-clauses) If so, return true, they are disjoint and false otherwise. +fn negative_impl<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + impl1_def_id: DefId, + impl2_def_id: DefId, +) -> bool { + debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); + let tcx = selcx.infcx().tcx; + + // Create an infcx, taking the predicates of impl1 as assumptions: + tcx.infer_ctxt().enter(|infcx| { + // create a parameter environment corresponding to a (placeholder) instantiation of impl1 + let impl_env = tcx.param_env(impl1_def_id); + let subject1 = match traits::fully_normalize( + &infcx, + FulfillmentContext::new(), + ObligationCause::dummy(), + impl_env, + tcx.impl_subject(impl1_def_id), + ) { + Ok(s) => s, + Err(err) => bug!("failed to fully normalize {:?}: {:?}", impl1_def_id, err), + }; + + // Attempt to prove that impl2 applies, given all of the above. + let selcx = &mut SelectionContext::new(&infcx); + let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); + let (subject2, obligations) = + impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); + + !equate(&infcx, impl_env, subject1, subject2, obligations) + }) +} + +fn equate<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + impl_env: ty::ParamEnv<'tcx>, + subject1: ImplSubject<'tcx>, + subject2: ImplSubject<'tcx>, + obligations: impl Iterator>, +) -> bool { + // do the impls unify? If not, not disjoint. + let Ok(InferOk { obligations: more_obligations, .. }) = + infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2) + else { + debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); + return true; + }; + + let selcx = &mut SelectionContext::new(&infcx); + let opt_failing_obligation = obligations + .into_iter() + .chain(more_obligations) + .find(|o| negative_impl_exists(selcx, impl_env, o)); + + if let Some(failing_obligation) = opt_failing_obligation { + debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); + false + } else { + true + } +} + +/// Try to prove that a negative impl exist for the given obligation and its super predicates. +#[instrument(level = "debug", skip(selcx))] +fn negative_impl_exists<'cx, 'tcx>( + selcx: &SelectionContext<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + o: &PredicateObligation<'tcx>, +) -> bool { + let infcx = &selcx.infcx().fork(); + + if resolve_negative_obligation(infcx, param_env, o) { + return true; + } + + // Try to prove a negative obligation exists for super predicates + for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { + if resolve_negative_obligation(infcx, param_env, &o) { + return true; + } + } + + false +} + +#[instrument(level = "debug", skip(infcx))] +fn resolve_negative_obligation<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + o: &PredicateObligation<'tcx>, +) -> bool { + let tcx = infcx.tcx; + + let Some(o) = o.flip_polarity(tcx) else { + return false; + }; + + let mut fulfillment_cx = >::new(infcx.tcx); + fulfillment_cx.register_predicate_obligation(infcx, o); + + let errors = fulfillment_cx.select_all_or_error(infcx); + + if !errors.is_empty() { + return false; + } + + // FIXME -- also add "assumed to be well formed" types into the `outlives_env` + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); + + infcx.resolve_regions(&outlives_env).is_empty() +} + +pub fn trait_ref_is_knowable<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, +) -> Option { + 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>), +} + +/// 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., `>` 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` is OK, because you can visit LocalType +/// going through `Box`, which is fundamental. +/// - similarly, `FundamentalPair, Box>` is OK for +/// the same reason. +/// - but (knowing that `Vec` is non-fundamental, and assuming it's +/// not local), `Vec` 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 Trait for Vec` is fine, as `Vec` is not fundamental. +/// - while `impl Trait for Box` 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>>` (or equivalently `Box>>`) +/// is bad, because the only local type with `T` as a subtree is +/// `LocalType`, and `Vec<->` is between it and the type parameter. +/// - similarly, `FundamentalPair, T>` is bad, because +/// the second occurrence of `T` is not a subtree of *any* local type. +/// - however, `LocalType>` is OK, because `T` is a subtree of +/// `LocalType>`, 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 +/// ```ignore (illustrative) +/// impl IntoIterator for Vec +/// impl 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 + ); + } + + let mut checker = OrphanChecker::new(tcx, in_crate); + match trait_ref.visit_with(&mut checker) { + ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), + ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => { + // Does there exist some local type after the `ParamTy`. + checker.search_first_local_ty = true; + if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) = + trait_ref.visit_with(&mut checker).break_value() + { + Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty))) + } else { + Err(OrphanCheckErr::UncoveredTy(ty, None)) + } + } + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()), + } +} + +struct OrphanChecker<'tcx> { + tcx: TyCtxt<'tcx>, + in_crate: InCrate, + in_self_ty: bool, + /// Ignore orphan check failures and exclusively search for the first + /// local type. + search_first_local_ty: bool, + non_local_tys: Vec<(Ty<'tcx>, bool)>, +} + +impl<'tcx> OrphanChecker<'tcx> { + fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self { + OrphanChecker { + tcx, + in_crate, + in_self_ty: true, + search_first_local_ty: false, + non_local_tys: Vec::new(), + } + } + + fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { + self.non_local_tys.push((t, self.in_self_ty)); + ControlFlow::CONTINUE + } + + fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { + if self.search_first_local_ty { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) + } + } + + fn def_id_is_local(&mut self, def_id: DefId) -> bool { + match self.in_crate { + InCrate::Local => def_id.is_local(), + InCrate::Remote => false, + } + } +} + +enum OrphanCheckEarlyExit<'tcx> { + ParamTy(Ty<'tcx>), + LocalTy(Ty<'tcx>), +} + +impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { + type BreakTy = OrphanCheckEarlyExit<'tcx>; + fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow { + ControlFlow::CONTINUE + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + let result = 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::Never + | ty::Tuple(..) + | ty::Projection(..) => self.found_non_local_ty(ty), + + ty::Param(..) => self.found_param_ty(ty), + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate { + InCrate::Local => self.found_non_local_ty(ty), + // The inference variable might be unified with a local + // type in that remote crate. + InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + }, + + // For fundamental types, we just look inside of them. + ty::Ref(_, ty, _) => ty.visit_with(self), + ty::Adt(def, substs) => { + if self.def_id_is_local(def.did()) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else if def.is_fundamental() { + substs.visit_with(self) + } else { + self.found_non_local_ty(ty) + } + } + ty::Foreign(def_id) => { + if self.def_id_is_local(def_id) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } + ty::Dynamic(tt, ..) => { + let principal = tt.principal().map(|p| p.def_id()); + if principal.map_or(false, |p| self.def_id_is_local(p)) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } + ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { + self.tcx.sess.delay_span_bug( + DUMMY_SP, + format!("ty_is_local invoked on closure or generator: {:?}", ty), + ); + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } + ty::Opaque(..) => { + // This merits some explanation. + // Normally, opaque types are not involved 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 + // the type of a field) when checking for auto trait or `Sized` + // impls. 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. + self.found_non_local_ty(ty) + } + }; + // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so + // the first type we visit is always the self type. + self.in_self_ty = false; + result + } + + // FIXME: Constants should participate in orphan checking. + fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs new file mode 100644 index 000000000..254bc4ab6 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -0,0 +1,308 @@ +//! Checking that constant values used in types can be successfully evaluated. +//! +//! For concrete constants, this is fairly simple as we can just try and evaluate it. +//! +//! When dealing with polymorphic constants, for example `std::mem::size_of::() - 1`, +//! this is not as easy. +//! +//! In this case we try to build an abstract representation of this constant using +//! `thir_abstract_const` which can then be checked for structural equality with other +//! generic constants mentioned in the `caller_bounds` of the current environment. +use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; +use rustc_infer::infer::InferCtxt; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::abstract_const::{ + walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable, +}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_session::lint; +use rustc_span::Span; + +use std::iter; +use std::ops::ControlFlow; + +pub struct ConstUnifyCtxt<'tcx> { + pub tcx: TyCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> ConstUnifyCtxt<'tcx> { + // Substitutes generics repeatedly to allow AbstractConsts to unify where a + // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g. + // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] + #[inline] + #[instrument(skip(self), level = "debug")] + fn try_replace_substs_in_root( + &self, + mut abstr_const: AbstractConst<'tcx>, + ) -> Option> { + while let Node::Leaf(ct) = abstr_const.root(self.tcx) { + match AbstractConst::from_const(self.tcx, ct) { + Ok(Some(act)) => abstr_const = act, + Ok(None) => break, + Err(_) => return None, + } + } + + Some(abstr_const) + } + + /// Tries to unify two abstract constants using structural equality. + #[instrument(skip(self), level = "debug")] + pub fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool { + let a = if let Some(a) = self.try_replace_substs_in_root(a) { + a + } else { + return true; + }; + + let b = if let Some(b) = self.try_replace_substs_in_root(b) { + b + } else { + return true; + }; + + let a_root = a.root(self.tcx); + let b_root = b.root(self.tcx); + debug!(?a_root, ?b_root); + + match (a_root, b_root) { + (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { + let a_ct = a_ct.eval(self.tcx, self.param_env); + debug!("a_ct evaluated: {:?}", a_ct); + let b_ct = b_ct.eval(self.tcx, self.param_env); + debug!("b_ct evaluated: {:?}", b_ct); + + if a_ct.ty() != b_ct.ty() { + return false; + } + + match (a_ct.kind(), b_ct.kind()) { + // We can just unify errors with everything to reduce the amount of + // emitted errors here. + (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, + (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { + a_param == b_param + } + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, + // If we have `fn a() -> [u8; N + 1]` and `fn b() -> [u8; 1 + M]` + // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This + // means that we only allow inference variables if they are equal. + (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, + // We expand generic anonymous constants at the start of this function, so this + // branch should only be taking when dealing with associated constants, at + // which point directly comparing them seems like the desired behavior. + // + // FIXME(generic_const_exprs): This isn't actually the case. + // We also take this branch for concrete anonymous constants and + // expand generic anonymous constants with concrete substs. + (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => { + a_uv == b_uv + } + // FIXME(generic_const_exprs): We may want to either actually try + // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like + // this, for now we just return false here. + _ => false, + } + } + (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { + self.try_unify(a.subtree(al), b.subtree(bl)) + && self.try_unify(a.subtree(ar), b.subtree(br)) + } + (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => { + self.try_unify(a.subtree(av), b.subtree(bv)) + } + (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) + if a_args.len() == b_args.len() => + { + self.try_unify(a.subtree(a_f), b.subtree(b_f)) + && iter::zip(a_args, b_args) + .all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn))) + } + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_kind == b_kind) => + { + self.try_unify(a.subtree(a_operand), b.subtree(b_operand)) + } + // use this over `_ => false` to make adding variants to `Node` less error prone + (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) + | (Node::Leaf(..), _) => false, + } + } +} + +#[instrument(skip(tcx), level = "debug")] +pub fn try_unify_abstract_consts<'tcx>( + tcx: TyCtxt<'tcx>, + (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>), + param_env: ty::ParamEnv<'tcx>, +) -> bool { + (|| { + if let Some(a) = AbstractConst::new(tcx, a)? { + if let Some(b) = AbstractConst::new(tcx, b)? { + let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env }; + return Ok(const_unify_ctxt.try_unify(a, b)); + } + } + + Ok(false) + })() + .unwrap_or_else(|_: ErrorGuaranteed| true) + // FIXME(generic_const_exprs): We should instead have this + // method return the resulting `ty::Const` and return `ConstKind::Error` + // on `ErrorGuaranteed`. +} + +/// Check if a given constant can be evaluated. +#[instrument(skip(infcx), level = "debug")] +pub fn is_const_evaluatable<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + uv: ty::Unevaluated<'tcx, ()>, + param_env: ty::ParamEnv<'tcx>, + span: Span, +) -> Result<(), NotConstEvaluatable> { + let tcx = infcx.tcx; + + if tcx.features().generic_const_exprs { + if let Some(ct) = AbstractConst::new(tcx, uv)? { + if satisfied_from_param_env(tcx, ct, param_env)? { + return Ok(()); + } + match ct.unify_failure_kind(tcx) { + FailureKind::MentionsInfer => { + return Err(NotConstEvaluatable::MentionsInfer); + } + FailureKind::MentionsParam => { + return Err(NotConstEvaluatable::MentionsParam); + } + // returned below + FailureKind::Concrete => {} + } + } + let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); + match concrete { + Err(ErrorHandled::TooGeneric) => { + Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( + span, + format!("Missing value for constant, but no error reported?"), + ))) + } + Err(ErrorHandled::Linted) => { + let reported = infcx + .tcx + .sess + .delay_span_bug(span, "constant in type had error reported as lint"); + Err(NotConstEvaluatable::Error(reported)) + } + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Ok(_) => Ok(()), + } + } else { + // FIXME: We should only try to evaluate a given constant here if it is fully concrete + // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. + // + // We previously did not check this, so we only emit a future compat warning if + // const evaluation succeeds and the given constant is still polymorphic for now + // and hopefully soon change this to an error. + // + // See #74595 for more details about this. + let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span)); + + match concrete { + // If we're evaluating a foreign constant, under a nightly compiler without generic + // const exprs, AND it would've passed if that expression had been evaluated with + // generic const exprs, then suggest using generic const exprs. + Err(_) if tcx.sess.is_nightly_build() + && let Ok(Some(ct)) = AbstractConst::new(tcx, uv) + && satisfied_from_param_env(tcx, ct, param_env) == Ok(true) => { + tcx.sess + .struct_span_fatal( + // Slightly better span than just using `span` alone + if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span }, + "failed to evaluate generic const expression", + ) + .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") + .span_suggestion_verbose( + rustc_span::DUMMY_SP, + "consider enabling this feature", + "#![feature(generic_const_exprs)]\n", + rustc_errors::Applicability::MaybeIncorrect, + ) + .emit() + } + + Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() { + NotConstEvaluatable::MentionsInfer + } else if uv.has_param_types_or_consts() { + NotConstEvaluatable::MentionsParam + } else { + let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?")); + NotConstEvaluatable::Error(guar) + }), + Err(ErrorHandled::Linted) => { + let reported = + infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint"); + Err(NotConstEvaluatable::Error(reported)) + } + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Ok(_) => { + if uv.substs.has_param_types_or_consts() { + assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst)); + let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); + + if mir_body.is_polymorphic { + let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) }; + tcx.struct_span_lint_hir( + lint::builtin::CONST_EVALUATABLE_UNCHECKED, + tcx.hir().local_def_id_to_hir_id(local_def_id), + span, + |err| { + err.build("cannot use constants which depend on generic parameters in types").emit(); + }) + } + } + + Ok(()) + }, + } + } +} + +#[instrument(skip(tcx), level = "debug")] +fn satisfied_from_param_env<'tcx>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Result { + for pred in param_env.caller_bounds() { + match pred.kind().skip_binder() { + ty::PredicateKind::ConstEvaluatable(uv) => { + if let Some(b_ct) = AbstractConst::new(tcx, uv)? { + let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env }; + + // Try to unify with each subtree in the AbstractConst to allow for + // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` + // predicate for `(N + 1) * 2` + let result = walk_abstract_const(tcx, b_ct, |b_ct| { + match const_unify_ctxt.try_unify(ct, b_ct) { + true => ControlFlow::BREAK, + false => ControlFlow::CONTINUE, + } + }); + + if let ControlFlow::Break(()) = result { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(true); + } + } + } + _ => {} // don't care + } + } + + Ok(false) +} 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 000000000..6c177f638 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -0,0 +1,112 @@ +use std::cell::RefCell; + +use super::TraitEngine; +use super::{ChalkFulfillmentContext, FulfillmentContext}; +use crate::infer::InferCtxtExt; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::traits::{ + FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, +}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub trait TraitEngineExt<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Box; +} + +impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Box { + if tcx.sess.opts.unstable_opts.chalk { + Box::new(ChalkFulfillmentContext::new()) + } else { + Box::new(FulfillmentContext::new()) + } + } +} + +/// Used if you want to have pleasant experience when dealing +/// with obligations outside of hir or mir typeck. +pub struct ObligationCtxt<'a, 'tcx> { + pub infcx: &'a InferCtxt<'a, 'tcx>, + engine: RefCell>>, +} + +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + Self { infcx, engine: RefCell::new(>::new(infcx.tcx)) } + } + + pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { + self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); + } + + pub fn register_obligations( + &self, + obligations: impl IntoIterator>, + ) { + // Can't use `register_predicate_obligations` because the iterator + // may also use this `ObligationCtxt`. + for obligation in obligations { + self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation) + } + } + + pub fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + let InferOk { value, obligations } = infer_ok; + self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations); + value + } + + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). + pub fn register_bound( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + ) { + let tcx = self.infcx.tcx; + let trait_ref = ty::TraitRef { def_id, substs: tcx.mk_substs_trait(ty, &[]) }; + self.register_obligation(Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + }); + } + + pub fn normalize>( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> T { + let infer_ok = self.infcx.partially_normalize_associated_types_in(cause, param_env, value); + self.register_infer_ok_obligations(infer_ok) + } + + pub fn equate_types( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + ) -> Result<(), TypeError<'tcx>> { + match self.infcx.at(cause, param_env).eq(expected, actual) { + Ok(InferOk { obligations, value: () }) => { + self.register_obligations(obligations); + Ok(()) + } + Err(e) => Err(e), + } + } + + pub fn select_all_or_error(&self) -> Vec> { + self.engine.borrow_mut().select_all_or_error(self.infcx) + } +} 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 000000000..e442c5c91 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -0,0 +1,2765 @@ +pub mod on_unimplemented; +pub mod suggestions; + +use super::{ + EvaluationResult, FulfillmentContext, 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, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + MultiSpan, Style, +}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; +use rustc_hir::GenericParam; +use rustc_hir::Item; +use rustc_hir::Node; +use rustc_infer::traits::TraitEngine; +use rustc_middle::traits::select::OverflowError; +use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{ + self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, + TypeVisitable, +}; +use rustc_span::symbol::{kw, sym}; +use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use std::fmt; +use std::iter; +use std::ops::ControlFlow; + +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use crate::traits::query::normalize::AtExt as _; +use crate::traits::specialize::to_pretty_impl_header; +use on_unimplemented::InferCtxtExt as _; +use suggestions::InferCtxtExt as _; + +pub use rustc_infer::traits::error_reporting::*; + +// When outputting impl candidates, prefer showing those that are more similar. +// +// We also compare candidates after skipping lifetimes, which has a lower +// priority than exact matches. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum CandidateSimilarity { + Exact { ignoring_lifetimes: bool }, + Fuzzy { ignoring_lifetimes: bool }, +} + +#[derive(Debug, Clone, Copy)] +pub struct ImplCandidate<'tcx> { + pub trait_ref: ty::TraitRef<'tcx>, + pub similarity: CandidateSimilarity, +} + +pub trait InferCtxtExt<'tcx> { + fn report_fulfillment_errors( + &self, + errors: &[FulfillmentError<'tcx>], + body_id: Option, + fallback_has_occurred: bool, + ) -> ErrorGuaranteed; + + fn report_overflow_error( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: fmt::Display + TypeFoldable<'tcx>; + + fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; + + /// The `root_obligation` parameter should be the `root_obligation` field + /// from a `FulfillmentError`. If no `FulfillmentError` is available, + /// then it should be the same as `obligation`. + fn report_selection_error( + &self, + obligation: PredicateObligation<'tcx>, + root_obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>, + fallback_has_occurred: 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)>; + + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + fn report_arg_count_mismatch( + &self, + span: Span, + found_span: Option, + expected_args: Vec, + found_args: Vec, + is_closure: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + + /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` + /// in that order, and returns the generic type corresponding to the + /// argument of that trait (corresponding to the closure arguments). + fn type_implements_fn_trait( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Binder<'tcx, Ty<'tcx>>, + constness: ty::BoundConstness, + polarity: ty::ImplPolarity, + ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>; +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { + fn report_fulfillment_errors( + &self, + errors: &[FulfillmentError<'tcx>], + body_id: Option, + fallback_has_occurred: bool, + ) -> ErrorGuaranteed { + #[derive(Debug)] + struct ErrorDescriptor<'tcx> { + predicate: ty::Predicate<'tcx>, + index: Option, // None if this is an old error + } + + let mut error_map: FxHashMap<_, Vec<_>> = self + .reported_trait_errors + .borrow() + .iter() + .map(|(&span, predicates)| { + ( + span, + predicates + .iter() + .map(|&predicate| ErrorDescriptor { predicate, index: None }) + .collect(), + ) + }) + .collect(); + + for (index, error) in errors.iter().enumerate() { + // We want to ignore desugarings here: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let mut span = error.obligation.cause.span; + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { + span = expn_data.call_site; + } + + error_map.entry(span).or_default().push(ErrorDescriptor { + predicate: error.obligation.predicate, + index: Some(index), + }); + + self.reported_trait_errors + .borrow_mut() + .entry(span) + .or_default() + .push(error.obligation.predicate); + } + + // 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 iter::zip(errors, is_suppressed) { + if !suppressed { + self.report_fulfillment_error(error, body_id, fallback_has_occurred); + } + } + + self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fullfillment errors") + } + + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + fn report_overflow_error( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: fmt::Display + TypeFoldable<'tcx>, + { + let predicate = self.resolve_vars_if_possible(obligation.predicate.clone()); + 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.param_env, + obligation.cause.code(), + &mut vec![], + &mut Default::default(), + ); + + 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!(?cycle, "report_overflow_error_cycle"); + + // The 'deepest' obligation is most likely to have a useful + // cause 'backtrace' + self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false); + } + + fn report_selection_error( + &self, + mut obligation: PredicateObligation<'tcx>, + root_obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>, + fallback_has_occurred: bool, + ) { + self.set_tainted_by_errors(); + let tcx = self.tcx; + let mut span = obligation.cause.span; + + let mut err = match *error { + SelectionError::Ambiguous(ref impls) => { + let mut err = self.tcx.sess.struct_span_err( + obligation.cause.span, + &format!("multiple applicable `impl`s for `{}`", obligation.predicate), + ); + self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate); + err.emit(); + return; + } + SelectionError::Unimplemented => { + // If this obligation was generated as a result of well-formedness checking, see if we + // can get a better error message by performing HIR-based well-formedness checking. + if let ObligationCauseCode::WellFormed(Some(wf_loc)) = + root_obligation.cause.code().peel_derives() + { + if let Some(cause) = self + .tcx + .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc)) + { + obligation.cause = cause.clone(); + span = obligation.cause.span; + } + } + if let ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id, + trait_item_def_id, + kind: _, + } = *obligation.cause.code() + { + self.report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{}`", obligation.predicate), + ) + .emit(); + return; + } + + let bound_predicate = obligation.predicate.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(trait_predicate) => { + let trait_predicate = bound_predicate.rebind(trait_predicate); + let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); + + trait_predicate.remap_constness_diag(obligation.param_env); + let predicate_is_const = ty::BoundConstness::ConstIfConst + == trait_predicate.skip_binder().constness; + + if self.tcx.sess.has_errors().is_some() + && 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, + append_const_msg, + } = self.on_unimplemented_note(trait_ref, &obligation); + let have_alt_message = message.is_some() || label.is_some(); + let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); + let is_unsize = + Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait(); + let (message, note, append_const_msg) = if is_try_conversion { + ( + 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(), + ), + Some(None), + ) + } else { + (message, note, append_const_msg) + }; + + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0277, + "{}", + message + .and_then(|cannot_do_this| { + match (predicate_is_const, append_const_msg) { + // do nothing if predicate is not const + (false, _) => Some(cannot_do_this), + // suggested using default post message + (true, Some(None)) => { + Some(format!("{cannot_do_this} in const contexts")) + } + // overridden post message + (true, Some(Some(post_message))) => { + Some(format!("{cannot_do_this}{post_message}")) + } + // fallback to generic message + (true, None) => None, + } + }) + .unwrap_or_else(|| format!( + "the trait bound `{}` is not satisfied{}", + trait_predicate, post_message, + )) + ); + + if is_try_conversion { + 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` into a `Result` \ + using `Option::ok_or` or `Option::ok_or_else`", + ".ok_or_else(|| /* error value */)", + Applicability::HasPlaceholders, + ); + } else if should_convert_result_to_option { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider converting the `Result` into an `Option` \ + using `Result::ok`", + ".ok()", + 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() + ), + ); + } + } + + if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait() + && predicate_is_const + { + err.note("`~const Drop` was renamed to `~const Destruct`"); + err.note("See for more details"); + } + + let explanation = if let ObligationCauseCode::MainFunctionType = + obligation.cause.code() + { + "consider using `()`, or a `Result`".to_owned() + } else { + format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ) + }; + + if self.suggest_add_reference_to_arg( + &obligation, + &mut err, + trait_predicate, + 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); + 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 ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() && + Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); + } + + if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { + let non_const_predicate = trait_ref.without_const(); + let non_const_obligation = Obligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env.without_const(), + predicate: non_const_predicate.to_predicate(tcx), + recursion_depth: obligation.recursion_depth, + }; + if self.predicate_may_hold(&non_const_obligation) { + err.span_note( + span, + &format!( + "the trait `{}` is implemented for `{}`, \ + but that implementation is not `const`", + non_const_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + ); + } + } + + 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); + } + + self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); + self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); + let mut suggested = + self.suggest_dereferences(&obligation, &mut err, trait_predicate); + suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); + suggested |= + self.suggest_remove_reference(&obligation, &mut err, trait_predicate); + suggested |= self.suggest_semicolon_removal( + &obligation, + &mut err, + span, + trait_predicate, + ); + self.note_version_mismatch(&mut err, &trait_ref); + self.suggest_remove_await(&obligation, &mut err); + self.suggest_derive(&obligation, &mut err, trait_predicate); + + if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { + self.suggest_await_before_try( + &mut err, + &obligation, + trait_predicate, + span, + ); + } + + if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) { + 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 \ + \ + 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 is_fn_trait + && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( + obligation.param_env, + trait_ref.self_ty(), + trait_predicate.skip_binder().constness, + trait_predicate.skip_binder().polarity, + ) + { + // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following + // suggestion to add trait bounds for the type, since we only typically implement + // these traits once. + + // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying + // to implement. + let selected_kind = + ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id()) + .expect("expected to map DefId to ClosureKind"); + if !implemented_kind.extends(selected_kind) { + err.note( + &format!( + "`{}` implements `{}`, but it must implement `{}`, which is more general", + trait_ref.skip_binder().self_ty(), + implemented_kind, + selected_kind + ) + ); + } + + // Note any argument mismatches + let given_ty = params.skip_binder(); + let expected_ty = trait_ref.skip_binder().substs.type_at(1); + if let ty::Tuple(given) = given_ty.kind() + && let ty::Tuple(expected) = expected_ty.kind() + { + if expected.len() != given.len() { + // Note number of types that were expected and given + err.note( + &format!( + "expected a closure taking {} argument{}, but one taking {} argument{} was given", + given.len(), + pluralize!(given.len()), + expected.len(), + pluralize!(expected.len()), + ) + ); + } else if !self.same_type_modulo_infer(given_ty, expected_ty) { + // Print type mismatch + let (expected_args, given_args) = + self.cmp(given_ty, expected_ty); + err.note_expected_found( + &"a closure with arguments", + expected_args, + &"a closure with arguments", + given_args, + ); + } + } + } else 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_predicate, + None, + obligation.cause.body_id, + ); + } else if !suggested { + // Can't show anything else useful, try to find similar impls. + let impl_candidates = self.find_similar_impl_candidates(trait_predicate); + if !self.report_similar_impl_candidates( + impl_candidates, + trait_ref, + obligation.cause.body_id, + &mut err, + ) { + // This is *almost* equivalent to + // `obligation.cause.code().peel_derives()`, but it gives us the + // trait predicate for that corresponding root obligation. This + // lets us get a derived obligation from a type parameter, like + // when calling `string.strip_suffix(p)` where `p` is *not* an + // implementer of `Pattern<'_>`. + let mut code = obligation.cause.code(); + let mut trait_pred = trait_predicate; + let mut peeled = false; + while let Some((parent_code, parent_trait_pred)) = code.parent() { + code = parent_code; + if let Some(parent_trait_pred) = parent_trait_pred { + trait_pred = parent_trait_pred; + peeled = true; + } + } + let def_id = trait_pred.def_id(); + // Mention *all* the `impl`s for the *top most* obligation, the + // user might have meant to use one of them, if any found. We skip + // auto-traits or fundamental traits that might not be exactly what + // the user might expect to be presented with. Instead this is + // useful for less general traits. + if peeled + && !self.tcx.trait_is_auto(def_id) + && !self.tcx.lang_items().items().contains(&Some(def_id)) + { + let trait_ref = trait_pred.to_poly_trait_ref(); + let impl_candidates = + self.find_similar_impl_candidates(trait_pred); + self.report_similar_impl_candidates( + impl_candidates, + trait_ref, + obligation.cause.body_id, + &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_predicate); + } + + // 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.to_predicate(tcx)); + if self.predicate_may_hold(&unit_obligation) { + err.note( + "this error might have been caused by changes to \ + Rust's type-inference algorithm (see issue #48950 \ + \ + for more information)", + ); + err.help("did you intend to use the type `()` here instead?"); + } + } + + // Return early if the trait is Debug or Display and the invocation + // originates within a standard library macro, because the output + // is otherwise overwhelming and unhelpful (see #85844 for an + // example). + + let in_std_macro = + match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { + Some(macro_def_id) => { + let crate_name = tcx.crate_name(macro_def_id.krate); + crate_name == sym::std || crate_name == sym::core + } + None => false, + }; + + if in_std_macro + && matches!( + self.tcx.get_diagnostic_name(trait_ref.def_id()), + Some(sym::Debug | sym::Display) + ) + { + err.emit(); + return; + } + + err + } + + ty::PredicateKind::Subtype(predicate) => { + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) + } + + ty::PredicateKind::Coerce(predicate) => { + // Errors for Coerce predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) + } + + ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::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::PredicateKind::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::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { + let found_kind = self.closure_kind(closure_substs).unwrap(); + let closure_span = self.tcx.def_span(closure_def_id); + 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 hir_id = self + .tcx + .hir() + .local_def_id_to_hir_id(closure_def_id.expect_local()); + let typeck_results = typeck_results.borrow(); + match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { + (ty::ClosureKind::FnOnce, Some((span, place))) => { + err.span_label( + *span, + format!( + "closure is `FnOnce` because it moves the \ + variable `{}` out of its environment", + ty::place_to_string_for_capture(tcx, place) + ), + ); + } + (ty::ClosureKind::FnMut, Some((span, place))) => { + err.span_label( + *span, + format!( + "closure is `FnMut` because it mutates the \ + variable `{}` here", + ty::place_to_string_for_capture(tcx, place) + ), + ); + } + _ => {} + } + } + + err.emit(); + return; + } + + ty::PredicateKind::WellFormed(ty) => { + if !self.tcx.sess.opts.unstable_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::PredicateKind::ConstEvaluatable(..) => { + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-evaluatable requirement gave wrong error: `{:?}`", + obligation + ) + } + + ty::PredicateKind::ConstEquate(..) => { + // Errors for `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-equate requirement gave wrong error: `{:?}`", + obligation + ) + } + + ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!( + span, + "TypeWellFormedFromEnv predicate should only exist in the environment" + ), + } + } + + OutputTypeParameterMismatch(found_trait_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 Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else { + return; + }; + + let found_did = match *found_trait_ty.kind() { + ty::Closure(did, _) + | ty::Foreign(did) + | ty::FnDef(did, _) + | ty::Generator(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)); + + 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, 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) + } + + SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { + bug!( + "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`" + ) + } + SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => { + if !self.tcx.features().generic_const_exprs { + 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). + // + // Note that with `feature(generic_const_exprs)` this case should not + // be reachable. + err.note("this may fail depending on what value the parameter takes"); + err.emit(); + return; + } + + match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::ConstEvaluatable(uv) => { + let mut err = + self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); + let const_span = self.tcx.def_span(uv.def.did); + match self.tcx.sess.source_map().span_to_snippet(const_span) { + Ok(snippet) => err.help(&format!( + "try adding a `where` bound using this expression: `where [(); {}]:`", + snippet + )), + _ => err.help("consider adding a `where` bound using this expression"), + }; + err + } + _ => { + span_bug!( + span, + "unexpected non-ConstEvaluatable predicate, this should not be reachable" + ) + } + } + } + + // Already reported in the query. + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => { + // FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token. + self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error"); + return; + } + // Already reported. + Overflow(OverflowError::Error(_)) => { + self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported"); + return; + } + Overflow(_) => { + bug!("overflow should be handled before the `report_selection_error` path"); + } + SelectionError::ErrorReporting => { + bug!("ErrorReporting Overflow should not reach `report_selection_err` call") + } + }; + + 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)> { + let sm = self.tcx.sess.source_map(); + let hir = self.tcx.hir(); + Some(match node { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }), + .. + }) => ( + fn_decl_span, + hir.body(body) + .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::>>()?, + )) + } else { + let name = sm.span_to_snippet(arg.pat.span).ok()?; + Some(ArgKind::Arg(name, "_".to_owned())) + } + }) + .collect::>>()?, + ), + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) + | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Fn(ref sig, _), .. + }) => ( + sig.span, + sig.decl + .inputs + .iter() + .map(|arg| match arg.kind { + hir::TyKind::Tup(ref tys) => ArgKind::Tuple( + Some(arg.span), + vec![("_".to_owned(), "_".to_owned()); tys.len()], + ), + _ => ArgKind::empty(), + }) + .collect::>(), + ), + Node::Ctor(ref variant_data) => { + let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); + (span, vec![ArgKind::empty(); variant_data.fields().len()]) + } + _ => panic!("non-FnLike node found: {:?}", node), + }) + } + + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + fn report_arg_count_mismatch( + &self, + span: Span, + found_span: Option, + expected_args: Vec, + found_args: Vec, + is_closure: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + let kind = if is_closure { "closure" } else { "function" }; + + let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { + let arg_length = arguments.len(); + let distinct = matches!(other, &[ArgKind::Tuple(..)]); + 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::>() + .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[..] + && fields.len() == found_args.len() + && is_closure + { + let sugg = format!( + "|({}){}|", + found_args + .iter() + .map(|arg| match arg { + ArgKind::Arg(name, _) => name.to_owned(), + _ => "_".to_owned(), + }) + .collect::>() + .join(", "), + // add type annotations if available + if found_args.iter().any(|arg| match arg { + ArgKind::Arg(_, ty) => ty != "_", + _ => false, + }) { + format!( + ": ({})", + fields + .iter() + .map(|(_, ty)| ty.to_owned()) + .collect::>() + .join(", ") + ) + } else { + String::new() + }, + ); + err.span_suggestion_verbose( + found_span, + "change the closure to accept a tuple instead of individual arguments", + sugg, + Applicability::MachineApplicable, + ); + } + } + + err + } + + fn type_implements_fn_trait( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Binder<'tcx, Ty<'tcx>>, + constness: ty::BoundConstness, + polarity: ty::ImplPolarity, + ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { + self.commit_if_ok(|_| { + for trait_def_id in [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] { + let Some(trait_def_id) = trait_def_id else { continue }; + // Make a fresh inference variable so we can determine what the substitutions + // of the trait are. + let var = self.next_ty_var(TypeVariableOrigin { + span: DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }); + let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + ty.rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef::new(trait_def_id, substs), + constness, + polarity, + }) + .to_predicate(self.tcx), + ); + let mut fulfill_cx = FulfillmentContext::new_in_snapshot(); + fulfill_cx.register_predicate_obligation(self, obligation); + if fulfill_cx.select_all_or_error(self).is_empty() { + return Ok(( + ty::ClosureKind::from_def_id(self.tcx, trait_def_id) + .expect("expected to map DefId to ClosureKind"), + ty.rebind(self.resolve_vars_if_possible(var)), + )); + } + } + + Err(()) + }) + } +} + +trait InferCtxtPrivExt<'hir, 'tcx> { + // returns if `cond` not occurring implies that `error` does not occur - i.e., that + // `error` occurring implies that `cond` occurs. + fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; + + fn report_fulfillment_error( + &self, + error: &FulfillmentError<'tcx>, + body_id: Option, + fallback_has_occurred: bool, + ); + + fn report_projection_error( + &self, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>, + ); + + fn fuzzy_match_tys( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + ignoring_lifetimes: bool, + ) -> Option; + + fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; + + fn find_similar_impl_candidates( + &self, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Vec>; + + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec>, + trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, + err: &mut Diagnostic, + ) -> bool; + + /// Gets the parent trait chain start + fn get_parent_trait_ref( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(String, Option)>; + + /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait + /// with the same path as `trait_ref`, a help message about + /// a probable version mismatch is added to `err` + fn note_version_mismatch( + &self, + err: &mut Diagnostic, + trait_ref: &ty::PolyTraitRef<'tcx>, + ) -> bool; + + /// 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_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, + ) -> PredicateObligation<'tcx>; + + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option, + ); + + fn predicate_can_apply( + &self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>, + ) -> bool; + + fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>); + + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + ); + + fn annotate_source_of_ambiguity( + &self, + err: &mut Diagnostic, + impls: &[DefId], + predicate: ty::Predicate<'tcx>, + ); + + fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>); + + fn maybe_indirection_for_unsized( + &self, + err: &mut Diagnostic, + item: &'hir Item<'hir>, + param: &'hir GenericParam<'hir>, + ) -> bool; + + fn is_recursive_obligation( + &self, + obligated_types: &mut Vec>, + cause_code: &ObligationCauseCode<'tcx>, + ) -> bool; +} + +impl<'a, 'tcx> InferCtxtPrivExt<'a, '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 bound_error = error.kind(); + let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) { + (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error)) => { + (cond, bound_error.rebind(error)) + } + _ => { + // FIXME: make this work in other cases too. + return false; + } + }; + + for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { + let bound_predicate = obligation.predicate.kind(); + if let ty::PredicateKind::Trait(implication) = bound_predicate.skip_binder() { + let error = error.to_poly_trait_ref(); + let implication = bound_predicate.rebind(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 + } + + #[instrument(skip(self), level = "debug")] + fn report_fulfillment_error( + &self, + error: &FulfillmentError<'tcx>, + body_id: Option, + fallback_has_occurred: bool, + ) { + match error.code { + FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { + self.report_selection_error( + error.obligation.clone(), + &error.root_obligation, + selection_error, + fallback_has_occurred, + ); + } + 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(); + } + } + } + + #[instrument(level = "debug", skip_all)] + 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. + let bound_predicate = predicate.kind(); + if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() { + let mut selcx = SelectionContext::new(self); + let data = self.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + bound_predicate.rebind(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!(?obligation.cause, ?obligation.param_env); + + debug!(?normalized_ty, data.ty = ?data.term); + + let is_normalized_ty_expected = !matches!( + obligation.cause.code().peel_derives(), + ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::BindingObligation(_, _) + | ObligationCauseCode::ObjectCastObligation(..) + | ObligationCauseCode::OpaqueType + ); + if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( + is_normalized_ty_expected, + normalized_ty, + data.term, + ) { + values = Some(infer::ValuePairs::Terms(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ty, + data.term, + ))); + err_buf = error; + err = &err_buf; + } + } + + let mut diag = struct_span_err!( + self.tcx.sess, + obligation.cause.span, + E0271, + "type mismatch resolving `{}`", + predicate + ); + let secondary_span = match predicate.kind().skip_binder() { + ty::PredicateKind::Projection(proj) => self + .tcx + .opt_associated_item(proj.projection_ty.item_def_id) + .and_then(|trait_assoc_item| { + self.tcx + .trait_of_item(proj.projection_ty.item_def_id) + .map(|id| (trait_assoc_item, id)) + }) + .and_then(|(trait_assoc_item, id)| { + let trait_assoc_ident = trait_assoc_item.ident(self.tcx); + self.tcx.find_map_relevant_impl(id, proj.projection_ty.self_ty(), |did| { + self.tcx + .associated_items(did) + .in_definition_order() + .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident) + }) + }) + .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) { + Some( + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Type(_, Some(ty)), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::TyAlias(ty), + .. + }), + ) => Some((ty.span, format!("type mismatch resolving `{}`", predicate))), + _ => None, + }), + _ => None, + }; + self.note_type_err( + &mut diag, + &obligation.cause, + secondary_span, + values, + err, + true, + false, + ); + self.note_obligation_cause(&mut diag, obligation); + diag.emit(); + }); + } + + fn fuzzy_match_tys( + &self, + mut a: Ty<'tcx>, + mut b: Ty<'tcx>, + ignoring_lifetimes: bool, + ) -> Option { + /// returns the fuzzy category of a given type, or None + /// if the type can be equated to any type. + fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option { + match t.kind() { + ty::Bool => Some(0), + ty::Char => Some(1), + ty::Str => Some(2), + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did()) => Some(2), + ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Infer(ty::IntVar(..) | 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::Param(..) => Some(11), + ty::Projection(..) => Some(12), + ty::Opaque(..) => Some(13), + ty::Never => Some(14), + ty::Adt(..) => Some(15), + ty::Generator(..) => Some(16), + ty::Foreign(..) => Some(17), + ty::GeneratorWitness(..) => Some(18), + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, + } + } + + let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> { + loop { + match t.kind() { + ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => { + t = *inner + } + _ => break t, + } + } + }; + + if !ignoring_lifetimes { + a = strip_references(a); + b = strip_references(b); + } + + let cat_a = type_category(self.tcx, a)?; + let cat_b = type_category(self.tcx, b)?; + if a == b { + Some(CandidateSimilarity::Exact { ignoring_lifetimes }) + } else if cat_a == cat_b { + match (a.kind(), b.kind()) { + (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b, + (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b, + // Matching on references results in a lot of unhelpful + // suggestions, so let's just not do that for now. + // + // We still upgrade successful matches to `ignoring_lifetimes: true` + // to prioritize that impl. + (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => { + self.fuzzy_match_tys(a, b, true).is_some() + } + _ => true, + } + .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes }) + } else if ignoring_lifetimes { + None + } else { + self.fuzzy_match_tys(a, b, 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_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Vec> { + self.tcx + .all_impls(trait_pred.def_id()) + .filter_map(|def_id| { + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative + || !trait_pred + .skip_binder() + .is_constness_satisfied_by(self.tcx.constness(def_id)) + { + return None; + } + + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + + self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false) + .map(|similarity| ImplCandidate { trait_ref: imp, similarity }) + }) + .collect() + } + + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec>, + trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, + err: &mut Diagnostic, + ) -> bool { + let report = |mut candidates: Vec>, err: &mut Diagnostic| { + candidates.sort(); + candidates.dedup(); + let len = candidates.len(); + if candidates.len() == 0 { + return false; + } + if candidates.len() == 1 { + err.highlighted_help(vec![ + ( + format!("the trait `{}` ", candidates[0].print_only_trait_path()), + Style::NoStyle, + ), + ("is".to_string(), Style::Highlight), + (" implemented for `".to_string(), Style::NoStyle), + (candidates[0].self_ty().to_string(), Style::Highlight), + ("`".to_string(), Style::NoStyle), + ]); + return true; + } + let trait_ref = TraitRef::identity(self.tcx, candidates[0].def_id); + // Check if the trait is the same in all cases. If so, we'll only show the type. + let mut traits: Vec<_> = + candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect(); + traits.sort(); + traits.dedup(); + + let mut candidates: Vec = candidates + .into_iter() + .map(|c| { + if traits.len() == 1 { + format!("\n {}", c.self_ty()) + } else { + format!("\n {}", c) + } + }) + .collect(); + + candidates.sort(); + candidates.dedup(); + let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; + err.help(&format!( + "the following other types implement trait `{}`:{}{}", + trait_ref.print_only_trait_path(), + candidates[..end].join(""), + if len > 9 { format!("\nand {} others", len - 8) } else { String::new() } + )); + true + }; + + let def_id = trait_ref.def_id(); + if impl_candidates.is_empty() { + if self.tcx.trait_is_auto(def_id) + || self.tcx.lang_items().items().contains(&Some(def_id)) + || self.tcx.get_diagnostic_name(def_id).is_some() + { + // Mentioning implementers of `Copy`, `Debug` and friends is not useful. + return false; + } + let normalized_impl_candidates: Vec<_> = self + .tcx + .all_impls(def_id) + // Ignore automatically derived impls and `!Trait` impls. + .filter(|&def_id| { + self.tcx.impl_polarity(def_id) != ty::ImplPolarity::Negative + || self.tcx.is_builtin_derive(def_id) + }) + .filter_map(|def_id| self.tcx.impl_trait_ref(def_id)) + .filter(|trait_ref| { + let self_ty = trait_ref.self_ty(); + // Avoid mentioning type parameters. + if let ty::Param(_) = self_ty.kind() { + false + } + // Avoid mentioning types that are private to another crate + else if let ty::Adt(def, _) = self_ty.peel_refs().kind() { + // FIXME(compiler-errors): This could be generalized, both to + // be more granular, and probably look past other `#[fundamental]` + // types, too. + self.tcx + .visibility(def.did()) + .is_accessible_from(body_id.owner.to_def_id(), self.tcx) + } else { + true + } + }) + .collect(); + return report(normalized_impl_candidates, err); + } + + 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) => normalized.value, + None => candidate, + } + }) + }; + + // Sort impl candidates so that ordering is consistent for UI tests. + // because the ordering of `impl_candidates` may not be deterministic: + // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 + // + // Prefer more similar candidates first, then sort lexicographically + // by their normalized string representation. + let mut normalized_impl_candidates_and_similarities = impl_candidates + .into_iter() + .map(|ImplCandidate { trait_ref, similarity }| { + let normalized = normalize(trait_ref); + (similarity, normalized) + }) + .collect::>(); + normalized_impl_candidates_and_similarities.sort(); + normalized_impl_candidates_and_similarities.dedup(); + + let normalized_impl_candidates = normalized_impl_candidates_and_similarities + .into_iter() + .map(|(_, normalized)| normalized) + .collect::>(); + + report(normalized_impl_candidates, err) + } + + /// Gets the parent trait chain start + fn get_parent_trait_ref( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(String, Option)> { + match code { + ObligationCauseCode::BuiltinDerivedObligation(data) => { + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + 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(self.tcx, ty) + .map(|(_, def_id)| self.tcx.def_span(def_id)); + Some((ty.to_string(), span)) + } + } + } + ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { + self.get_parent_trait_ref(&parent_code) + } + _ => 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 Diagnostic, + trait_ref: &ty::PolyTraitRef<'tcx>, + ) -> bool { + let get_trait_impl = |trait_def_id| { + self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some) + }; + let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); + let traits_with_same_path: std::collections::BTreeSet<_> = self + .tcx + .all_traits() + .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(); + let mut suggested = false; + 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); + suggested = true; + } + } + suggested + } + + fn mk_trait_obligation_with_new_self_ty( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, + ) -> PredicateObligation<'tcx> { + let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate { + trait_ref: ty::TraitRef { + substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]), + ..tr.trait_ref + }, + ..*tr + }); + + Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx)) + } + + #[instrument(skip(self), level = "debug")] + fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + body_id: Option, + ) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + + let predicate = self.resolve_vars_if_possible(obligation.predicate); + let span = obligation.cause.span; + + debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code())); + + // Ambiguity errors are often caused as fallout from earlier errors. + // We ignore them if this `infcx` is tainted in some cases below. + + let bound_predicate = predicate.kind(); + let mut err = match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(data) => { + let trait_ref = bound_predicate.rebind(data.trait_ref); + debug!(?trait_ref); + + if predicate.references_error() { + return; + } + + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // avoid inundating the user with unnecessary errors, but we now + // check upstream for type errors and don't add the obligations to + // begin with in those cases. + if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if !self.is_tainted_by_errors() { + self.emit_inference_failure_err( + body_id, + span, + trait_ref.self_ty().skip_binder().into(), + ErrorCode::E0282, + false, + ) + .emit(); + } + 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. + + // Pick the first substitution that still contains inference variables as the one + // we're going to emit an error for. If there are none (see above), fall back to + // a more general error. + let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts()); + + let mut err = if let Some(subst) = subst { + self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true) + } else { + struct_span_err!( + self.tcx.sess, + span, + E0283, + "type annotations needed: cannot satisfy `{}`", + predicate, + ) + }; + + let obligation = Obligation::new( + obligation.cause.clone(), + obligation.param_env, + trait_ref.to_poly_trait_predicate(), + ); + let mut selcx = SelectionContext::with_query_mode( + &self, + crate::traits::TraitQueryMode::Standard, + ); + match selcx.select_from_obligation(&obligation) { + Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => { + self.annotate_source_of_ambiguity(&mut err, &impls, predicate); + } + _ => { + if self.is_tainted_by_errors() { + err.cancel(); + return; + } + 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(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('>') + && !generics.has_impl_trait() + && !self.tcx.fn_trait_kind_from_lang_item(def_id).is_some() + { + // FIXME: To avoid spurious suggestions in functions where type arguments + // where already supplied, we check the snippet to make sure it doesn't + // end with a turbofish. Ideally we would have access to a `PathSegment` + // instead. Otherwise we would produce the following output: + // + // error[E0283]: type annotations needed + // --> $DIR/issue-54954.rs:3:24 + // | + // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); + // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + // | | + // | cannot infer type + // | help: consider specifying the type argument + // | in the function call: + // | `Tt::const_val::<[i8; 123]>::` + // ... + // LL | const fn const_val() -> usize { + // | - required by this bound in `Tt::const_val` + // | + // = note: cannot satisfy `_: Tt` + + // Clear any more general suggestions in favor of our specific one + err.clear_suggestions(); + + 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::>() + .join(", ") + ), + Applicability::HasPlaceholders, + ); + } + } + + if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = + (body_id, subst.map(|subst| subst.unpack())) + { + struct FindExprBySpan<'hir> { + span: Span, + result: Option<&'hir hir::Expr<'hir>>, + } + + impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if self.span == ex.span { + self.result = Some(ex); + } else { + hir::intravisit::walk_expr(self, ex); + } + } + } + + let mut expr_finder = FindExprBySpan { span, result: None }; + + expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); + + if let Some(hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. } + ) = expr_finder.result + && let [ + .., + trait_path_segment @ hir::PathSegment { + res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)), + .. + }, + hir::PathSegment { + ident: assoc_item_name, + res: Some(rustc_hir::def::Res::Def(_, item_id)), + .. + } + ] = path.segments + && data.trait_ref.def_id == *trait_id + && self.tcx.trait_of_item(*item_id) == Some(*trait_id) + && !self.is_tainted_by_errors() + { + let (verb, noun) = match self.tcx.associated_item(item_id).kind { + ty::AssocKind::Const => ("refer to the", "constant"), + ty::AssocKind::Fn => ("call", "function"), + ty::AssocKind::Type => ("refer to the", "type"), // this is already covered by E0223, but this single match arm doesn't hurt here + }; + + // Replace the more general E0283 with a more specific error + err.cancel(); + err = self.tcx.sess.struct_span_err_with_code( + span, + &format!( + "cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type", + ), + rustc_errors::error_code!(E0790), + ); + + if let Some(local_def_id) = data.trait_ref.def_id.as_local() + && let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id) + && let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) { + err.span_label(method_ref.span, format!("`{}::{}` defined here", trait_name, assoc_item_name)); + } + + err.span_label(span, format!("cannot {verb} associated {noun} of trait")); + + let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); + + if trait_impls.blanket_impls().is_empty() + && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next() + && let Some(impl_def_id) = impl_ty.def() { + let message = if trait_impls.non_blanket_impls().len() == 1 { + "use the fully-qualified path to the only available implementation".to_string() + } else { + format!( + "use a fully-qualified path to a specific available implementation ({} found)", + trait_impls.non_blanket_impls().len() + ) + }; + + err.multipart_suggestion( + message, + vec![ + (trait_path_segment.ident.span.shrink_to_lo(), format!("<{} as ", self.tcx.def_path(impl_def_id).to_string_no_crate_verbose())), + (trait_path_segment.ident.span.shrink_to_hi(), format!(">")) + ], + Applicability::MaybeIncorrect + ); + } + } + }; + + err + } + + ty::PredicateKind::WellFormed(arg) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if arg.references_error() + || self.tcx.sess.has_errors().is_some() + || self.is_tainted_by_errors() + { + return; + } + + self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false) + } + + ty::PredicateKind::Subtype(data) => { + if data.references_error() + || self.tcx.sess.has_errors().is_some() + || self.is_tainted_by_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.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true) + } + ty::PredicateKind::Projection(data) => { + if predicate.references_error() || self.is_tainted_by_errors() { + return; + } + let subst = data + .projection_ty + .substs + .iter() + .chain(Some(data.term.into_arg())) + .find(|g| g.has_infer_types_or_consts()); + if let Some(subst) = subst { + let mut err = self.emit_inference_failure_err( + body_id, + span, + subst, + ErrorCode::E0284, + true, + ); + err.note(&format!("cannot satisfy `{}`", predicate)); + err + } else { + // If we can't find a substitution, just print a generic error + 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 + } + } + + ty::PredicateKind::ConstEvaluatable(data) => { + if predicate.references_error() || self.is_tainted_by_errors() { + return; + } + let subst = data.substs.iter().find(|g| g.has_infer_types_or_consts()); + if let Some(subst) = subst { + let err = self.emit_inference_failure_err( + body_id, + span, + subst, + ErrorCode::E0284, + true, + ); + err + } else { + // If we can't find a substitution, just print a generic error + 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().is_some() || self.is_tainted_by_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(); + } + + fn annotate_source_of_ambiguity( + &self, + err: &mut Diagnostic, + impls: &[DefId], + predicate: ty::Predicate<'tcx>, + ) { + let mut spans = vec![]; + let mut crates = vec![]; + let mut post = vec![]; + for def_id in impls { + match self.tcx.span_of_impl(*def_id) { + Ok(span) => spans.push(span), + Err(name) => { + crates.push(name); + if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) { + post.push(header); + } + } + } + } + let msg = format!("multiple `impl`s satisfying `{}` found", predicate); + let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect(); + crate_names.sort(); + crate_names.dedup(); + post.sort(); + post.dedup(); + + if self.is_tainted_by_errors() + && (crate_names.len() == 1 + && spans.len() == 0 + && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) + || predicate.visit_with(&mut HasNumericInferVisitor).is_break()) + { + // Avoid complaining about other inference issues for expressions like + // `42 >> 1`, where the types are still `{integer}`, but we want to + // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too? + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); + return; + } + let post = if post.len() > 4 { + format!( + ":\n{}\nand {} more", + post.iter().map(|p| format!("- {}", p)).take(4).collect::>().join("\n"), + post.len() - 4, + ) + } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) { + format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::>().join("\n"),) + } else if post.len() == 1 { + format!(": `{}`", post[0]) + } else { + String::new() + }; + + match (spans.len(), crates.len(), crate_names.len()) { + (0, 0, 0) => { + err.note(&format!("cannot satisfy `{}`", predicate)); + } + (0, _, 1) => { + err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,)); + } + (0, _, _) => { + err.note(&format!( + "{} in the following crates: {}{}", + msg, + crate_names.join(", "), + post, + )); + } + (_, 0, 0) => { + let span: MultiSpan = spans.into(); + err.span_note(span, &msg); + } + (_, 1, 1) => { + let span: MultiSpan = spans.into(); + err.span_note(span, &msg); + err.note( + &format!("and another `impl` found in the `{}` crate{}", crates[0], post,), + ); + } + _ => { + let span: MultiSpan = spans.into(); + err.span_note(span, &msg); + err.note(&format!( + "and more `impl`s found in the following crates: {}{}", + crate_names.join(", "), + post, + )); + } + } + } + + /// Returns `true` if the trait predicate may apply for *some* assignment + /// to the type parameters. + fn predicate_can_apply( + &self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>, + ) -> bool { + struct ParamToVarFolder<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + var_map: FxHashMap, Ty<'tcx>>, + } + + impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() { + let infcx = self.infcx; + *self.var_map.entry(ty).or_insert_with(|| { + infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), + span: DUMMY_SP, + }) + }) + } else { + ty.super_fold_with(self) + } + } + } + + self.probe(|_| { + let mut selcx = SelectionContext::new(self); + + let cleaned_pred = + pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() }); + + let cleaned_pred = super::project::normalize( + &mut selcx, + param_env, + ObligationCause::dummy(), + cleaned_pred, + ) + .value; + + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + cleaned_pred.without_const().to_predicate(selcx.tcx()), + ); + + self.predicate_may_hold(&obligation) + }) + } + + fn note_obligation_cause(&self, err: &mut Diagnostic, 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.param_env, + obligation.cause.code(), + &mut vec![], + &mut Default::default(), + ); + self.suggest_unsized_bound_if_applicable(err, obligation); + } + } + + #[instrument(level = "debug", skip_all)] + fn suggest_unsized_bound_if_applicable( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + ) { + let ( + ty::PredicateKind::Trait(pred), + &ObligationCauseCode::BindingObligation(item_def_id, span), + ) = ( + obligation.predicate.kind().skip_binder(), + obligation.cause.code().peel_derives(), + ) else { + return; + }; + debug!(?pred, ?item_def_id, ?span); + + let (Some(node), true) = ( + self.tcx.hir().get_if_local(item_def_id), + Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + ) else { + return; + }; + self.maybe_suggest_unsized_generics(err, span, node); + } + + #[instrument(level = "debug", skip_all)] + fn maybe_suggest_unsized_generics<'hir>( + &self, + err: &mut Diagnostic, + span: Span, + node: Node<'hir>, + ) { + let Some(generics) = node.generics() else { + return; + }; + let sized_trait = self.tcx.lang_items().sized_trait(); + debug!(?generics.params); + debug!(?generics.predicates); + let Some(param) = generics.params.iter().find(|param| param.span == span) else { + return; + }; + let param_def_id = self.tcx.hir().local_def_id(param.hir_id); + // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit + // `Sized` bound is there intentionally and we don't need to suggest relaxing it. + let explicitly_sized = generics + .bounds_for_param(param_def_id) + .flat_map(|bp| bp.bounds) + .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); + if explicitly_sized { + return; + } + debug!(?param); + match node { + hir::Node::Item( + item @ hir::Item { + // Only suggest indirection for uses of type parameters in ADTs. + kind: + hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..), + .. + }, + ) => { + if self.maybe_indirection_for_unsized(err, item, param) { + return; + } + } + _ => {} + }; + // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`. + let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id) + { + (s, " +") + } else { + (span.shrink_to_hi(), ":") + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{} ?Sized", separator), + Applicability::MachineApplicable, + ); + } + + fn maybe_indirection_for_unsized<'hir>( + &self, + err: &mut Diagnostic, + item: &'hir Item<'hir>, + param: &'hir GenericParam<'hir>, + ) -> bool { + // 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);` + // is not. Look for invalid "bare" parameter uses, and suggest using indirection. + let mut visitor = + FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false }; + visitor.visit_item(item); + if visitor.invalid_spans.is_empty() { + return false; + } + 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 were 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(), + ), + ); + true + } + + fn is_recursive_obligation( + &self, + obligated_types: &mut Vec>, + 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_pred); + let self_ty = parent_trait_ref.skip_binder().self_ty(); + if obligated_types.iter().any(|ot| ot == &self_ty) { + return true; + } + if let ty::Adt(def, substs) = self_ty.kind() + && let [arg] = &substs[..] + && let ty::subst::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Adt(inner_def, _) = ty.kind() + && inner_def == def + { + 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, + nested: bool, +} + +impl<'v> Visitor<'v> for FindTypeParam { + fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) { + // Skip where-clauses, to avoid suggesting indirection for type parameters found there. + } + + 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` and `Vec`, 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 { + debug!(?ty, "FindTypeParam::visit_ty"); + 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>( + tcx: TyCtxt<'tcx>, + type_def_id: DefId, + spans: Vec<(Span, Option)>, +) { + assert!(type_def_id.is_local()); + let span = tcx.def_span(type_def_id); + 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 { + // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed + err.multipart_suggestion( + &msg, + spans + .into_iter() + .flat_map(|(span, field_id)| { + if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) { + // If we match an `Option` and can grab the span of the Option's generic, then + // suggest boxing the generic arg for a non-null niche optimization. + vec![ + (generic_span.shrink_to_lo(), "Box<".to_string()), + (generic_span.shrink_to_hi(), ">".to_string()), + ] + } else { + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ] + } + }) + .collect(), + Applicability::HasPlaceholders, + ); + } else { + err.help(&msg); + } + err.emit(); +} + +/// Extract the span for the generic type `T` of `Option` in a field definition +fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option) -> Option { + let node = tcx.hir().find(field_id?); + + // Expect a field from our field_id + let Some(hir::Node::Field(field_def)) = node + else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) }; + + // Match a type that is a simple QPath with no Self + let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind + else { return None }; + + // Check if the path we're checking resolves to Option + let hir::def::Res::Def(_, did) = path.res + else { return None }; + + // Bail if this path doesn't describe `::core::option::Option` + if !tcx.is_diagnostic_item(sym::Option, did) { + return None; + } + + // Match a single generic arg in the 0th path segment + let generic_arg = path.segments.last()?.args?.args.get(0)?; + + // Take the span out of the type, if it's a type + if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None } +} + +/// 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 location in the source of the pattern. For an "expected" + /// argument, it will be None. The vector is a list of (name, ty) + /// strings for the components of the tuple. + Tuple(Option, Vec<(String, String)>), +} + +impl ArgKind { + fn empty() -> ArgKind { + ArgKind::Arg("_".to_owned(), "_".to_owned()) + } + + /// Creates an `ArgKind` from the expected type of an + /// argument. It has no name (`_`) and an optional source span. + pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { + match t.kind() { + ty::Tuple(tys) => ArgKind::Tuple( + span, + tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::>(), + ), + _ => ArgKind::Arg("_".to_owned(), t.to_string()), + } + } +} + +struct HasNumericInferVisitor; + +impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { + type BreakTy = (); + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { + ControlFlow::Break(()) + } else { + ControlFlow::CONTINUE + } + } +} 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 000000000..e6907637c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -0,0 +1,272 @@ +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, SubstsRef}; +use rustc_middle::ty::{self, GenericParamDefKind}; +use rustc_span::symbol::sym; +use std::iter; + +use super::InferCtxtPrivExt; + +pub trait InferCtxtExt<'tcx> { + /*private*/ + fn impl_similar_to( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>, + ) -> Option<(DefId, SubstsRef<'tcx>)>; + + /*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, SubstsRef<'tcx>)> { + 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.bound_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, impl_substs)); + + if iter::zip( + trait_ref.substs.types().skip(1), + impl_trait_ref.substs.types().skip(1), + ) + .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) + { + fuzzy_match_impls.push((def_id, impl_substs)); + } + } + }); + + let impl_def_id_and_substs = 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_and_substs.0, sym::rustc_on_unimplemented) + .then_some(impl_def_id_and_substs) + } + + /// 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(hir::Closure { body, movability, .. }), + .. + }) => self.describe_generator(*body).or_else(|| { + Some(if 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, substs) = self + .impl_similar_to(trait_ref, obligation) + .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs)); + let trait_ref = trait_ref.skip_binder(); + + let mut flags = vec![( + 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(k) = obligation.cause.span.desugaring_kind() { + flags.push((sym::from_desugaring, None)); + flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); + } + + // Add all types without trimmed paths. + ty::print::with_no_trimmed_paths!({ + 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 { .. } => { + substs[param.index as usize].to_string() + } + GenericParamDefKind::Lifetime => continue, + }; + let name = param.name; + flags.push((name, Some(value))); + + if let GenericParamDefKind::Type { .. } = param.kind { + let param_ty = substs[param.index as usize].expect_ty(); + if let Some(def) = param_ty.ty_adt_def() { + // We also want to be able to select the parameter's + // original signature with no type arguments resolved + flags.push((name, Some(self.tcx.type_of(def.did()).to_string()))); + } + } + } + + 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 self_ty.is_array_slice() { + flags.push((sym::_Self, Some("&[]".to_owned()))); + } + + if self_ty.is_fn() { + let fn_sig = self_ty.fn_sig(self.tcx); + let shortname = match fn_sig.unsafety() { + hir::Unsafety::Normal => "fn", + hir::Unsafety::Unsafe => "unsafe fn", + }; + flags.push((sym::_Self, Some(shortname.to_owned()))); + } + + // Slices give us `[]`, `[{ty}]` + if let ty::Slice(aty) = self_ty.kind() { + flags.push((sym::_Self, Some("[]".to_string()))); + if let Some(def) = aty.ty_adt_def() { + // We also want to be able to select the slice's type's original + // signature with no type arguments resolved + flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did()))))); + } + if aty.is_integral() { + flags.push((sym::_Self, Some("[{integral}]".to_string()))); + } + } + + // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` + if let ty::Array(aty, len) = self_ty.kind() { + flags.push((sym::_Self, Some("[]".to_string()))); + let len = len.kind().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); + flags.push((sym::_Self, Some(format!("[{}; _]", aty)))); + if let Some(n) = len { + flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n)))); + } + 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 + let def_ty = self.tcx.type_of(def.did()); + flags.push((sym::_Self, Some(format!("[{def_ty}; _]")))); + if let Some(n) = len { + flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]")))); + } + } + if aty.is_integral() { + flags.push((sym::_Self, Some("[{integral}; _]".to_string()))); + if let Some(n) = len { + flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]")))); + } + } + } + if let ty::Dynamic(traits, _) = self_ty.kind() { + for t in traits.iter() { + if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { + flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) + } + } + } + }); + + if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, 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 000000000..219413121 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -0,0 +1,3119 @@ +use super::{ + EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionContext, +}; + +use crate::autoderef::Autoderef; +use crate::infer::InferCtxt; +use crate::traits::normalize_to; + +use hir::HirId; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::{ + error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, MultiSpan, 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_infer::infer::TyCtxtInferExt; +use rustc_middle::hir::map; +use rustc_middle::ty::{ + self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, + ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitable, +}; +use rustc_middle::ty::{TypeAndMut, TypeckResults}; +use rustc_session::Limit; +use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP}; +use rustc_target::spec::abi; +use std::fmt; + +use super::InferCtxtPrivExt; +use crate::infer::InferCtxtExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_middle::ty::print::with_no_trimmed_paths; + +#[derive(Debug)] +pub enum GeneratorInteriorOrUpvar { + // span of interior type + Interior(Span), + // span of upvar + Upvar(Span), +} + +// This type provides a uniform interface to retrieve data on generators, whether it originated from +// the local crate being compiled or from a foreign crate. +#[derive(Debug)] +pub enum GeneratorData<'tcx, 'a> { + Local(&'a TypeckResults<'tcx>), + Foreign(&'tcx GeneratorDiagnosticData<'tcx>), +} + +impl<'tcx, 'a> GeneratorData<'tcx, 'a> { + // Try to get information about variables captured by the generator that matches a type we are + // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to + // meet an obligation + fn try_get_upvar_span( + &self, + infer_context: &InferCtxt<'a, 'tcx>, + generator_did: DefId, + ty_matches: F, + ) -> Option + where + F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool, + { + match self { + GeneratorData::Local(typeck_results) => { + infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| { + upvars.iter().find_map(|(upvar_id, upvar)| { + let upvar_ty = typeck_results.node_type(*upvar_id); + let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty); + if ty_matches(ty::Binder::dummy(upvar_ty)) { + Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) + } else { + None + } + }) + }) + } + GeneratorData::Foreign(_) => None, + } + } + + // Try to get the span of a type being awaited on that matches the type we are looking with the + // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an + // obligation + fn get_from_await_ty( + &self, + visitor: AwaitsVisitor, + hir: map::Map<'tcx>, + ty_matches: F, + ) -> Option + where + F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool, + { + match self { + GeneratorData::Local(typeck_results) => visitor + .awaits + .into_iter() + .map(|id| hir.expect_expr(id)) + .find(|await_expr| { + ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr))) + }) + .map(|expr| expr.span), + GeneratorData::Foreign(generator_diagnostic_data) => visitor + .awaits + .into_iter() + .map(|id| hir.expect_expr(id)) + .find(|await_expr| { + ty_matches(ty::Binder::dummy( + generator_diagnostic_data + .adjustments + .get(&await_expr.hir_id.local_id) + .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..]) + .last() + .map_or_else::, _, _>( + || { + generator_diagnostic_data + .nodes_types + .get(&await_expr.hir_id.local_id) + .cloned() + .unwrap_or_else(|| { + bug!( + "node_type: no type for node `{}`", + ty::tls::with(|tcx| tcx + .hir() + .node_to_string(await_expr.hir_id)) + ) + }) + }, + |adj| adj.target, + ), + )) + }) + .map(|expr| expr.span), + } + } + + /// Get the type, expression, span and optional scope span of all types + /// that are live across the yield of this generator + fn get_generator_interior_types( + &self, + ) -> ty::Binder<'tcx, &[GeneratorInteriorTypeCause<'tcx>]> { + match self { + GeneratorData::Local(typeck_result) => { + typeck_result.generator_interior_types.as_deref() + } + GeneratorData::Foreign(generator_diagnostic_data) => { + generator_diagnostic_data.generator_interior_types.as_deref() + } + } + } + + // Used to get the source of the data, note we don't have as much information for generators + // originated from foreign crates + fn is_foreign(&self) -> bool { + match self { + GeneratorData::Local(_) => false, + GeneratorData::Foreign(_) => true, + } + } +} + +// This trait is public to expose the diagnostics methods to clippy. +pub trait InferCtxtExt<'tcx> { + fn suggest_restricting_param_bound( + &self, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + proj_pred: Option>, + body_id: hir::HirId, + ); + + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool; + + fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option; + + fn suggest_fn_call( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool; + + fn suggest_add_reference_to_arg( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + has_custom_message: bool, + ) -> bool; + + fn suggest_borrowing_for_object_cast( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + self_ty: Ty<'tcx>, + object_ty: Ty<'tcx>, + ); + + fn suggest_remove_reference( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool; + + fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic); + + fn suggest_change_mut( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ); + + fn suggest_semicolon_removal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + span: Span, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool; + + fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option; + + fn suggest_impl_trait( + &self, + err: &mut Diagnostic, + span: Span, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool; + + fn point_at_returns_when_relevant( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + ); + + fn report_closure_arg_mismatch( + &self, + span: Span, + found_span: Option, + found: ty::PolyTraitRef<'tcx>, + expected: ty::PolyTraitRef<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + + fn suggest_fully_qualified_path( + &self, + err: &mut Diagnostic, + item_def_id: DefId, + span: Span, + trait_ref: DefId, + ); + + fn maybe_note_obligation_cause_for_async_await( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + ) -> bool; + + fn note_obligation_cause_for_async_await( + &self, + err: &mut Diagnostic, + interior_or_upvar_span: GeneratorInteriorOrUpvar, + interior_extra_info: Option<(Option, Span, Option, Option)>, + is_async: bool, + outer_generator: Option, + trait_pred: ty::TraitPredicate<'tcx>, + target_ty: Ty<'tcx>, + typeck_results: Option<&ty::TypeckResults<'tcx>>, + obligation: &PredicateObligation<'tcx>, + next_code: Option<&ObligationCauseCode<'tcx>>, + ); + + fn note_obligation_cause_code( + &self, + err: &mut Diagnostic, + predicate: &T, + param_env: ty::ParamEnv<'tcx>, + cause_code: &ObligationCauseCode<'tcx>, + obligated_types: &mut Vec>, + seen_requirements: &mut FxHashSet, + ) where + T: fmt::Display; + + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); + + /// Suggest to await before try: future? => future.await? + fn suggest_await_before_try( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + span: Span, + ); + + fn suggest_floating_point_literal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_ref: &ty::PolyTraitRef<'tcx>, + ); + + fn suggest_derive( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ); + + fn suggest_dereferencing_index( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ); +} + +fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { + ( + generics.tail_span_for_predicate_suggestion(), + format!("{} {}", generics.add_where_or_trailing_comma(), 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>( + tcx: TyCtxt<'tcx>, + hir_id: HirId, + hir_generics: &hir::Generics<'tcx>, + msg: &str, + err: &mut Diagnostic, + fn_sig: Option<&hir::FnSig<'_>>, + projection: Option<&ty::ProjectionTy<'_>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + // When we are dealing with a trait, `super_traits` will be `Some`: + // Given `trait T: A + B + C {}` + // - ^^^^^^^^^ GenericBounds + // | + // &Ident + super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, +) { + if hir_generics.where_clause_span.from_expansion() + || hir_generics.where_clause_span.desugaring_kind().is_some() + { + return; + } + let Some(item_id) = hir_id.as_owner() else { return; }; + let generics = tcx.generics_of(item_id); + // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... + if let Some((param, 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) => { + let param_def = generics.type_param(param, tcx); + if param_def.kind.is_synthetic() { + let bound_str = + param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string(); + return Some((param_def, bound_str, sig)); + } + None + } + _ => None, + }) + { + let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str)); + let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder { + tcx, + param, + replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name)) + .to_ty(tcx), + }); + if !trait_pred.is_suggestable(tcx, false) { + return; + } + // We know we have an `impl Trait` that doesn't satisfy a required projection. + + // Find all of the occurrences 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![]; + for input in fn_sig.decl.inputs { + ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id } + .visit_ty(input); + } + // The type param `T: Trait` we will suggest to introduce. + let type_param = format!("{}: {}", type_param_name, bound_str); + + let mut sugg = vec![ + if let Some(span) = hir_generics.span_for_param_suggestion() { + (span, format!(", {}", type_param)) + } else { + (hir_generics.span, format!("<{}>", type_param)) + }, + // `fn foo(t: impl Trait)` + // ^ suggest `where ::A: Bound` + predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()), + ]; + sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string()))); + + // Suggest `fn foo(t: T) where ::A: Bound`. + // FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest + // `fn foo(t: impl Trait)` instead. + err.multipart_suggestion( + "introduce a type parameter with a trait bound instead of using `impl Trait`", + sugg, + Applicability::MaybeIncorrect, + ); + } else { + if !trait_pred.is_suggestable(tcx, false) { + return; + } + // Trivial case: `T` needs an extra bound: `T: Bound`. + let (sp, suggestion) = match ( + hir_generics + .params + .iter() + .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })), + super_traits, + ) { + (_, None) => { + predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()) + } + (None, Some((ident, []))) => ( + ident.span.shrink_to_hi(), + format!(": {}", trait_pred.print_modifiers_and_trait_path()), + ), + (_, Some((_, [.., bounds]))) => ( + bounds.span().shrink_to_hi(), + format!(" + {}", trait_pred.print_modifiers_and_trait_path()), + ), + (Some(_), Some((_, []))) => ( + hir_generics.span.shrink_to_hi(), + format!(": {}", trait_pred.print_modifiers_and_trait_path()), + ), + }; + + 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 Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + proj_pred: Option>, + body_id: hir::HirId, + ) { + let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); + + let self_ty = trait_pred.skip_binder().self_ty(); + let (param_ty, projection) = match self_ty.kind() { + ty::Param(_) => (true, None), + ty::Projection(projection) => (false, Some(projection)), + _ => (false, None), + }; + + // 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, + hir_id, + &generics, + "`Self`", + err, + None, + projection, + trait_pred, + 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, hir_id, &generics, "`Self`", err, None, projection, trait_pred, + 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, + hir_id, + &generics, + "the associated type", + err, + Some(fn_sig), + projection, + trait_pred, + None, + ); + return; + } + hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Trait(_, _, generics, ..) + | hir::ItemKind::Impl(hir::Impl { generics, .. }), + .. + }) if projection.is_some() => { + // Missing restriction on associated type of type parameter (unmet projection). + suggest_restriction( + self.tcx, + hir_id, + &generics, + "the associated type", + err, + None, + projection, + trait_pred, + 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(hir::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 => + { + // We skip the 0'th subst (self) because we do not want + // to consider the predicate as not suggestible if the + // self type is an arg position `impl Trait` -- instead, + // we handle that by adding ` + Bound` below. + // FIXME(compiler-errors): It would be nice to do the same + // this that we do in `suggest_restriction` and pull the + // `impl Trait` into a new generic if it shows up somewhere + // else in the predicate. + if !trait_pred.skip_binder().trait_ref.substs[1..] + .iter() + .all(|g| g.is_suggestable(self.tcx, false)) + { + return; + } + // Missing generic type parameter bound. + let param_name = self_ty.to_string(); + let mut constraint = with_no_trimmed_paths!( + trait_pred.print_modifiers_and_trait_path().to_string() + ); + + if let Some(proj_pred) = proj_pred { + let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder(); + let item = self.tcx.associated_item(projection_ty.item_def_id); + + // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. + // That should be extracted into a helper function. + if constraint.ends_with('>') { + constraint = format!( + "{}, {}={}>", + &constraint[..constraint.len() - 1], + item.name, + term + ); + } else { + constraint.push_str(&format!("<{}={}>", item.name, term)); + } + } + + if suggest_constraining_type_param( + self.tcx, + generics, + &mut err, + ¶m_name, + &constraint, + Some(trait_pred.def_id()), + ) { + 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(hir::Impl { generics, .. }) + | hir::ItemKind::Fn(_, generics, _) + | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::TraitAlias(generics, _) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + .. + }) if !param_ty => { + // Missing generic type parameter bound. + if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) { + return; + } + } + hir::Node::Crate(..) => return, + + _ => {} + } + + hir_id = self.tcx.hir().local_def_id_to_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 Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { + // It only make sense when suggesting dereferences for arguments + let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else { + return false; + }; + let param_env = obligation.param_env; + let body_id = obligation.cause.body_id; + let span = obligation.cause.span; + let mut real_trait_pred = trait_pred; + let mut code = obligation.cause.code(); + while let Some((parent_code, parent_trait_pred)) = code.parent() { + code = parent_code; + if let Some(parent_trait_pred) = parent_trait_pred { + real_trait_pred = parent_trait_pred; + } + + // Skipping binder here, remapping below + let real_ty = real_trait_pred.self_ty().skip_binder(); + + if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); + if let Some(steps) = autoderef.find_map(|(ty, steps)| { + // Re-add the `&` + let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + + // Remapping bound vars here + let real_trait_pred_and_ty = + real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty)); + let obligation = self + .mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_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 dereferencing here", + format!("&{}{}", derefs, &src[1..]), + Applicability::MachineApplicable, + ); + return true; + } + } + } + } else if real_trait_pred != trait_pred { + // This branch addresses #87437. + + // Remapping bound vars here + let real_trait_pred_and_base_ty = + real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty)); + let obligation = self.mk_trait_obligation_with_new_self_ty( + param_env, + real_trait_pred_and_base_ty, + ); + if self.predicate_may_hold(&obligation) { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider dereferencing here", + "*", + Applicability::MachineApplicable, + ); + return true; + } + } + } + } + false + } + + /// 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 Diagnostic, msg: &str) -> Option { + let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option { + // 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, _, ident, None) => { + Some(ident.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`. + 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 Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { + // Skipping binder here, remapping below + let self_ty = trait_pred.self_ty().skip_binder(); + + 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 false, + }; + let msg = format!("use parentheses to call the {}", callable); + + // "We should really create a single list of bound vars from the combined vars + // from the predicate and function, but instead we just liberate the function bound vars" + let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty); + + // Remapping bound vars here + let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty)); + + let new_obligation = + self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self); + + match self.evaluate_obligation(&new_obligation) { + Ok( + EvaluationResult::EvaluatedToOk + | EvaluationResult::EvaluatedToOkModuloRegions + | EvaluationResult::EvaluatedToOkModuloOpaqueTypes + | EvaluationResult::EvaluatedToAmbig, + ) => {} + _ => return false, + } + 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(hir::Closure { fn_decl, fn_decl_span, .. }), + .. + })) => { + err.span_label(*fn_decl_span, "consider calling this closure"); + let Some(name) = self.get_closure_name(def_id, err, &msg) else { + return false; + }; + let args = fn_decl.inputs.iter().map(|_| "_").collect::>().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::>() + .join(", "); + let sugg = format!("({})", args); + (format!("{}{}", ident, sugg), sugg) + } + _ => return false, + }; + if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }) + { + // 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. 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)); + } + true + } + + fn suggest_add_reference_to_arg( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + poly_trait_pred: ty::PolyTraitPredicate<'tcx>, + has_custom_message: bool, + ) -> bool { + let span = obligation.cause.span; + + let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = + obligation.cause.code() + { + &parent_code + } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = + span.ctxt().outer_expn_data().kind + { + obligation.cause.code() + } else { + return false; + }; + + // List of traits for which it would be nonsensical to suggest borrowing. + // For instance, immutable references are always Copy, so suggesting to + // borrow would always succeed, but it's probably not what the user wanted. + let mut never_suggest_borrow: Vec<_> = + [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized] + .iter() + .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) + .collect(); + + if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) { + never_suggest_borrow.push(def_id); + } + + let param_env = obligation.param_env; + + // Try to apply the original trait binding obligation by borrowing. + let mut try_borrowing = + |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool { + if blacklist.contains(&old_pred.def_id()) { + return false; + } + // We map bounds to `&T` and `&mut T` + let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| { + ( + trait_pred, + self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + ) + }); + let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| { + ( + trait_pred, + self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()), + ) + }); + + let mk_result = |trait_pred_and_new_ty| { + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); + self.predicate_must_hold_modulo_regions(&obligation) + }; + let imm_result = mk_result(trait_pred_and_imm_ref); + let mut_result = mk_result(trait_pred_and_mut_ref); + + if imm_result || mut_result { + 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", old_pred); + if has_custom_message { + err.note(&msg); + } else { + err.message = + vec![(rustc_errors::DiagnosticMessage::Str(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 `{}`", + old_pred.print_modifiers_and_trait_path(), + ), + ); + + // This if is to prevent a special edge-case + if matches!( + span.ctxt().outer_expn_data().kind, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) + ) { + // We don't want a borrowing suggestion on the fields in structs, + // ``` + // struct Foo { + // the_foos: Vec + // } + // ``` + + if imm_result && mut_result { + err.span_suggestions( + span.shrink_to_lo(), + "consider borrowing here", + ["&".to_string(), "&mut ".to_string()].into_iter(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider{} borrowing here", + if mut_result { " mutably" } else { "" } + ), + format!("&{}", if mut_result { "mut " } else { "" }), + Applicability::MaybeIncorrect, + ); + } + } + return true; + } + } + return false; + }; + + if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code { + try_borrowing(cause.derived.parent_trait_pred, &[]) + } else if let ObligationCauseCode::BindingObligation(_, _) + | ObligationCauseCode::ItemObligation(_) = code + { + try_borrowing(poly_trait_pred, &never_suggest_borrow) + } else { + false + } + } + + // Suggest borrowing the type + fn suggest_borrowing_for_object_cast( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + self_ty: Ty<'tcx>, + object_ty: Ty<'tcx>, + ) { + let ty::Dynamic(predicates, _) = object_ty.kind() else { return; }; + let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); + + for predicate in predicates.iter() { + if !self.predicate_must_hold_modulo_regions( + &obligation.with(predicate.with_self_ty(self.tcx, self_ref_ty)), + ) { + return; + } + } + + err.span_suggestion( + obligation.cause.span.shrink_to_lo(), + &format!( + "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`" + ), + "&", + Applicability::MaybeIncorrect, + ); + } + + /// 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 Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { + let span = obligation.cause.span; + + let mut suggested = false; + 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 false; + } + + // Skipping binder here, remapping below + let mut suggested_ty = trait_pred.self_ty().skip_binder(); + + for refs_remaining in 0..refs_number { + let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { + break; + }; + suggested_ty = *inner_ty; + + // Remapping bound vars here + let trait_pred_and_suggested_ty = + trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); + + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred_and_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, "", Applicability::MachineApplicable); + suggested = true; + break; + } + } + } + suggested + } + + fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { + let span = obligation.cause.span; + + if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() { + let hir = self.tcx.hir(); + if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) { + if let hir::Node::Expr(expr) = node { + // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` + // and if not maybe suggest doing something else? If we kept the expression around we + // could also check if it is an fn call (very likely) and suggest changing *that*, if + // it is from the local crate. + err.span_suggestion_verbose( + expr.span.shrink_to_hi().with_hi(span.hi()), + "remove the `.await`", + "", + Applicability::MachineApplicable, + ); + // FIXME: account for associated `async fn`s. + if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr { + if let ty::PredicateKind::Trait(pred) = + obligation.predicate.kind().skip_binder() + { + err.span_label( + *span, + &format!("this call returns `{}`", pred.self_ty()), + ); + } + if let Some(typeck_results) = + self.in_progress_typeck_results.map(|t| t.borrow()) + && let ty = typeck_results.expr_ty_adjusted(base) + && let ty::FnDef(def_id, _substs) = ty.kind() + && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = + hir.get_if_local(*def_id) + { + let msg = format!( + "alternatively, consider making `fn {}` asynchronous", + ident + ); + if vis_span.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &msg, + "async ", + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + vis_span.shrink_to_hi(), + &msg, + " async", + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + } + } + + /// 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 Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) { + let points_at_arg = matches!( + obligation.cause.code(), + ObligationCauseCode::FunctionArgumentObligation { .. }, + ); + + 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_pred = self.resolve_vars_if_possible(trait_pred); + if trait_pred.has_infer_types_or_consts() { + // Do not ICE while trying to find if a reborrow would succeed on a trait with + // unresolved bindings. + return; + } + + // Skipping binder here, remapping below + if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind() + { + 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), + }; + + // Remapping bound vars here + let trait_pred_and_suggested_ty = + trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); + + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred_and_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 ", + Applicability::MachineApplicable, + ); + } else { + err.note(&format!( + "`{}` is implemented for `{:?}`, but not for `{:?}`", + trait_pred.print_modifiers_and_trait_path(), + suggested_ty, + trait_pred.skip_binder().self_ty(), + )); + } + } + } + } + } + + fn suggest_semicolon_removal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + span: Span, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { + 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 hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind + && sig.decl.output.span().overlaps(span) + && blk.expr.is_none() + && trait_pred.self_ty().skip_binder().is_unit() + && let Some(stmt) = blk.stmts.last() + && let hir::StmtKind::Semi(expr) = stmt.kind + // Only suggest this if the expression behind the semicolon implements the predicate + && let Some(typeck_results) = self.in_progress_typeck_results + && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr) + && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty)) + )) + { + err.span_label( + expr.span, + &format!( + "this expression has type `{}`, which implements `{}`", + ty, + trait_pred.print_modifiers_and_trait_path() + ) + ); + err.span_suggestion( + self.tcx.sess.source_map().end_point(stmt.span), + "remove this semicolon", + "", + Applicability::MachineApplicable + ); + return true; + } + false + } + + fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { + let hir = self.tcx.hir(); + let parent_node = hir.get_parent_node(obligation.cause.body_id); + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else { + 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 Diagnostic, + span: Span, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'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 fn_hir_id = hir.get_parent_node(obligation.cause.body_id); + let node = hir.find(fn_hir_id); + let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(sig, _, body_id), + .. + })) = node + else { + return false; + }; + let body = hir.body(*body_id); + let trait_pred = self.resolve_vars_if_possible(trait_pred); + let ty = trait_pred.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`. + 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 hir::FnRetTy::Return(ret_ty) = sig.decl.output 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` 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 Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; + + let ret_types = visitor + .returns + .iter() + .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?))) + .map(|(expr_span, ty)| (expr_span, 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>, 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 mut spans_and_needs_box = vec![]; + + match liberated_sig.output().kind() { + ty::Dynamic(predicates, _) => { + let cause = ObligationCause::misc(ret_ty.span, fn_hir_id); + let param_env = ty::ParamEnv::empty(); + + if !only_never_return { + for (expr_span, return_ty) in ret_types { + let self_ty_satisfies_dyn_predicates = |self_ty| { + predicates.iter().all(|predicate| { + let pred = predicate.with_self_ty(self.tcx, self_ty); + let obl = Obligation::new(cause.clone(), param_env, pred); + self.predicate_may_hold(&obl) + }) + }; + + if let ty::Adt(def, substs) = return_ty.kind() + && def.is_box() + && self_ty_satisfies_dyn_predicates(substs.type_at(0)) + { + spans_and_needs_box.push((expr_span, false)); + } else if self_ty_satisfies_dyn_predicates(return_ty) { + spans_and_needs_box.push((expr_span, true)); + } else { + return false; + } + } + } + } + _ => return false, + }; + + let sm = self.tcx.sess.source_map(); + if !ret_ty.span.overlaps(span) { + return false; + } + let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind { + if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) { + snippet + } else { + return false; + } + } else { + // Substitute the type, so we can print a fixup given `type Alias = dyn Trait` + let name = liberated_sig.output().to_string(); + let name = + name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name); + if !name.starts_with("dyn ") { + return false; + } + name.to_owned() + }; + + 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 \ + "; + let trait_obj_msg = "for information on trait objects, see \ + "; + + 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`. + 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` and `Box::new(returned_value)`. + err.multipart_suggestion( + "return a boxed trait object instead", + vec![ + (ret_ty.span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MaybeIncorrect, + ); + for (span, needs_box) in spans_and_needs_box { + if needs_box { + err.multipart_suggestion( + "... and box this value", + vec![ + (span.shrink_to_lo(), "Box::new(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ], + 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 `{}` were 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 Diagnostic, + 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, + found: ty::PolyTraitRef<'tcx>, + expected: ty::PolyTraitRef<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + pub(crate) fn build_fn_sig_ty<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx> { + let inputs = trait_ref.skip_binder().substs.type_at(1); + let sig = match inputs.kind() { + ty::Tuple(inputs) + if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() => + { + tcx.mk_fn_sig( + inputs.iter(), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), + false, + hir::Unsafety::Normal, + abi::Abi::Rust, + ) + } + _ => tcx.mk_fn_sig( + std::iter::once(inputs), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), + false, + hir::Unsafety::Normal, + abi::Abi::Rust, + ), + }; + + tcx.mk_fn_ptr(trait_ref.rebind(sig)) + } + + let argument_kind = match expected.skip_binder().self_ty().kind() { + ty::Closure(..) => "closure", + ty::Generator(..) => "generator", + _ => "function", + }; + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0631, + "type mismatch in {argument_kind} arguments", + ); + + err.span_label(span, "expected due to this"); + + let found_span = found_span.unwrap_or(span); + err.span_label(found_span, "found signature defined here"); + + let expected = build_fn_sig_ty(self.tcx, expected); + let found = build_fn_sig_ty(self.tcx, found); + + let (expected_str, found_str) = + self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found)); + + let signature_kind = format!("{argument_kind} signature"); + err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str); + + err + } + + fn suggest_fully_qualified_path( + &self, + err: &mut Diagnostic, + item_def_id: DefId, + span: Span, + trait_ref: DefId, + ) { + if let Some(assoc_item) = self.tcx.opt_associated_item(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(item_def_id) + )); + err.span_suggestion( + span, + "use the fully qualified path to an implementation", + format!("::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), + 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: 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. + #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] + fn maybe_note_obligation_cause_for_async_await( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + 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 an `async fn` A that calls an `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.kind().skip_binder() { + ty::PredicateKind::Trait(p) => (Some(p), Some(p.self_ty())), + _ => (None, None), + }; + let mut generator = None; + let mut outer_generator = None; + let mut next_code = Some(obligation.cause.code()); + + let mut seen_upvar_tys_infer_tuple = false; + + while let Some(code) = next_code { + debug!(?code); + match code { + ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { + next_code = Some(parent_code); + } + ObligationCauseCode::ImplDerivedObligation(cause) => { + let ty = cause.derived.parent_trait_pred.skip_binder().self_ty(); + debug!( + parent_trait_ref = ?cause.derived.parent_trait_pred, + self_ty.kind = ?ty.kind(), + "ImplDerived", + ); + + match *ty.kind() { + ty::Generator(did, ..) => { + generator = generator.or(Some(did)); + outer_generator = Some(did); + } + ty::GeneratorWitness(..) => {} + ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { + // By introducing a tuple of upvar types into the chain of obligations + // of a generator, the first non-generator item is now the tuple itself, + // we shall ignore this. + + seen_upvar_tys_infer_tuple = true; + } + _ if generator.is_none() => { + trait_ref = Some(cause.derived.parent_trait_pred.skip_binder()); + target_ty = Some(ty); + } + _ => {} + } + + next_code = Some(&cause.derived.parent_code); + } + ObligationCauseCode::DerivedObligation(derived_obligation) + | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => { + let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty(); + debug!( + parent_trait_ref = ?derived_obligation.parent_trait_pred, + self_ty.kind = ?ty.kind(), + ); + + match *ty.kind() { + ty::Generator(did, ..) => { + generator = generator.or(Some(did)); + outer_generator = Some(did); + } + ty::GeneratorWitness(..) => {} + ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { + // By introducing a tuple of upvar types into the chain of obligations + // of a generator, the first non-generator item is now the tuple itself, + // we shall ignore this. + + seen_upvar_tys_infer_tuple = true; + } + _ if generator.is_none() => { + trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder()); + target_ty = Some(ty); + } + _ => {} + } + + next_code = Some(&derived_obligation.parent_code); + } + _ => break, + } + } + + // Only continue if a generator was found. + debug!(?generator, ?trait_ref, ?target_ty); + let (Some(generator_did), Some(trait_ref), Some(target_ty)) = (generator, trait_ref, target_ty) else { + return false; + }; + + let span = self.tcx.def_span(generator_did); + + let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()); + let generator_did_root = self.tcx.typeck_root_def_id(generator_did); + debug!( + ?generator_did, + ?generator_did_root, + in_progress_typeck_results.hir_owner = ?in_progress_typeck_results.as_ref().map(|t| t.hir_owner), + ?span, + ); + + let generator_body = generator_did + .as_local() + .and_then(|def_id| hir.maybe_body_owned_by(def_id)) + .map(|body_id| hir.body(body_id)); + let is_async = match generator_did.as_local() { + Some(_) => generator_body + .and_then(|body| body.generator_kind()) + .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..))) + .unwrap_or(false), + None => self + .tcx + .generator_kind(generator_did) + .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..))) + .unwrap_or(false), + }; + let mut visitor = AwaitsVisitor::default(); + if let Some(body) = generator_body { + visitor.visit_body(body); + } + debug!(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); + let ty_erased = self.tcx.erase_regions(ty_erased); + let eq = ty_erased == target_ty_erased; + debug!(?ty_erased, ?target_ty_erased, ?eq); + eq + }; + + let mut interior_or_upvar_span = None; + let mut interior_extra_info = None; + + // 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. If we can't use resolved types because the generator comes from another crate, + // we still provide a targeted error but without all the relevant spans. + let generator_data: Option> = match &in_progress_typeck_results { + Some(t) if t.hir_owner.to_def_id() == generator_did_root => { + Some(GeneratorData::Local(&t)) + } + _ if generator_did.is_local() => { + Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local()))) + } + _ => self + .tcx + .generator_diagnostic_data(generator_did) + .as_ref() + .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)), + }; + + if let Some(generator_data) = generator_data.as_ref() { + interior_or_upvar_span = + generator_data.try_get_upvar_span(&self, generator_did, ty_matches); + + // The generator interior types share the same binders + if let Some(cause) = + generator_data.get_generator_interior_types().skip_binder().iter().find( + |ty::GeneratorInteriorTypeCause { ty, .. }| { + ty_matches(generator_data.get_generator_interior_types().rebind(*ty)) + }, + ) + { + let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches); + 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)); + } + + if interior_or_upvar_span.is_none() && generator_data.is_foreign() { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span)); + } + } + + if let Some(interior_or_upvar_span) = interior_or_upvar_span { + let typeck_results = generator_data.and_then(|generator_data| match generator_data { + GeneratorData::Local(typeck_results) => Some(typeck_results), + GeneratorData::Foreign(_) => None, + }); + self.note_obligation_cause_for_async_await( + err, + interior_or_upvar_span, + interior_extra_info, + is_async, + 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. + #[instrument(level = "debug", skip_all)] + fn note_obligation_cause_for_async_await( + &self, + err: &mut Diagnostic, + interior_or_upvar_span: GeneratorInteriorOrUpvar, + interior_extra_info: Option<(Option, Span, Option, Option)>, + is_async: bool, + outer_generator: Option, + trait_pred: ty::TraitPredicate<'tcx>, + target_ty: Ty<'tcx>, + typeck_results: Option<&ty::TypeckResults<'tcx>>, + obligation: &PredicateObligation<'tcx>, + next_code: Option<&ObligationCauseCode<'tcx>>, + ) { + let source_map = self.tcx.sess.source_map(); + + 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 hir = self.tcx.hir(); + let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = + self.tcx.get_diagnostic_name(trait_pred.def_id()) + { + let (trait_name, trait_verb) = + if name == sym::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) + .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_pred.print_modifiers_and_trait_path()) + }; + + let mut explain_yield = |interior_span: Span, + yield_span: Span, + scope_span: Option| { + let mut span = MultiSpan::from_span(yield_span); + if let Ok(snippet) = source_map.span_to_snippet(interior_span) { + // #70935: If snippet contains newlines, display "the value" instead + // so that we do not emit complex diagnostics. + let snippet = &format!("`{}`", snippet); + let snippet = if snippet.contains('\n') { "the value" } else { snippet }; + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | baz(|| async { + // | ______________- + // | | + // | | + // LL | | foo(tx.clone()); + // LL | | }).await; + // | | - ^^^^^^ await occurs here, with value maybe used later + // | |__________| + // | has type `closure` which is not `Send` + // note: value is later dropped here + // LL | | }).await; + // | | ^ + // + span.push_span_label( + yield_span, + format!("{} occurs here, with {} maybe used later", await_or_yield, snippet), + ); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + // If available, use the scope span to annotate the drop location. + let mut scope_note = None; + if let Some(scope_span) = scope_span { + let scope_span = source_map.end_point(scope_span); + + let msg = format!("{} is later dropped here", snippet); + if source_map.is_multiline(yield_span.between(scope_span)) { + span.push_span_label(scope_span, msg); + } else { + scope_note = Some((scope_span, msg)); + } + } + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + if let Some((span, msg)) = scope_note { + err.span_note(span, &msg); + } + } + }; + 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!( + generator_interior_types = ?format_args!( + "{:#?}", typeck_results.as_ref().map(|t| &t.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 = if let Some(typeck_results) = typeck_results { + typeck_results + .expr_adjustments(expr) + .iter() + .any(|adj| adj.is_region_borrow()) + } else { + false + }; + + // ```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 let Some(typeck_results) = typeck_results { + 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) => { + // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync` + let refers_to_non_sync = match target_ty.kind() { + ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) { + Ok(eval) if !eval.may_apply() => Some(ref_ty), + _ => None, + }, + _ => None, + }; + + let (span_label, span_note) = match refers_to_non_sync { + // if `target_ty` is `&T` and `T` fails to impl `Sync`, + // include suggestions to make `T: Sync` so that `&T: Send` + Some(ref_ty) => ( + format!( + "has type `{}` which {}, because `{}` is not `Sync`", + target_ty, trait_explanation, ref_ty + ), + format!( + "captured value {} because `&` references cannot be sent unless their referent is `Sync`", + trait_explanation + ), + ), + None => ( + format!("has type `{}` which {}", target_ty, trait_explanation), + format!("captured value {}", trait_explanation), + ), + }; + + let mut span = MultiSpan::from_span(upvar_span); + span.push_span_label(upvar_span, span_label); + err.span_note(span, &span_note); + } + } + + // 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!(?next_code); + self.note_obligation_cause_code( + err, + &obligation.predicate, + obligation.param_env, + next_code.unwrap(), + &mut Vec::new(), + &mut Default::default(), + ); + } + + fn note_obligation_cause_code( + &self, + err: &mut Diagnostic, + predicate: &T, + param_env: ty::ParamEnv<'tcx>, + cause_code: &ObligationCauseCode<'tcx>, + obligated_types: &mut Vec>, + seen_requirements: &mut FxHashSet, + ) 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::OpaqueType + | ObligationCauseCode::MiscObligation + | ObligationCauseCode::WellFormed(..) + | ObligationCauseCode::MatchImpl(..) + | ObligationCauseCode::ReturnType + | ObligationCauseCode::ReturnValue(_) + | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::AwaitableExpr(_) + | ObligationCauseCode::ForLoopIterator + | ObligationCauseCode::QuestionMark + | ObligationCauseCode::CheckAssociatedTypeBounds { .. } + | ObligationCauseCode::LetElse + | ObligationCauseCode::BinOp { .. } => {} + 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) => { + // We hold the `DefId` of the item introducing the obligation, but displaying it + // doesn't add user usable information. It always point at an associated item. + } + ObligationCauseCode::BindingObligation(item_def_id, span) => { + let item_name = tcx.def_path_str(item_def_id); + let mut multispan = MultiSpan::from(span); + if let Some(ident) = tcx.opt_item_ident(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 { + multispan.push_span_label(ident.span, "required by a bound in this"); + } + } + let descr = format!("required by a bound in `{}`", item_name); + if span != DUMMY_SP { + let msg = format!("required by this bound in `{}`", item_name); + multispan.push_span_label(span, msg); + err.span_note(multispan, &descr); + } else { + err.span_note(tcx.def_span(item_def_id), &descr); + } + } + ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => { + err.note(&format!( + "required for the cast from `{}` to the object type `{}`", + self.ty_to_string(concrete_ty), + self.ty_to_string(object_ty) + )); + } + ObligationCauseCode::Coercion { source: _, target } => { + err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); + } + ObligationCauseCode::RepeatElementCopy { is_const_fn } => { + err.note( + "the `Copy` trait is required because this value will be copied for each element of the array", + ); + + if is_const_fn { + err.help( + "consider creating a new `const` item and initializing it with the result \ + of the function call to be used in the repeat position, like \ + `const VAL: Type = const_fn();` and `let x = [VAL; 42];`", + ); + } + + if self.tcx.sess.is_nightly_build() && is_const_fn { + err.help( + "create an inline `const` block, see RFC #2920 \ + for more information", + ); + } + } + 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", + "&", + 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", + "&", + 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", + "&", + 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_fn_params + { + err.help("unsized fn params 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::SizedBoxType => { + err.note("the type of a box expression 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", + "&", + 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_pred); + let ty = parent_trait_ref.skip_binder().self_ty(); + if parent_trait_ref.references_error() { + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); + return; + } + + // If the obligation for a tuple is set directly by a Generator or Closure, + // then the tuple must be the one containing capture types. + let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { + false + } else { + if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code + { + let parent_trait_ref = + self.resolve_vars_if_possible(data.parent_trait_pred); + let nested_ty = parent_trait_ref.skip_binder().self_ty(); + matches!(nested_ty.kind(), ty::Generator(..)) + || matches!(nested_ty.kind(), ty::Closure(..)) + } else { + false + } + }; + + let from_generator = tcx.lang_items().from_generator_fn().unwrap(); + + // Don't print the tuple of capture types + 'print: { + if !is_upvar_tys_infer_tuple { + let msg = format!("required because it appears within the type `{}`", ty); + match ty.kind() { + ty::Adt(def, _) => { + // `gen_future` is used in all async functions; it doesn't add any additional info. + if self.tcx.is_diagnostic_item(sym::gen_future, def.did()) { + break 'print; + } + match self.tcx.opt_item_ident(def.did()) { + Some(ident) => err.span_note(ident.span, &msg), + None => err.note(&msg), + } + } + ty::Opaque(def_id, _) => { + // Avoid printing the future from `core::future::from_generator`, it's not helpful + if tcx.parent(*def_id) == from_generator { + break 'print; + } + + // If the previous type is `from_generator`, this is the future generated by the body of an async function. + // Avoid printing it twice (it was already printed in the `ty::Generator` arm below). + let is_future = tcx.ty_is_opaque_future(ty); + debug!( + ?obligated_types, + ?is_future, + "note_obligation_cause_code: check for async fn" + ); + if is_future + && obligated_types.last().map_or(false, |ty| match ty.kind() { + ty::Opaque(last_def_id, _) => { + tcx.parent(*last_def_id) == from_generator + } + _ => false, + }) + { + break 'print; + } + err.span_note(self.tcx.def_span(def_id), &msg) + } + ty::GeneratorWitness(bound_tys) => { + use std::fmt::Write; + + // FIXME: this is kind of an unusual format for rustc, can we make it more clear? + // Maybe we should just remove this note altogether? + // FIXME: only print types which don't meet the trait requirement + let mut msg = + "required because it captures the following types: ".to_owned(); + for ty in bound_tys.skip_binder() { + write!(msg, "`{}`, ", ty).unwrap(); + } + err.note(msg.trim_end_matches(", ")) + } + ty::Generator(def_id, _, _) => { + let sp = self.tcx.def_span(def_id); + + // Special-case this to say "async block" instead of `[static generator]`. + let kind = tcx.generator_kind(def_id).unwrap(); + err.span_note( + sp, + &format!("required because it's used within this {}", kind), + ) + } + ty::Closure(def_id, _) => err.span_note( + self.tcx.def_span(def_id), + &format!("required because it's used within this closure"), + ), + _ => err.note(&msg), + }; + } + } + + obligated_types.push(ty); + + let parent_predicate = parent_trait_ref.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, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ) + }); + } else { + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + &parent_predicate, + param_env, + cause_code.peel_derives(), + obligated_types, + seen_requirements, + ) + }); + } + } + ObligationCauseCode::ImplDerivedObligation(ref data) => { + let mut parent_trait_pred = + self.resolve_vars_if_possible(data.derived.parent_trait_pred); + parent_trait_pred.remap_constness_diag(param_env); + let parent_def_id = parent_trait_pred.def_id(); + let msg = format!( + "required because of the requirements on the impl of `{}` for `{}`", + parent_trait_pred.print_modifiers_and_trait_path(), + parent_trait_pred.skip_binder().self_ty() + ); + let mut is_auto_trait = false; + match self.tcx.hir().get_if_local(data.impl_def_id) { + Some(Node::Item(hir::Item { + kind: hir::ItemKind::Trait(is_auto, ..), + ident, + .. + })) => { + // FIXME: we should do something else so that it works even on crate foreign + // auto traits. + is_auto_trait = matches!(is_auto, hir::IsAuto::Yes); + err.span_note(ident.span, &msg) + } + Some(Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), + .. + })) => { + let mut spans = Vec::with_capacity(2); + if let Some(trait_ref) = of_trait { + spans.push(trait_ref.path.span); + } + spans.push(self_ty.span); + err.span_note(spans, &msg) + } + _ => err.note(&msg), + }; + + let mut parent_predicate = parent_trait_pred.to_predicate(tcx); + let mut data = &data.derived; + let mut count = 0; + seen_requirements.insert(parent_def_id); + if is_auto_trait { + // We don't want to point at the ADT saying "required because it appears within + // the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`. + while let ObligationCauseCode::BuiltinDerivedObligation(derived) = + &*data.parent_code + { + let child_trait_ref = + self.resolve_vars_if_possible(derived.parent_trait_pred); + let child_def_id = child_trait_ref.def_id(); + if seen_requirements.insert(child_def_id) { + break; + } + data = derived; + parent_predicate = child_trait_ref.to_predicate(tcx); + parent_trait_pred = child_trait_ref; + } + } + while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code { + // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`. + let child_trait_pred = + self.resolve_vars_if_possible(child.derived.parent_trait_pred); + let child_def_id = child_trait_pred.def_id(); + if seen_requirements.insert(child_def_id) { + break; + } + count += 1; + data = &child.derived; + parent_predicate = child_trait_pred.to_predicate(tcx); + parent_trait_pred = child_trait_pred; + } + if count > 0 { + err.note(&format!( + "{} redundant requirement{} hidden", + count, + pluralize!(count) + )); + err.note(&format!( + "required because of the requirements on the impl of `{}` for `{}`", + parent_trait_pred.print_modifiers_and_trait_path(), + parent_trait_pred.skip_binder().self_ty() + )); + } + // #74711: avoid a stack overflow + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + &parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ) + }); + } + ObligationCauseCode::DerivedObligation(ref data) => { + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_predicate = parent_trait_ref.to_predicate(tcx); + // #74711: avoid a stack overflow + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + &parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ) + }); + } + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id, + call_hir_id, + ref parent_code, + } => { + let hir = self.tcx.hir(); + if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) = + hir.find(arg_hir_id) + { + let in_progress_typeck_results = + self.in_progress_typeck_results.map(|t| t.borrow()); + let parent_id = hir.get_parent_item(arg_hir_id); + let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results { + Some(t) if t.hir_owner == parent_id => t, + _ => self.tcx.typeck(parent_id), + }; + let ty = typeck_results.expr_ty_adjusted(expr); + let span = expr.peel_blocks().span; + if Some(span) != err.span.primary_span() { + err.span_label( + span, + &if ty.references_error() { + String::new() + } else { + format!("this tail expression is of type `{:?}`", ty) + }, + ); + } + } + if let Some(Node::Expr(hir::Expr { + kind: + hir::ExprKind::Call(hir::Expr { span, .. }, _) + | hir::ExprKind::MethodCall( + hir::PathSegment { ident: Ident { span, .. }, .. }, + .., + ), + .. + })) = hir.find(call_hir_id) + { + if Some(*span) != err.span.primary_span() { + err.span_label(*span, "required by a bound introduced by this call"); + } + } + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + err, + predicate, + param_env, + &parent_code, + obligated_types, + seen_requirements, + ) + }); + } + ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { + let item_name = self.tcx.item_name(trait_item_def_id); + let msg = format!( + "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \ + corresponding trait's {kind}", + predicate, item_name, + ); + let sp = self + .tcx + .opt_item_ident(trait_item_def_id) + .map(|i| i.span) + .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id)); + let mut assoc_span: MultiSpan = sp.into(); + assoc_span.push_span_label( + sp, + format!("this trait's {kind} doesn't have the requirement `{}`", predicate), + ); + if let Some(ident) = self + .tcx + .opt_associated_item(trait_item_def_id) + .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx))) + { + assoc_span.push_span_label(ident.span, "in this trait"); + } + err.span_note(assoc_span, &msg); + } + 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"); + } + } + ObligationCauseCode::OpaqueReturnType(expr_info) => { + if let Some((expr_ty, expr_span)) = expr_info { + let expr_ty = self.resolve_vars_if_possible(expr_ty); + err.span_label( + expr_span, + format!("return type was inferred to be `{expr_ty}` here"), + ); + } + } + } + } + + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { + let suggested_limit = match self.tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; + err.help(&format!( + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + suggested_limit, + self.tcx.crate_name(LOCAL_CRATE), + )); + } + + #[instrument( + level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty()) + )] + fn suggest_await_before_try( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + span: Span, + ) { + 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(self.tcx.hir().local_def_id(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_pred.self_ty()); + let impls_future = self.type_implements_trait( + future_trait, + self.tcx.erase_late_bound_regions(self_ty), + ty::List::empty(), + obligation.param_env, + ); + if !impls_future.must_apply_modulo_regions() { + return; + } + + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; + // `::Output` + let projection_ty = trait_pred.map_bound(|trait_pred| { + self.tcx.mk_projection( + item_def_id, + // Future::Output has no substs + self.tcx.mk_substs_trait(trait_pred.self_ty(), &[]), + ) + }); + let projection_ty = normalize_to( + &mut SelectionContext::new(self), + obligation.param_env, + obligation.cause.clone(), + projection_ty, + &mut vec![], + ); + + debug!( + normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) + ); + let try_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), + ); + debug!(try_trait_obligation = ?try_obligation); + if self.predicate_may_hold(&try_obligation) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && snippet.ends_with('?') + { + err.span_suggestion_verbose( + span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await", + Applicability::MaybeIncorrect, + ); + } + } + } + } + + fn suggest_floating_point_literal( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_ref: &ty::PolyTraitRef<'tcx>, + ) { + let rhs_span = match obligation.cause.code() { + ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span, + _ => return, + }; + match ( + trait_ref.skip_binder().self_ty().kind(), + trait_ref.skip_binder().substs.type_at(1).kind(), + ) { + (ty::Float(_), ty::Infer(InferTy::IntVar(_))) => { + err.span_suggestion_verbose( + rhs_span.shrink_to_hi(), + "consider using a floating-point literal by writing it with `.0`", + ".0", + Applicability::MaybeIncorrect, + ); + } + _ => {} + } + } + + fn suggest_derive( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) { + let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { + return; + }; + let (adt, substs) = match trait_pred.skip_binder().self_ty().kind() { + ty::Adt(adt, substs) if adt.did().is_local() => (adt, substs), + _ => return, + }; + let can_derive = { + let is_derivable_trait = match diagnostic_name { + sym::Default => !adt.is_enum(), + sym::PartialEq | sym::PartialOrd => { + let rhs_ty = trait_pred.skip_binder().trait_ref.substs.type_at(1); + trait_pred.skip_binder().self_ty() == rhs_ty + } + sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, + _ => false, + }; + is_derivable_trait && + // Ensure all fields impl the trait. + adt.all_fields().all(|field| { + let field_ty = field.ty(self.tcx, substs); + let trait_substs = match diagnostic_name { + sym::PartialEq | sym::PartialOrd => { + self.tcx.mk_substs_trait(field_ty, &[field_ty.into()]) + } + _ => self.tcx.mk_substs_trait(field_ty, &[]), + }; + let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { + trait_ref: ty::TraitRef { + substs: trait_substs, + ..trait_pred.skip_binder().trait_ref + }, + ..*tr + }); + let field_obl = Obligation::new( + obligation.cause.clone(), + obligation.param_env, + trait_pred.to_predicate(self.tcx), + ); + self.predicate_must_hold_modulo_regions(&field_obl) + }) + }; + if can_derive { + err.span_suggestion_verbose( + self.tcx.def_span(adt.did()).shrink_to_lo(), + &format!( + "consider annotating `{}` with `#[derive({})]`", + trait_pred.skip_binder().self_ty(), + diagnostic_name, + ), + format!("#[derive({})]\n", diagnostic_name), + Applicability::MaybeIncorrect, + ); + } + } + + fn suggest_dereferencing_index( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) { + if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() + && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) + && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.substs.type_at(1).kind() + && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind() + && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind() + { + err.span_suggestion_verbose( + obligation.cause.span.shrink_to_lo(), + "dereference this index", + '*', + Applicability::MachineApplicable, + ); + } + } +} + +/// 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> { + 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::If(_, then, else_opt) if self.in_block_tail => { + self.visit_expr(then); + if let Some(el) = else_opt { + self.visit_expr(el); + } + } + 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, +} + +impl<'v> Visitor<'v> for AwaitsVisitor { + 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::>(); + + 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 Diagnostic, + 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", + 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.multipart_suggestion( + &format!( + "use a boxed trait object if all return paths implement trait `{}`", + trait_obj, + ), + vec![ + (ret_ty.shrink_to_lo(), "Box<".to_string()), + (ret_ty.shrink_to_hi(), ">".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } +} + +/// Collect the spans that we see the generic param `param_did` +struct ReplaceImplTraitVisitor<'a> { + ty_spans: &'a mut Vec, + param_did: DefId, +} + +impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { + fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { + if let hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, + )) = t.kind + { + if self.param_did == *segment_did { + // `fn foo(t: impl Trait)` + // ^^^^^^^^^^ get this to suggest `T` instead + + // There might be more than one `impl Trait`. + self.ty_spans.push(t.span); + return; + } + } + + hir::intravisit::walk_ty(self, t); + } +} + +// Replace `param` with `replace_ty` +struct ReplaceImplTraitFolder<'tcx> { + tcx: TyCtxt<'tcx>, + param: &'tcx ty::GenericParamDef, + replace_ty: Ty<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Param(ty::ParamTy { index, .. }) = t.kind() { + if self.param.index == *index { + return self.replace_ty; + } + } + t.super_fold_with(self) + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} 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 000000000..556ef466c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -0,0 +1,757 @@ +use crate::infer::{InferCtxt, TyOrConstInferVar}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::obligation_forest::ProcessResult; +use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; +use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; +use rustc_infer::traits::ProjectionCacheKey; +use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable}; +use std::marker::PhantomData; + +use super::const_evaluatable; +use super::project::{self, ProjectAndUnifyResult}; +use super::select::SelectionContext; +use super::wf; +use super::CodeAmbiguity; +use super::CodeProjectionError; +use super::CodeSelectionError; +use super::EvaluationResult; +use super::Unimplemented; +use super::{FulfillmentError, FulfillmentErrorCode}; +use super::{ObligationCause, PredicateObligation}; + +use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::project::PolyProjectionObligation; +use crate::traits::project::ProjectionCacheKeyExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; + +impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { + /// Note that we include both the `ParamEnv` and the `Predicate`, + /// as the `ParamEnv` can influence whether fulfillment succeeds + /// 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>, + + relationships: FxHashMap, + + // 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>, +} + +// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(PendingPredicateObligation<'_>, 72); + +impl<'a, 'tcx> FulfillmentContext<'tcx> { + /// Creates a new fulfillment context. + pub fn new() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + relationships: FxHashMap::default(), + usable_in_snapshot: false, + } + } + + pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { + FulfillmentContext { + predicates: ObligationForest::new(), + relationships: FxHashMap::default(), + usable_in_snapshot: true, + } + } + + /// Attempts to select obligations using `selcx`. + fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec> { + let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); + let _enter = span.enter(); + + // Process pending obligations. + let outcome: Outcome<_, _> = + self.predicates.process_obligations(&mut FulfillProcessor { selcx }); + + // FIXME: if we kept the original cache key, we could mark projection + // obligations as complete for the projection cache here. + + let errors: Vec> = + outcome.errors.into_iter().map(to_fulfillment_error).collect(); + + debug!( + "select({} predicates remaining, {} errors) done", + self.predicates.len(), + errors.len() + ); + + errors + } +} + +impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { + /// "Normalize" a projection type `::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `::X == $0`. When the + /// 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. + #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))] + 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_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!(?normalized_ty); + + normalized_ty.ty().unwrap() + } + + 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!(?obligation, "register_predicate_obligation"); + + assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); + + super::relationships::update(self, infcx, &obligation); + + self.predicates + .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); + } + + fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec> { + { + let errors = self.select_where_possible(infcx); + if !errors.is_empty() { + return errors; + } + } + + self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() + } + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Vec> { + let mut selcx = SelectionContext::new(infcx); + self.select(&mut selcx) + } + + fn pending_obligations(&self) -> Vec> { + self.predicates.map_pending_obligations(|o| o.obligation.clone()) + } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } +} + +struct FulfillProcessor<'a, 'b, 'tcx> { + selcx: &'a mut SelectionContext<'b, 'tcx>, +} + +fn mk_pending(os: Vec>) -> Vec> { + 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>; + + /// Identifies whether a predicate obligation needs processing. + /// + /// This is always inlined, despite its size, because it has a single + /// callsite and it is called *very* frequently. + #[inline(always)] + fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { + // 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. + 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 + })() + } + } + } + + /// 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 called much less often than `needs_process_obligation`, so we + /// never inline it. + #[inline(never)] + #[instrument(level = "debug", skip(self, pending_obligation))] + fn process_obligation( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { + pending_obligation.stalled_on.truncate(0); + + let obligation = &mut pending_obligation.obligation; + + debug!(?obligation, "pre-resolve"); + + if obligation.predicate.has_infer_types_or_consts() { + obligation.predicate = + self.selcx.infcx().resolve_vars_if_possible(obligation.predicate); + } + + let obligation = &pending_obligation.obligation; + + let infcx = self.selcx.infcx(); + + if obligation.predicate.has_projections() { + let mut obligations = Vec::new(); + let predicate = crate::traits::project::try_normalize_with_depth_to( + self.selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.predicate, + &mut obligations, + ); + if predicate != obligation.predicate { + obligations.push(obligation.with(predicate)); + return ProcessResult::Changed(mk_pending(obligations)); + } + } + let binder = obligation.predicate.kind(); + match binder.no_bound_vars() { + None => 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::PredicateKind::Trait(trait_ref) => { + let trait_obligation = obligation.with(binder.rebind(trait_ref)); + + self.process_trait_obligation( + obligation, + trait_obligation, + &mut pending_obligation.stalled_on, + ) + } + ty::PredicateKind::Projection(data) => { + let project_obligation = obligation.with(binder.rebind(data)); + + self.process_projection_obligation( + obligation, + project_obligation, + &mut pending_obligation.stalled_on, + ) + } + ty::PredicateKind::RegionOutlives(_) + | ty::PredicateKind::TypeOutlives(_) + | ty::PredicateKind::WellFormed(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::Coerce(_) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => { + let pred = + ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); + ProcessResult::Changed(mk_pending(vec![ + obligation.with(pred.to_predicate(self.selcx.tcx())), + ])) + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } + }, + Some(pred) => match pred { + ty::PredicateKind::Trait(data) => { + let trait_obligation = obligation.with(Binder::dummy(data)); + + self.process_trait_obligation( + obligation, + trait_obligation, + &mut pending_obligation.stalled_on, + ) + } + + ty::PredicateKind::RegionOutlives(data) => { + if infcx.considering_regions || data.has_placeholders() { + infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); + } + + ProcessResult::Changed(vec![]) + } + + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => { + if infcx.considering_regions { + infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); + } + ProcessResult::Changed(vec![]) + } + + ty::PredicateKind::Projection(ref data) => { + let project_obligation = obligation.with(Binder::dummy(*data)); + + self.process_projection_obligation( + obligation, + project_obligation, + &mut pending_obligation.stalled_on, + ) + } + + ty::PredicateKind::ObjectSafe(trait_def_id) => { + if !self.selcx.tcx().is_object_safe(trait_def_id) { + ProcessResult::Error(CodeSelectionError(Unimplemented)) + } else { + ProcessResult::Changed(vec![]) + } + } + + ty::PredicateKind::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::PredicateKind::WellFormed(arg) => { + match wf::obligations( + self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + obligation.recursion_depth + 1, + 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::PredicateKind::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::PredicateKind::Coerce(coerce) => { + match self.selcx.infcx().coerce_predicate( + &obligation.cause, + obligation.param_env, + Binder::dummy(coerce), + ) { + None => { + // None means that both are unresolved. + pending_obligation.stalled_on = vec![ + TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(), + TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(), + ]; + ProcessResult::Unchanged + } + Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Some(Err(err)) => { + let expected_found = ExpectedFound::new(false, coerce.a, coerce.b); + ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( + expected_found, + err, + )) + } + } + } + + ty::PredicateKind::ConstEvaluatable(uv) => { + match const_evaluatable::is_const_evaluatable( + self.selcx.infcx(), + uv, + obligation.param_env, + obligation.cause.span, + ) { + Ok(()) => ProcessResult::Changed(vec![]), + Err(NotConstEvaluatable::MentionsInfer) => { + pending_obligation.stalled_on.clear(); + pending_obligation.stalled_on.extend( + uv.substs + .iter() + .filter_map(TyOrConstInferVar::maybe_from_generic_arg), + ); + ProcessResult::Unchanged + } + Err( + e @ NotConstEvaluatable::MentionsParam + | e @ NotConstEvaluatable::Error(_), + ) => ProcessResult::Error(CodeSelectionError( + SelectionError::NotConstEvaluatable(e), + )), + } + } + + ty::PredicateKind::ConstEquate(c1, c2) => { + debug!(?c1, ?c2, "equating consts"); + let tcx = self.selcx.tcx(); + if tcx.features().generic_const_exprs { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = + (c1.kind(), c2.kind()) + { + if infcx.try_unify_abstract_consts( + a.shrink(), + b.shrink(), + obligation.param_env, + ) { + return ProcessResult::Changed(vec![]); + } + } + } + + let stalled_on = &mut pending_obligation.stalled_on; + + let mut evaluate = |c: Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { + match self.selcx.infcx().try_const_eval_resolve( + obligation.param_env, + unevaluated, + c.ty(), + Some(obligation.cause.span), + ) { + Ok(val) => Ok(val), + Err(e) => match e { + ErrorHandled::TooGeneric => { + stalled_on.extend( + unevaluated.substs.iter().filter_map( + TyOrConstInferVar::maybe_from_generic_arg, + ), + ); + Err(ErrorHandled::TooGeneric) + } + _ => Err(e), + }, + } + } 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(reported)), _) + | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error( + CodeSelectionError(SelectionError::NotConstEvaluatable( + NotConstEvaluatable::Error(reported), + )), + ), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { + span_bug!( + obligation.cause.span(), + "ConstEquate: const_eval_resolve returned an unexpected error" + ) + } + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() { + ProcessResult::Unchanged + } else { + // Two different constants using generic parameters ~> error. + let expected_found = ExpectedFound::new(true, c1, c2); + ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError( + expected_found, + TypeError::ConstMismatch(expected_found), + )) + } + } + } + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } + }, + } + } + + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) where + I: Clone + Iterator>, + { + 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> { + #[instrument(level = "debug", skip(self, obligation, stalled_on))] + fn process_trait_obligation( + &mut self, + obligation: &PredicateObligation<'tcx>, + trait_obligation: TraitObligation<'tcx>, + stalled_on: &mut Vec>, + ) -> ProcessResult, 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.recursion_depth + ); + return ProcessResult::Changed(vec![]); + } + } + + match self.selcx.select(&trait_obligation) { + Ok(Some(impl_source)) => { + debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth); + ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) + } + Ok(None) => { + debug!("selecting trait at depth {} yielded Ok(None)", 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.clear(); + stalled_on.extend(substs_infer_vars( + self.selcx, + trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs), + )); + + debug!( + "process_predicate: pending obligation {:?} now stalled on {:?}", + infcx.resolve_vars_if_possible(obligation.clone()), + stalled_on + ); + + ProcessResult::Unchanged + } + Err(selection_err) => { + debug!("selecting trait at depth {} yielded Err", obligation.recursion_depth); + + ProcessResult::Error(CodeSelectionError(selection_err)) + } + } + } + + fn process_projection_obligation( + &mut self, + obligation: &PredicateObligation<'tcx>, + project_obligation: PolyProjectionObligation<'tcx>, + stalled_on: &mut Vec>, + ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { + let tcx = self.selcx.tcx(); + + if obligation.predicate.is_global() { + // no type variables present, can use evaluation for better caching. + // FIXME: consider caching errors too. + if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) { + if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate( + &mut self.selcx, + project_obligation.predicate, + ) { + // If `predicate_must_hold_considering_regions` succeeds, then we've + // evaluated all sub-obligations. We can therefore mark the 'root' + // obligation as complete, and skip evaluating sub-obligations. + self.selcx + .infcx() + .inner + .borrow_mut() + .projection_cache() + .complete(key, EvaluationResult::EvaluatedToOk); + } + return ProcessResult::Changed(vec![]); + } else { + debug!("Does NOT hold: {:?}", obligation); + } + } + + match project::poly_project_and_unify_type(self.selcx, &project_obligation) { + ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)), + ProjectAndUnifyResult::FailedNormalization => { + stalled_on.clear(); + stalled_on.extend(substs_infer_vars( + self.selcx, + project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs), + )); + ProcessResult::Unchanged + } + // Let the caller handle the recursion + ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![ + project_obligation.with(project_obligation.predicate.to_predicate(tcx)), + ])), + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { + ProcessResult::Error(CodeProjectionError(e)) + } + } + } +} + +/// Returns the set of inference variables contained in `substs`. +fn substs_infer_vars<'a, 'tcx>( + selcx: &mut SelectionContext<'a, 'tcx>, + substs: ty::Binder<'tcx, SubstsRef<'tcx>>, +) -> impl Iterator> { + selcx + .infcx() + .resolve_vars_if_possible(substs) + .skip_binder() // ok because this check doesn't care about regions + .iter() + .filter(|arg| arg.has_infer_types_or_consts()) + .flat_map(|arg| { + let mut walker = arg.walk(); + while let Some(c) = walker.next() { + if !c.has_infer_types_or_consts() { + walker.visited.remove(&c); + walker.skip_current_subtree(); + } + } + walker.visited.into_iter() + }) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg) +} + +fn to_fulfillment_error<'tcx>( + error: Error, FulfillmentErrorCode<'tcx>>, +) -> FulfillmentError<'tcx> { + let mut iter = error.backtrace.into_iter(); + let obligation = iter.next().unwrap().obligation; + // The root obligation is the last item in the backtrace - if there's only + // one item, then it's the same as the main obligation + let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation); + FulfillmentError::new(obligation, error.error, root_obligation) +} 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 000000000..dd2769c71 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -0,0 +1,88 @@ +//! 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, TypeVisitable}; + +use crate::traits::error_reporting::InferCtxtExt; + +#[derive(Clone)] +pub enum CopyImplementationError<'tcx> { + InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>), + NotAnAdt, + HasDestructor, +} + +pub fn can_type_implement_copy<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_type: Ty<'tcx>, + parent_cause: ObligationCause<'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) + | ty::Array(..) => 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); + // FIXME(compiler-errors): This gives us better spans for bad + // projection types like in issue-50480. + // If the ADT has substs, point to the cause we are given. + // If it does not, then this field probably doesn't normalize + // to begin with, and point to the bad field's span instead. + let cause = if field + .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) + .has_param_types_or_consts() + { + parent_cause.clone() + } else { + 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, ty)); + } + } + 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 000000000..9c6bb0731 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -0,0 +1,863 @@ +//! 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 + +pub mod auto_trait; +mod chalk_fulfill; +pub mod codegen; +mod coherence; +pub mod const_evaluatable; +mod engine; +pub mod error_reporting; +mod fulfill; +pub mod misc; +mod object_safety; +mod on_unimplemented; +mod project; +pub mod query; +pub(crate) mod relationships; +mod select; +mod specialize; +mod structural_match; +mod util; +pub mod wf; + +use crate::infer::outlives::env::OutlivesEnvironment; +use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; +use rustc_span::{sym, Span}; +use smallvec::SmallVec; + +use std::fmt::Debug; +use std::ops::ControlFlow; + +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::{ObligationCtxt, 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_adt_const_param_violation, search_for_structural_match_violation, +}; +pub use self::util::{ + elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, + 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, transitive_bounds_that_define_assoc_type, + 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. +/// +/// The "default" for skip-leak-check corresponds to the current +/// behavior (do not skip the leak check) -- not the behavior we are +/// transitioning into. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] +pub enum SkipLeakCheck { + Yes, + #[default] + No, +} + +impl SkipLeakCheck { + fn is_yes(self) -> bool { + self == SkipLeakCheck::Yes + } +} + +/// 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> { + 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::Binder::dummy(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 = >::new(infcx.tcx); + + // 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).as_slice() { + [] => { + debug!( + "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", + ty, + infcx.tcx.def_path_str(def_id) + ); + true + } + errors => { + debug!( + ?ty, + bound = %infcx.tcx.def_path_str(def_id), + ?errors, + "type_known_to_meet_bound_modulo_regions" + ); + false + } + } + } else { + result + } +} + +#[instrument(level = "debug", skip(tcx, elaborated_env))] +fn do_normalize_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + cause: ObligationCause<'tcx>, + elaborated_env: ty::ParamEnv<'tcx>, + predicates: Vec>, +) -> Result>, ErrorGuaranteed> { + let span = cause.span; + // 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*. + tcx.infer_ctxt().ignoring_regions().enter(|infcx| { + let fulfill_cx = FulfillmentContext::new(); + let predicates = + match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) { + Ok(predicates) => predicates, + Err(errors) => { + let reported = infcx.report_fulfillment_errors(&errors, None, false); + return Err(reported); + } + }; + + 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); + + // FIXME: It's very weird that we ignore region obligations but apparently + // still need to use `resolve_regions` as we need the resolved regions in + // the normalized predicates. + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + span, + format!( + "failed region resolution while normalizing {elaborated_env:?}: {errors:?}" + ), + ); + } + + match infcx.fully_resolve(predicates) { + Ok(predicates) => Ok(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. + // + // @lcnr: Let's still ICE here for now. I want a test case + // for that. + span_bug!( + span, + "inference variables in normalized parameter environment: {}", + fixup_err + ); + } + } + }) +} + +// FIXME: this is gonna need to be removed ... +/// Normalizes the parameter environment, reporting errors if they occur. +#[instrument(level = "debug", skip(tcx))] +pub fn normalize_param_env_or_error<'tcx>( + tcx: TyCtxt<'tcx>, + 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 outside of type inference we + // can be sure that no errors should occur. + 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.constness(), + ); + + // 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| { + matches!(predicate.kind().skip_binder(), ty::PredicateKind::TypeOutlives(..)) + }) + .collect(); + + debug!( + "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", + predicates, outlives_predicates + ); + let Ok(non_outlives_predicates) = do_normalize_predicates( + tcx, + cause.clone(), + elaborated_env, + predicates, + ) else { + // An unnormalized env is better than nothing. + 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(), + unnormalized_env.constness(), + ); + let Ok(outlives_predicates) = do_normalize_predicates( + tcx, + cause, + outlives_env, + outlives_predicates, + ) else { + // An unnormalized env is better than nothing. + 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.constness(), + ) +} + +pub fn fully_normalize<'a, 'tcx, T>( + infcx: &InferCtxt<'a, 'tcx>, + mut fulfill_cx: FulfillmentContext<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, +) -> Result>> +where + T: TypeFoldable<'tcx>, +{ + debug!("fully_normalize_with_fulfillcx(value={:?})", value); + let selcx = &mut SelectionContext::new(infcx); + let Normalized { value: normalized_value, obligations } = + project::normalize(selcx, param_env, cause, value); + debug!( + "fully_normalize: normalized_value={:?} obligations={:?}", + normalized_value, obligations + ); + for obligation in obligations { + fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); + } + + debug!("fully_normalize: select_all_or_error start"); + let errors = fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { + return Err(errors); + } + 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>, +) -> bool { + debug!("impossible_predicates(predicates={:?})", predicates); + + let result = tcx.infer_ctxt().enter(|infcx| { + // HACK: Set tainted by errors to gracefully exit in case of overflow. + infcx.set_tainted_by_errors(); + + 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); + } + + let errors = fulfill_cx.select_all_or_error(&infcx); + + // Clean up after ourselves + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + !errors.is_empty() + }); + debug!("impossible_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; + + // Specifically check trait fulfillment to avoid an error when trying to resolve + // associated items. + if let Some(trait_def_id) = tcx.trait_of_item(key.0) { + let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1); + predicates.push(ty::Binder::dummy(trait_ref).to_poly_trait_predicate().to_predicate(tcx)); + } + + predicates.retain(|predicate| !predicate.needs_subst()); + let result = impossible_predicates(tcx, predicates); + + debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); + result +} + +#[derive(Clone, Debug)] +enum VtblSegment<'tcx> { + MetadataDSA, + TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool }, +} + +/// Prepare the segments for a vtable +fn prepare_vtable_segments<'tcx, T>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow, +) -> Option { + // The following constraints holds for the final arrangement. + // 1. The whole virtual table of the first direct super trait is included as the + // the prefix. If this trait doesn't have any super traits, then this step + // consists of the dsa metadata. + // 2. Then comes the proper pointer metadata(vptr) and all own methods for all + // other super traits except those already included as part of the first + // direct super trait virtual table. + // 3. finally, the own methods of this trait. + + // This has the advantage that trait upcasting to the first direct super trait on each level + // is zero cost, and to another trait includes only replacing the pointer with one level indirection, + // while not using too much extra memory. + + // For a single inheritance relationship like this, + // D --> C --> B --> A + // The resulting vtable will consists of these segments: + // DSA, A, B, C, D + + // For a multiple inheritance relationship like this, + // D --> C --> A + // \-> B + // The resulting vtable will consists of these segments: + // DSA, A, B, B-vptr, C, D + + // For a diamond inheritance relationship like this, + // D --> B --> A + // \-> C -/ + // The resulting vtable will consists of these segments: + // DSA, A, B, C, C-vptr, D + + // For a more complex inheritance relationship like this: + // O --> G --> C --> A + // \ \ \-> B + // | |-> F --> D + // | \-> E + // |-> N --> J --> H + // \ \-> I + // |-> M --> K + // \-> L + // The resulting vtable will consists of these segments: + // DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G, + // H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr, + // N, N-vptr, O + + // emit dsa segment first. + if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) { + return Some(v); + } + + let mut emit_vptr_on_new_entry = false; + let mut visited = util::PredicateSet::new(tcx); + let predicate = trait_ref.without_const().to_predicate(tcx); + let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> = + smallvec![(trait_ref, emit_vptr_on_new_entry, None)]; + visited.insert(predicate); + + // the main traversal loop: + // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes + // that each node is emitted after all its descendents have been emitted. + // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set. + // this is done on the fly. + // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it + // stops after it finds a node that has a next-sibling node. + // This next-sibling node will used as the starting point of next slice. + + // Example: + // For a diamond inheritance relationship like this, + // D#1 --> B#0 --> A#0 + // \-> C#1 -/ + + // Starting point 0 stack [D] + // Loop run #0: Stack after diving in is [D B A], A is "childless" + // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one. + // Loop run #0: Emitting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here. + // Loop run #0: Stack after exiting out is [D C], C is the next starting point. + // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted). + // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node. + // Loop run #1: Stack after exiting out is []. Now the function exits. + + loop { + // dive deeper into the stack, recording the path + 'diving_in: loop { + if let Some((inner_most_trait_ref, _, _)) = stack.last() { + let inner_most_trait_ref = *inner_most_trait_ref; + let mut direct_super_traits_iter = tcx + .super_predicates_of(inner_most_trait_ref.def_id()) + .predicates + .into_iter() + .filter_map(move |(pred, _)| { + pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred() + }); + + 'diving_in_skip_visited_traits: loop { + if let Some(next_super_trait) = direct_super_traits_iter.next() { + if visited.insert(next_super_trait.to_predicate(tcx)) { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref); + stack.push(( + next_super_trait, + emit_vptr_on_new_entry, + Some(direct_super_traits_iter), + )); + break 'diving_in_skip_visited_traits; + } else { + continue 'diving_in_skip_visited_traits; + } + } else { + break 'diving_in; + } + } + } + } + + // Other than the left-most path, vptr should be emitted for each trait. + emit_vptr_on_new_entry = true; + + // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. + 'exiting_out: loop { + if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() { + if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries { + trait_ref: *inner_most_trait_ref, + emit_vptr: *emit_vptr, + }) { + return Some(v); + } + + 'exiting_out_skip_visited_traits: loop { + if let Some(siblings) = siblings_opt { + if let Some(next_inner_most_trait_ref) = siblings.next() { + if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_inner_most_trait_ref = + next_inner_most_trait_ref.map_bound(|t| t.trait_ref); + *inner_most_trait_ref = next_inner_most_trait_ref; + *emit_vptr = emit_vptr_on_new_entry; + break 'exiting_out; + } else { + continue 'exiting_out_skip_visited_traits; + } + } + } + stack.pop(); + continue 'exiting_out; + } + } + // all done + return None; + } + } +} + +fn dump_vtable_entries<'tcx>( + tcx: TyCtxt<'tcx>, + sp: Span, + trait_ref: ty::PolyTraitRef<'tcx>, + entries: &[VtblEntry<'tcx>], +) { + let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries); + tcx.sess.struct_span_err(sp, &msg).emit(); +} + +fn own_existential_vtable_entries<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyExistentialTraitRef<'tcx>, +) -> &'tcx [DefId] { + 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 (for within its trait). + let own_entries = trait_methods.filter_map(move |trait_method| { + debug!("own_existential_vtable_entry: 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!("own_existential_vtable_entry: not vtable safe"); + return None; + } + + Some(def_id) + }); + + tcx.arena.alloc_from_iter(own_entries.into_iter()) +} + +/// Given a trait `trait_ref`, iterates the vtable entries +/// that come from `trait_ref`, including its supertraits. +fn vtable_entries<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, +) -> &'tcx [VtblEntry<'tcx>] { + debug!("vtable_entries({:?})", trait_ref); + + let mut entries = vec![]; + + let vtable_segment_callback = |segment| -> ControlFlow<()> { + match segment { + VtblSegment::MetadataDSA => { + entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES); + } + VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + let existential_trait_ref = trait_ref + .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + + // Lookup the shape of vtable for the trait. + let own_existential_entries = + tcx.own_existential_vtable_entries(existential_trait_ref); + + let own_entries = own_existential_entries.iter().copied().map(|def_id| { + debug!("vtable_entries: trait_method={:?}", def_id); + + // 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_entries: predicates do not hold"); + return VtblEntry::Vacant; + } + + let instance = ty::Instance::resolve_for_vtable( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .expect("resolution failed during building vtable representation"); + VtblEntry::Method(instance) + }); + + entries.extend(own_entries); + + if emit_vptr { + entries.push(VtblEntry::TraitVPtr(trait_ref)); + } + } + } + + ControlFlow::Continue(()) + }; + + let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback); + + if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) { + let sp = tcx.def_span(trait_ref.def_id()); + dump_vtable_entries(tcx, sp, trait_ref, &entries); + } + + tcx.arena.alloc_from_iter(entries.into_iter()) +} + +/// Find slot base for trait methods within vtable entries of another trait +fn vtable_trait_first_method_offset<'tcx>( + tcx: TyCtxt<'tcx>, + key: ( + ty::PolyTraitRef<'tcx>, // trait_to_be_found + ty::PolyTraitRef<'tcx>, // trait_owning_vtable + ), +) -> usize { + let (trait_to_be_found, trait_owning_vtable) = key; + + // #90177 + let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found); + + let vtable_segment_callback = { + let mut vtable_base = 0; + + move |segment| { + match segment { + VtblSegment::MetadataDSA => { + vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + } + VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + if tcx.erase_regions(trait_ref) == trait_to_be_found_erased { + return ControlFlow::Break(vtable_base); + } + vtable_base += util::count_own_vtable_entries(tcx, trait_ref); + if emit_vptr { + vtable_base += 1; + } + } + } + ControlFlow::Continue(()) + } + }; + + if let Some(vtable_base) = + prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback) + { + vtable_base + } else { + bug!("Failed to find info for expected trait in vtable"); + } +} + +/// Find slot offset for trait vptr within vtable entries of another trait +pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( + tcx: TyCtxt<'tcx>, + key: ( + Ty<'tcx>, // trait object type whose trait owning vtable + Ty<'tcx>, // trait object for supertrait + ), +) -> Option { + let (source, target) = key; + assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer()); + assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer()); + + // this has been typecked-before, so diagnostics is not really needed. + let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None); + + let trait_ref = ty::TraitRef { + def_id: unsize_trait_did, + substs: tcx.mk_substs_trait(source, &[target.into()]), + }; + let obligation = Obligation::new( + ObligationCause::dummy(), + ty::ParamEnv::reveal_all(), + ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }), + ); + + let implsrc = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + selcx.select(&obligation).unwrap() + }); + + let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else { + bug!(); + }; + + implsrc_traitcasting.vtable_vptr_slot +} + +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, + own_existential_vtable_entries, + vtable_entries, + vtable_trait_upcasting_coercion_new_vptr_slot, + subst_and_check_impossible_predicates, + try_unify_abstract_consts: |tcx, param_env_and| { + let (param_env, (a, b)) = param_env_and.into_parts(); + const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env) + }, + ..*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 000000000..612f51309 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -0,0 +1,866 @@ +//! "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::{FatalError, MultiSpan}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; +use rustc_middle::ty::{ + self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; +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; +use std::ops::ControlFlow; + +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 { + 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<'_>, trait_def_id: DefId) -> &'_ [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 { + // 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.name, code, span)) + }) + .filter(|violation| { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation + { + lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); + 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)); + } + let spans = bounds_reference_self(tcx, trait_def_id); + 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| { + let ident = item.ident(tcx); + ObjectSafetyViolation::AssocConst(ident.name, ident.span) + }), + ); + + if !tcx.features().generic_associated_types_extended { + violations.extend( + tcx.associated_items(trait_def_id) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| !tcx.generics_of(item.def_id).params.is_empty()) + .map(|item| { + let ident = item.ident(tcx); + ObjectSafetyViolation::GAT(ident.name, ident.span) + }), + ); + } + + debug!( + "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, violations + ); + + violations +} + +/// Lint object-unsafe trait. +fn lint_object_unsafe_trait( + tcx: TyCtxt<'_>, + span: Span, + trait_def_id: DefId, + violation: &ObjectSafetyViolation, +) { + // 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 mut spans = MultiSpan::from_span(span); + if let Some(hir::Node::Item(item)) = node { + spans.push_span_label(item.ident.span, "this trait cannot be made into an object..."); + spans.push_span_label(span, format!("...because {}", violation.error_msg())); + } else { + spans.push_span_label( + span, + format!( + "the trait cannot be made into an object because {}", + violation.error_msg() + ), + ); + }; + err.span_note( + spans, + "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \ + call to be resolvable dynamically; for more information visit \ + ", + ); + if node.is_some() { + // Only provide the help if its a local trait, otherwise it's not + violation.solution(&mut err); + } + err.emit(); + }); +} + +fn sized_trait_bound_spans<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: hir::GenericBounds<'tcx>, +) -> impl 'tcx + Iterator { + 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 + .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::>(), + ), + _ => 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::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) + }; + predicates + .predicates + .iter() + .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) + .filter_map(|predicate| predicate_references_self(tcx, predicate)) + .collect() +} + +fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { + tcx.associated_items(trait_def_id) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .flat_map(|item| tcx.explicit_item_bounds(item.def_id)) + .filter_map(|pred_span| predicate_references_self(tcx, *pred_span)) + .collect() +} + +fn predicate_references_self<'tcx>( + tcx: TyCtxt<'tcx>, + (predicate, sp): (ty::Predicate<'tcx>, Span), +) -> Option { + let self_ty = tcx.types.self_param; + let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into()); + match predicate.kind().skip_binder() { + ty::PredicateKind::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::PredicateKind::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. + // + // It's also won't be redundant if we allow type-generic associated + // types for trait objects. + // + // Note that we *do* allow projection *outputs* to contain + // `self` (i.e., `trait Foo: Bar { type Result; }`), + // we just require the user to specify *both* outputs + // in the object type (i.e., `dyn Foo`). + // + // This is ALT2 in issue #56288, see that for discussion of the + // possible alternatives. + if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } + } + ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, + } +} + +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 Some(sized_def_id) = tcx.lang_items().sized_trait() else { + 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.kind().skip_binder() { + ty::PredicateKind::Trait(ref trait_pred) => { + trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) + } + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => 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(Some(span)), _) => *span, + (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span()) + } + _ => method.ident(tcx).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 { + let sig = tcx.fn_sig(method.def_id); + + // The method's first parameter must be named `self` + if !method.fn_has_self_parameter { + let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Fn(sig, _), + .. + })) = tcx.hir().get_if_local(method.def_id).as_ref() + { + let sm = tcx.sess.source_map(); + Some(( + ( + format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }), + sm.span_through_char(sig.span, '(').shrink_to_hi(), + ), + ( + format!("{} Self: Sized", generics.add_where_or_trailing_comma()), + generics.tail_span_for_predicate_suggestion(), + ), + )) + } else { + None + }; + return Some(MethodViolationCode::StaticMethod(sugg)); + } + + for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) { + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { + let span = if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + .. + })) = tcx.hir().get_if_local(method.def_id).as_ref() + { + Some(sig.decl.inputs[i].span) + } else { + None + }; + return Some(MethodViolationCode::ReferencesSelfInput(span)); + } + } + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { + return Some(MethodViolationCode::ReferencesSelfOutput); + } + + // We can't monomorphize things like `fn foo(...)`. + 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()) + .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred)) + { + return Some(MethodViolationCode::WhereClauseReferencesSelf); + } + + let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(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 dyn Trait]>`. + if receiver_ty != tcx.types.self_param { + if !receiver_is_dispatchable(tcx, method, receiver_ty) { + let span = if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + .. + })) = tcx.hir().get_if_local(method.def_id).as_ref() + { + Some(sig.decl.inputs[0].span) + } else { + None + }; + return Some(MethodViolationCode::UndispatchableReceiver(span)); + } 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>| -> Option { + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) => Some(layout.abi), + Err(err) => { + // #78372 + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!("error: {}\n while computing layout for type {:?}", err, ty), + ); + None + } + } + }; + + // 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) { + Some(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` + let trait_object_receiver = + receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); + + match abi_of_ty(trait_object_receiver) { + Some(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` and `self_ty = Foo`, returns `Rc`. +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 = EarlyBinder(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 + '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 = trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) + }); + + let mut associated_types = traits::supertraits(tcx, 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::>(); + + // 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>`. + super_trait_ref.map_bound(|super_trait_ref| { + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(), + item_def_id: item.def_id, + substs: super_trait_ref.substs, + }) + }) + }); + + let existential_predicates = tcx + .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); + + let object_ty = tcx.mk_dynamic(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`, +/// - require the following bound: +/// +/// ```ignore (not-rust) +/// Receiver[Self => T]: DispatchFromDyn 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` requires `Rc: DispatchFromDyn>`, +/// - `self: Pin>` requires `Pin>: DispatchFromDyn>>`. +/// +/// 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: Box>`. 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 ). +/// Instead, we fudge a little by introducing a new type parameter `U` such that +/// `Self: Unsize` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. +/// Written as a chalk-style query: +/// ```ignore (not-rust) +/// forall (U: Trait + ?Sized) { +/// if (Self: Unsize) { +/// Receiver: DispatchFromDyn U]> +/// } +/// } +/// ``` +/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` +/// for `self: Rc`, this means `Rc: DispatchFromDyn>` +/// for `self: Pin>`, this means `Pin>: DispatchFromDyn>>` +// +// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this +// fallback query: `Receiver: Unsize U]>` to support receivers like +// `self: Wrapper`. +#[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 (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits 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` 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 + let unsize_predicate = ty::Binder::dummy(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 + let trait_predicate = { + let substs = + InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| { + if param.index == 0 { + unsized_self_ty.into() + } else { + tcx.mk_param_from_def(param) + } + }); + + ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs }) + .without_const() + .to_predicate(tcx) + }; + + let caller_bounds: Vec> = + param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect(); + + ty::ParamEnv::new( + tcx.intern_predicates(&caller_bounds), + param_env.reveal(), + param_env.constness(), + ) + }; + + // Receiver: DispatchFromDyn U]> + let obligation = { + let predicate = ty::Binder::dummy(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, T: TypeVisitable<'tcx>>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + value: T, +) -> 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 // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> ::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> ::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) -> ::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>, + trait_def_id: DefId, + supertraits: Option>, + } + + impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + match t.kind() { + ty::Param(_) => { + if t == self.tcx.types.self_param { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } + } + ty::Projection(ref data) => { + // This is a projected type `::X`. + + // Compute supertraits of current trait lazily. + if self.supertraits.is_none() { + let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id); + self.supertraits = Some( + traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).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 is_supertrait_of_current_trait = self + .supertraits + .as_ref() + .unwrap() + .contains(&data.trait_ref(self.tcx).def_id); + + if is_supertrait_of_current_trait { + ControlFlow::CONTINUE // 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_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { + // Constants can only influence object safety if they reference `Self`. + // This is only possible for unevaluated constants, so we walk these here. + // + // If `AbstractConst::new` returned an error we already failed compilation + // so we don't have to emit an additional error here. + // + // We currently recurse into abstract consts here but do not recurse in + // `is_const_evaluatable`. This means that the object safety check is more + // liberal than the const eval check. + // + // This shouldn't really matter though as we can't really use any + // constants which are not considered const evaluatable. + use rustc_middle::ty::abstract_const::Node; + if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { + walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) { + Node::Leaf(leaf) => self.visit_const(leaf), + Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } + }) + } else { + ControlFlow::CONTINUE + } + } + } + + value + .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) + .is_break() +} + +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 000000000..9227bbf01 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -0,0 +1,425 @@ +use rustc_ast::{MetaItem, NestedMetaItem}; +use rustc_attr as attr; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{struct_span_err, ErrorGuaranteed}; +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, DUMMY_SP}; + +#[derive(Clone, Debug)] +pub struct OnUnimplementedFormatString(Symbol); + +#[derive(Debug)] +pub struct OnUnimplementedDirective { + pub condition: Option, + pub subcommands: Vec, + pub message: Option, + pub label: Option, + pub note: Option, + pub enclosing_scope: Option, + pub append_const_msg: Option>, +} + +#[derive(Default)] +pub struct OnUnimplementedNote { + pub message: Option, + pub label: Option, + pub note: Option, + pub enclosing_scope: Option, + /// Append a message for `~const Trait` errors. `None` means not requested and + /// should fallback to a generic message, `Some(None)` suggests using the default + /// appended message, `Some(Some(s))` suggests use the `s` message instead of the + /// default one.. + pub append_const_msg: Option>, +} + +fn parse_error( + tcx: TyCtxt<'_>, + span: Span, + message: &str, + label: &str, + note: Option<&str>, +) -> ErrorGuaranteed { + 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() +} + +impl<'tcx> OnUnimplementedDirective { + fn parse( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + items: &[NestedMetaItem], + span: Span, + is_root: bool, + ) -> Result { + let mut errored = None; + let mut item_iter = items.iter(); + + let parse_value = |value_str| { + OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some) + }; + + 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 |cfg| { + if let Some(value) = cfg.value && let Err(guar) = parse_value(value) { + errored = Some(guar); + } + 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 mut append_const_msg = None; + + 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() { + match Self::parse(tcx, item_def_id, &items, item.span(), false) { + Ok(subcommand) => subcommands.push(subcommand), + Err(reported) => errored = Some(reported), + }; + continue; + } + } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() { + if let Some(msg) = item.value_str() { + append_const_msg = Some(Some(msg)); + continue; + } else if item.is_word() { + append_const_msg = Some(None); + 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 let Some(reported) = errored { + Err(reported) + } else { + Ok(OnUnimplementedDirective { + condition, + subcommands, + message, + label, + note, + enclosing_scope, + append_const_msg, + }) + } + } + + pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, ErrorGuaranteed> { + let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else { + return Ok(None); + }; + + let result = if let Some(items) = attr.meta_item_list() { + Self::parse(tcx, item_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, + item_def_id, + value, + attr.span, + )?), + note: None, + enclosing_scope: None, + append_const_msg: None, + })) + } else { + let reported = + tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); + return Err(reported); + }; + debug!("of_item({:?}) = {:?}", item_def_id, result); + result + } + + pub fn evaluate( + &self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + options: &[(Symbol, Option)], + ) -> OnUnimplementedNote { + let mut message = None; + let mut label = None; + let mut note = None; + let mut enclosing_scope = None; + let mut append_const_msg = None; + info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); + + let options_map: FxHashMap = + options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect(); + + for command in self.subcommands.iter().chain(Some(self)).rev() { + if let Some(ref condition) = command.condition && !attr::eval_condition( + condition, + &tcx.sess.parse_sess, + Some(tcx.features()), + &mut |cfg| { + let value = cfg.value.map(|v| { + OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map) + }); + + options.contains(&(cfg.name, value)) + }, + ) { + 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()); + } + + append_const_msg = command.append_const_msg; + } + + OnUnimplementedNote { + label: label.map(|l| l.format(tcx, trait_ref, &options_map)), + message: message.map(|m| m.format(tcx, trait_ref, &options_map)), + note: note.map(|n| n.format(tcx, trait_ref, &options_map)), + enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), + append_const_msg, + } + } +} + +impl<'tcx> OnUnimplementedFormatString { + fn try_parse( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + from: Symbol, + err_sp: Span, + ) -> Result { + let result = OnUnimplementedFormatString(from); + result.verify(tcx, item_def_id, err_sp)?; + Ok(result) + } + + fn verify( + &self, + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + span: Span, + ) -> Result<(), ErrorGuaranteed> { + let trait_def_id = if tcx.is_trait(item_def_id) { + item_def_id + } else { + tcx.trait_id_of_impl(item_def_id) + .expect("expected `on_unimplemented` to correspond to a trait") + }; + let trait_name = tcx.item_name(trait_def_id); + let generics = tcx.generics_of(item_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 { + Position::ArgumentNamed(s) => { + match Symbol::intern(s) { + // `{Self}` is allowed + kw::SelfUpper => (), + // `{ThisTraitsName}` is allowed + s if s == trait_name => (), + // `{from_method}` is allowed + sym::from_method => (), + // `{from_desugaring}` is allowed + sym::from_desugaring => (), + // `{ItemContext}` is allowed + sym::ItemContext => (), + // `{integral}` and `{integer}` and `{float}` are allowed + sym::integral | sym::integer_ | sym::float => (), + // So is `{A}` if A is a type parameter + s => match generics.params.iter().find(|param| param.name == s) { + Some(_) => (), + None => { + let reported = struct_span_err!( + tcx.sess, + span, + E0230, + "there is no parameter `{}` on {}", + s, + if trait_def_id == item_def_id { + format!("trait `{}`", trait_name) + } else { + "impl".to_string() + } + ) + .emit(); + result = Err(reported); + } + }, + } + } + // `{:1}` and `{}` are not to be used + Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { + let reported = struct_span_err!( + tcx.sess, + span, + E0231, + "only named substitution parameters are allowed" + ) + .emit(); + result = Err(reported); + } + }, + } + } + + result + } + + pub fn format( + &self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + options: &FxHashMap, + ) -> 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::>(); + 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) => { + let s = Symbol::intern(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 if s == sym::integral { + "{integral}" + } else if s == sym::integer_ { + "{integer}" + } else if s == sym::float { + "{float}" + } 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 000000000..c4e80e1ba --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -0,0 +1,2150 @@ +//! Code for projecting associated types out of trait references. + +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, ImplSourcePointeeData, 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 as _; +use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +use crate::traits::select::ProjectionMatchesProjection; +use rustc_data_structures::sso::SsoHashSet; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_middle::traits::select::OverflowError; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; +use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; +use rustc_span::symbol::sym; + +use std::collections::BTreeMap; + +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 `::Name` ... +#[derive(Debug)] +pub enum ProjectionError<'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 ProjectionCandidate<'tcx> { + /// From a where-clause in the env or object type + ParamEnv(ty::PolyProjectionPredicate<'tcx>), + + /// From the definition of `Trait` when you have something like <::B as Trait2>::C + TraitDef(ty::PolyProjectionPredicate<'tcx>), + + /// Bounds specified on an object type + Object(ty::PolyProjectionPredicate<'tcx>), + + /// From an "impl" (or a "pseudo-impl" returned by select) + Select(Selection<'tcx>), +} + +enum ProjectionCandidateSet<'tcx> { + None, + Single(ProjectionCandidate<'tcx>), + Ambiguous, + Error(SelectionError<'tcx>), +} + +impl<'tcx> ProjectionCandidateSet<'tcx> { + fn mark_ambiguous(&mut self) { + *self = ProjectionCandidateSet::Ambiguous; + } + + fn mark_error(&mut self, err: SelectionError<'tcx>) { + *self = ProjectionCandidateSet::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: ProjectionCandidate<'tcx>) -> bool { + use self::ProjectionCandidate::*; + use self::ProjectionCandidateSet::*; + + // 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 + } +} + +/// States returned from `poly_project_and_unify_type`. Takes the place +/// of the old return type, which was: +/// ```ignore (not-rust) +/// Result< +/// Result>>, InProgress>, +/// MismatchedProjectionTypes<'tcx>, +/// > +/// ``` +pub(super) enum ProjectAndUnifyResult<'tcx> { + /// The projection bound holds subject to the given obligations. If the + /// projection cannot be normalized because the required trait bound does + /// not hold, this is returned, with `obligations` being a predicate that + /// cannot be proven. + Holds(Vec>), + /// The projection cannot be normalized due to ambiguity. Resolving some + /// inference variables in the projection may fix this. + FailedNormalization, + /// The project cannot be normalized because `poly_project_and_unify_type` + /// is called recursively while normalizing the same projection. + Recursive, + // the projection can be normalized, but is not equal to the expected type. + // Returns the type error that arose from the mismatch. + MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), +} + +/// Evaluates constraints of the form: +/// ```ignore (not-rust) +/// for<...> ::U == V +/// ``` +/// If successful, this may result in additional obligations. Also returns +/// the projection cache key used to track these additional obligations. +#[instrument(level = "debug", skip(selcx))] +pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &PolyProjectionObligation<'tcx>, +) -> ProjectAndUnifyResult<'tcx> { + let infcx = selcx.infcx(); + let r = infcx.commit_if_ok(|_snapshot| { + let old_universe = infcx.universe(); + let placeholder_predicate = + infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let new_universe = infcx.universe(); + + let placeholder_obligation = obligation.with(placeholder_predicate); + match project_and_unify_type(selcx, &placeholder_obligation) { + ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e), + ProjectAndUnifyResult::Holds(obligations) + if old_universe != new_universe + && selcx.tcx().features().generic_associated_types_extended => + { + // If the `generic_associated_types_extended` feature is active, then we ignore any + // obligations references lifetimes from any universe greater than or equal to the + // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`, + // which isn't quite what we want. Ideally, we want either an implied + // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we + // substitute concrete regions. There is design work to be done here; until then, + // however, this allows experimenting potential GAT features without running into + // well-formedness issues. + let new_obligations = obligations + .into_iter() + .filter(|obligation| { + let mut visitor = MaxUniverse::new(); + obligation.predicate.visit_with(&mut visitor); + visitor.max_universe() < new_universe + }) + .collect(); + Ok(ProjectAndUnifyResult::Holds(new_obligations)) + } + other => Ok(other), + } + }); + + match r { + Ok(inner) => inner, + Err(err) => ProjectAndUnifyResult::MismatchedProjectionTypes(err), + } +} + +/// Evaluates constraints of the form: +/// ```ignore (not-rust) +/// ::U == V +/// ``` +/// If successful, this may result in additional obligations. +/// +/// See [poly_project_and_unify_type] for an explanation of the return value. +#[tracing::instrument(level = "debug", skip(selcx))] +fn project_and_unify_type<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionObligation<'tcx>, +) -> ProjectAndUnifyResult<'tcx> { + let mut obligations = vec![]; + + let infcx = selcx.infcx(); + let normalized = 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 ProjectAndUnifyResult::FailedNormalization, + Err(InProgress) => return ProjectAndUnifyResult::Recursive, + }; + debug!(?normalized, ?obligations, "project_and_unify_type result"); + let actual = obligation.predicate.term; + // For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs + // This allows users to omit re-mentioning all bounds on an associated type and just use an + // `impl Trait` for the assoc type to add more bounds. + let InferOk { value: actual, obligations: new } = + selcx.infcx().replace_opaque_types_with_inference_vars( + actual, + obligation.cause.body_id, + obligation.cause.span, + obligation.param_env, + ); + obligations.extend(new); + + match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) { + Ok(InferOk { obligations: inferred_obligations, value: () }) => { + obligations.extend(inferred_obligations); + ProjectAndUnifyResult::Holds(obligations) + } + Err(err) => { + debug!("equating types encountered error {:?}", err); + ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err }) + } + } +} + +/// Normalizes any associated type projections in `value`, replacing +/// them with a fully resolved type where possible. The return value +/// combines the normalized result and any additional obligations that +/// were incurred as result. +pub fn normalize<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + value: T, +) -> Normalized<'tcx, T> +where + T: TypeFoldable<'tcx>, +{ + let mut obligations = Vec::new(); + let value = normalize_to(selcx, param_env, cause, value, &mut obligations); + Normalized { value, obligations } +} + +pub fn normalize_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + value: T, + obligations: &mut Vec>, +) -> T +where + T: TypeFoldable<'tcx>, +{ + normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) +} + +/// As `normalize`, but with a custom depth. +pub fn normalize_with_depth<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: T, +) -> Normalized<'tcx, T> +where + T: TypeFoldable<'tcx>, +{ + let mut obligations = Vec::new(); + let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); + Normalized { value, obligations } +} + +#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] +pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: T, + obligations: &mut Vec>, +) -> T +where + T: TypeFoldable<'tcx>, +{ + debug!(obligations.len = obligations.len()); + let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); + let result = ensure_sufficient_stack(|| normalizer.fold(value)); + debug!(?result, obligations.len = normalizer.obligations.len()); + debug!(?normalizer.obligations,); + result +} + +#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] +pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: T, + obligations: &mut Vec>, +) -> T +where + T: TypeFoldable<'tcx>, +{ + debug!(obligations.len = obligations.len()); + let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement( + selcx, + param_env, + cause, + depth, + obligations, + ); + let result = ensure_sufficient_stack(|| normalizer.fold(value)); + debug!(?result, obligations.len = normalizer.obligations.len()); + debug!(?normalizer.obligations,); + result +} + +pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool { + match reveal { + Reveal::UserFacing => value + .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), + Reveal::All => value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_OPAQUE + | ty::TypeFlags::HAS_CT_PROJECTION, + ), + } +} + +struct AssocTypeNormalizer<'a, 'b, 'tcx> { + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + obligations: &'a mut Vec>, + depth: usize, + universes: Vec>, + /// If true, when a projection is unable to be completed, an inference + /// variable will be created and an obligation registered to project to that + /// inference variable. Also, constants will be eagerly evaluated. + eager_inference_replacement: bool, +} + +impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { + fn new( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &'a mut Vec>, + ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { + AssocTypeNormalizer { + selcx, + param_env, + cause, + obligations, + depth, + universes: vec![], + eager_inference_replacement: true, + } + } + + fn new_without_eager_inference_replacement( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &'a mut Vec>, + ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { + AssocTypeNormalizer { + selcx, + param_env, + cause, + obligations, + depth, + universes: vec![], + eager_inference_replacement: false, + } + } + + fn fold>(&mut self, value: T) -> T { + let value = self.selcx.infcx().resolve_vars_if_possible(value); + debug!(?value); + + assert!( + !value.has_escaping_bound_vars(), + "Normalizing {:?} without wrapping in a `Binder`", + value + ); + + if !needs_normalization(&value, self.param_env.reveal()) { + 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_binder>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + self.universes.push(None); + let t = t.super_fold_with(self); + self.universes.pop(); + t + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !needs_normalization(&ty, self.param_env.reveal()) { + return ty; + } + + // We try to be a little clever here as a performance optimization in + // cases where there are nested projections under binders. + // For example: + // ``` + // for<'a> fn(::One<'a, Box::Two<'a>>>>) + // ``` + // We normalize the substs on the projection before the projecting, but + // if we're naive, we'll + // replace bound vars on inner, project inner, replace placeholders on inner, + // replace bound vars on outer, project outer, replace placeholders on outer + // + // However, if we're a bit more clever, we can replace the bound vars + // on the entire type before normalizing nested projections, meaning we + // replace bound vars on outer, project inner, + // project outer, replace placeholders on outer + // + // This is possible because the inner `'a` will already be a placeholder + // when we need to normalize the inner projection + // + // On the other hand, this does add a bit of complexity, since we only + // replace bound vars if the current type is a `Projection` and we need + // to make sure we don't forget to fold the substs regardless. + + match *ty.kind() { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { + // Only normalize `impl Trait` outside of type inference, usually in codegen. + match self.param_env.reveal() { + Reveal::UserFacing => ty.super_fold_with(self), + + Reveal::All => { + let recursion_limit = self.tcx().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 substs = substs.fold_with(self); + let generic_ty = self.tcx().bound_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(data) if !data.has_escaping_bound_vars() => { + // This branch is *mostly* just an optimization: when we don't + // have escaping bound vars, we don't need to replace them with + // placeholders (see branch below). *Also*, we know that we can + // register an obligation to *later* project, since we know + // there won't be bound vars there. + let data = data.fold_with(self); + let normalized_ty = if self.eager_inference_replacement { + normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + &mut self.obligations, + ) + } else { + opt_normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + &mut self.obligations, + ) + .ok() + .flatten() + .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self))) + }; + debug!( + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" + ); + normalized_ty.ty().unwrap() + } + + ty::Projection(data) => { + // If there are escaping bound vars, we temporarily replace the + // bound vars with placeholders. Note though, that in the case + // that we still can't project for whatever reason (e.g. self + // type isn't known enough), we *can't* register an obligation + // and return an inference variable (since then that obligation + // would have bound vars and that's a can of worms). Instead, + // we just give up and fall back to pretending like we never tried! + // + // Note: this isn't necessarily the final approach here; we may + // want to figure out how to register obligations with escaping vars + // or handle this some other way. + + let infcx = self.selcx.infcx(); + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let data = data.fold_with(self); + let normalized_ty = opt_normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + &mut self.obligations, + ) + .ok() + .flatten() + .map(|term| term.ty().unwrap()) + .map(|normalized_ty| { + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_ty, + ) + }) + .unwrap_or_else(|| ty.super_fold_with(self)); + + debug!( + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" + ); + normalized_ty + } + + _ => ty.super_fold_with(self), + } + } + + #[instrument(skip(self), level = "debug")] + fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { + if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement { + constant + } else { + let constant = constant.super_fold_with(self); + debug!(?constant); + debug!("self.param_env: {:?}", self.param_env); + constant.eval(self.selcx.tcx(), self.param_env) + } + } +} + +pub struct BoundVarReplacer<'me, 'tcx> { + infcx: &'me InferCtxt<'me, 'tcx>, + // These three maps track the bound variable that were replaced by placeholders. It might be + // nice to remove these since we already have the `kind` in the placeholder; we really just need + // the `var` (but we *could* bring that into scope if we were to track them as we pass them). + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, ty::BoundVar>, + // The current depth relative to *this* folding, *not* the entire normalization. In other words, + // the depth of binders we've passed here. + current_index: ty::DebruijnIndex, + // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: + // we don't actually create a universe until we see a bound var we have to replace. + universe_indices: &'me mut Vec>, +} + +impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { + /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that + /// use a binding level above `universe_indices.len()`, we fail. + pub fn replace_bound_vars>( + infcx: &'me InferCtxt<'me, 'tcx>, + universe_indices: &'me mut Vec>, + value: T, + ) -> ( + T, + BTreeMap, + BTreeMap, + BTreeMap, ty::BoundVar>, + ) { + let mapped_regions: BTreeMap = BTreeMap::new(); + let mapped_types: BTreeMap = BTreeMap::new(); + let mapped_consts: BTreeMap, ty::BoundVar> = BTreeMap::new(); + + let mut replacer = BoundVarReplacer { + infcx, + mapped_regions, + mapped_types, + mapped_consts, + current_index: ty::INNERMOST, + universe_indices, + }; + + let value = value.fold_with(&mut replacer); + + (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) + } + + fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { + let infcx = self.infcx; + let index = + self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; + let universe = self.universe_indices[index].unwrap_or_else(|| { + for i in self.universe_indices.iter_mut().take(index + 1) { + *i = i.or_else(|| Some(infcx.create_next_universe())) + } + self.universe_indices[index].unwrap() + }); + universe + } +} + +impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_binder>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReLateBound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + bug!("Bound vars outside of `self.universe_indices`"); + } + ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderRegion { universe, name: br.kind }; + self.mapped_regions.insert(p, br); + self.infcx.tcx.mk_region(ty::RePlaceholder(p)) + } + _ => r, + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match *t.kind() { + ty::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + bug!("Bound vars outside of `self.universe_indices`"); + } + ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderType { universe, name: bound_ty.var }; + self.mapped_types.insert(p, bound_ty); + self.infcx.tcx.mk_ty(ty::Placeholder(p)) + } + _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), + _ => t, + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.kind() { + ty::ConstKind::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + bug!("Bound vars outside of `self.universe_indices`"); + } + ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderConst { universe, name: bound_const }; + self.mapped_consts.insert(p, bound_const); + self.infcx + .tcx + .mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(p), ty: ct.ty() }) + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } +} + +// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came. +pub struct PlaceholderReplacer<'me, 'tcx> { + infcx: &'me InferCtxt<'me, 'tcx>, + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, ty::BoundVar>, + universe_indices: &'me [Option], + current_index: ty::DebruijnIndex, +} + +impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { + pub fn replace_placeholders>( + infcx: &'me InferCtxt<'me, 'tcx>, + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, ty::BoundVar>, + universe_indices: &'me [Option], + value: T, + ) -> T { + let mut replacer = PlaceholderReplacer { + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + current_index: ty::INNERMOST, + }; + value.fold_with(&mut replacer) + } +} + +impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_binder>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + if !t.has_placeholders() && !t.has_infer_regions() { + return t; + } + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { + let r1 = match *r0 { + ty::ReVar(_) => self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_region(self.infcx.tcx, r0), + _ => r0, + }; + + let r2 = match *r1 { + ty::RePlaceholder(p) => { + let replace_var = self.mapped_regions.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + self.tcx().mk_region(ty::ReLateBound(db, *replace_var)) + } + None => r1, + } + } + _ => r1, + }; + + debug!(?r0, ?r1, ?r2, "fold_region"); + + r2 + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Placeholder(p) => { + let replace_var = self.mapped_types.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + self.tcx().mk_ty(ty::Bound(db, *replace_var)) + } + None => ty, + } + } + + _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self), + _ => ty, + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Placeholder(p) = ct.kind() { + let replace_var = self.mapped_consts.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + self.tcx().mk_const(ty::ConstS { + kind: ty::ConstKind::Bound(db, *replace_var), + ty: ct.ty(), + }) + } + None => ct, + } + } else { + ct.super_fold_with(self) + } + } +} + +/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly +/// additional obligations). If ambiguity arises, which implies that +/// there are unresolved type variables in the projection, we will +/// substitute a fresh type variable `$X` and generate a new +/// obligation `::Item == $X` for later. +pub fn normalize_projection_type<'a, 'b, 'tcx>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &mut Vec>, +) -> Term<'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. + + selcx + .infcx() + .infer_projection(param_env, projection_ty, cause, depth + 1, obligations) + .into() + }) +} + +/// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly +/// additional obligations). Returns `None` in the case of ambiguity, +/// which indicates that there are unbound type variables. +/// +/// This function used to return `Option>`, which contains a +/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very +/// often immediately appended to another obligations vector. So now this +/// function takes an obligations vector and appends to it directly, which is +/// slightly uglier but avoids the need for an extra short-lived allocation. +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] +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>, +) -> Result>, InProgress> { + let infcx = selcx.infcx(); + // Don't use the projection cache in intercrate mode - + // the `infcx` may be re-used between intercrate in non-intercrate + // mode, which could lead to using incorrect cache results. + let use_cache = !selcx.is_intercrate(); + + let projection_ty = infcx.resolve_vars_if_possible(projection_ty); + let cache_key = ProjectionCacheKey::new(projection_ty); + + // FIXME(#20304) For now, I am caching here, which is good, but it + // means we don't capture the type variables that are created in + // the case of ambiguity. Which means we may create a large stream + // of such variables. OTOH, if we move the caching up a level, we + // would not benefit from caching when proving `T: Trait` + // bounds. It might be the case that we want two distinct caches, + // or else another kind of cache entry. + + let cache_result = if use_cache { + infcx.inner.borrow_mut().projection_cache().try_start(cache_key) + } else { + Ok(()) + }; + match cache_result { + Ok(()) => debug!("no cache"), + 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!("found cache entry: ambiguous"); + return Ok(None); + } + Err(ProjectionCacheEntry::InProgress) => { + // 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!("found cache entry: in-progress"); + + // Cache that normalizing this projection resulted in a cycle. This + // should ensure that, unless this happens within a snapshot that's + // rolled back, fulfillment or evaluation will notice the cycle. + + if use_cache { + infcx.inner.borrow_mut().projection_cache().recur(cache_key); + } + return Err(InProgress); + } + Err(ProjectionCacheEntry::Recur) => { + debug!("recur cache"); + return Err(InProgress); + } + Err(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => { + // 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!(?ty, "found normalized ty"); + obligations.extend(ty.obligations); + 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.into())); + } + } + + let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); + + match project(selcx, &obligation) { + Ok(Projected::Progress(Progress { + term: projected_term, + 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 + + let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term); + + let mut result = if projected_term.has_projections() { + let mut normalizer = AssocTypeNormalizer::new( + selcx, + param_env, + cause, + depth + 1, + &mut projected_obligations, + ); + let normalized_ty = normalizer.fold(projected_term); + + Normalized { value: normalized_ty, obligations: projected_obligations } + } else { + Normalized { value: projected_term, obligations: projected_obligations } + }; + + let mut deduped: SsoHashSet<_> = Default::default(); + result.obligations.drain_filter(|projected_obligation| { + if !deduped.insert(projected_obligation.clone()) { + return true; + } + false + }); + + if use_cache { + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); + } + obligations.extend(result.obligations); + Ok(Some(result.value)) + } + Ok(Projected::NoProgress(projected_ty)) => { + let result = Normalized { value: projected_ty, obligations: vec![] }; + if use_cache { + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); + } + // No need to extend `obligations`. + Ok(Some(result.value)) + } + Err(ProjectionError::TooManyCandidates) => { + debug!("opt_normalize_projection_type: too many candidates"); + if use_cache { + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); + } + Ok(None) + } + Err(ProjectionError::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 + + if use_cache { + 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.into())) + } + } +} + +/// If we are projecting `::Item`, but `T: Trait` does not +/// hold. In various error cases, we cannot generate a valid +/// normalized projection. Therefore, we create an inference variable +/// return an associated obligation that, when fulfilled, will lead to +/// an error. +/// +/// Note that we used to return `Error` here, but that was quite +/// dubious -- the premise was that an error would *eventually* be +/// reported, when the obligation was processed. But in general once +/// you see an `Error` you are supposed to be able to assume that an +/// error *has been* reported, so that you can take whatever heuristic +/// paths you want to take. To make things worse, it was possible for +/// cycles to arise, where you basically had a setup like ` +/// as Trait>::Foo == $0`. Here, normalizing ` as +/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// ` as Trait>::Foo`. We are supposed to report +/// an error for this obligation, but we legitimately should not, +/// because it contains `[type error]`. Yuck! (See issue #29857 for +/// one case where this arose.) +fn normalize_to_error<'a, 'tcx>( + selcx: &mut SelectionContext<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, +) -> NormalizedTy<'tcx> { + let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx())); + 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 Projected<'tcx> { + Progress(Progress<'tcx>), + NoProgress(ty::Term<'tcx>), +} + +struct Progress<'tcx> { + term: ty::Term<'tcx>, + obligations: Vec>, +} + +impl<'tcx> Progress<'tcx> { + fn error(tcx: TyCtxt<'tcx>) -> Self { + Progress { term: tcx.ty_error().into(), obligations: vec![] } + } + + fn with_addl_obligations(mut self, mut obligations: Vec>) -> Self { + self.obligations.append(&mut obligations); + self + } +} + +/// Computes the result of a projection type (if we can). +/// +/// IMPORTANT: +/// - `obligation` must be fully normalized +#[tracing::instrument(level = "info", skip(selcx))] +fn project<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, +) -> Result, ProjectionError<'tcx>> { + if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) { + // This should really be an immediate error, but some existing code + // relies on being able to recover from this. + return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow( + OverflowError::Canonical, + ))); + } + + if obligation.predicate.references_error() { + return Ok(Projected::Progress(Progress::error(selcx.tcx()))); + } + + let mut candidates = ProjectionCandidateSet::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, &mut candidates); + + assemble_candidates_from_trait_def(selcx, obligation, &mut candidates); + + assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); + + if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates { + // Avoid normalization cycle from selection (see + // `assemble_candidates_from_object_ty`). + // FIXME(lazy_normalization): Lazy normalization should save us from + // having to special case this. + } else { + assemble_candidates_from_impls(selcx, obligation, &mut candidates); + }; + + match candidates { + ProjectionCandidateSet::Single(candidate) => { + Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate))) + } + ProjectionCandidateSet::None => Ok(Projected::NoProgress( + // FIXME(associated_const_generics): this may need to change in the future? + // need to investigate whether or not this is fine. + selcx + .tcx() + .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs) + .into(), + )), + // Error occurred while trying to processing impls. + ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)), + // Inherent ambiguity that prevents us from even enumerating the + // candidates. + ProjectionCandidateSet::Ambiguous => Err(ProjectionError::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>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, +) { + assemble_candidates_from_predicates( + selcx, + obligation, + candidate_set, + ProjectionCandidate::ParamEnv, + obligation.param_env.caller_bounds().iter(), + false, + ); +} + +/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find +/// that the definition of `Foo` has some clues: +/// +/// ```ignore (illustrative) +/// trait Foo { +/// type FooT : Bar +/// } +/// ``` +/// +/// Here, for example, we could conclude that the result is `i32`. +fn assemble_candidates_from_trait_def<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'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.predicate.self_ty().kind() { + ty::Projection(ref data) => tcx.bound_item_bounds(data.item_def_id).subst(tcx, data.substs), + ty::Opaque(def_id, substs) => tcx.bound_item_bounds(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, + candidate_set, + ProjectionCandidate::TraitDef, + bounds.iter(), + true, + ); +} + +/// In the case of a trait object like +/// ` as Iterator>::Item` we can use the existential +/// predicate in the trait object. +/// +/// We don't go through the select candidate for these bounds to avoid cycles: +/// In the above case, `dyn Iterator: Iterator` would create a +/// nested obligation of ` as Iterator>::Item: Sized`, +/// this then has to be normalized without having to prove +/// `dyn Iterator: Iterator` again. +fn assemble_candidates_from_object_ty<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, +) { + debug!("assemble_candidates_from_object_ty(..)"); + + let tcx = selcx.tcx(); + + let self_ty = obligation.predicate.self_ty(); + let object_ty = selcx.infcx().shallow_resolve(self_ty); + let data = match object_ty.kind() { + ty::Dynamic(data, ..) => data, + ty::Infer(ty::TyVar(_)) => { + // If the self-type is an inference variable, then it MAY wind up + // being an object type, so induce an ambiguity. + candidate_set.mark_ambiguous(); + return; + } + _ => return, + }; + let env_predicates = data + .projection_bounds() + .filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id) + .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx)); + + assemble_candidates_from_predicates( + selcx, + obligation, + candidate_set, + ProjectionCandidate::Object, + env_predicates, + false, + ); +} + +#[tracing::instrument( + level = "debug", + skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates) +)] +fn assemble_candidates_from_predicates<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, + ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>, + env_predicates: impl Iterator>, + potentially_unnormalized_candidates: bool, +) { + let infcx = selcx.infcx(); + for predicate in env_predicates { + let bound_predicate = predicate.kind(); + if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() { + let data = bound_predicate.rebind(data); + if data.projection_def_id() != obligation.predicate.item_def_id { + continue; + } + + let is_match = infcx.probe(|_| { + selcx.match_projection_projections( + obligation, + data, + potentially_unnormalized_candidates, + ) + }); + + match is_match { + ProjectionMatchesProjection::Yes => { + candidate_set.push_candidate(ctor(data)); + + if potentially_unnormalized_candidates + && !obligation.predicate.has_infer_types_or_consts() + { + // HACK: Pick the first trait def candidate for a fully + // inferred predicate. This is to allow duplicates that + // differ only in normalization. + return; + } + } + ProjectionMatchesProjection::Ambiguous => { + candidate_set.mark_ambiguous(); + } + ProjectionMatchesProjection::No => {} + } + } + } +} + +#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))] +fn assemble_candidates_from_impls<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, +) { + // If we are resolving `>::Item == Type`, + // start out by selecting the predicate `T as TraitRef<...>`: + let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); + 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!(error = ?e, "selection error"); + candidate_set.mark_error(e); + return Err(()); + } + }; + + let eligible = match &impl_source { + super::ImplSource::Closure(_) + | super::ImplSource::Generator(_) + | super::ImplSource::FnPointer(_) + | super::ImplSource::TraitAlias(_) => true, + super::ImplSource::UserDefined(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_utils::instance::resolve_associated_item()`. + let node_item = + assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) + .map_err(|ErrorGuaranteed { .. }| ())?; + + 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!( + assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), + ?obligation.predicate, + "assemble_candidates_from_impls: not eligible due to default", + ); + false + } + } + } + super::ImplSource::DiscriminantKind(..) => { + // 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::ImplSource::Pointee(..) => { + // While `Pointee` is automatically implemented for every type, + // the concrete metadata type may not be known yet. + // + // Any type with multiple potential metadata types is therefore not eligible. + let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); + + let tail = selcx.tcx().struct_tail_with_normalize( + self_ty, + |ty| { + // We throw away any obligations we get from this, since we normalize + // and confirm these obligations once again during confirmation + normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty, + ) + .value + }, + || {}, + ); + + match tail.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Never + // Extern types have unit metadata, according to RFC 2850 + | ty::Foreign(_) + // If returned by `struct_tail_without_normalization` this is a unit struct + // without any fields, or not a struct, and therefore is Sized. + | ty::Adt(..) + // If returned by `struct_tail_without_normalization` this is the empty tuple. + | ty::Tuple(..) + // Integers and floats are always Sized, and so have unit type metadata. + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + + // type parameters, opaques, and unnormalized projections have pointer + // metadata if they're known (e.g. by the param_env) to be sized + ty::Param(_) | ty::Projection(..) | ty::Opaque(..) + if selcx.infcx().predicate_must_hold_modulo_regions( + &obligation.with( + ty::Binder::dummy(ty::TraitRef::new( + selcx.tcx().require_lang_item(LangItem::Sized, None), + selcx.tcx().mk_substs_trait(self_ty, &[]), + )) + .without_const() + .to_predicate(selcx.tcx()), + ), + ) => + { + true + } + + // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? + ty::Param(_) + | ty::Projection(..) + | ty::Opaque(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) + | ty::Error(_) => { + if tail.has_infer_types() { + candidate_set.mark_ambiguous(); + } + false + } + } + } + super::ImplSource::Param(..) => { + // This case tell us nothing about the value of an + // associated type. Consider: + // + // ``` + // trait SomeTrait { type Foo; } + // fn foo(...) { } + // ``` + // + // If the user writes `::Foo`, then the `T + // : SomeTrait` binding does not help us decide what the + // type `Foo` is (at least, not more specifically than + // what we already knew). + // + // But wait, you say! What about an example like this: + // + // ``` + // fn bar>(...) { ... } + // ``` + // + // Doesn't the `T : SomeTrait` predicate help + // resolve `T::Foo`? And of course it does, but in fact + // that single predicate is desugared into two predicates + // in the compiler: a trait predicate (`T : SomeTrait`) and a + // projection. And the projection where clause is handled + // in `assemble_candidates_from_param_env`. + false + } + super::ImplSource::Object(_) => { + // Handled by the `Object` projection candidate. See + // `assemble_candidates_from_object_ty` for an explanation of + // why we special case object types. + false + } + super::ImplSource::AutoImpl(..) + | super::ImplSource::Builtin(..) + | super::ImplSource::TraitUpcasting(_) + | super::ImplSource::ConstDestruct(_) => { + // 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(ProjectionCandidate::Select(impl_source)) { + Ok(()) + } else { + Err(()) + } + } else { + Err(()) + } + }); +} + +fn confirm_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate: ProjectionCandidate<'tcx>, +) -> Progress<'tcx> { + debug!(?obligation, ?candidate, "confirm_candidate"); + let mut progress = match candidate { + ProjectionCandidate::ParamEnv(poly_projection) + | ProjectionCandidate::Object(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection, false) + } + + ProjectionCandidate::TraitDef(poly_projection) => { + confirm_param_env_candidate(selcx, obligation, poly_projection, true) + } + + ProjectionCandidate::Select(impl_source) => { + confirm_select_candidate(selcx, obligation, 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.term.has_infer_regions() { + progress.term = + progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx())); + } + progress +} + +fn confirm_select_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + impl_source: Selection<'tcx>, +) -> Progress<'tcx> { + match impl_source { + super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), + super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::ImplSource::DiscriminantKind(data) => { + confirm_discriminant_kind_candidate(selcx, obligation, data) + } + super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data), + super::ImplSource::Object(_) + | super::ImplSource::AutoImpl(..) + | super::ImplSource::Param(..) + | super::ImplSource::Builtin(..) + | super::ImplSource::TraitUpcasting(_) + | super::ImplSource::TraitAlias(..) + | super::ImplSource::ConstDestruct(_) => { + // 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_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!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate"); + + 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).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, + }, + term: ty.into(), + } + }); + + confirm_param_env_candidate(selcx, obligation, predicate, false) + .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()); + // We get here from `poly_project_and_unify_type` which replaces bound vars + // with placeholders + debug_assert!(!self_ty.has_escaping_bound_vars()); + 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 }, + term: self_ty.discriminant_ty(tcx).into(), + }; + + // We get here from `poly_project_and_unify_type` which replaces bound vars + // with placeholders, so dummy is okay here. + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) +} + +fn confirm_pointee_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + _: ImplSourcePointeeData, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); + + let mut obligations = vec![]; + let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| { + normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty, + &mut obligations, + ) + }); + if check_is_sized { + let sized_predicate = ty::Binder::dummy(ty::TraitRef::new( + tcx.require_lang_item(LangItem::Sized, None), + tcx.mk_substs_trait(self_ty, &[]), + )) + .without_const() + .to_predicate(tcx); + obligations.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + sized_predicate, + )); + } + + let substs = tcx.mk_substs([self_ty.into()].iter()); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id }, + term: metadata_ty.into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) + .with_addl_obligations(obligations) +} + +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!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); + + 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!(?obligation, ?fn_sig, "confirm_callable_candidate"); + + 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, + }, + term: ret_type.into(), + }); + + confirm_param_env_candidate(selcx, obligation, predicate, true) +} + +fn confirm_param_env_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, + potentially_unnormalized_candidate: bool, +) -> 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_projection = cache_entry.projection_ty; + let mut nested_obligations = Vec::new(); + let obligation_projection = obligation.predicate; + let obligation_projection = ensure_sufficient_stack(|| { + normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation_projection, + &mut nested_obligations, + ) + }); + let cache_projection = if potentially_unnormalized_candidate { + ensure_sufficient_stack(|| { + normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + cache_projection, + &mut nested_obligations, + ) + }) + } else { + cache_projection + }; + + debug!(?cache_projection, ?obligation_projection); + + match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { + Ok(InferOk { value: _, obligations }) => { + nested_obligations.extend(obligations); + assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); + // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take + // a term instead. + Progress { term: cache_entry.term, obligations: nested_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 { term: err.into(), 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, mut 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 Ok(assoc_ty) = assoc_def(selcx, impl_def_id, assoc_item_id) else { + return Progress { term: tcx.ty_error().into(), obligations: nested }; + }; + + if !assoc_ty.item.defaultness(tcx).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.name, obligation.predicate + ); + return Progress { term: tcx.ty_error().into(), obligations: nested }; + } + // If we're trying to normalize ` as X>::A` using + //`impl X for Vec { type A = Box; }`, then: + // + // * `obligation.predicate.substs` is `[Vec, 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.bound_type_of(assoc_ty.item.def_id); + let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); + let term: ty::EarlyBinder> = if is_const { + let identity_substs = + crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); + let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id); + let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs)); + ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into()) + } else { + ty.map_bound(|ty| ty.into()) + }; + if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { + let err = tcx.ty_error_with_message( + obligation.cause.span, + "impl item and trait item have different parameter counts", + ); + Progress { term: err.into(), obligations: nested } + } else { + assoc_ty_own_obligations(selcx, obligation, &mut nested); + Progress { term: term.subst(tcx, substs), obligations: nested } + } +} + +// Get obligations corresponding to the predicates from the where-clause of the +// associated type itself. +// Note: `feature(generic_associated_types)` is required to write such +// predicates, even for non-generic associated types. +fn assoc_ty_own_obligations<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + nested: &mut Vec>, +) { + let tcx = selcx.tcx(); + for predicate in tcx + .predicates_of(obligation.predicate.item_def_id) + .instantiate_own(tcx, obligation.predicate.substs) + .predicates + { + let normalized = normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + predicate, + nested, + ); + nested.push(Obligation::with_depth( + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + normalized, + )); + } +} + +/// 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_def( + selcx: &SelectionContext<'_, '_>, + impl_def_id: DefId, + assoc_def_id: DefId, +) -> Result { + let tcx = selcx.tcx(); + 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. + if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) { + let item = tcx.associated_item(impl_item_id); + let impl_node = specialization_graph::Node::Impl(impl_def_id); + return Ok(specialization_graph::LeafDef { + item: *item, + defining_node: impl_node, + finalizing_node: if item.defaultness(tcx).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_def_id) { + 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 {}", + tcx.item_name(assoc_def_id), + tcx.def_path_str(impl_def_id) + ) + } +} + +pub(crate) trait ProjectionCacheKeyExt<'cx, 'tcx>: Sized { + fn from_poly_projection_predicate( + selcx: &mut SelectionContext<'cx, 'tcx>, + predicate: ty::PolyProjectionPredicate<'tcx>, + ) -> Option; +} + +impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { + fn from_poly_projection_predicate( + selcx: &mut SelectionContext<'cx, 'tcx>, + predicate: ty::PolyProjectionPredicate<'tcx>, + ) -> Option { + let infcx = selcx.infcx(); + // We don't do cross-snapshot caching of obligations with escaping regions, + // so there's no cache key to use + predicate.no_bound_vars().map(|predicate| { + ProjectionCacheKey::new( + // We don't attempt to match up with a specific type-variable state + // from a specific call to `opt_normalize_projection_type` - if + // there's no precise match, the original cache entry is "stranded" + // anyway. + infcx.resolve_vars_if_possible(predicate.projection_ty), + ) + }) + } +} diff --git a/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 000000000..aad3c37f8 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -0,0 +1,73 @@ +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; + +/// 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. +/// +// FIXME(@lcnr): remove this module and move this function somewhere else. +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 *all* of them are trivial. + ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), + ty::Closure(_, ref substs) => { + trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty()) + } + + 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 000000000..32669e23d --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -0,0 +1,118 @@ +use rustc_middle::ty; + +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; + + // 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 { + let mut _orig_values = OriginalQueryValues::default(); + + let param_env = match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => { + // we ignore the value set to it. + let mut _constness = pred.constness; + obligation + .param_env + .with_constness(_constness.and(obligation.param_env.constness())) + } + // constness has no effect on the given predicate. + _ => obligation.param_env.without_const(), + }; + + let c_pred = self + .canonicalize_query_keep_static(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.at(obligation.cause.span()).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::Canonical) => { + let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); + selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r { + OverflowError::Canonical => { + span_bug!( + obligation.cause.span, + "Overflow should be caught earlier in standard query mode: {:?}, {:?}", + obligation, + r, + ) + } + OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr, + OverflowError::Error(_) => EvaluationResult::EvaluatedToErr, + }) + } + Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr, + Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr, + } + } +} 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 000000000..3c0ebec93 --- /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 000000000..ef3493678 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/mod.rs @@ -0,0 +1,14 @@ +//! 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 +//! `rustc_traits`. + +pub mod dropck_outlives; +pub mod evaluate_obligation; +pub mod method_autoderef; +pub mod normalize; +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 000000000..449d7a7b4 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -0,0 +1,354 @@ +//! 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::project::needs_normalization; +use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use rustc_data_structures::sso::SsoHashMap; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_infer::traits::Normalized; +use rustc_middle::mir; +use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; + +use std::ops::ControlFlow; + +use super::NoSolution; + +pub use rustc_middle::traits::query::NormalizationResult; + +pub trait AtExt<'tcx> { + fn normalize(&self, value: T) -> Result, NoSolution> + where + T: TypeFoldable<'tcx>; +} + +impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { + /// Normalize `value` in the context of the inference context, + /// yielding a resulting type, or an error if `value` cannot be + /// normalized. If you don't care about regions, you should prefer + /// `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(&self, value: T) -> Result, NoSolution> + where + T: TypeFoldable<'tcx>, + { + debug!( + "normalize::<{}>(value={:?}, param_env={:?})", + std::any::type_name::(), + value, + self.param_env, + ); + if !needs_normalization(&value, self.param_env.reveal()) { + return Ok(Normalized { value, obligations: vec![] }); + } + + let mut normalizer = QueryNormalizer { + infcx: self.infcx, + cause: self.cause, + param_env: self.param_env, + obligations: vec![], + cache: SsoHashMap::new(), + anon_depth: 0, + universes: vec![], + }; + + // This is actually a consequence by the way `normalize_erasing_regions` works currently. + // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds + // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us + // with trying to normalize with escaping bound vars. + // + // Here, we just add the universes that we *would* have created had we passed through the binders. + // + // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary. + // The rest of the code is already set up to be lazy about replacing bound vars, + // and only when we actually have to normalize. + if value.has_escaping_bound_vars() { + let mut max_visitor = + MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 }; + value.visit_with(&mut max_visitor); + if max_visitor.escaping > 0 { + normalizer.universes.extend((0..max_visitor.escaping).map(|_| None)); + } + } + let result = value.try_fold_with(&mut normalizer); + info!( + "normalize::<{}>: result={:?} with {} obligations", + std::any::type_name::(), + result, + normalizer.obligations.len(), + ); + debug!( + "normalize::<{}>: obligations={:?}", + std::any::type_name::(), + normalizer.obligations, + ); + result.map(|value| Normalized { value, obligations: normalizer.obligations }) + } +} + +// Visitor to find the maximum escaping bound var +struct MaxEscapingBoundVarVisitor { + // The index which would count as escaping + outer_index: ty::DebruijnIndex, + escaping: usize, +} + +impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { + fn visit_binder>( + &mut self, + t: &ty::Binder<'tcx, T>, + ) -> ControlFlow { + self.outer_index.shift_in(1); + let result = t.super_visit_with(self); + self.outer_index.shift_out(1); + result + } + + #[inline] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if t.outer_exclusive_binder() > self.outer_index { + self.escaping = self + .escaping + .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); + } + ControlFlow::CONTINUE + } + + #[inline] + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + match *r { + ty::ReLateBound(debruijn, _) if debruijn > self.outer_index => { + self.escaping = + self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); + } + _ => {} + } + ControlFlow::CONTINUE + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { + match ct.kind() { + ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { + self.escaping = + self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); + ControlFlow::CONTINUE + } + _ => ct.super_visit_with(self), + } + } +} + +struct QueryNormalizer<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + cause: &'cx ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + obligations: Vec>, + cache: SsoHashMap, Ty<'tcx>>, + anon_depth: usize, + universes: Vec>, +} + +impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { + type Error = NoSolution; + + fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn try_fold_binder>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> Result, Self::Error> { + self.universes.push(None); + let t = t.try_super_fold_with(self); + self.universes.pop(); + t + } + + #[instrument(level = "debug", skip(self))] + fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { + if !needs_normalization(&ty, self.param_env.reveal()) { + return Ok(ty); + } + + if let Some(ty) = self.cache.get(&ty) { + return Ok(*ty); + } + + // See note in `rustc_trait_selection::traits::project` about why we + // wait to fold the substs. + + // Wrap this in a closure so we don't accidentally return from the outer function + let res = (|| match *ty.kind() { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { + // Only normalize `impl Trait` outside of type inference, usually in codegen. + match self.param_env.reveal() { + Reveal::UserFacing => ty.try_super_fold_with(self), + + Reveal::All => { + let substs = substs.try_fold_with(self)?; + let recursion_limit = self.tcx().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().bound_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.try_fold_ty(concrete_ty)); + self.anon_depth -= 1; + folded_ty + } + } + } + + ty::Projection(data) if !data.has_escaping_bound_vars() => { + // This branch is just an optimization: when we don't have escaping bound vars, + // we don't need to replace them with placeholders (see branch below). + + let tcx = self.infcx.tcx; + let data = data.try_fold_with(self)?; + + 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_query_keep_static(self.param_env.and(data), &mut orig_values); + debug!("QueryNormalizer: c_data = {:#?}", c_data); + debug!("QueryNormalizer: orig_values = {:#?}", orig_values); + let result = tcx.normalize_projection_ty(c_data)?; + // We don't expect ambiguity. + if result.is_ambiguous() { + bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + } + let InferOk { value: result, obligations } = + self.infcx.instantiate_query_response_and_region_obligations( + self.cause, + self.param_env, + &orig_values, + result, + )?; + debug!("QueryNormalizer: result = {:#?}", result); + debug!("QueryNormalizer: obligations = {:#?}", obligations); + self.obligations.extend(obligations); + Ok(result.normalized_ty) + } + + ty::Projection(data) => { + // See note in `rustc_trait_selection::traits::project` + + let tcx = self.infcx.tcx; + let infcx = self.infcx; + let (data, mapped_regions, mapped_types, mapped_consts) = + crate::traits::project::BoundVarReplacer::replace_bound_vars( + infcx, + &mut self.universes, + data, + ); + let data = data.try_fold_with(self)?; + + 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_query_keep_static(self.param_env.and(data), &mut orig_values); + debug!("QueryNormalizer: c_data = {:#?}", c_data); + debug!("QueryNormalizer: orig_values = {:#?}", orig_values); + let result = tcx.normalize_projection_ty(c_data)?; + // We don't expect ambiguity. + if result.is_ambiguous() { + bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + } + let InferOk { value: result, obligations } = + self.infcx.instantiate_query_response_and_region_obligations( + self.cause, + self.param_env, + &orig_values, + result, + )?; + debug!("QueryNormalizer: result = {:#?}", result); + debug!("QueryNormalizer: obligations = {:#?}", obligations); + self.obligations.extend(obligations); + Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + result.normalized_ty, + )) + } + + _ => ty.try_super_fold_with(self), + })()?; + self.cache.insert(ty, res); + Ok(res) + } + + fn try_fold_const( + &mut self, + constant: ty::Const<'tcx>, + ) -> Result, Self::Error> { + let constant = constant.try_super_fold_with(self)?; + Ok(constant.eval(self.infcx.tcx, self.param_env)) + } + + fn try_fold_mir_const( + &mut self, + constant: mir::ConstantKind<'tcx>, + ) -> Result, Self::Error> { + Ok(match constant { + mir::ConstantKind::Ty(c) => { + let const_folded = c.try_super_fold_with(self)?; + match const_folded.kind() { + ty::ConstKind::Value(valtree) => { + let tcx = self.infcx.tcx; + let ty = const_folded.ty(); + let const_val = tcx.valtree_to_const_val((ty, valtree)); + debug!(?ty, ?valtree, ?const_val); + + mir::ConstantKind::Val(const_val, ty) + } + _ => mir::ConstantKind::Ty(const_folded), + } + } + mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?, + }) + } +} 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 000000000..86b015767 --- /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 { + None + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + 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 000000000..c99564936 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -0,0 +1,117 @@ +use crate::infer::canonical::query_response; +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::engine::TraitEngineExt as _; +use crate::traits::query::type_op::TypeOpOutput; +use crate::traits::query::Fallible; +use crate::traits::TraitEngine; +use rustc_infer::infer::region_constraints::RegionConstraintData; +use rustc_infer::traits::TraitEngineExt as _; +use rustc_span::source_map::DUMMY_SP; + +use std::fmt; + +pub struct CustomTypeOp { + closure: F, + description: G, +} + +impl CustomTypeOp { + pub fn new<'tcx, R>(closure: F, description: G) -> Self + where + F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible>, + G: Fn() -> String, + { + CustomTypeOp { closure, description } + } +} + +impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp +where + F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible>, + G: Fn() -> String, +{ + type Output = R; + /// We can't do any custom error reporting for `CustomTypeOp`, so + /// we can use `!` to enforce that the implementation never provides it. + type ErrorInfo = !; + + /// 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> { + if cfg!(debug_assertions) { + info!("fully_perform({:?})", self); + } + + Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0) + } +} + +impl fmt::Debug for CustomTypeOp +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. +pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( + infcx: &InferCtxt<'_, 'tcx>, + op: impl FnOnce() -> Fallible>, +) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { + let mut fulfill_cx = >::new(infcx.tcx); + + // 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())?; + fulfill_cx.register_predicate_obligations(infcx, obligations); + let errors = fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { + infcx.tcx.sess.diagnostic().delay_span_bug( + DUMMY_SP, + &format!("errors selecting obligation during MIR typeck: {:?}", errors), + ); + } + + 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(( + TypeOpOutput { output: value, constraints: None, error_info: None }, + region_constraint_data, + )) + } else { + Ok(( + TypeOpOutput { + output: value, + constraints: Some(infcx.tcx.arena.alloc(region_constraints)), + error_info: None, + }, + region_constraint_data, + )) + } +} 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 000000000..490114aac --- /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 { + if key.value.a == key.value.b { Some(()) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + 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 000000000..2a3319f0f --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -0,0 +1,42 @@ +use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; +use crate::traits::query::Fallible; +use rustc_infer::traits::query::OutlivesBound; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] +pub struct ImpliedOutlivesBounds<'tcx> { + pub ty: Ty<'tcx>, +} + +impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { + type QueryResponse = Vec>; + + fn try_fast_path( + _tcx: TyCtxt<'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + // Don't go into the query for things that can't possibly have lifetimes. + match key.value.ty.kind() { + ty::Tuple(elems) if elems.is_empty() => Some(vec![]), + ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { + Some(vec![]) + } + _ => None, + } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + // FIXME this `unchecked_map` is only necessary because the + // query is defined as taking a `ParamEnvAnd`; it should + // take an `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 000000000..578e1d00c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -0,0 +1,168 @@ +use crate::infer::canonical::{ + Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints, +}; +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::query::Fallible; +use crate::traits::ObligationCause; +use rustc_infer::infer::canonical::{Canonical, Certainty}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::PredicateObligations; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use std::fmt; + +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; +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; + type ErrorInfo; + + /// 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>; +} + +/// The output from performing a type op +pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> { + /// The output from the type op. + pub output: Op::Output, + /// Any region constraints from performing the type op. + pub constraints: Option<&'tcx QueryRegionConstraints<'tcx>>, + /// Used for error reporting to be able to rerun the query + pub error_info: Option, +} + +/// "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`, 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 + Copy + 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; + + /// 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>; + + fn fully_perform_into( + query_key: ParamEnvAnd<'tcx, Self>, + infcx: &InferCtxt<'_, 'tcx>, + output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, + ) -> Fallible<( + Self::QueryResponse, + Option>>, + PredicateObligations<'tcx>, + Certainty, + )> { + if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { + return Ok((result, None, vec![], Certainty::Proven)); + } + + // FIXME(#33684) -- We need to use + // `canonicalize_query_keep_static` here because of things + // like the subtype query, which go awry around + // `'static` otherwise. + let mut canonical_var_values = OriginalQueryValues::default(); + let old_param_env = query_key.param_env; + let canonical_self = + infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values); + let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; + + let InferOk { value, obligations } = infcx + .instantiate_nll_query_response_and_region_obligations( + &ObligationCause::dummy(), + old_param_env, + &canonical_var_values, + canonical_result, + output_query_region_constraints, + )?; + + Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty)) + } +} + +impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q> +where + Q: QueryTypeOp<'tcx>, +{ + type Output = Q::QueryResponse; + type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; + + fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { + let mut region_constraints = QueryRegionConstraints::default(); + let (output, error_info, mut obligations, _) = + Q::fully_perform_into(self, infcx, &mut 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. + while !obligations.is_empty() { + trace!("{:#?}", obligations); + let mut progress = false; + for obligation in std::mem::take(&mut obligations) { + let obligation = infcx.resolve_vars_if_possible(obligation); + match ProvePredicate::fully_perform_into( + obligation.param_env.and(ProvePredicate::new(obligation.predicate)), + infcx, + &mut region_constraints, + ) { + Ok(((), _, new, certainty)) => { + obligations.extend(new); + progress = true; + if let Certainty::Ambiguous = certainty { + obligations.push(obligation); + } + } + Err(_) => obligations.push(obligation), + } + } + if !progress { + return Err(NoSolution); + } + } + + Ok(TypeOpOutput { + output, + constraints: if region_constraints.is_empty() { + None + } else { + Some(infcx.tcx.arena.alloc(region_constraints)) + }, + error_info, + }) + } +} 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 000000000..e92ca7325 --- /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 +where + T: Normalizable<'tcx> + 'tcx, +{ + type QueryResponse = T; + + fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option { + 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> { + 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>>, + ) -> Fallible>; +} + +impl<'tcx> Normalizable<'tcx> for Ty<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_ty(canonicalized) + } +} + +impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_predicate(canonicalized) + } +} + +impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_poly_fn_sig(canonicalized) + } +} + +impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> { + fn type_op_method( + tcx: TyCtxt<'tcx>, + canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + 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 000000000..b63382429 --- /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, TypeVisitable, 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<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { + type QueryResponse = DropckOutlivesResult<'tcx>; + + fn try_fast_path( + tcx: TyCtxt<'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + 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> { + // 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 000000000..081308ac7 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -0,0 +1,43 @@ +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 { + // 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::PredicateKind::Trait(trait_ref) = key.value.predicate.kind().skip_binder() { + 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>, + mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + match canonicalized.value.value.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => { + canonicalized.value.param_env.remap_constness_with(pred.constness); + } + _ => canonicalized.value.param_env = canonicalized.value.param_env.without_const(), + } + 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 000000000..57290b669 --- /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> { + tcx.type_op_subtype(canonicalized) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs new file mode 100644 index 000000000..8148e2b78 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -0,0 +1,58 @@ +use crate::infer::InferCtxt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{ObligationCause, PredicateObligation}; +use rustc_infer::traits::TraitEngine; +use rustc_middle::ty::{self, ToPredicate}; + +pub(crate) fn update<'tcx, T>( + engine: &mut T, + infcx: &InferCtxt<'_, 'tcx>, + obligation: &PredicateObligation<'tcx>, +) where + T: TraitEngine<'tcx>, +{ + // (*) binder skipped + if let ty::PredicateKind::Trait(tpred) = obligation.predicate.kind().skip_binder() + && let Some(ty) = infcx.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| infcx.root_var(t)) + && infcx.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id) + { + let new_self_ty = infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: infcx.tcx.mk_substs_trait(new_self_ty, &tpred.trait_ref.substs[1..]), + ..tpred.trait_ref + }; + + // Then construct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + obligation + .predicate + .kind() + .rebind( + // (*) binder moved here + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: tpred.constness, + polarity: tpred.polarity, + }) + ) + .to_predicate(infcx.tcx), + ); + // Don't report overflow errors. Otherwise equivalent to may_hold. + if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() { + engine.relationships().entry(ty).or_default().self_in_trait = true; + } + } + + if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() { + // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, + // we need to make it into one. + if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) { + debug!("relationship: {:?}.output = true", vid); + engine.relationships().entry(vid).or_default().output = true; + } + } +} 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 000000000..a60ce0f34 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -0,0 +1,1009 @@ +//! 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 hir::LangItem; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; +use rustc_target::spec::abi::Abi; + +use crate::traits; +use crate::traits::coherence::Conflict; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{util, SelectionResult}; +use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented}; + +use super::BuiltinImplConditions; +use super::IntercrateAmbiguityCause; +use super::OverflowError; +use super::SelectionCandidate::{self, *}; +use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + #[instrument(level = "debug", skip(self))] + 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!(?cache_fresh_trait_pred); + 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!(candidate = ?c, "CACHE HIT"); + 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!(?candidate, "CACHE MISS"); + self.insert_candidate_cache( + stack.obligation.param_env, + cache_fresh_trait_pred, + dep_node, + candidate.clone(), + ); + 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, self_desc) = with_no_trimmed_paths!({ + 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 + }; + (trait_desc, self_desc) + }); + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!(?cause, "evaluate_stack: pushing cause"); + self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); + } + } + } + return Ok(None); + } + + let candidate_set = self.assemble_candidates(stack)?; + + if candidate_set.ambiguous { + debug!("candidate set contains ambig"); + return Ok(None); + } + + let candidates = candidate_set.vec; + + debug!(?stack, ?candidates, "assembled {} candidates", candidates.len()); + + // 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. + + let mut candidates = self.filter_impls(candidates, stack.obligation); + + // 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 Vec { fn push_clone(...) { ... } } + // + // and we were to see some code `foo.push_clone()` where `boo` + // is a `Vec` 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_reservation_impls(candidates.pop().unwrap(), stack.obligation); + } + + // 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::Canonical) => Err(Overflow(OverflowError::Canonical)), + Err(OverflowError::ErrorReporting) => Err(ErrorReporting), + Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))), + }) + .flat_map(Result::transpose) + .collect::, _>>()?; + + debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len()); + + let needs_infer = stack.obligation.predicate.has_infer_types_or_consts(); + + // 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!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); + candidates.swap_remove(i); + } else { + debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len()); + i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Err(Ambiguous( + candidates + .into_iter() + .filter_map(|c| match c.candidate { + SelectionCandidate::ImplCandidate(def_id) => Some(def_id), + _ => None, + }) + .collect(), + )); + } + } + } + } + + // 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.predicate.references_error() { + debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous"); + return Ok(None); + } + return Err(Unimplemented); + } + + // Just one candidate left. + self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation) + } + + #[instrument(skip(self, stack), level = "debug")] + pub(super) fn assemble_candidates<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> Result, 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() { + debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type"); + // Self is a type variable (e.g., `_: AsRef`). + // + // 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 }; + + // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl. + // There are no compiler built-in rules for this. + if obligation.polarity() == ty::ImplPolarity::Negative { + self.assemble_candidates_for_trait_alias(obligation, &mut candidates); + self.assemble_candidates_from_impls(obligation, &mut candidates); + } else { + 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 = ?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.pointee_trait() == Some(def_id) { + // `Pointee` is automatically implemented for every type. + candidates.vec.push(PointeeCandidate); + } 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.destruct_trait() == Some(def_id) { + self.assemble_const_destruct_candidates(obligation, &mut candidates); + } else if lang_items.transmute_trait() == Some(def_id) { + // User-defined transmutability impls are permitted. + self.assemble_candidates_from_impls(obligation, &mut candidates); + self.assemble_candidates_for_transmutability(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) + } + + #[tracing::instrument(level = "debug", skip(self, candidates))] + fn assemble_candidates_from_projected_tys( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + // 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)); + + candidates.vec.extend(result.into_iter().map(ProjectionCandidate)); + } + + /// Given an obligation like ``, searches the obligations that the caller + /// supplied to find out whether it is listed among them. + /// + /// Never affects the inference environment. + #[tracing::instrument(level = "debug", skip(self, stack, candidates))] + fn assemble_candidates_from_caller_bounds<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + debug!(?stack.obligation); + + let all_bounds = stack + .obligation + .param_env + .caller_bounds() + .iter() + .filter_map(|o| o.to_opt_poly_trait_pred()); + + // 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. + for bound in matching_bounds { + // FIXME(oli-obk): it is suspicious that we are dropping the constness and + // polarity here. + let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; + if wc.may_apply() { + candidates.vec.push(ParamCandidate(bound)); + } + } + + Ok(()) + } + + fn assemble_generator_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { + return; + } + + // 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!(?self_ty, ?obligation, "assemble_generator_candidates",); + + candidates.vec.push(GeneratorCandidate); + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_generator_candidates: ambiguous self-type"); + candidates.ambiguous = true; + } + _ => {} + } + } + + /// 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>, + ) { + let Some(kind) = self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) else { + return; + }; + + // 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!(?kind, ?obligation, "assemble_unboxed_candidates"); + match self.infcx.closure_kind(closure_substs) { + Some(closure_kind) => { + debug!(?closure_kind, "assemble_unboxed_candidates"); + 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; + } + _ => {} + } + } + + /// Implements one of the `Fn()` family for a fn pointer. + fn assemble_fn_pointer_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'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; + } + + // 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 { is_const: false }); + } + } + // 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 { is_const: self.tcx().is_const_fn(def_id) }); + } + } + } + _ => {} + } + } + + /// Searches for impls that might apply to `obligation`. + fn assemble_candidates_from_impls( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + debug!(?obligation, "assemble_candidates_from_impls"); + + // 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. + // We don't check for errors in the `ParamEnv` - in practice, + // it seems to cause us to be overly aggressive in deciding + // to give up searching for candidates, leading to spurious errors. + if obligation.predicate.references_error() { + return; + } + + self.tcx().for_each_relevant_impl( + obligation.predicate.def_id(), + obligation.predicate.skip_binder().trait_ref.self_ty(), + |impl_def_id| { + // Before we create the substitutions and everything, first + // consider a "quick reject". This avoids creating more types + // and so forth that we need to. + let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); + if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) { + return; + } + + self.infcx.probe(|_| { + if let Ok(_substs) = self.match_impl(impl_def_id, impl_trait_ref, obligation) { + candidates.vec.push(ImplCandidate(impl_def_id)); + } + }); + }, + ); + } + + fn assemble_candidates_from_auto_impls( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'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!(?self_ty, "assemble_candidates_from_auto_impls"); + + 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 + // `ui/typeck/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)), + } + } + } + + /// Searches for impls that might apply to `obligation`. + fn assemble_candidates_from_object_ty( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + debug!( + self_ty = ?obligation.self_ty().skip_binder(), + "assemble_candidates_from_object_ty", + ); + + 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!(?poly_trait_ref, "assemble_candidates_from_object_ty"); + + 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); + + // 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`, + // but `Foo` is declared as `trait Foo: Bar`. + let candidate_supertraits = util::supertraits(self.tcx(), poly_trait_ref) + .enumerate() + .filter(|&(_, upcast_trait_ref)| { + self.infcx.probe(|_| { + self.match_normalize_trait_ref( + obligation, + upcast_trait_ref, + placeholder_trait_predicate.trait_ref, + ) + .is_ok() + }) + }) + .map(|(idx, _)| ObjectCandidate(idx)); + + candidates.vec.extend(candidate_supertraits); + }) + } + + /// Temporary migration for #89190 + fn need_migrate_deref_output_trait_object( + &mut self, + ty: Ty<'tcx>, + cause: &traits::ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option<(Ty<'tcx>, DefId)> { + let tcx = self.tcx(); + if tcx.features().trait_upcasting { + return None; + } + + // + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let obligation = traits::Obligation::new( + cause.clone(), + param_env, + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + param_env, + ty::ProjectionTy { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, + cause.clone(), + ); + + let ty::Dynamic(data, ..) = normalized_ty.kind() else { + return None; + }; + + let def_id = data.principal_def_id()?; + + return Some((normalized_ty, def_id)); + } + + /// 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` 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` obligation is always used as part of a `T: CoerceUnsize` + // 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> + // 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 Some(source) = obligation.self_ty().no_bound_vars() else { + // Don't add any candidates if there are bound regions. + return; + }; + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + + debug!(?source, ?target, "assemble_candidates_for_unsizing"); + + match (source.kind(), target.kind()) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + // Upcast coercions permit several 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` + // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar` + // + // Note that neither of the first two of these changes requires any + // change at runtime. The third needs to change pointer metadata at runtime. + // + // We always perform upcasting coercions when we can because of reason + // #2 (region bounds). + let auto_traits_compatible = 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)); + if auto_traits_compatible { + let principal_def_id_a = data_a.principal_def_id(); + let principal_def_id_b = data_b.principal_def_id(); + if principal_def_id_a == principal_def_id_b { + // no cyclic + candidates.vec.push(BuiltinUnsizeCandidate); + } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { + // not casual unsizing, now check whether this is trait upcasting coercion. + let principal_a = data_a.principal().unwrap(); + let target_trait_did = principal_def_id_b.unwrap(); + let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some((deref_output_ty, deref_output_trait_did)) = self + .need_migrate_deref_output_trait_object( + source, + &obligation.cause, + obligation.param_env, + ) + { + if deref_output_trait_did == target_trait_did { + self.tcx().struct_span_lint_hir( + DEREF_INTO_DYN_SUPERTRAIT, + obligation.cause.body_id, + obligation.cause.span, + |lint| { + lint.build(&format!( + "`{}` implements `Deref` with supertrait `{}` as output", + source, + deref_output_ty + )).emit(); + }, + ); + return; + } + } + + for (idx, upcast_trait_ref) in + util::supertraits(self.tcx(), source_trait_ref).enumerate() + { + if upcast_trait_ref.def_id() == target_trait_did { + candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + } + } + } + } + } + + // `T` -> `Trait` + (_, &ty::Dynamic(..)) => { + candidates.vec.push(BuiltinUnsizeCandidate); + } + + // Ambiguous handling is below `T` -> `Trait`, because inference + // variables can still implement `Unsize` 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; + } + + // `[T; n]` -> `[T]` + (&ty::Array(..), &ty::Slice(_)) => { + candidates.vec.push(BuiltinUnsizeCandidate); + } + + // `Struct` -> `Struct` + (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => { + if def_id_a == def_id_b { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + + // `(.., T)` -> `(.., U)` + (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { + if tys_a.len() == tys_b.len() { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + + _ => {} + }; + } + + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + fn assemble_candidates_for_transmutability( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if obligation.has_param_types_or_consts() { + return; + } + + if obligation.has_infer_types_or_consts() { + candidates.ambiguous = true; + return; + } + + candidates.vec.push(TransmutabilityCandidate); + } + + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + fn assemble_candidates_for_trait_alias( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'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!(?self_ty); + + let def_id = obligation.predicate.def_id(); + + if self.tcx().is_trait_alias(def_id) { + candidates.vec.push(TraitAliasCandidate(def_id)); + } + } + + /// Assembles the trait which are built-in to the language itself: + /// `Copy`, `Clone` and `Sized`. + #[tracing::instrument(level = "debug", skip(self, candidates))] + fn assemble_builtin_bound_candidates( + &mut self, + conditions: BuiltinImplConditions<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match conditions { + BuiltinImplConditions::Where(nested) => { + candidates + .vec + .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); + } + BuiltinImplConditions::None => {} + BuiltinImplConditions::Ambiguous => { + candidates.ambiguous = true; + } + } + } + + fn assemble_const_destruct_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + // If the predicate is `~const Destruct` in a non-const environment, we don't actually need + // to check anything. We'll short-circuit checking any obligations in confirmation, too. + if !obligation.is_const() { + candidates.vec.push(ConstDestructCandidate(None)); + return; + } + + let self_ty = self.infcx().shallow_resolve(obligation.self_ty()); + match self_ty.skip_binder().kind() { + ty::Opaque(..) + | ty::Dynamic(..) + | ty::Error(_) + | ty::Bound(..) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Projection(_) => { + // We don't know if these are `~const Destruct`, at least + // not structurally... so don't push a candidate. + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Str + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Never + | ty::Foreign(_) + | ty::Array(..) + | ty::Slice(_) + | ty::Closure(..) + | ty::Generator(..) + | ty::Tuple(_) + | ty::GeneratorWitness(_) => { + // These are built-in, and cannot have a custom `impl const Destruct`. + candidates.vec.push(ConstDestructCandidate(None)); + } + + ty::Adt(..) => { + // Find a custom `impl Drop` impl, if it exists + let relevant_impl = self.tcx().find_map_relevant_impl( + self.tcx().require_lang_item(LangItem::Drop, None), + obligation.predicate.skip_binder().trait_ref.self_ty(), + Some, + ); + + if let Some(impl_def_id) = relevant_impl { + // Check that `impl Drop` is actually const, if there is a custom impl + if self.tcx().constness(impl_def_id) == hir::Constness::Const { + candidates.vec.push(ConstDestructCandidate(Some(impl_def_id))); + } + } else { + // Otherwise check the ADT like a built-in type (structurally) + candidates.vec.push(ConstDestructCandidate(None)); + } + } + + ty::Infer(_) => { + candidates.ambiguous = true; + } + } + } +} 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 000000000..2a1099fc8 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -0,0 +1,1266 @@ +//! 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_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt}; +use rustc_middle::ty::{ToPolyTraitRef, ToPredicate}; +use rustc_span::def_id::DefId; + +use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; +use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::{ + BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, + ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, + ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, + ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData, + ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation, + Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, + SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment, +}; + +use super::BuiltinImplConditions; +use super::SelectionCandidate::{self, *}; +use super::SelectionContext; + +use std::iter; +use std::ops::ControlFlow; + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + #[instrument(level = "debug", skip(self))] + pub(super) fn confirm_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + candidate: SelectionCandidate<'tcx>, + ) -> Result, SelectionError<'tcx>> { + let mut impl_src = match candidate { + BuiltinCandidate { has_nested } => { + let data = self.confirm_builtin_candidate(obligation, has_nested); + ImplSource::Builtin(data) + } + + TransmutabilityCandidate => { + let data = self.confirm_transmutability_candidate(obligation)?; + ImplSource::Builtin(data) + } + + ParamCandidate(param) => { + let obligations = + self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); + ImplSource::Param(obligations, param.skip_binder().constness) + } + + ImplCandidate(impl_def_id) => { + ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)) + } + + AutoImplCandidate(trait_def_id) => { + let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); + ImplSource::AutoImpl(data) + } + + ProjectionCandidate(idx) => { + let obligations = self.confirm_projection_candidate(obligation, idx)?; + // FIXME(jschievink): constness + ImplSource::Param(obligations, ty::BoundConstness::NotConst) + } + + ObjectCandidate(idx) => { + let data = self.confirm_object_candidate(obligation, idx)?; + ImplSource::Object(data) + } + + ClosureCandidate => { + let vtable_closure = self.confirm_closure_candidate(obligation)?; + ImplSource::Closure(vtable_closure) + } + + GeneratorCandidate => { + let vtable_generator = self.confirm_generator_candidate(obligation)?; + ImplSource::Generator(vtable_generator) + } + + FnPointerCandidate { .. } => { + let data = self.confirm_fn_pointer_candidate(obligation)?; + ImplSource::FnPointer(data) + } + + DiscriminantKindCandidate => { + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) + } + + PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData), + + TraitAliasCandidate(alias_def_id) => { + let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); + ImplSource::TraitAlias(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. + ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst) + } + + BuiltinUnsizeCandidate => { + let data = self.confirm_builtin_unsize_candidate(obligation)?; + ImplSource::Builtin(data) + } + + TraitUpcastingUnsizeCandidate(idx) => { + let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; + ImplSource::TraitUpcasting(data) + } + + ConstDestructCandidate(def_id) => { + let data = self.confirm_const_destruct_candidate(obligation, def_id)?; + ImplSource::ConstDestruct(data) + } + }; + + if !obligation.predicate.is_const_if_const() { + // normalize nested predicates according to parent predicate's constness. + impl_src = impl_src.map(|mut o| { + o.predicate = o.predicate.without_const(self.tcx()); + o + }); + } + + Ok(impl_src) + } + + fn confirm_projection_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + idx: usize, + ) -> Result>, SelectionError<'tcx>> { + let tcx = self.tcx(); + + let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); + let placeholder_trait_predicate = + self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref; + let placeholder_self_ty = placeholder_trait_predicate.self_ty(); + let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); + let (def_id, substs) = match *placeholder_self_ty.kind() { + ty::Projection(proj) => (proj.item_def_id, proj.substs), + ty::Opaque(def_id, substs) => (def_id, substs), + _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), + }; + + let candidate_predicate = + tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); + let candidate = candidate_predicate + .to_opt_poly_trait_pred() + .expect("projection candidate is not a trait predicate") + .map_bound(|t| t.trait_ref); + let mut obligations = Vec::new(); + let candidate = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + candidate, + &mut obligations, + ); + + obligations.extend(self.infcx.commit_if_ok(|_| { + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(placeholder_trait_predicate, candidate) + .map(|InferOk { obligations, .. }| obligations) + .map_err(|_| Unimplemented) + })?); + + if let ty::Projection(..) = placeholder_self_ty.kind() { + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates; + debug!(?predicates, "projection predicates"); + for predicate in predicates { + let normalized = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + predicate, + &mut obligations, + ); + obligations.push(Obligation::with_depth( + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + normalized, + )); + } + } + + Ok(obligations) + } + + fn confirm_param_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + param: ty::PolyTraitRef<'tcx>, + ) -> Vec> { + debug!(?obligation, ?param, "confirm_param_candidate"); + + // 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> { + debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); + + 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 BuiltinImplConditions::Where(nested) = conditions else { + 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!(?obligations); + + ImplSourceBuiltinData { nested: obligations } + } + + fn confirm_transmutability_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + debug!(?obligation, "confirm_transmutability_candidate"); + + let predicate = obligation.predicate; + + let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); + let bool_at = |i| { + predicate + .skip_binder() + .trait_ref + .substs + .const_at(i) + .try_eval_bool(self.tcx(), obligation.param_env) + .unwrap_or(true) + }; + + let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { + src: p.trait_ref.substs.type_at(1), + dst: p.trait_ref.substs.type_at(0), + }); + + let scope = type_at(2).skip_binder(); + + let assume = rustc_transmute::Assume { + alignment: bool_at(3), + lifetimes: bool_at(4), + validity: bool_at(5), + visibility: bool_at(6), + }; + + let cause = obligation.cause.clone(); + + let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); + + let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume); + + use rustc_transmute::Answer; + + match maybe_transmutable { + Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), + _ => Err(Unimplemented), + } + } + + /// This handles the case where an `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> { + debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate"); + + let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); + let types = 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<'tcx, Vec>>, + ) -> ImplSourceAutoImplData> { + debug!(?nested, "vtable_auto_impl"); + ensure_sufficient_stack(|| { + let cause = obligation.derived_cause(BuiltinDerivedObligation); + + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); + let trait_obligations: Vec> = self.impl_or_trait_obligations( + &cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + obligation.predicate, + ); + + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def_id, + nested, + ); + + // 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!(?obligations, "vtable_auto_impl"); + + ImplSourceAutoImplData { trait_def_id, nested: obligations } + }) + } + + fn confirm_impl_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: DefId, + ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); + + // First, create the substitutions by matching the impl again, + // this time not in a probe. + let substs = self.rematch_impl(impl_def_id, obligation); + debug!(?substs, "impl substs"); + ensure_sufficient_stack(|| { + self.vtable_impl( + impl_def_id, + substs, + &obligation.cause, + obligation.recursion_depth + 1, + obligation.param_env, + obligation.predicate, + ) + }) + } + + fn vtable_impl( + &mut self, + impl_def_id: DefId, + substs: Normalized<'tcx, SubstsRef<'tcx>>, + cause: &ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { + debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl"); + + let mut impl_obligations = self.impl_or_trait_obligations( + cause, + recursion_depth, + param_env, + impl_def_id, + &substs.value, + parent_trait_pred, + ); + + debug!(?impl_obligations, "vtable_impl"); + + // 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> Foo<::T> for V` + impl_obligations.extend(substs.obligations); + + ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations } + } + + fn confirm_object_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + index: usize, + ) -> Result>, SelectionError<'tcx>> { + let tcx = self.tcx(); + debug!(?obligation, ?index, "confirm_object_candidate"); + + let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate); + let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); + let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); + let ty::Dynamic(data, ..) = *self_ty.kind() else { + span_bug!(obligation.cause.span, "object candidate with non-object"); + }; + + let object_trait_ref = data.principal().unwrap_or_else(|| { + span_bug!(obligation.cause.span, "object candidate with no principal") + }); + let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + object_trait_ref, + ); + let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); + + let mut nested = vec![]; + + let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref)); + let unnormalized_upcast_trait_ref = + supertraits.nth(index).expect("supertraits iterator no longer has as many elements"); + + let upcast_trait_ref = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + unnormalized_upcast_trait_ref, + &mut nested, + ); + + nested.extend(self.infcx.commit_if_ok(|_| { + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation_trait_ref, upcast_trait_ref) + .map(|InferOk { obligations, .. }| obligations) + .map_err(|_| Unimplemented) + })?); + + // Check supertraits hold. This is so that their associated type bounds + // will be checked in the code below. + for super_trait in tcx + .super_predicates_of(trait_predicate.def_id()) + .instantiate(tcx, trait_predicate.trait_ref.substs) + .predicates + .into_iter() + { + let normalized_super_trait = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + super_trait, + &mut nested, + ); + nested.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + normalized_super_trait, + )); + } + + let assoc_types: Vec<_> = tcx + .associated_items(trait_predicate.def_id()) + .in_definition_order() + .filter_map( + |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None }, + ) + .collect(); + + for assoc_type in assoc_types { + let defs: &ty::Generics = tcx.generics_of(assoc_type); + + if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended { + tcx.sess.delay_span_bug( + obligation.cause.span, + "GATs in trait object shouldn't have been considered", + ); + return Err(SelectionError::Unimplemented); + } + + // This maybe belongs in wf, but that can't (doesn't) handle + // higher-ranked things. + // Prevent, e.g., `dyn Iterator`. + for bound in self.tcx().bound_item_bounds(assoc_type).transpose_iter() { + let subst_bound = + if defs.count() == 0 { + bound.subst(tcx, trait_predicate.trait_ref.substs) + } else { + let mut substs = smallvec::SmallVec::with_capacity(defs.count()); + substs.extend(trait_predicate.trait_ref.substs.iter()); + let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = + smallvec::SmallVec::with_capacity( + bound.0.kind().bound_vars().len() + defs.count(), + ); + bound_vars.extend(bound.0.kind().bound_vars().into_iter()); + InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param + .kind + { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + tcx.mk_ty(ty::Bound( + ty::INNERMOST, + ty::BoundTy { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + )) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }, + )) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + tcx.mk_const(ty::ConstS { + ty: tcx.type_of(param.def_id), + kind: ty::ConstKind::Bound( + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + ), + }) + .into() + } + }); + let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); + let assoc_ty_substs = tcx.intern_substs(&substs); + + let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); + let bound = + bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs); + tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars)) + }; + let normalized_bound = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + subst_bound, + &mut nested, + ); + nested.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + normalized_bound, + )); + } + } + + debug!(?nested, "object nested obligations"); + + let vtable_base = super::super::vtable_trait_first_method_offset( + tcx, + (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)), + ); + + Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested }) + } + + fn confirm_fn_pointer_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> + { + debug!(?obligation, "confirm_fn_pointer_candidate"); + + // 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 nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested }) + } + + fn confirm_trait_alias_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + alias_def_id: DefId, + ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> { + debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate"); + + 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, + obligation.recursion_depth, + obligation.param_env, + trait_def_id, + &substs, + obligation.predicate, + ); + + debug!(?trait_def_id, ?trait_obligations, "trait alias obligations"); + + ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations } + } + + fn confirm_generator_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, 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 ty::Generator(generator_def_id, substs, _) = *self_ty.kind() else { + bug!("closure candidate for non-closure {:?}", obligation); + }; + + debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate"); + + let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); + + let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + debug!(?trait_ref, ?nested, "generator candidate obligations"); + + Ok(ImplSourceGeneratorData { generator_def_id, substs, nested }) + } + + #[instrument(skip(self), level = "debug")] + fn confirm_closure_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + 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 ty::Closure(closure_def_id, substs) = *self_ty.kind() else { + bug!("closure candidate for non-closure {:?}", obligation); + }; + + let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); + let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + + debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); + + // FIXME: Chalk + + if !self.tcx().sess.opts.unstable_opts.chalk { + nested.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)) + .to_predicate(self.tcx()), + )); + } + + Ok(ImplSourceClosureData { closure_def_id, substs, nested }) + } + + /// 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: + /// ```ignore (illustrative) + /// 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. + #[instrument(skip(self), level = "trace")] + fn confirm_poly_trait_refs( + &mut self, + obligation: &TraitObligation<'tcx>, + expected_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + let obligation_trait_ref = obligation.predicate.to_poly_trait_ref(); + // Normalize the obligation and expected trait refs together, because why not + let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } = + ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + (obligation_trait_ref, expected_trait_ref), + ) + }); + + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation_trait_ref, expected_trait_ref) + .map(|InferOk { mut obligations, .. }| { + obligations.extend(nested); + obligations + }) + .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } + + fn confirm_trait_upcasting_unsize_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + idx: usize, + ) -> Result>, 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!(?source, ?target, "confirm_trait_upcasting_unsize_candidate"); + + let mut nested = vec![]; + let source_trait_ref; + let upcast_trait_ref; + match (source.kind(), target.kind()) { + // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion). + (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + // See `assemble_candidates_for_unsizing` for more info. + // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. + let principal_a = data_a.principal().unwrap(); + source_trait_ref = principal_a.with_self_ty(tcx, source); + upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap(); + assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id())); + let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty( + tcx, trait_ref, + )) + }); + let iter = Some(existential_predicate) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ); + let existential_predicates = tcx.mk_poly_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(source, target), + ); + let outlives = ty::OutlivesPredicate(r_a, r_b); + nested.push(Obligation::with_depth( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + obligation.predicate.rebind(outlives).to_predicate(tcx), + )); + } + _ => bug!(), + }; + + let vtable_segment_callback = { + let mut vptr_offset = 0; + move |segment| { + match segment { + VtblSegment::MetadataDSA => { + vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + } + VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + vptr_offset += util::count_own_vtable_entries(tcx, trait_ref); + if trait_ref == upcast_trait_ref { + if emit_vptr { + return ControlFlow::Break(Some(vptr_offset)); + } else { + return ControlFlow::Break(None); + } + } + + if emit_vptr { + vptr_offset += 1; + } + } + } + ControlFlow::Continue(()) + } + }; + + let vtable_vptr_slot = + super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback) + .unwrap(); + + Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested }) + } + + fn confirm_builtin_unsize_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, 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!(?source, ?target, "confirm_builtin_unsize_candidate"); + + let mut nested = vec![]; + match (source.kind(), target.kind()) { + // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). + (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + // See `assemble_candidates_for_unsizing` for more info. + // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. + let iter = data_a + .principal() + .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ); + let existential_predicates = tcx.mk_poly_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(source, target), + ); + let outlives = ty::OutlivesPredicate(r_a, r_b); + nested.push(Obligation::with_depth( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + obligation.predicate.rebind(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(source, 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::Binder::dummy(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` -> `Struct` + (&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.kind() { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, + }; + + // 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. + + // 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.bound_type_of(tail_field.did); + + let mut unsizing_params = GrowableBitSet::new_empty(); + for arg in tail_field_ty.0.walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); + } + } + + // Ensure none of the other fields mention the parameters used + // in unsizing. + for field in prefix_fields { + for arg in tcx.type_of(field.did).walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.remove(i); + } + } + } + + if unsizing_params.is_empty() { + return Err(Unimplemented); + } + + // Extract `TailField` and `TailField` from `Struct` and `Struct`. + 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: Unsize>` 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().copied().chain(iter::once(b_last))); + 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` 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, + &[b_last.into()], + ) + })); + } + + _ => bug!(), + }; + + Ok(ImplSourceBuiltinData { nested }) + } + + fn confirm_const_destruct_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: Option, + ) -> Result>, SelectionError<'tcx>> { + // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` + if !obligation.is_const() { + return Ok(ImplSourceConstDestructData { nested: vec![] }); + } + + let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None); + + let tcx = self.tcx(); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + + let mut nested = vec![]; + let cause = obligation.derived_cause(BuiltinDerivedObligation); + + // If we have a custom `impl const Drop`, then + // first check it like a regular impl candidate. + // This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand. + if let Some(impl_def_id) = impl_def_id { + let mut new_obligation = obligation.clone(); + new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| { + trait_pred.trait_ref.def_id = drop_trait; + trait_pred + }); + let substs = self.rematch_impl(impl_def_id, &new_obligation); + debug!(?substs, "impl substs"); + + let cause = obligation.derived_cause(|derived| { + ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + derived, + impl_def_id, + span: obligation.cause.span, + })) + }); + let obligations = ensure_sufficient_stack(|| { + self.vtable_impl( + impl_def_id, + substs, + &cause, + new_obligation.recursion_depth + 1, + new_obligation.param_env, + obligation.predicate, + ) + }); + nested.extend(obligations.nested); + } + + // We want to confirm the ADT's fields if we have an ADT + let mut stack = match *self_ty.skip_binder().kind() { + ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(), + _ => vec![self_ty.skip_binder()], + }; + + while let Some(nested_ty) = stack.pop() { + match *nested_ty.kind() { + // We know these types are trivially drop + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Str + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Never + | ty::Foreign(_) => {} + + // These types are built-in, so we can fast-track by registering + // nested predicates for their constituent type(s) + ty::Array(ty, _) | ty::Slice(ty) => { + stack.push(ty); + } + ty::Tuple(tys) => { + stack.extend(tys.iter()); + } + ty::Closure(_, substs) => { + stack.push(substs.as_closure().tupled_upvars_ty()); + } + ty::Generator(_, substs, _) => { + let generator = substs.as_generator(); + stack.extend([generator.tupled_upvars_ty(), generator.witness()]); + } + ty::GeneratorWitness(tys) => { + stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); + } + + // If we have a projection type, make sure to normalize it so we replace it + // with a fresh infer variable + ty::Projection(..) => { + let predicate = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + self_ty + .rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(LangItem::Destruct, None), + substs: self.tcx().mk_substs_trait(nested_ty, &[]), + }, + constness: ty::BoundConstness::ConstIfConst, + polarity: ty::ImplPolarity::Positive, + }) + .to_predicate(tcx), + &mut nested, + ); + + nested.push(Obligation::with_depth( + cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate, + )); + } + + // If we have any other type (e.g. an ADT), just register a nested obligation + // since it's either not `const Drop` (and we raise an error during selection), + // or it's an ADT (and we need to check for a custom impl during selection) + _ => { + let predicate = self_ty + .rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(LangItem::Destruct, None), + substs: self.tcx().mk_substs_trait(nested_ty, &[]), + }, + constness: ty::BoundConstness::ConstIfConst, + polarity: ty::ImplPolarity::Positive, + }) + .to_predicate(tcx); + + nested.push(Obligation::with_depth( + cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate, + )); + } + } + } + + Ok(ImplSourceConstDestructData { 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 000000000..c01ac1979 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -0,0 +1,2698 @@ +//! 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::const_evaluatable; +use super::project; +use super::project::normalize_with_depth_to; +use super::project::ProjectionTyObligation; +use super::util; +use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::wf; +use super::{ + ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, + ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError, + SelectionResult, TraitObligation, TraitQueryMode, +}; + +use crate::infer::{InferCtxt, InferOk, TypeFreshener}; +use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::ProjectAndUnifyResult; +use crate::traits::project::ProjectionCacheKeyExt; +use crate::traits::ProjectionCacheKey; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::relate::TypeRelation; +use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; +use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_span::symbol::sym; + +use std::cell::{Cell, RefCell}; +use std::cmp; +use std::fmt::{self, Display}; +use std::iter; + +pub use rustc_middle::traits::select::*; + +mod candidate_assembly; +mod confirmation; + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum IntercrateAmbiguityCause { + DownstreamCrate { trait_desc: String, self_desc: Option }, + UpstreamCrateUpdate { trait_desc: String, self_desc: Option }, + ReservationImpl { message: String }, +} + +impl IntercrateAmbiguityCause { + /// Emits notes when the overlap is caused by complex intercrate ambiguities. + /// See #23980 for details. + pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) { + err.note(&self.intercrate_ambiguity_hint()); + } + + pub fn intercrate_ambiguity_hint(&self) -> String { + match self { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => { + let self_desc = if let Some(ty) = self_desc { + format!(" for type `{}`", ty) + } else { + String::new() + }; + format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) + } + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => { + let self_desc = if let Some(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 { 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>, + + /// During coherence we have to assume that other crates may add + /// additional impls which we currently don't know about. + /// + /// To deal with this evaluation should be conservative + /// and consider the possibility of impls from 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`. + /// + /// Outside of coherence 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, + /// If `intercrate` is set, we remember predicates which were + /// considered ambiguous because of impls potentially added in other crates. + /// This is used in coherence to give improved diagnostics. + /// We don't do his until we detect a coherence error because it can + /// lead to false overflow results (#47139) and because always + /// computing it may negatively impact performance. + intercrate_ambiguity_causes: Option>, + + /// 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 predicate from `obligation` but "freshened" with the + /// selection-context's freshener. Used to check for recursion. + fresh_trait_pred: ty::PolyTraitPredicate<'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, + + 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>, + + // 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? +#[derive(Debug)] +enum BuiltinImplConditions<'tcx> { + /// The impl is conditional on `T1, T2, ...: Trait`. + Where(ty::Binder<'tcx, Vec>>), + /// 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_keep_static(), + intercrate: false, + intercrate_ambiguity_causes: None, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx, + freshener: infcx.freshener_keep_static(), + intercrate: true, + intercrate_ambiguity_causes: None, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_query_mode( + infcx: &'cx InferCtxt<'cx, 'tcx>, + query_mode: TraitQueryMode, + ) -> SelectionContext<'cx, 'tcx> { + debug!(?query_mode, "with_query_mode"); + SelectionContext { + infcx, + freshener: infcx.freshener_keep_static(), + intercrate: false, + intercrate_ambiguity_causes: None, + query_mode, + } + } + + /// Enables tracking of intercrate ambiguity causes. See + /// the documentation of [`Self::intercrate_ambiguity_causes`] for more. + pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { + assert!(self.intercrate); + assert!(self.intercrate_ambiguity_causes.is_none()); + self.intercrate_ambiguity_causes = Some(FxIndexSet::default()); + 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) -> FxIndexSet { + assert!(self.intercrate); + self.intercrate_ambiguity_causes.take().unwrap_or_default() + } + + pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + pub fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + pub fn is_intercrate(&self) -> bool { + self.intercrate + } + + /////////////////////////////////////////////////////////////////////////// + // 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: Iterable`, but the impl specifies + // `impl Iterable for Vec`, than an error would result. + + /// Attempts to satisfy the obligation. If successful, this will affect the surrounding + /// type environment by performing unification. + #[instrument(level = "debug", skip(self))] + pub fn select( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, Selection<'tcx>> { + let candidate = match self.select_from_obligation(obligation) { + Err(SelectionError::Overflow(OverflowError::Canonical)) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow(OverflowError::Canonical)); + } + Err(SelectionError::Ambiguous(_)) => { + return Ok(None); + } + Err(e) => { + return Err(e); + } + Ok(None) => { + return Ok(None); + } + Ok(Some(candidate)) => candidate, + }; + + match self.confirm_candidate(obligation, candidate) { + Err(SelectionError::Overflow(OverflowError::Canonical)) => { + assert!(self.query_mode == TraitQueryMode::Canonical); + Err(SelectionError::Overflow(OverflowError::Canonical)) + } + Err(e) => Err(e), + Ok(candidate) => { + debug!(?candidate, "confirmed"); + Ok(Some(candidate)) + } + } + } + + pub(crate) fn select_from_obligation( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + debug_assert!(!obligation.predicate.has_escaping_bound_vars()); + + let pec = &ProvisionalEvaluationCache::default(); + let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation); + + self.candidate_from_obligation(&stack) + } + + /////////////////////////////////////////////////////////////////////////// + // 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!(?obligation, "predicate_may_hold_fatal"); + + // 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 { + 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, + ) -> Result { + self.infcx.probe(|snapshot| -> Result { + let result = op(self)?; + + match self.infcx.leak_check(true, snapshot) { + Ok(()) => {} + Err(_) => return Ok(EvaluatedToErr), + } + + if self.infcx.opaque_types_added_in_snapshot(snapshot) { + return Ok(result.max(EvaluatedToOkModuloOpaqueTypes)); + } + + 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. + #[instrument(skip(self, stack), level = "debug")] + fn evaluate_predicates_recursively<'o, I>( + &mut self, + stack: TraitObligationStackList<'o, 'tcx>, + predicates: I, + ) -> Result + where + I: IntoIterator> + std::fmt::Debug, + { + let mut result = EvaluatedToOk; + for obligation in predicates { + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + 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) + } + + #[instrument( + level = "debug", + skip(self, previous_stack), + fields(previous_stack = ?previous_stack.head()) + )] + fn evaluate_predicate_recursively<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) -> Result { + // `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)?, + } + + let result = ensure_sufficient_stack(|| { + let bound_predicate = obligation.predicate.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(t) => { + let t = bound_predicate.rebind(t); + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(t); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } + + ty::PredicateKind::Subtype(p) => { + let p = bound_predicate.rebind(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::PredicateKind::Coerce(p) => { + let p = bound_predicate.rebind(p); + // Does this code ever run? + match self.infcx.coerce_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::PredicateKind::WellFormed(arg) => { + // So, there is a bit going on here. First, `WellFormed` predicates + // are coinductive, like trait predicates with auto traits. + // This means that we need to detect if we have recursively + // evaluated `WellFormed(X)`. Otherwise, we would run into + // a "natural" overflow error. + // + // Now, the next question is whether we need to do anything + // special with caching. Considering the following tree: + // - `WF(Foo)` + // - `Bar: Send` + // - `WF(Foo)` + // - `Foo: Trait` + // In this case, the innermost `WF(Foo)` should return + // `EvaluatedToOk`, since it's coinductive. Then if + // `Bar: Send` is resolved to `EvaluatedToOk`, it can be + // inserted into a cache (because without thinking about `WF` + // goals, it isn't in a cycle). If `Foo: Trait` later doesn't + // hold, then `Bar: Send` shouldn't hold. Therefore, we + // *do* need to keep track of coinductive cycles. + + let cache = previous_stack.cache; + let dfn = cache.next_dfn(); + + for stack_arg in previous_stack.cache.wf_args.borrow().iter().rev() { + if stack_arg.0 != arg { + continue; + } + debug!("WellFormed({:?}) on stack", arg); + if let Some(stack) = previous_stack.head { + // Okay, let's imagine we have two different stacks: + // `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait` + // `WF(T) -> T: NonAutoTrait -> WF(T)` + // Because of this, we need to check that all + // predicates between the WF goals are coinductive. + // Otherwise, we can say that `T: NonAutoTrait` is + // true. + // Let's imagine we have a predicate stack like + // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto + // depth ^1 ^2 ^3 + // and the current predicate is `WF(T)`. `wf_args` + // would contain `(T, 1)`. We want to check all + // trait predicates greater than `1`. The previous + // stack would be `T: Auto`. + let cycle = stack.iter().take_while(|s| s.depth > stack_arg.1); + let tcx = self.tcx(); + let cycle = + cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx)); + if self.coinductive_match(cycle) { + stack.update_reached_depth(stack_arg.1); + return Ok(EvaluatedToOk); + } else { + return Ok(EvaluatedToRecur); + } + } + return Ok(EvaluatedToOk); + } + + match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + obligation.recursion_depth + 1, + arg, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + + cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); + let result = + self.evaluate_predicates_recursively(previous_stack, obligations); + cache.wf_args.borrow_mut().pop(); + + let result = result?; + + if !result.must_apply_modulo_regions() { + cache.on_failure(dfn); + } + + cache.on_completion(dfn); + + Ok(result) + } + None => Ok(EvaluatedToAmbig), + } + } + + ty::PredicateKind::TypeOutlives(pred) => { + // A global type with no late-bound regions can only + // contain the "'static" lifetime (any other lifetime + // would either be late-bound or local), so it is guaranteed + // to outlive any other lifetime + if pred.0.is_global() && !pred.0.has_late_bound_regions() { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToOkModuloRegions) + } + } + + ty::PredicateKind::RegionOutlives(..) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) + } + + ty::PredicateKind::ObjectSafe(trait_def_id) => { + if self.tcx().is_object_safe(trait_def_id) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } + } + + ty::PredicateKind::Projection(data) => { + let data = bound_predicate.rebind(data); + let project_obligation = obligation.with(data); + match project::poly_project_and_unify_type(self, &project_obligation) { + ProjectAndUnifyResult::Holds(mut subobligations) => { + 'compute_res: { + // If we've previously marked this projection as 'complete', then + // use the final cached result (either `EvaluatedToOk` or + // `EvaluatedToOkModuloRegions`), and skip re-evaluating the + // sub-obligations. + if let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate(self, data) + { + if let Some(cached_res) = self + .infcx + .inner + .borrow_mut() + .projection_cache() + .is_complete(key) + { + break 'compute_res Ok(cached_res); + } + } + + self.add_depth( + subobligations.iter_mut(), + obligation.recursion_depth, + ); + let res = self.evaluate_predicates_recursively( + previous_stack, + subobligations, + ); + if let Ok(eval_rslt) = res + && (eval_rslt == EvaluatedToOk || eval_rslt == EvaluatedToOkModuloRegions) + && let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate( + self, data, + ) + { + // If the result is something that we can cache, then mark this + // entry as 'complete'. This will allow us to skip evaluating the + // subobligations at all the next time we evaluate the projection + // predicate. + self.infcx + .inner + .borrow_mut() + .projection_cache() + .complete(key, eval_rslt); + } + res + } + } + ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), + ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur), + ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), + } + } + + ty::PredicateKind::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::PredicateKind::ConstEvaluatable(uv) => { + match const_evaluatable::is_const_evaluatable( + self.infcx, + uv, + obligation.param_env, + obligation.cause.span, + ) { + Ok(()) => Ok(EvaluatedToOk), + Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig), + Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr), + Err(_) => Ok(EvaluatedToErr), + } + } + + ty::PredicateKind::ConstEquate(c1, c2) => { + debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts"); + + if self.tcx().features().generic_const_exprs { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = + (c1.kind(), c2.kind()) + { + if self.infcx.try_unify_abstract_consts( + a.shrink(), + b.shrink(), + obligation.param_env, + ) { + return Ok(EvaluatedToOk); + } + } + } + + let evaluate = |c: ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { + match self.infcx.try_const_eval_resolve( + obligation.param_env, + unevaluated, + c.ty(), + Some(obligation.cause.span), + ) { + Ok(val) => Ok(val), + Err(e) => Err(e), + } + } 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(_)), _) + | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { + span_bug!( + obligation.cause.span(), + "ConstEquate: const_eval_resolve returned an unexpected error" + ) + } + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() { + Ok(EvaluatedToAmbig) + } else { + // Two different constants using generic parameters ~> error. + Ok(EvaluatedToErr) + } + } + } + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for chalk") + } + } + }); + + debug!("finished: {:?} from {:?}", result, obligation); + + result + } + + #[instrument(skip(self, previous_stack), level = "debug")] + fn evaluate_trait_predicate_recursively<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + mut obligation: TraitObligation<'tcx>, + ) -> Result { + 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!("in global"); + obligation.param_env = obligation.param_env.without_caller_bounds(); + } + + let stack = self.push_stack(previous_stack, &obligation); + let mut fresh_trait_pred = stack.fresh_trait_pred; + let mut param_env = obligation.param_env; + + fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { + pred.remap_constness(&mut param_env); + pred + }); + + debug!(?fresh_trait_pred); + + // If a trait predicate is in the (local or global) evaluation cache, + // then we know it holds without cycles. + if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { + debug!(?result, "CACHE HIT"); + return Ok(result); + } + + if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) { + debug!(?result, "PROVISIONAL CACHE HIT"); + stack.update_reached_depth(result.reached_depth); + return Ok(result.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!(?result, "CACHE MISS"); + self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); + stack.cache().on_completion(stack.dfn); + } else { + debug!(?result, "PROVISIONAL"); + debug!( + "caching provisionally because {:?} \ + is a cycle participant (at depth {}, reached depth {})", + fresh_trait_pred, stack.depth, reached_depth, + ); + + stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, 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 { data: T, next: Option>> } + /// + /// `Box>` will be `Send` if `T` is `Send` and + /// `Option>>` is `Send`, and in turn + /// `Option>>` is `Send` if `Box>` 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 { + 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_pred == prev.fresh_trait_pred + }) + .map(|stack| stack.depth) + { + debug!("evaluate_stack --> recursive at depth {}", 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.to_predicate(tcx)); + if self.coinductive_match(cycle) { + debug!("evaluate_stack --> recursive, coinductive"); + Some(EvaluatedToOk) + } else { + debug!("evaluate_stack --> recursive, inductive"); + Some(EvaluatedToRecur) + } + } else { + None + } + } + + fn evaluate_stack<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> Result { + // 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 Eq for Vec + // + // 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_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh()); + + if stack.obligation.polarity() != ty::ImplPolarity::Negative { + // 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",); + // 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 = with_no_trimmed_paths!({ + 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!(?cause, "evaluate_stack: pushing cause"); + self.intercrate_ambiguity_causes.as_mut().unwrap().insert(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_pred, + prev.fresh_trait_pred, + prev.obligation.param_env, + ) + }) + { + debug!("evaluate_stack --> unbound argument, recursive --> giving up",); + return Ok(EvaluatedToUnknown); + } + + match self.candidate_from_obligation(stack) { + Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig), + Ok(None) => Ok(EvaluatedToAmbig), + Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), + Err(ErrorReporting) => Err(OverflowError::ErrorReporting), + 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(crate) fn coinductive_match(&mut self, mut cycle: I) -> bool + where + I: Iterator>, + { + cycle.all(|predicate| self.coinductive_predicate(predicate)) + } + + fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { + let result = match predicate.kind().skip_binder() { + ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()), + ty::PredicateKind::WellFormed(_) => true, + _ => false, + }; + debug!(?predicate, ?result, "coinductive_predicate"); + 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. + #[instrument( + level = "debug", + skip(self, stack), + fields(depth = stack.obligation.recursion_depth) + )] + fn evaluate_candidate<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidate: &SelectionCandidate<'tcx>, + ) -> Result { + let mut result = self.evaluation_probe(|this| { + let candidate = (*candidate).clone(); + match this.confirm_candidate(stack.obligation, candidate) { + Ok(selection) => { + debug!(?selection); + this.evaluate_predicates_recursively( + stack.list(), + selection.nested_obligations().into_iter(), + ) + } + Err(..) => Ok(EvaluatedToErr), + } + })?; + + // If we erased any lifetimes, then we want to use + // `EvaluatedToOkModuloRegions` instead of `EvaluatedToOk` + // as your final result. The result will be cached using + // the freshened trait predicate as a key, so we need + // our result to be correct by *any* choice of original lifetimes, + // not just the lifetime choice for this particular (non-erased) + // predicate. + // See issue #80691 + if stack.fresh_trait_pred.has_erased_regions() { + result = result.max(EvaluatedToOkModuloRegions); + } + + debug!(?result); + Ok(result) + } + + fn check_evaluation_cache( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Option { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return None; + } + + let tcx = self.tcx(); + if self.can_use_global_caches(param_env) { + if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) { + return Some(res); + } + } + self.infcx.evaluation_cache.get(&(param_env, trait_pred), tcx) + } + + fn insert_evaluation_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + trait_pred: ty::PolyTraitPredicate<'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; + } + + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return; + } + + if self.can_use_global_caches(param_env) { + if !trait_pred.needs_infer() { + debug!(?trait_pred, ?result, "insert_evaluation_cache global"); + // 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, trait_pred), dep_node, result); + return; + } + } + + debug!(?trait_pred, ?result, "insert_evaluation_cache"); + self.infcx.evaluation_cache.insert((param_env, trait_pred), 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 `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 decreases, we force all subobligations + /// to have at least the depth of the original obligation. + fn add_depth>>( + &self, + it: I, + min_depth: usize, + ) { + it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); + } + + fn check_recursion_depth>( + &self, + depth: usize, + error_obligation: &Obligation<'tcx, T>, + ) -> Result<(), OverflowError> { + if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { + match self.query_mode { + TraitQueryMode::Standard => { + if self.infcx.is_tainted_by_errors() { + return Err(OverflowError::Error( + ErrorGuaranteed::unchecked_claim_error_was_emitted(), + )); + } + self.infcx.report_overflow_error(error_obligation, true); + } + TraitQueryMode::Canonical => { + return Err(OverflowError::Canonical); + } + } + } + Ok(()) + } + + /// 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. + #[inline(always)] + fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( + &self, + obligation: &Obligation<'tcx, T>, + error_obligation: &Obligation<'tcx, V>, + ) -> Result<(), OverflowError> { + self.check_recursion_depth(obligation.recursion_depth, error_obligation) + } + + fn in_task(&mut self, op: OP) -> (R, DepNodeIndex) + where + OP: FnOnce(&mut Self) -> R, + { + let (result, dep_node) = + self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.read_index(dep_node); + (result, dep_node) + } + + /// filter_impls filters constant trait obligations and candidates that have a positive impl + /// for a negative goal and a negative impl for a positive goal + #[instrument(level = "debug", skip(self))] + fn filter_impls( + &mut self, + candidates: Vec>, + obligation: &TraitObligation<'tcx>, + ) -> Vec> { + let tcx = self.tcx(); + let mut result = Vec::with_capacity(candidates.len()); + + for candidate in candidates { + // Respect const trait obligations + if obligation.is_const() { + match candidate { + // const impl + ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {} + // const param + ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {} + // auto trait impl + AutoImplCandidate(..) => {} + // generator, this will raise error in other places + // or ignore error with const_async_blocks feature + GeneratorCandidate => {} + // FnDef where the function is const + FnPointerCandidate { is_const: true } => {} + ConstDestructCandidate(_) => {} + _ => { + // reject all other types of candidates + continue; + } + } + } + + if let ImplCandidate(def_id) = candidate { + if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id) + || obligation.polarity() == tcx.impl_polarity(def_id) + { + result.push(candidate); + } + } else { + result.push(candidate); + } + } + + result + } + + /// filter_reservation_impls filter reservation impl for any goal as ambiguous + #[instrument(level = "debug", skip(self))] + fn filter_reservation_impls( + &mut self, + candidate: SelectionCandidate<'tcx>, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + let tcx = self.tcx(); + // Treat reservation impls as ambiguity. + if let ImplCandidate(def_id) = candidate { + if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) { + if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes { + let value = tcx + .get_attr(def_id, sym::rustc_reservation_impl) + .and_then(|a| a.value_str()); + if let Some(value) = value { + debug!( + "filter_reservation_impls: \ + reservation impl ambiguity on {:?}", + def_id + ); + intercrate_ambiguity_clauses.insert( + IntercrateAmbiguityCause::ReservationImpl { + message: value.to_string(), + }, + ); + } + } + return Ok(None); + } + } + Ok(Some(candidate)) + } + + fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { + debug!("is_knowable(intercrate={:?})", self.intercrate); + + if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative { + 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. + 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, + mut param_env: ty::ParamEnv<'tcx>, + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Option>> { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return None; + } + let tcx = self.tcx(); + let mut pred = cache_fresh_trait_pred.skip_binder(); + pred.remap_constness(&mut param_env); + + if self.can_use_global_caches(param_env) { + if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) { + return Some(res); + } + } + self.infcx.selection_cache.get(&(param_env, pred), 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 { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return false; + } + match result { + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), + _ => true, + } + } + + #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")] + fn insert_candidate_cache( + &mut self, + mut 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 mut pred = cache_fresh_trait_pred.skip_binder(); + + pred.remap_constness(&mut param_env); + + if !self.can_cache_candidate(&candidate) { + debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); + return; + } + + if self.can_use_global_caches(param_env) { + if let Err(Overflow(OverflowError::Canonical)) = candidate { + // Don't cache overflow globally; we only produce this in certain modes. + } else if !pred.needs_infer() { + if !candidate.needs_infer() { + debug!(?pred, ?candidate, "insert_candidate_cache global"); + // This may overwrite the cache with the same value. + tcx.selection_cache.insert((param_env, pred), dep_node, candidate); + return; + } + } + } + + debug!(?pred, ?candidate, "insert_candidate_cache local"); + self.infcx.selection_cache.insert((param_env, pred), dep_node, candidate); + } + + /// Matches a predicate against the bounds of its self type. + /// + /// Given an obligation like `::Bar: Baz` where the self type is + /// a projection, look at the bounds of `T::Bar`, see if we can find a + /// `Baz` bound. We return indexes into the list returned by + /// `tcx.item_bounds` for any applicable bounds. + #[instrument(level = "debug", skip(self))] + fn match_projection_obligation_against_definition_bounds( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> smallvec::SmallVec<[usize; 2]> { + 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!(?placeholder_trait_predicate); + + let tcx = self.infcx.tcx; + let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { + ty::Projection(ref data) => (data.item_def_id, data.substs), + ty::Opaque(def_id, substs) => (def_id, 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 bounds = tcx.bound_item_bounds(def_id).subst(tcx, substs); + + // The bounds returned by `item_bounds` may contain duplicates after + // normalization, so try to deduplicate when possible to avoid + // unnecessary ambiguity. + let mut distinct_normalized_bounds = FxHashSet::default(); + + let matching_bounds = bounds + .iter() + .enumerate() + .filter_map(|(idx, bound)| { + let bound_predicate = bound.kind(); + if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() { + let bound = bound_predicate.rebind(pred.trait_ref); + if self.infcx.probe(|_| { + match self.match_normalize_trait_ref( + obligation, + bound, + placeholder_trait_predicate.trait_ref, + ) { + Ok(None) => true, + Ok(Some(normalized_trait)) + if distinct_normalized_bounds.insert(normalized_trait) => + { + true + } + _ => false, + } + }) { + return Some(idx); + } + } + None + }) + .collect(); + + debug!(?matching_bounds); + matching_bounds + } + + /// Equates the trait in `obligation` with trait bound. If the two traits + /// can be equated and the normalized trait bound doesn't contain inference + /// variables or placeholders, the normalized bound is returned. + fn match_normalize_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_bound: ty::PolyTraitRef<'tcx>, + placeholder_trait_ref: ty::TraitRef<'tcx>, + ) -> Result>, ()> { + debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); + if placeholder_trait_ref.def_id != trait_bound.def_id() { + // Avoid unnecessary normalization + return Err(()); + } + + let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_bound, + ) + }); + self.infcx + .at(&obligation.cause, obligation.param_env) + .define_opaque_types(false) + .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) + .map(|InferOk { obligations: _, value: () }| { + // This method is called within a probe, so we can't have + // inference variables and placeholders escape. + if !trait_bound.needs_infer() && !trait_bound.has_placeholders() { + Some(trait_bound) + } else { + None + } + }) + .map_err(|_| ()) + } + + fn where_clause_may_apply<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result { + 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), + Err(()) => Ok(EvaluatedToErr), + } + }) + } + + /// Return `Yes` if the obligation's predicate type applies to the env_predicate, and + /// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT, + /// and applying this env_predicate constrains any of the obligation's GAT substitutions. + /// + /// This behavior is a somewhat of a hack to prevent over-constraining inference variables + /// in cases like #91762. + pub(super) fn match_projection_projections( + &mut self, + obligation: &ProjectionTyObligation<'tcx>, + env_predicate: PolyProjectionPredicate<'tcx>, + potentially_unnormalized_candidates: bool, + ) -> ProjectionMatchesProjection { + let mut nested_obligations = Vec::new(); + let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + LateBoundRegionConversionTime::HigherRankedType, + env_predicate, + ); + let infer_projection = if potentially_unnormalized_candidates { + ensure_sufficient_stack(|| { + project::normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + infer_predicate.projection_ty, + &mut nested_obligations, + ) + }) + } else { + infer_predicate.projection_ty + }; + + let is_match = self + .infcx + .at(&obligation.cause, obligation.param_env) + .define_opaque_types(false) + .sup(obligation.predicate, infer_projection) + .map_or(false, |InferOk { obligations, value: () }| { + self.evaluate_predicates_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + nested_obligations.into_iter().chain(obligations), + ) + .map_or(false, |res| res.may_apply()) + }); + + if is_match { + let generics = self.tcx().generics_of(obligation.predicate.item_def_id); + // FIXME(generic-associated-types): Addresses aggressive inference in #92917. + // If this type is a GAT, and of the GAT substs resolve to something new, + // that means that we must have newly inferred something about the GAT. + // We should give up in that case. + if !generics.params.is_empty() + && obligation.predicate.substs[generics.parent_count..] + .iter() + .any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p) + { + ProjectionMatchesProjection::Ambiguous + } else { + ProjectionMatchesProjection::Yes + } + } else { + ProjectionMatchesProjection::No + } + } + + /////////////////////////////////////////////////////////////////////////// + // 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::PolyTraitPredicate<'tcx>| { + cand.is_global() && !cand.has_late_bound_regions() + }; + + // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, + // `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else. + // + // This is a fix for #53123 and prevents winnowing from accidentally extending the + // lifetime of a variable. + match (&other.candidate, &victim.candidate) { + (_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates" + ); + } + + // FIXME(@jswrenn): this should probably be more sophisticated + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + + // (*) + ( + BuiltinCandidate { has_nested: false } + | DiscriminantKindCandidate + | PointeeCandidate + | ConstDestructCandidate(_), + _, + ) => true, + ( + _, + BuiltinCandidate { has_nested: false } + | DiscriminantKindCandidate + | PointeeCandidate + | ConstDestructCandidate(_), + ) => false, + + (ParamCandidate(other), ParamCandidate(victim)) => { + let same_except_bound_vars = other.skip_binder().trait_ref + == victim.skip_binder().trait_ref + && other.skip_binder().constness == victim.skip_binder().constness + && other.skip_binder().polarity == victim.skip_binder().polarity + && !other.skip_binder().trait_ref.has_escaping_bound_vars(); + if same_except_bound_vars { + // See issue #84398. In short, we can generate multiple ParamCandidates which are + // the same except for unused bound vars. Just pick the one with the fewest bound vars + // or the current one if tied (they should both evaluate to the same answer). This is + // probably best characterized as a "hack", since we might prefer to just do our + // best to *not* create essentially duplicate candidates in the first place. + other.bound_vars().len() <= victim.bound_vars().len() + } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref + && victim.skip_binder().constness == ty::BoundConstness::NotConst + && other.skip_binder().polarity == victim.skip_binder().polarity + { + // Drop otherwise equivalent non-const candidates in favor of const candidates. + true + } else { + false + } + } + + // Drop otherwise equivalent non-const fn pointer candidates + (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true, + + // 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. + // Arbitrarily give param candidates priority + // over projection and object candidates. + ( + ParamCandidate(ref cand), + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate { .. } + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | TraitUpcastingUnsizeCandidate(_) + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) + | ObjectCandidate(_) + | ProjectionCandidate(_), + ) => !is_global(cand), + (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => { + // Prefer these to a global where-clause bound + // (see issue #50825). + is_global(cand) + } + ( + ImplCandidate(_) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate { .. } + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | TraitUpcastingUnsizeCandidate(_) + | BuiltinCandidate { has_nested: true } + | TraitAliasCandidate(..), + ParamCandidate(ref cand), + ) => { + // Prefer these to a global where-clause bound + // (see issue #50825). + is_global(cand) && other.evaluation.must_apply_modulo_regions() + } + + (ProjectionCandidate(i), ProjectionCandidate(j)) + | (ObjectCandidate(i), ObjectCandidate(j)) => { + // Arbitrarily pick the lower numbered candidate for backwards + // compatibility reasons. Don't let this affect inference. + i < j && !needs_infer + } + (ObjectCandidate(_), ProjectionCandidate(_)) + | (ProjectionCandidate(_), ObjectCandidate(_)) => { + bug!("Have both object and projection candidate") + } + + // Arbitrarily give projection and object candidates priority. + ( + ObjectCandidate(_) | ProjectionCandidate(_), + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate { .. } + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | TraitUpcastingUnsizeCandidate(_) + | BuiltinCandidate { .. } + | TraitAliasCandidate(..), + ) => true, + + ( + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate { .. } + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | TraitUpcastingUnsizeCandidate(_) + | BuiltinCandidate { .. } + | TraitAliasCandidate(..), + ObjectCandidate(_) | ProjectionCandidate(_), + ) => false, + + (&ImplCandidate(other_def), &ImplCandidate(victim_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`. + // + // FIXME(@lcnr): Using `modulo_regions` here seems kind of scary + // to me but is required for `std` to compile, so I didn't change it + // for now. + let tcx = self.tcx(); + if other.evaluation.must_apply_modulo_regions() { + if tcx.specializes((other_def, victim_def)) { + return true; + } + } + + if other.evaluation.must_apply_considering_regions() { + 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 + // constraining 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 constrain) + // 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, + } + } else { + false + } + } + + // Everything else is ambiguous + ( + ImplCandidate(_) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate { .. } + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | TraitUpcastingUnsizeCandidate(_) + | BuiltinCandidate { has_nested: true } + | TraitAliasCandidate(..), + ImplCandidate(_) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate { .. } + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | TraitUpcastingUnsizeCandidate(_) + | BuiltinCandidate { has_nested: true } + | TraitAliasCandidate(..), + ) => 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( + obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])), + ), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(self.tcx()); + // (*) binder moved here + Where(obligation.predicate.rebind({ + sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*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) + | ty::Array(..) => { + // Implementations provided in libcore + None + } + + ty::Dynamic(..) + | ty::Str + | ty::Slice(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Foreign(..) + | ty::Ref(_, _, hir::Mutability::Mut) => None, + + ty::Tuple(tys) => { + // (*) binder moved here + Where(obligation.predicate.rebind(tys.iter().collect())) + } + + ty::Closure(_, substs) => { + // (*) binder moved here + let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + if let ty::Infer(ty::TyVar(_)) = ty.kind() { + // Not yet resolved. + Ambiguous + } else { + Where(obligation.predicate.rebind(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: + /// + /// ```ignore (illustrative) + /// (i32, u32) -> [i32, u32] + /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] + /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] + /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] + /// ``` + fn constituent_types_for_ty( + &self, + t: ty::Binder<'tcx, Ty<'tcx>>, + ) -> ty::Binder<'tcx, Vec>> { + match *t.skip_binder().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 => ty::Binder::dummy(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, _) => { + t.rebind(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + t.rebind(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => { + let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + t.rebind(vec![ty]) + } + + ty::Generator(_, ref substs, _) => { + let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); + let witness = substs.as_generator().witness(); + t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) + } + + ty::GeneratorWitness(types) => { + debug_assert!(!types.has_escaping_bound_vars()); + types.map_bound(|types| types.to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), + + ty::Adt(def, substs) => { + t.rebind(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. + t.rebind(vec![self.tcx().bound_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<'tcx, Vec>>, + ) -> Vec> { + // 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 + .as_ref() + .skip_binder() // binder moved -\ + .iter() + .flat_map(|ty| { + let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ + + 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>> { + let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); + match self.match_impl(impl_def_id, impl_trait_ref, obligation) { + Ok(substs) => substs, + Err(()) => { + self.infcx.tcx.sess.delay_span_bug( + obligation.cause.span, + &format!( + "Impl {:?} was matchable against {:?} but now is not", + impl_def_id, obligation + ), + ); + let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); + let err = self.tcx().ty_error(); + let value = value.fold_with(&mut BottomUpFolder { + tcx: self.tcx(), + ty_op: |_| err, + lt_op: |l| l, + ct_op: |c| c, + }); + Normalized { value, obligations: vec![] } + } + } + } + + #[tracing::instrument(level = "debug", skip(self))] + fn match_impl( + &mut self, + impl_def_id: DefId, + impl_trait_ref: EarlyBinder>, + obligation: &TraitObligation<'tcx>, + ) -> Result>, ()> { + 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); + + debug!(?impl_trait_ref); + + 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!(?impl_trait_ref, ?placeholder_obligation_trait_ref); + + let cause = ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id), + ); + + let InferOk { obligations, .. } = self + .infcx + .at(&cause, obligation.param_env) + .define_opaque_types(false) + .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!(?impl_substs, ?nested_obligations, "match_impl: success"); + Ok(Normalized { value: impl_substs, obligations: nested_obligations }) + } + + fn fast_reject_trait_refs( + &mut self, + obligation: &TraitObligation<'tcx>, + impl_trait_ref: &ty::TraitRef<'tcx>, + ) -> 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. + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder }; + iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs) + .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp)) + } + + /// Normalize `where_clause_trait_ref` and try to match it against + /// `obligation`. If successful, return any predicates that + /// result from the normalization. + fn match_where_clause_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result>, ()> { + self.match_poly_trait_ref(obligation, where_clause_trait_ref) + } + + /// Returns `Ok` if `poly_trait_ref` being true implies that the + /// obligation is satisfied. + #[instrument(skip(self), level = "debug")] + fn match_poly_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result>, ()> { + self.infcx + .at(&obligation.cause, obligation.param_env) + // We don't want predicates for opaque types to just match all other types, + // if there is an obligation on the opaque type, then that obligation must be met + // opaquely. Otherwise we'd match any obligation to the opaque type and then error + // out later. + .define_opaque_types(false) + .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::PolyTraitPredicate<'tcx>, + current: ty::PolyTraitPredicate<'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_pred = obligation.predicate.fold_with(&mut self.freshener); + + let dfn = previous_stack.cache.next_dfn(); + let depth = previous_stack.depth() + 1; + TraitObligationStack { + obligation, + fresh_trait_pred, + reached_depth: Cell::new(depth), + previous: previous_stack, + dfn, + depth, + } + } + + #[instrument(skip(self), level = "debug")] + fn closure_trait_ref_unnormalized( + &mut self, + obligation: &TraitObligation<'tcx>, + substs: SubstsRef<'tcx>, + ) -> ty::PolyTraitRef<'tcx> { + let closure_sig = substs.as_closure().sig(); + + debug!(?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. + #[tracing::instrument(level = "debug", skip(self, cause, param_env))] + 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 + parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + ) -> Vec> { + 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, V: Iterator> Foo for V + // the impl will have the following predicates: + // ::Item = U, + // U: Iterator, U: Sized, + // V: Iterator, V: Sized, + // ::Item: Copy + // When we substitute, say, `V => IntoIter, 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.bound_predicates_of(def_id); + debug!(?predicates); + assert_eq!(predicates.0.parent, None); + let mut obligations = Vec::with_capacity(predicates.0.predicates.len()); + for (predicate, span) in predicates.0.predicates { + let span = *span; + let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { + ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + derived, + impl_def_id: def_id, + span, + })) + }); + let predicate = normalize_with_depth_to( + self, + param_env, + cause.clone(), + recursion_depth, + predicates.rebind(*predicate).subst(tcx, substs), + &mut obligations, + ); + obligations.push(Obligation { cause, recursion_depth, param_env, predicate }); + } + + obligations + } +} + +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!(reached_depth, "update_reached_depth"); + let mut p = self; + while reached_depth < p.depth { + debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant"); + 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: Send` :- +/// - `Bar: Send` :- +/// - `Foo: Send` -- cycle, but ok +/// - `Baz: Send` +/// +/// Here, to prove `Foo: Send`, we have to prove `Bar: Send` and +/// `Baz: Send`. Proving `Bar: Send` in turn required `Foo: 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: Send`, we have in fact only proven it +/// *provisionally*. In particular, we proved that `Bar: Send` +/// *under the assumption* that `Foo: Send`. But what if we later +/// find out this assumption is wrong? Specifically, we could +/// encounter some kind of error proving `Baz: Send`. In that case, +/// `Bar: 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: Send`. But this led +/// to large slowdowns. +/// +/// Specifically, imagine this scenario, where proving `Baz: Send` +/// first requires proving `Bar: Send` (which is true: +/// +/// - `Foo: Send` :- +/// - `Bar: Send` :- +/// - `Foo: Send` -- cycle, but ok +/// - `Baz: Send` +/// - `Bar: 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, + + /// 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 dependencies 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, ProvisionalEvaluation>>, + + /// The stack of args that we assume to be true because a `WF(arg)` predicate + /// is on the stack above (and because of wellformedness is coinductive). + /// In an "ideal" world, this would share a stack with trait predicates in + /// `TraitObligationStack`. However, trait predicates are *much* hotter than + /// `WellFormed` predicates, and it's very likely that the additional matches + /// will have a perf effect. The value here is the well-formed `GenericArg` + /// and the depth of the trait predicate *above* that well-formed predicate. + wf_args: RefCell, usize)>>, +} + +/// A cache value for the provisional cache: contains the depth-first +/// number (DFN) and result. +#[derive(Copy, Clone, Debug)] +struct ProvisionalEvaluation { + from_dfn: usize, + reached_depth: usize, + result: EvaluationResult, +} + +impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { + fn default() -> Self { + Self { dfn: Cell::new(0), map: Default::default(), wf_args: 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 + /// `reached_depth` (from the returned value). + fn get_provisional( + &self, + fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Option { + debug!( + ?fresh_trait_pred, + "get_provisional = {:#?}", + self.map.borrow().get(&fresh_trait_pred), + ); + Some(*self.map.borrow().get(&fresh_trait_pred)?) + } + + /// 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_pred` + /// and resulted in `result`. + fn insert_provisional( + &self, + from_dfn: usize, + reached_depth: usize, + fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + result: EvaluationResult, + ) { + debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional"); + + let mut map = self.map.borrow_mut(); + + // Subtle: when we complete working on the DFN `from_dfn`, anything + // that remains in the provisional cache must be dependent on some older + // stack entry than `from_dfn`. We have to update their depth with our transitive + // depth in that case or else it would be referring to some popped note. + // + // Example: + // A (reached depth 0) + // ... + // B // depth 1 -- reached depth = 0 + // C // depth 2 -- reached depth = 1 (should be 0) + // B + // A // depth 0 + // D (reached depth 1) + // C (cache -- reached depth = 2) + for (_k, v) in &mut *map { + if v.from_dfn >= from_dfn { + v.reached_depth = reached_depth.min(v.reached_depth); + } + } + + map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, 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!(?dfn, "on_failure"); + 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). + /// + /// Note that we may still have provisional cache items remaining + /// in the cache when this is done. For example, if there is a + /// cycle: + /// + /// * A depends on... + /// * B depends on A + /// * C depends on... + /// * D depends on C + /// * ... + /// + /// Then as we complete the C node we will have a provisional cache + /// with results for A, B, C, and D. This method would clear out + /// the C and D results, but leave A and B provisional. + /// + /// This is determined based on the DFN: we remove any provisional + /// results created since `dfn` started (e.g., in our example, dfn + /// would be 2, representing the C node, and hence we would + /// remove the result for D, which has DFN 3, but not the results for + /// A and B, which have DFNs 0 and 1 respectively). + /// + /// Note that we *do not* attempt to cache these cycle participants + /// in the evaluation cache. Doing so would require carefully computing + /// the correct `DepNode` to store in the cache entry: + /// cycle participants may implicitly depend on query results + /// related to other participants in the cycle, due to our logic + /// which examines the evaluation stack. + /// + /// We used to try to perform this caching, + /// but it lead to multiple incremental compilation ICEs + /// (see #92987 and #96319), and was very hard to understand. + /// Fortunately, removing the caching didn't seem to + /// have a performance impact in practice. + fn on_completion(&self, dfn: usize) { + debug!(?dfn, "on_completion"); + + for (fresh_trait_pred, eval) in + self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn) + { + debug!(?fresh_trait_pred, ?eval, "on_completion"); + } + } +} + +#[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>> { + let o = self.head?; + *self = o.previous; + Some(o) + } +} + +impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TraitObligationStack({:?})", self.obligation) + } +} + +pub enum ProjectionMatchesProjection { + Yes, + Ambiguous, + No, +} 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 000000000..6223c5ea3 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -0,0 +1,531 @@ +//! 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, TraitEngineExt, +}; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::{self, ImplSubject, TyCtxt}; +use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; +use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; +use rustc_span::{Span, DUMMY_SP}; + +use super::SelectionContext; +use super::{util, FulfillmentContext}; + +/// Information pertinent to an overlapping impl error. +#[derive(Debug)] +pub struct OverlapError { + pub with_impl: DefId, + pub trait_desc: String, + pub self_desc: Option, + pub intercrate_ambiguity_causes: FxIndexSet, + 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: +/// +/// ```ignore (illustrative) +/// trait Foo { ... } +/// impl Foo for (T, U) { ... } // target impl +/// impl 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: +/// +/// ```ignore (illustrative) +/// impl<'a, I, T: 'a> Iterator for Cloned +/// where I: Iterator, 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.bound_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. +#[instrument(skip(tcx), level = "debug")] +pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool { + // 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 an infcx, taking the predicates of impl1 as assumptions: + tcx.infer_ctxt().enter(|infcx| { + 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(_errors) => { + tcx.sess.delay_span_bug( + tcx.def_span(impl1_def_id), + format!("failed to fully normalize {impl1_trait_ref}"), + ); + impl1_trait_ref + } + }; + + // 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, ()> { + debug!( + "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", + param_env, source_trait_ref, target_impl + ); + + let source_trait = ImplSubject::Trait(source_trait_ref); + + let selcx = &mut SelectionContext::new(&infcx); + let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); + let (target_trait, obligations) = + util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs); + + // do the impls unify? If not, no specialization. + let Ok(InferOk { obligations: more_obligations, .. }) = + infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait) + else { + debug!( + "fulfill_implication: {:?} does not unify with {:?}", + source_trait, target_trait + ); + 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| { + let mut fulfill_cx = >::new(infcx.tcx); + for oblig in obligations.chain(more_obligations) { + fulfill_cx.register_predicate_obligation(&infcx, oblig); + } + match fulfill_cx.select_all_or_error(infcx).as_slice() { + [] => { + debug!( + "fulfill_implication: an impl for {:?} specializes {:?}", + source_trait, target_trait + ); + + // 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)) + } + errors => { + // no dice! + debug!( + "fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + source_trait, + target_trait, + errors, + param_env.caller_bounds() + ); + Err(()) + } + } + }) +} + +// 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 overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id); + + 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(), overlap_mode); + // 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 +} + +// This function is only used when +// encountering errors and inlining +// it negatively impacts perf. +#[cold] +#[inline(never)] +fn report_overlap_conflict( + tcx: TyCtxt<'_>, + overlap: OverlapError, + impl_def_id: LocalDefId, + used_to_be_allowed: Option, + 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.def_span(local_impl_def_id); + + 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_else(String::new, |ty| format!(" for type `{}`", ty)) + ); + + match tcx.span_of_impl(negative_impl_def_id) { + Ok(span) => { + err.span_label(span, "negative implementation here"); + } + Err(cname) => { + err.note(&format!("negative implementation in crate `{}`", cname)); + } + } + + match tcx.span_of_impl(positive_impl_def_id) { + Ok(span) => { + err.span_label(span, "positive implementation here"); + } + Err(cname) => { + err.note(&format!("positive implementation in crate `{}`", cname)); + } + } + + sg.has_errored = Some(err.emit()); +} + +fn report_conflicting_impls( + tcx: TyCtxt<'_>, + overlap: OverlapError, + impl_def_id: LocalDefId, + used_to_be_allowed: Option, + sg: &mut specialization_graph::Graph, +) { + let impl_span = tcx.def_span(impl_def_id); + + // 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. + fn decorate( + tcx: TyCtxt<'_>, + overlap: OverlapError, + used_to_be_allowed: Option, + impl_span: Span, + err: LintDiagnosticBuilder<'_, G>, + ) -> G { + let msg = format!( + "conflicting implementations of trait `{}`{}{}", + overlap.trait_desc, + overlap + .self_desc + .clone() + .map_or_else(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(span, "first implementation here"); + + err.span_label( + impl_span, + format!( + "conflicting implementation{}", + overlap.self_desc.map_or_else(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 => { + let reported = if overlap.with_impl.is_local() + || tcx.orphan_check_impl(impl_def_id).is_ok() + { + let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); + Some(decorate( + tcx, + overlap, + used_to_be_allowed, + impl_span, + LintDiagnosticBuilder::new(err), + )) + } else { + Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check")) + }; + sg.has_errored = reported; + } + 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, + |ldb| { + decorate(tcx, overlap, used_to_be_allowed, impl_span, ldb); + }, + ); + } + }; +} + +/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a +/// string. +pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option { + 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_empty() { + types_without_default_bounds.extend(substs.types()); + w.push('<'); + w.push_str( + &substs + .iter() + .map(|k| k.to_string()) + .filter(|k| k != "'_") + .collect::>() + .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 (mut p, _) in predicates { + if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() { + if Some(poly_trait_ref.def_id()) == sized_trait { + types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder()); + continue; + } + + if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness { + let new_trait_pred = poly_trait_ref.map_bound(|mut trait_pred| { + trait_pred.constness = ty::BoundConstness::NotConst; + trait_pred + }); + + p = tcx.mk_predicate(new_trait_pred.map_bound(ty::PredicateKind::Trait)) + } + } + 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 000000000..fcb73b43f --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -0,0 +1,395 @@ +use super::OverlapError; + +use crate::traits; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; + +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), + + /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc. + ReplaceChildren(Vec), + + /// The impl is a specialization of an existing child. + ShouldRecurseOn(DefId), +} + +trait ChildrenExt<'tcx> { + 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, + overlap_mode: OverlapMode, + ) -> Result; +} + +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<'_>, 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(), TreatParams::AsInfer) + { + debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); + self.non_blanket_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<'_>, impl_def_id: DefId) { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let vec: &mut Vec; + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer) + { + debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); + vec = self.non_blanket_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<'_>, + impl_def_id: DefId, + simplified_self: Option, + overlap_mode: OverlapMode, + ) -> Result { + 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(); + + // FIXME: should postpone string formatting until we decide to actually emit. + with_no_trimmed_paths!({ + 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(), + overlap_mode, + |_| 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_mode, + |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 + '_ { + let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); + children.blanket_impls.iter().chain(nonblanket).cloned() +} + +fn filtered_children( + children: &mut Children, + st: SimplifiedType, +) -> impl Iterator + '_ { + let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); + children.blanket_impls.iter().chain(nonblanket).cloned() +} + +// A custom iterator used by Children::insert +enum PotentialSiblings +where + I: Iterator, + J: Iterator, +{ + Unfiltered(I), + Filtered(J), +} + +impl Iterator for PotentialSiblings +where + I: Iterator, + J: Iterator, +{ + type Item = DefId; + + fn next(&mut self) -> Option { + 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<'_>, + impl_def_id: DefId, + overlap_mode: OverlapMode, + ) -> Result, OverlapError>; + + /// Insert cached metadata mapping from a child impl back to its parent. + fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, 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<'_>, + impl_def_id: DefId, + overlap_mode: OverlapMode, + ) -> Result, 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(), TreatParams::AsInfer); + + // 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, + overlap_mode, + )?; + + 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<'_>, 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 000000000..5829a0f92 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -0,0 +1,273 @@ +use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::traits::ObligationCause; +use crate::traits::{TraitEngine, TraitEngineExt}; + +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, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_span::Span; +use std::ops::ControlFlow; + +/// 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`. +/// +/// 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>( + span: Span, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option> { + ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: false }) + .break_value() +} + +/// This method traverses the structure of `ty`, trying to find any +/// types that are not allowed to be used in a const generic. +/// +/// This is either because the type does not implement `StructuralEq` +/// and `StructuralPartialEq`, or because the type is intentionally +/// not supported in const generics (such as floats and raw pointers, +/// which are allowed in match blocks). +pub fn search_for_adt_const_param_violation<'tcx>( + span: Span, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option> { + ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: true }) + .break_value() +} + +/// 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<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + adt_ty: Ty<'tcx>, + cause: ObligationCause<'tcx>, +) -> bool { + let mut fulfillment_cx = >::new(infcx.tcx); + // 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_empty() +} + +/// 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<'tcx> { + span: Span, + + tcx: TyCtxt<'tcx>, + + /// Tracks ADTs previously encountered during search, so that + /// we will not recur on them again. + seen: FxHashSet, + + // Additionally deny things that have been allowed in patterns, + // but are not allowed in adt const params, such as floats and + // fn ptrs. + adt_const_param: bool, +} + +impl<'tcx> Search<'tcx> { + fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { + adt_ty.is_structural_eq_shallow(self.tcx) + } +} + +impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + debug!("Search visiting ty: {:?}", ty); + + let (adt_def, substs) = match *ty.kind() { + ty::Adt(adt_def, substs) => (adt_def, substs), + ty::Param(_) => { + return ControlFlow::Break(ty); + } + ty::Dynamic(..) => { + return ControlFlow::Break(ty); + } + ty::Foreign(_) => { + return ControlFlow::Break(ty); + } + ty::Opaque(..) => { + return ControlFlow::Break(ty); + } + ty::Projection(..) => { + return ControlFlow::Break(ty); + } + ty::Closure(..) => { + return ControlFlow::Break(ty); + } + ty::Generator(..) | ty::GeneratorWitness(..) => { + return ControlFlow::Break(ty); + } + ty::FnDef(..) => { + // Types of formals and return in `fn(_) -> _` are also irrelevant; + // so we do not recur into them via `super_visit_with` + return ControlFlow::CONTINUE; + } + 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. + return ControlFlow::CONTINUE; + } + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | 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. + return ControlFlow::CONTINUE; + } + + ty::FnPtr(..) => { + if !self.adt_const_param { + return ControlFlow::CONTINUE; + } else { + return ControlFlow::Break(ty); + } + } + + ty::RawPtr(..) => { + if !self.adt_const_param { + // 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. + return ControlFlow::CONTINUE; + } else { + return ControlFlow::Break(ty); + } + } + + ty::Float(_) => { + if !self.adt_const_param { + return ControlFlow::CONTINUE; + } else { + return ControlFlow::Break(ty); + } + } + + ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { + // First check all contained types and then tell the caller to continue searching. + return ty.super_visit_with(self); + } + 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. + return ControlFlow::CONTINUE; + } + }; + + if !self.seen.insert(adt_def.did()) { + debug!("Search already seen adt_def: {:?}", adt_def); + return ControlFlow::CONTINUE; + } + + if !self.type_marked_structural(ty) { + debug!("Search found ty: {:?}", ty); + return ControlFlow::Break(ty); + } + + // 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` 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; + adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| { + let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); + debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); + ty.visit_with(self) + }) + } +} + +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 000000000..d25006016 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -0,0 +1,368 @@ +use rustc_errors::Diagnostic; +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, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable}; + +use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; +pub use rustc_infer::traits::{self, util::*}; + +use std::iter; + +/////////////////////////////////////////////////////////////////////////// +// `TraitAliasExpander` iterator +/////////////////////////////////////////////////////////////////////////// + +/// "Trait alias expansion" is the process of expanding a sequence of trait +/// references into another sequence by transitively following all trait +/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias +/// `trait Foo = Bar + Sync;`, and another trait alias +/// `trait Bar = Read + Write`, then the bounds would expand to +/// `Read + Write + Sync + Send`. +/// Expansion is done via a DFS (depth-first search), and the `visited` field +/// is used to avoid cycles. +pub struct TraitAliasExpander<'tcx> { + tcx: TyCtxt<'tcx>, + stack: Vec>, +} + +/// Stores information about the expansion of a trait via a path of zero or more trait aliases. +#[derive(Debug, Clone)] +pub struct TraitAliasExpansionInfo<'tcx> { + pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, +} + +impl<'tcx> TraitAliasExpansionInfo<'tcx> { + fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { + Self { path: smallvec![(trait_ref, span)] } + } + + /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate + /// trait aliases. + pub fn label_with_exp_info(&self, diag: &mut Diagnostic, 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, 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()); + debug!(?predicates); + + let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { + pred.subst_supertrait(tcx, &trait_ref) + .to_opt_poly_trait_pred() + .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) + }); + debug!("expand_trait_aliases: items={:?}", items.clone().collect::>()); + + self.stack.extend(items); + + false + } +} + +impl<'tcx> Iterator for TraitAliasExpander<'tcx> { + type Item = TraitAliasExpansionInfo<'tcx>; + + fn size_hint(&self) -> (usize, Option) { + (self.stack.len(), None) + } + + fn next(&mut self) -> Option> { + while let Some(item) = self.stack.pop() { + if self.expand(&item) { + return Some(item); + } + } + None + } +} + +/////////////////////////////////////////////////////////////////////////// +// Iterator over def-IDs of supertraits +/////////////////////////////////////////////////////////////////////////// + +pub struct SupertraitDefIds<'tcx> { + tcx: TyCtxt<'tcx>, + stack: Vec, + visited: FxHashSet, +} + +pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> { + SupertraitDefIds { + tcx, + stack: vec![trait_def_id], + visited: Some(trait_def_id).into_iter().collect(), + } +} + +impl Iterator for SupertraitDefIds<'_> { + type Item = DefId; + + fn next(&mut self) -> Option { + let def_id = self.stack.pop()?; + let predicates = self.tcx.super_predicates_of(def_id); + let visited = &mut self.visited; + self.stack.extend( + predicates + .predicates + .iter() + .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred()) + .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 subject with the given substs, +/// returning the resulting subject and all obligations that arise. +/// The obligations are closed under normalization. +pub fn impl_subject_and_oblig<'a, 'tcx>( + selcx: &mut SelectionContext<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: DefId, + impl_substs: SubstsRef<'tcx>, +) -> (ImplSubject<'tcx>, impl Iterator>) { + let subject = selcx.tcx().bound_impl_subject(impl_def_id); + let subject = subject.subst(selcx.tcx(), impl_substs); + let Normalized { value: subject, obligations: normalization_obligations1 } = + super::normalize(selcx, param_env, ObligationCause::dummy(), subject); + + 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()); + + (subject, 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> { + debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); + + iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| { + let cause = match *cause.code() { + traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new( + cause.span, + cause.body_id, + traits::BindingObligation(def_id, span), + ), + _ => cause.clone(), + }; + Obligation { cause, 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: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + } +} + +pub fn predicate_for_trait_def<'tcx>( + 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>( + tcx: TyCtxt<'tcx>, + source_trait_ref: ty::PolyTraitRef<'tcx>, + target_trait_def_id: DefId, +) -> Vec> { + if source_trait_ref.def_id() == target_trait_def_id { + return vec![source_trait_ref]; // Shortcut the most common case. + } + + supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() +} + +/// Given a trait `trait_ref`, returns the number of vtable entries +/// that come from `trait_ref`, excluding its supertraits. Used in +/// computing the vtable base for an upcast trait of a trait object. +pub fn count_own_vtable_entries<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, +) -> usize { + let existential_trait_ref = + trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let existential_trait_ref = tcx.erase_regions(existential_trait_ref); + tcx.own_existential_vtable_entries(existential_trait_ref).len() +} + +/// Given an upcast trait object described by `object`, returns the +/// index of the method `method_def_id` (which should be part of +/// `object.upcast_trait_ref`) within the vtable for `object`. +pub fn get_vtable_index_of_object_method<'tcx, N>( + tcx: TyCtxt<'tcx>, + object: &super::ImplSourceObjectData<'tcx, N>, + method_def_id: DefId, +) -> Option { + let existential_trait_ref = object + .upcast_trait_ref + .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let existential_trait_ref = tcx.erase_regions(existential_trait_ref); + + // Count number of methods preceding the one we are selecting and + // add them to the total offset. + if let Some(index) = tcx + .own_existential_vtable_entries(existential_trait_ref) + .iter() + .copied() + .position(|def_id| def_id == method_def_id) + { + Some(object.vtable_base + index) + } else { + None + } +} + +pub fn closure_trait_ref_and_return_type<'tcx>( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyFnSig<'tcx>, + tuple_arguments: TupleArgumentsFlag, +) -> ty::Binder<'tcx, (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()), + }; + debug_assert!(!self_ty.has_escaping_bound_vars()); + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), + }; + sig.map_bound(|sig| (trait_ref, sig.output())) +} + +pub fn generator_trait_ref_and_outputs<'tcx>( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyGenSig<'tcx>, +) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + debug_assert!(!self_ty.has_escaping_bound_vars()); + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), + }; + sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) +} + +pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { + assoc_item.defaultness(tcx).is_final() + && tcx.impl_defaultness(assoc_item.container_id(tcx)).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 000000000..414857f0a --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -0,0 +1,888 @@ +use crate::infer::InferCtxt; +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, TypeVisitable}; +use rustc_span::Span; + +use std::iter; +/// 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, + recursion_depth: usize, + arg: GenericArg<'tcx>, + span: Span, +) -> Option>> { + // 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.kind() { + ty::ConstKind::Infer(infer) => { + let resolved = infcx.shallow_resolve(infer); + if resolved == infer { + // No progress. + return None; + } + + infcx + .tcx + .mk_const(ty::ConstS { kind: 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 { + tcx: infcx.tcx, + param_env, + body_id, + span, + out: vec![], + recursion_depth, + item: None, + }; + wf.compute(arg); + debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); + + let result = wf.normalize(infcx); + 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`, then the trait reference `Foo: Set` 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_pred: &ty::TraitPredicate<'tcx>, + span: Span, + item: &'tcx hir::Item<'tcx>, +) -> Vec> { + let mut wf = WfPredicates { + tcx: infcx.tcx, + param_env, + body_id, + span, + out: vec![], + recursion_depth: 0, + item: Some(item), + }; + wf.compute_trait_pred(trait_pred, Elaborate::All); + debug!(obligations = ?wf.out); + wf.normalize(infcx) +} + +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> { + let mut wf = WfPredicates { + tcx: infcx.tcx, + param_env, + body_id, + span, + out: vec![], + recursion_depth: 0, + item: None, + }; + + // It's ok to skip the binder here because wf code is prepared for it + match predicate.kind().skip_binder() { + ty::PredicateKind::Trait(t) => { + wf.compute_trait_pred(&t, Elaborate::None); + } + ty::PredicateKind::RegionOutlives(..) => {} + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { + wf.compute(ty.into()); + } + ty::PredicateKind::Projection(t) => { + wf.compute_projection(t.projection_ty); + wf.compute(match t.term { + ty::Term::Ty(ty) => ty.into(), + ty::Term::Const(c) => c.into(), + }) + } + ty::PredicateKind::WellFormed(arg) => { + wf.compute(arg); + } + ty::PredicateKind::ObjectSafe(_) => {} + ty::PredicateKind::ClosureKind(..) => {} + ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { + wf.compute(a.into()); + wf.compute(b.into()); + } + ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + wf.compute(a.into()); + wf.compute(b.into()); + } + ty::PredicateKind::ConstEvaluatable(uv) => { + let obligations = wf.nominal_obligations(uv.def.did, uv.substs); + wf.out.extend(obligations); + + for arg in uv.substs.iter() { + wf.compute(arg); + } + } + ty::PredicateKind::ConstEquate(c1, c2) => { + wf.compute(c1.into()); + wf.compute(c2.into()); + } + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } + } + + wf.normalize(infcx) +} + +struct WfPredicates<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + span: Span, + out: Vec>, + recursion_depth: usize, + 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: +/// +/// ```ignore (illustrative) +/// trait Foo: Copy { } +/// trait Bar: Foo { } +/// impl Foo for T { } +/// impl 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>, +) { + debug!( + "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", + trait_ref, item, cause, pred + ); + let (items, impl_def_id) = match item { + Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id), + _ => 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.kind().skip_binder() { + ty::PredicateKind::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 Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) + && let Some(&impl_item_id) = + tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id) + && let Some(impl_item_span) = items + .iter() + .find(|item| item.id.def_id.to_def_id() == impl_item_id) + .map(fix_span) + { + cause.span = impl_item_span; + } + } + ty::PredicateKind::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() + && let Some(&impl_item_id) = + tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id) + && let Some(impl_item_span) = items + .iter() + .find(|item| item.id.def_id.to_def_id() == impl_item_id) + .map(fix_span) + { + cause.span = impl_item_span; + } + } + _ => {} + } +} + +impl<'tcx> WfPredicates<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + traits::ObligationCause::new(self.span, self.body_id, code) + } + + fn normalize(self, infcx: &InferCtxt<'_, 'tcx>) -> Vec> { + let cause = self.cause(traits::WellFormed(None)); + let param_env = self.param_env; + let mut obligations = Vec::with_capacity(self.out.len()); + for mut obligation in self.out { + assert!(!obligation.has_escaping_bound_vars()); + let mut selcx = traits::SelectionContext::new(infcx); + // Don't normalize the whole obligation, the param env is either + // already normalized, or we're currently normalizing the + // param_env. Either way we should only normalize the predicate. + let normalized_predicate = traits::project::normalize_with_depth_to( + &mut selcx, + param_env, + cause.clone(), + self.recursion_depth, + obligation.predicate, + &mut obligations, + ); + obligation.predicate = normalized_predicate; + obligations.push(obligation); + } + obligations + } + + /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. + fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) { + let tcx = self.tcx; + let trait_ref = &trait_pred.trait_ref; + + // if the trait predicate is not const, the wf obligations should not be const as well. + let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { + self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) + } else { + self.nominal_obligations(trait_ref.def_id, trait_ref.substs) + }; + + debug!("compute_trait_pred obligations {:?}", obligations); + let param_env = self.param_env; + let depth = self.recursion_depth; + + let item = self.item; + + let extend = |traits::PredicateObligation { predicate, mut cause, .. }| { + if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() { + cause = cause.derived_cause( + parent_trait_pred, + traits::ObligationCauseCode::DerivedObligation, + ); + } + extend_cause_with_original_assoc_item_obligation( + tcx, trait_ref, item, &mut cause, predicate, + ); + traits::Obligation::with_depth(cause, depth, param_env, 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 cause = traits::ObligationCause::misc(self.span, self.body_id); + // The first subst is the self ty - use the correct span for it. + if i == 0 { + if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) = + item.map(|i| &i.kind) + { + cause.span = self_ty.span; + } + } + traits::Obligation::with_depth( + cause, + depth, + param_env, + ty::Binder::dummy(ty::PredicateKind::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) its predicates hold (*) + // (b) its substs are wf + // + // (*) The predicates of an associated type include the predicates of + // the trait that it's contained in. For example, given + // + // trait A: Clone { + // type X where T: Copy; + // } + // + // The predicates of `<() as A>::X` are: + // [ + // `(): Sized` + // `(): Clone` + // `(): A` + // `i32: Sized` + // `i32: Clone` + // `i32: Copy` + // ] + let obligations = self.nominal_obligations(data.item_def_id, data.substs); + self.out.extend(obligations); + + let tcx = self.tcx(); + let cause = self.cause(traits::WellFormed(None)); + let param_env = self.param_env; + let depth = self.recursion_depth; + + self.out.extend( + data.substs + .iter() + .filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) + .filter(|arg| !arg.has_escaping_bound_vars()) + .map(|arg| { + traits::Obligation::with_depth( + cause.clone(), + depth, + param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), + ) + }), + ); + } + + 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.tcx.require_lang_item(LangItem::Sized, None), + substs: self.tcx.mk_substs_trait(subty, &[]), + }; + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.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; + let depth = self.recursion_depth; + 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.kind() { + ty::ConstKind::Unevaluated(uv) => { + let obligations = self.nominal_obligations(uv.def.did, uv.substs); + self.out.extend(obligations); + + let predicate = + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) + .to_predicate(self.tcx()); + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } + ty::ConstKind::Infer(_) => { + let cause = self.cause(traits::WellFormed(None)); + + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(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, 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::with_depth( + cause, + depth, + param_env, + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(rty, r), + )) + .to_predicate(self.tcx()), + )); + } + } + + ty::Generator(did, substs, ..) => { + // 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. + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } + + ty::Closure(did, 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. + walker.skip_current_subtree(); // subtree handled below + // FIXME(eddyb) add the type to `walker` instead of recursing. + self.compute(substs.as_closure().tupled_upvars_ty().into()); + // Note that we cannot skip the generic types + // types. Normally, 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). + // But when a closure is part of a type-alias-impl-trait + // then the function that created the defining site may + // have had more bounds available than the type alias + // specifies. This may cause us to have a closure in the + // hidden type that is not actually well formed and + // can cause compiler crashes when the user abuses unsafe + // code to procure such a closure. + // See src/test/ui/type-alias-impl-trait/wf_check_closures.rs + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } + + 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 + // have already been checked for `impl Trait` in + // return position. We do need to check type-alias-impl-trait though. + if ty::is_impl_trait_defn(self.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::WellFormed(None)); + let component_traits = data.auto_traits().chain(data.principal_def_id()); + let tcx = self.tcx(); + self.out.extend(component_traits.map(|did| { + traits::Obligation::with_depth( + cause.clone(), + depth, + param_env, + ty::Binder::dummy(ty::PredicateKind::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 cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())) + .to_predicate(self.tcx()), + )); + } + } + } + } + + #[instrument(level = "debug", skip(self))] + fn nominal_obligations_inner( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + remap_constness: bool, + ) -> Vec> { + let predicates = self.tcx.predicates_of(def_id); + let mut origins = vec![def_id; predicates.predicates.len()]; + let mut head = predicates; + while let Some(parent) = head.parent { + head = self.tcx.predicates_of(parent); + origins.extend(iter::repeat(parent).take(head.predicates.len())); + } + + let predicates = predicates.instantiate(self.tcx, substs); + trace!("{:#?}", predicates); + debug_assert_eq!(predicates.predicates.len(), origins.len()); + + iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) + .map(|((mut pred, span), origin_def_id)| { + let code = if span.is_dummy() { + traits::MiscObligation + } else { + traits::BindingObligation(origin_def_id, span) + }; + let cause = self.cause(code); + if remap_constness { + pred = pred.without_const(self.tcx); + } + traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred) + }) + .filter(|pred| !pred.has_escaping_bound_vars()) + .collect() + } + + fn nominal_obligations( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec> { + self.nominal_obligations_inner(def_id, substs, false) + } + + fn nominal_obligations_without_const( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec> { + self.nominal_obligations_inner(def_id, substs, true) + } + + fn from_object_ty( + &mut self, + ty: Ty<'tcx>, + data: &'tcx ty::List>>, + 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.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::with_depth( + cause, + self.recursion_depth, + self.param_env, + outlives.to_predicate(self.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: &'tcx ty::List>>, +) -> Vec> { + // 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) +} + +/// 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. +#[instrument(skip(tcx, predicates), level = "debug")] +pub(crate) fn required_region_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + erased_self_ty: Ty<'tcx>, + predicates: impl Iterator>, +) -> Vec> { + assert!(!erased_self_ty.has_escaping_bound_vars()); + + traits::elaborate_predicates(tcx, predicates) + .filter_map(|obligation| { + debug!(?obligation); + match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Trait(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, + ty::PredicateKind::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() +} -- cgit v1.2.3