summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml1
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs23
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs102
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs43
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs246
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs93
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs172
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs67
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs51
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs921
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs716
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs115
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs112
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs312
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs202
-rw-r--r--compiler/rustc_trait_selection/src/traits/on_unimplemented.rs71
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs115
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs301
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs99
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/relationships.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs122
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs120
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs253
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs134
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs39
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs81
34 files changed, 2733 insertions, 1903 deletions
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index 566f236f2..67613e1a4 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_parse_format = { path = "../rustc_parse_format" }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 8b7e8984a..61cfeec4b 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -1,6 +1,6 @@
+use crate::errors::AutoDerefReachedRecursionLimit;
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};
@@ -25,7 +25,7 @@ struct AutoderefSnapshot<'tcx> {
pub struct Autoderef<'a, 'tcx> {
// Meta infos:
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
span: Span,
overloaded_span: Span,
body_id: hir::HirId,
@@ -94,7 +94,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
impl<'a, 'tcx> Autoderef<'a, 'tcx> {
pub fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
span: Span,
@@ -222,19 +222,10 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
Limit(0) => Limit(2),
limit => limit * 2,
};
- struct_span_err!(
- tcx.sess,
+ tcx.sess.emit_err(AutoDerefReachedRecursionLimit {
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 (`{}`)",
+ ty,
suggested_limit,
- tcx.crate_name(LOCAL_CRATE),
- ))
- .emit();
+ crate_name: tcx.crate_name(LOCAL_CRATE),
+ });
}
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
new file mode 100644
index 000000000..7f8705824
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -0,0 +1,102 @@
+use rustc_errors::{fluent, ErrorGuaranteed, Handler, IntoDiagnostic};
+use rustc_macros::Diagnostic;
+use rustc_middle::ty::{self, PolyTraitRef, Ty};
+use rustc_session::Limit;
+use rustc_span::{Span, Symbol};
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_dump_vtable_entries)]
+pub struct DumpVTableEntries<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_ref: PolyTraitRef<'a>,
+ pub entries: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_unable_to_construct_constant_value)]
+pub struct UnableToConstructConstantValue<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub unevaluated: ty::UnevaluatedConst<'a>,
+}
+
+#[derive(Diagnostic)]
+#[help]
+#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")]
+pub struct AutoDerefReachedRecursionLimit<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub ty: Ty<'a>,
+ pub suggested_limit: Limit,
+ pub crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+pub struct EmptyOnClauseInOnUnimplemented {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+pub struct InvalidOnClauseInOnUnimplemented {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")]
+#[note]
+pub struct NoValueInOnUnimplemented {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+pub struct NegativePositiveConflict<'a> {
+ pub impl_span: Span,
+ pub trait_desc: &'a str,
+ pub self_desc: &'a Option<String>,
+ pub negative_impl_span: Result<Span, Symbol>,
+ pub positive_impl_span: Result<Span, Symbol>,
+}
+
+impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
+ fn into_diagnostic(
+ self,
+ handler: &Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict);
+ diag.set_arg("trait_desc", self.trait_desc);
+ diag.set_arg(
+ "self_desc",
+ self.self_desc.clone().map_or_else(|| String::from("none"), |ty| ty),
+ );
+ diag.set_span(self.impl_span);
+ diag.code(rustc_errors::error_code!(E0751));
+ match self.negative_impl_span {
+ Ok(span) => {
+ diag.span_label(span, fluent::negative_implementation_here);
+ }
+ Err(cname) => {
+ diag.note(fluent::negative_implementation_in_crate);
+ diag.set_arg("negative_impl_cname", cname.to_string());
+ }
+ }
+ match self.positive_impl_span {
+ Ok(span) => {
+ diag.span_label(span, fluent::positive_implementation_here);
+ }
+ Err(cname) => {
+ diag.note(fluent::positive_implementation_in_crate);
+ diag.set_arg("positive_impl_cname", cname.to_string());
+ }
+ }
+ diag
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 9d30374f8..a335f8e06 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -24,6 +24,13 @@ pub trait InferCtxtExt<'tcx> {
span: Span,
) -> bool;
+ fn type_is_sized_modulo_regions(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ span: Span,
+ ) -> bool;
+
fn partially_normalize_associated_types_in<T>(
&self,
cause: ObligationCause<'tcx>,
@@ -52,7 +59,7 @@ pub trait InferCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult;
}
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
@@ -62,7 +69,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
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);
+ return ty.is_copy_modulo_regions(self.tcx, param_env);
}
let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
@@ -74,6 +81,16 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
}
+ fn type_is_sized_modulo_regions(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ span: Span,
+ ) -> bool {
+ let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+ traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
+ }
+
/// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed.
fn partially_normalize_associated_types_in<T>(
@@ -125,7 +142,7 @@ pub trait InferCtxtBuilderExt<'tcx> {
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
@@ -153,25 +170,17 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
R: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
{
- self.enter_with_canonical(
- DUMMY_SP,
- canonical_key,
- |ref infcx, key, canonical_inference_vars| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- let value = operation(infcx, &mut *fulfill_cx, key)?;
- infcx.make_canonicalized_query_response(
- canonical_inference_vars,
- value,
- &mut *fulfill_cx,
- )
- },
- )
+ let (ref infcx, key, canonical_inference_vars) =
+ self.build_with_canonical(DUMMY_SP, canonical_key);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::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
index 282ee632c..5d52aa075 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -16,11 +16,10 @@
#![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)]
+#![feature(type_alias_impl_trait)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
@@ -36,5 +35,6 @@ extern crate rustc_middle;
extern crate smallvec;
pub mod autoderef;
+pub mod errors;
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
index 294c81d0b..ed34ab95a 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -3,13 +3,14 @@
use super::*;
+use crate::errors::UnableToConstructConstantValue;
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_middle::ty::{PolyTraitRef, Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -65,13 +66,13 @@ impl<'tcx> AutoTraitFinder<'tcx> {
/// struct Foo<T> { data: Box<T> }
/// ```
///
- /// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type).
- /// The analysis attempts to account for custom impls as well as other complex cases. This
- /// result is intended for use by rustdoc and other such consumers.
+ /// then this might return that `Foo<T>: Send` if `T: Send` (encoded in the AutoTraitResult
+ /// type). The analysis attempts to account for custom impls as well as other complex cases.
+ /// This result is intended for use by rustdoc and other such consumers.
///
/// (Note that due to the coinductive nature of Send, the full and correct result is actually
/// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field
- /// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send.
+ /// types are all Send. So, in our example, we might have that `Foo<T>: Send` if `Box<T>: Send`.
/// But this is often not the best way to present to the user.)
///
/// Warning: The API should be considered highly unstable, and it may be refactored or removed
@@ -89,145 +90,105 @@ impl<'tcx> AutoTraitFinder<'tcx> {
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,
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ for f in [
+ PolyTraitRef::to_poly_trait_predicate,
+ PolyTraitRef::to_poly_trait_predicate_negative_polarity,
+ ] {
+ let result =
+ selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred)));
+ if let Ok(Some(ImplSource::UserDefined(_))) = result {
+ debug!(
+ "find_auto_trait_generics({:?}): \
+ manual impl found, bailing out",
+ trait_ref
+ );
+ // If an explicit impl exists, it always takes priority over an auto impl
+ return AutoTraitResult::ExplicitImpl;
}
- });
-
- // 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();
+ let infcx = tcx.infer_ctxt().build();
+ let mut fresh_preds = FxHashSet::default();
+
+ // Due to the way projections are handled by SelectionContext, we need to run
+ // evaluate_predicates twice: once on the original param env, and once on the result of
+ // the first evaluate_predicates call.
+ //
+ // The problem is this: most of rustc, including SelectionContext and traits::project,
+ // are designed to work with a concrete usage of a type (e.g., Vec<u8>
+ // fn<T>() { Vec<T> }. This information will generally never change - given
+ // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
+ // If we're unable to prove that 'T' implements a particular trait, we're done -
+ // there's nothing left to do but error out.
+ //
+ // However, synthesizing an auto trait impl works differently. Here, we start out with
+ // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
+ // with - and progressively discover the conditions we need to fulfill for it to
+ // implement a certain auto trait. This ends up breaking two assumptions made by trait
+ // selection and projection:
+ //
+ // * We can always cache the result of a particular trait selection for the lifetime of
+ // an InfCtxt
+ // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
+ // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
+ //
+ // We fix the first assumption by manually clearing out all of the InferCtxt's caches
+ // in between calls to SelectionContext.select. This allows us to keep all of the
+ // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
+ // them between calls.
+ //
+ // We fix the second assumption by reprocessing the result of our first call to
+ // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
+ // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
+ // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
+ // SelectionContext to return it back to us.
+
+ let 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)
+ });
- // Due to the way projections are handled by SelectionContext, we need to run
- // evaluate_predicates twice: once on the original param env, and once on the result of
- // the first evaluate_predicates call.
- //
- // The problem is this: most of rustc, including SelectionContext and traits::project,
- // are designed to work with a concrete usage of a type (e.g., Vec<u8>
- // fn<T>() { Vec<T> }. This information will generally never change - given
- // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
- // If we're unable to prove that 'T' implements a particular trait, we're done -
- // there's nothing left to do but error out.
- //
- // However, synthesizing an auto trait impl works differently. Here, we start out with
- // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
- // with - and progressively discover the conditions we need to fulfill for it to
- // implement a certain auto trait. This ends up breaking two assumptions made by trait
- // selection and projection:
- //
- // * We can always cache the result of a particular trait selection for the lifetime of
- // an InfCtxt
- // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
- // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
- //
- // We fix the first assumption by manually clearing out all of the InferCtxt's caches
- // in between calls to SelectionContext.select. This allows us to keep all of the
- // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
- // them between calls.
- //
- // We fix the second assumption by reprocessing the result of our first call to
- // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
- // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
- // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
- // SelectionContext to return it back to us.
-
- let 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 = <dyn TraitEngine<'tcx>>::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);
- }
+ 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 errors =
+ super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
- infcx.process_registered_region_obligations(&Default::default(), full_env);
+ infcx.process_registered_region_obligations(&Default::default(), full_env);
- let region_data = infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .region_constraint_data()
- .clone();
+ let region_data =
+ infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
- let vid_to_region = self.map_vid_to_region(&region_data);
+ let vid_to_region = self.map_vid_to_region(&region_data);
- let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
+ let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
- AutoTraitResult::PositiveImpl(auto_trait_callback(info))
- })
+ AutoTraitResult::PositiveImpl(auto_trait_callback(info))
}
}
@@ -273,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
/// user.
fn evaluate_predicates(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
trait_did: DefId,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -343,7 +304,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
}
- let obligations = impl_source.clone().nested_obligations().into_iter();
+ let obligations = impl_source.borrow_nested_obligations().iter().cloned();
if !self.evaluate_nested_obligations(
ty,
@@ -613,7 +574,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
- if let Term::Ty(ty) = p.term().skip_binder() {
+ if let Some(ty) = p.term().skip_binder().ty() {
matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
} else {
false
@@ -832,8 +793,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
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();
-
+ let reported =
+ tcx.sess.emit_err(UnableToConstructConstantValue {
+ span: tcx.def_span(def_id),
+ unevaluated: unevaluated,
+ });
Err(ErrorHandled::Reported(reported))
}
Err(err) => Err(err),
@@ -875,7 +839,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
pub fn clean_pred(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
p: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
infcx.freshen(p)
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 9ef7ac9a8..81e1d6449 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -28,7 +28,7 @@ impl FulfillmentContext<'_> {
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn normalize_projection_type(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
_param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
_cause: ObligationCause<'tcx>,
@@ -38,7 +38,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) {
assert!(!infcx.is_in_snapshot());
@@ -49,7 +49,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.obligations.insert(obligation);
}
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_where_possible(infcx);
@@ -71,10 +71,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.collect()
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Vec<FulfillmentError<'tcx>> {
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new();
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index c0700748c..8a62bf015 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -4,10 +4,12 @@
// general routines.
use crate::infer::{DefiningAnchor, TyCtxtInferExt};
+use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::{
ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
Unimplemented,
};
+use rustc_infer::traits::FulfillmentErrorCode;
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::{self, TyCtxt};
@@ -18,8 +20,7 @@ use rustc_middle::ty::{self, TyCtxt};
/// 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>(
+pub fn codegen_select_candidate<'tcx>(
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
@@ -28,53 +29,61 @@ pub fn codegen_fulfill_obligation<'tcx>(
// 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 infcx = tcx
+ .infer_ctxt()
+ .ignoring_regions()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .build();
+ //~^ 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 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)
- }
- };
+ 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);
+ 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 = <dyn TraitEngine<'tcx>>::new(tcx);
- let impl_source = selection.map(|predicate| {
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
- });
+ // 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 = <dyn TraitEngine<'tcx>>::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);
+ // 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() {
+ // `rustc_monomorphize::collector` assumes there are no type errors.
+ // Cycle errors are the only post-monomorphization errors possible; emit them now so
+ // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
+ for err in errors {
+ if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
+ infcx.err_ctxt().report_overflow_error_cycle(&cycle);
+ }
}
+ return Err(CodegenObligationError::FulfillmentError);
+ }
- let impl_source = infcx.resolve_vars_if_possible(impl_source);
- let impl_source = infcx.tcx.erase_regions(impl_source);
+ 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();
+ // 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))
- })
+ 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
index 1c8cdf4ca..8aab75490 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,21 +6,22 @@
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{CombinedSnapshot, InferOk};
+use crate::traits::outlives_bounds::InferCtxtExt as _;
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,
+ self, Normalized, Obligation, ObligationCause, ObligationCtxt, PredicateObligation,
+ PredicateObligations, SelectionContext,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::CRATE_HIR_ID;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{util, TraitEngine};
+use rustc_infer::traits::util;
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;
@@ -59,23 +60,17 @@ pub fn add_placeholder_note(err: &mut Diagnostic) {
);
}
-/// If there are types that satisfy both impls, invokes `on_overlap`
+/// If there are types that satisfy both impls, returns `Some`
/// 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<F1, F2, R>(
+/// substituted. Otherwise, returns `None`.
+#[instrument(skip(tcx, skip_leak_check), 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,
-{
+) -> Option<OverlapResult<'_>> {
// 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.
@@ -96,28 +91,24 @@ where
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();
+ return None;
}
- 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()
- });
-
+ let infcx = tcx.infer_ctxt().build();
+ let selcx = &mut SelectionContext::intercrate(&infcx);
+ let overlaps =
+ overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
if !overlaps {
- return no_overlap();
+ return None;
}
// 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(),
- )
- })
+ let infcx = tcx.infer_ctxt().build();
+ let selcx = &mut SelectionContext::intercrate(&infcx);
+ selcx.enable_tracking_intercrate_ambiguity_causes();
+ Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
}
fn with_fresh_ty_vars<'cx, 'tcx>(
@@ -166,7 +157,7 @@ fn overlap_within_probe<'cx, 'tcx>(
impl1_def_id: DefId,
impl2_def_id: DefId,
overlap_mode: OverlapMode,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> Option<OverlapResult<'tcx>> {
let infcx = selcx.infcx();
@@ -196,7 +187,7 @@ fn overlap_within_probe<'cx, 'tcx>(
}
}
- // We disable the leak when when creating the `snapshot` by using
+ // We disable the leak 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");
@@ -297,36 +288,41 @@ fn negative_impl<'cx, 'tcx>(
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),
- };
+ let infcx = tcx.infer_ctxt().build();
+ // 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,
+ ObligationCause::dummy(),
+ impl_env,
+ tcx.impl_subject(impl1_def_id),
+ ) {
+ Ok(s) => s,
+ Err(err) => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(impl1_def_id),
+ format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
+ );
+ return false;
+ }
+ };
- // 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);
+ // 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)
- })
+ !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
}
-fn equate<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+fn equate<'tcx>(
+ infcx: &InferCtxt<'tcx>,
impl_env: ty::ParamEnv<'tcx>,
subject1: ImplSubject<'tcx>,
subject2: ImplSubject<'tcx>,
obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
+ body_def_id: DefId,
) -> bool {
// do the impls unify? If not, not disjoint.
let Ok(InferOk { obligations: more_obligations, .. }) =
@@ -340,7 +336,7 @@ fn equate<'cx, 'tcx>(
let opt_failing_obligation = obligations
.into_iter()
.chain(more_obligations)
- .find(|o| negative_impl_exists(selcx, impl_env, o));
+ .find(|o| negative_impl_exists(selcx, o, body_def_id));
if let Some(failing_obligation) = opt_failing_obligation {
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@@ -354,18 +350,16 @@ fn equate<'cx, 'tcx>(
#[instrument(level = "debug", skip(selcx))]
fn negative_impl_exists<'cx, 'tcx>(
selcx: &SelectionContext<'cx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
o: &PredicateObligation<'tcx>,
+ body_def_id: DefId,
) -> bool {
- let infcx = &selcx.infcx().fork();
-
- if resolve_negative_obligation(infcx, param_env, o) {
+ if resolve_negative_obligation(selcx.infcx().fork(), o, body_def_id) {
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) {
+ for o in util::elaborate_predicates(selcx.tcx(), iter::once(o.predicate)) {
+ if resolve_negative_obligation(selcx.infcx().fork(), &o, body_def_id) {
return true;
}
}
@@ -374,10 +368,10 @@ fn negative_impl_exists<'cx, 'tcx>(
}
#[instrument(level = "debug", skip(infcx))]
-fn resolve_negative_obligation<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
+fn resolve_negative_obligation<'tcx>(
+ infcx: InferCtxt<'tcx>,
o: &PredicateObligation<'tcx>,
+ body_def_id: DefId,
) -> bool {
let tcx = infcx.tcx;
@@ -385,17 +379,25 @@ fn resolve_negative_obligation<'cx, 'tcx>(
return false;
};
- let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
- fulfillment_cx.register_predicate_obligation(infcx, o);
-
- let errors = fulfillment_cx.select_all_or_error(infcx);
-
- if !errors.is_empty() {
+ let param_env = o.param_env;
+ if !super::fully_solve_obligation(&infcx, o).is_empty() {
return false;
}
- // FIXME -- also add "assumed to be well formed" types into the `outlives_env`
- let outlives_env = OutlivesEnvironment::new(param_env);
+ let (body_id, body_def_id) = if let Some(body_def_id) = body_def_id.as_local() {
+ (tcx.hir().local_def_id_to_hir_id(body_def_id), body_def_id)
+ } else {
+ (CRATE_HIR_ID, CRATE_DEF_ID)
+ };
+
+ let ocx = ObligationCtxt::new(&infcx);
+ let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
+ let outlives_env = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(&infcx),
+ infcx.implied_bounds_tys(param_env, body_id, wf_tys),
+ );
+
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
infcx.resolve_regions(&outlives_env).is_empty()
@@ -404,12 +406,12 @@ fn resolve_negative_obligation<'cx, 'tcx>(
pub fn trait_ref_is_knowable<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
-) -> Option<Conflict> {
+) -> Result<(), Conflict> {
debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
// A downstream or cousin crate is allowed to implement some
// substitution of this trait-ref.
- return Some(Conflict::Downstream);
+ return Err(Conflict::Downstream);
}
if trait_ref_is_local_or_fundamental(tcx, trait_ref) {
@@ -418,7 +420,7 @@ pub fn trait_ref_is_knowable<'tcx>(
// 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;
+ return Ok(());
}
// This is a remote non-fundamental trait, so if another crate
@@ -431,10 +433,10 @@ pub fn trait_ref_is_knowable<'tcx>(
// 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
+ Ok(())
} else {
debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned");
- Some(Conflict::Upstream)
+ Err(Conflict::Upstream)
}
}
@@ -740,7 +742,21 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
result
}
- // FIXME: Constants should participate in orphan checking.
+ /// All possible values for a constant parameter already exist
+ /// in the crate defining the trait, so they are always non-local[^1].
+ ///
+ /// Because there's no way to have an impl where the first local
+ /// generic argument is a constant, we also don't have to fail
+ /// the orphan check when encountering a parameter or a generic constant.
+ ///
+ /// This means that we can completely ignore constants during the orphan check.
+ ///
+ /// See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
+ ///
+ /// [^1]: This might not hold for function pointers or trait objects in the future.
+ /// As these should be quite rare as const arguments and especially rare as impl
+ /// parameters, allowing uncovered const parameters in impls seems more useful
+ /// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
ControlFlow::CONTINUE
}
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 254bc4ab6..84038625f 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -9,14 +9,12 @@
//! `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;
@@ -101,7 +99,7 @@ impl<'tcx> ConstUnifyCtxt<'tcx> {
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
+ // to evaluate `a_ct` and `b_ct` if they are fully concrete or something like
// this, for now we just return false here.
_ => false,
}
@@ -138,7 +136,7 @@ impl<'tcx> ConstUnifyCtxt<'tcx> {
#[instrument(skip(tcx), level = "debug")]
pub fn try_unify_abstract_consts<'tcx>(
tcx: TyCtxt<'tcx>,
- (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
+ (a, b): (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>),
param_env: ty::ParamEnv<'tcx>,
) -> bool {
(|| {
@@ -159,13 +157,22 @@ pub fn try_unify_abstract_consts<'tcx>(
/// 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, ()>,
+pub fn is_const_evaluatable<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
) -> Result<(), NotConstEvaluatable> {
let tcx = infcx.tcx;
+ let uv = match ct.kind() {
+ ty::ConstKind::Unevaluated(uv) => uv,
+ ty::ConstKind::Param(_)
+ | ty::ConstKind::Bound(_, _)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Value(_)
+ | ty::ConstKind::Error(_) => return Ok(()),
+ ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
+ };
if tcx.features().generic_const_exprs {
if let Some(ct) = AbstractConst::new(tcx, uv)? {
@@ -183,7 +190,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
FailureKind::Concrete => {}
}
}
- let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
+ let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
match concrete {
Err(ErrorHandled::TooGeneric) => {
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
@@ -210,7 +217,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
// 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));
+ let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
match concrete {
// If we're evaluating a foreign constant, under a nightly compiler without generic
@@ -235,39 +242,25 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
.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::TooGeneric) => {
+ let err = if uv.has_non_region_infer() {
+ NotConstEvaluatable::MentionsInfer
+ } else if uv.has_non_region_param() {
+ 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(err)
+ },
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(())
- },
+ Ok(_) => Ok(()),
}
}
}
@@ -281,7 +274,7 @@ fn satisfied_from_param_env<'tcx>(
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)? {
+ if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? {
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
// Try to unify with each subtree in the AbstractConst to allow for
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 6c177f638..e0c8deec9 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -3,7 +3,8 @@ use std::cell::RefCell;
use super::TraitEngine;
use super::{ChalkFulfillmentContext, FulfillmentContext};
use crate::infer::InferCtxtExt;
-use rustc_hir::def_id::DefId;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
@@ -12,9 +13,11 @@ use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
pub trait TraitEngineExt<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
+ fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self>;
}
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
@@ -25,20 +28,32 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
Box::new(FulfillmentContext::new())
}
}
+
+ fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
+ if tcx.sess.opts.unstable_opts.chalk {
+ Box::new(ChalkFulfillmentContext::new())
+ } else {
+ Box::new(FulfillmentContext::new_in_snapshot())
+ }
+ }
}
/// 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>,
+ pub infcx: &'a InferCtxt<'tcx>,
engine: RefCell<Box<dyn TraitEngine<'tcx>>>,
}
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
}
+ pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self {
+ Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx.tcx)) }
+ }
+
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
}
@@ -109,4 +124,34 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
self.engine.borrow_mut().select_all_or_error(self.infcx)
}
+
+ pub fn assumed_wf_types(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span,
+ def_id: LocalDefId,
+ ) -> FxHashSet<Ty<'tcx>> {
+ let tcx = self.infcx.tcx;
+ let assumed_wf_types = tcx.assumed_wf_types(def_id);
+ let mut implied_bounds = FxHashSet::default();
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let cause = ObligationCause::misc(span, hir_id);
+ for ty in assumed_wf_types {
+ // FIXME(@lcnr): rustc currently does not check wf for types
+ // pre-normalization, meaning that implied bounds are sometimes
+ // incorrect. See #100910 for more details.
+ //
+ // Not adding the unnormalized types here mostly fixes that, except
+ // that there are projections which are still ambiguous in the item definition
+ // but do normalize successfully when using the item, see #98543.
+ //
+ // Anyways, I will hopefully soon change implied bounds to make all of this
+ // sound and then uncomment this line again.
+
+ // implied_bounds.insert(ty);
+ let normalized = self.normalize(cause.clone(), param_env, ty);
+ implied_bounds.insert(normalized);
+ }
+ implied_bounds
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index e442c5c91..1217d264a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2,10 +2,10 @@ 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,
+ FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
+ Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
+ OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
+ SelectionContext, SelectionError, TraitNotObjectSafe,
};
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -22,6 +22,8 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::GenericParam;
use rustc_hir::Item;
use rustc_hir::Node;
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
+use rustc_infer::infer::TypeTrace;
use rustc_infer::traits::TraitEngine;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -31,6 +33,8 @@ use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
};
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym};
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
@@ -40,8 +44,8 @@ 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 _;
+use on_unimplemented::TypeErrCtxtExt as _;
+use suggestions::TypeErrCtxtExt as _;
pub use rustc_infer::traits::error_reporting::*;
@@ -62,6 +66,37 @@ pub struct ImplCandidate<'tcx> {
}
pub trait InferCtxtExt<'tcx> {
+ /// Given some node representing a fn-like thing in the HIR map,
+ /// returns a span and `ArgKind` information that describes the
+ /// arguments it expects. This can be supplied to
+ /// `report_arg_count_mismatch`.
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+
+ /// Reports an error when the number of arguments needed by a
+ /// trait match doesn't match the number that the expression
+ /// provides.
+ fn report_arg_count_mismatch(
+ &self,
+ span: Span,
+ found_span: Option<Span>,
+ expected_args: Vec<ArgKind>,
+ found_args: Vec<ArgKind>,
+ is_closure: bool,
+ ) -> DiagnosticBuilder<'tcx, 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>>), ()>;
+}
+
+pub trait TypeErrCtxtExt<'tcx> {
fn report_fulfillment_errors(
&self,
errors: &[FulfillmentError<'tcx>],
@@ -77,6 +112,8 @@ pub trait InferCtxtExt<'tcx> {
where
T: fmt::Display + TypeFoldable<'tcx>;
+ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
+
fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
/// The `root_obligation` parameter should be the `root_obligation` field
@@ -89,12 +126,71 @@ pub trait InferCtxtExt<'tcx> {
error: &SelectionError<'tcx>,
fallback_has_occurred: bool,
);
+}
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// Given some node representing a fn-like thing in the HIR map,
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
+ let sm = self.tcx.sess.source_map();
+ let hir = self.tcx.hir();
+ Some(match node {
+ Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::Closure(&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::<Option<Vec<_>>>()?,
+ ))
+ } else {
+ let name = sm.span_to_snippet(arg.pat.span).ok()?;
+ Some(ArgKind::Arg(name, "_".to_owned()))
+ }
+ })
+ .collect::<Option<Vec<ArgKind>>>()?,
+ ),
+ Node::Item(&hir::Item { 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::<Vec<ArgKind>>(),
+ ),
+ 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
@@ -106,21 +202,175 @@ pub trait InferCtxtExt<'tcx> {
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+ ) -> 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::<Vec<String>>()
+ .join(", ");
+ err.span_suggestion_verbose(
+ found_span,
+ "change the closure to take multiple arguments instead of a single tuple",
+ format!("|{}|", sugg),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
+ && fields.len() == found_args.len()
+ && is_closure
+ {
+ let sugg = format!(
+ "|({}){}|",
+ found_args
+ .iter()
+ .map(|arg| match arg {
+ ArgKind::Arg(name, _) => name.to_owned(),
+ _ => "_".to_owned(),
+ })
+ .collect::<Vec<String>>()
+ .join(", "),
+ // add type annotations if available
+ if found_args.iter().any(|arg| match arg {
+ ArgKind::Arg(_, ty) => ty != "_",
+ _ => false,
+ }) {
+ format!(
+ ": ({})",
+ fields
+ .iter()
+ .map(|(_, ty)| ty.to_owned())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+ } else {
+ String::new()
+ },
+ );
+ err.span_suggestion_verbose(
+ found_span,
+ "change the closure to accept a tuple instead of individual arguments",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ err
+ }
- /// 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>>), ()>;
-}
+ ) -> 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)),
+ ));
+ }
+ }
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+ Err(())
+ })
+ }
+}
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn report_fulfillment_errors(
&self,
errors: &[FulfillmentError<'tcx>],
@@ -250,6 +500,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
bug!();
}
+ 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),
+ ));
+ }
+
/// 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,
@@ -348,7 +611,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
message,
label,
note,
- enclosing_scope,
+ parent_label,
append_const_msg,
} = self.on_unimplemented_note(trait_ref, &obligation);
let have_alt_message = message.is_some() || label.is_some();
@@ -449,12 +712,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
{
"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(),
- )
+ let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+ ty::FnDef(_, _) => Some("fn item"),
+ ty::Closure(_, _) => Some("closure"),
+ _ => None,
+ };
+
+ match ty_desc {
+ Some(desc) => format!(
+ "{}the trait `{}` is not implemented for {} `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ desc,
+ trait_ref.skip_binder().self_ty(),
+ ),
+ None => 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(
@@ -482,10 +760,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
- Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+ 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);
}
+ let mut unsatisfied_const = false;
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 {
@@ -495,6 +774,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
recursion_depth: obligation.recursion_depth,
};
if self.predicate_may_hold(&non_const_obligation) {
+ unsatisfied_const = true;
err.span_note(
span,
&format!(
@@ -514,7 +794,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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 {
+ if let Some(ref s) = parent_label {
let body = tcx
.hir()
.opt_local_def_id(obligation.cause.body_id)
@@ -523,11 +803,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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);
+ err.span_label(tcx.def_span(body), s);
}
self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
@@ -594,11 +870,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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,
- )
+ 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
@@ -649,8 +925,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
);
}
}
- } else if !trait_ref.has_infer_types_or_consts()
- && self.predicate_can_apply(obligation.param_env, trait_ref)
+ } else if !trait_ref.has_non_region_infer()
+ && self.predicate_can_apply(obligation.param_env, trait_predicate)
{
// If a where-clause may be useful, remind the
// user that they can add it.
@@ -665,7 +941,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
None,
obligation.cause.body_id,
);
- } else if !suggested {
+ } else if !suggested && !unsatisfied_const {
// 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(
@@ -828,12 +1104,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Additional context information explaining why the closure only implements
// a particular trait.
- if let Some(typeck_results) = self.in_progress_typeck_results {
+ if let Some(typeck_results) = &self.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(
@@ -859,8 +1134,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
- err.emit();
- return;
+ err
}
ty::PredicateKind::WellFormed(ty) => {
@@ -941,9 +1215,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+ let mut not_tupled = false;
+
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()],
+ _ => {
+ not_tupled = true;
+ vec![ArgKind::empty()]
+ }
};
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
@@ -951,15 +1230,34 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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())],
+ _ => {
+ not_tupled = true;
+ vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
+ }
};
- if found.len() == expected.len() {
+ // If this is a `Fn` family trait and either the expected or found
+ // is not tupled, then fall back to just a regular mismatch error.
+ // This shouldn't be common unless manually implementing one of the
+ // traits manually, but don't make it more confusing when it does
+ // happen.
+ if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
+ self.report_and_explain_type_error(
+ TypeTrace::poly_trait_refs(
+ &obligation.cause,
+ true,
+ expected_trait_ref,
+ found_trait_ref,
+ ),
+ ty::error::TypeError::Mismatch,
+ )
+ } else if found.len() == expected.len() {
self.report_closure_arg_mismatch(
span,
found_span,
found_trait_ref,
expected_trait_ref,
+ obligation.cause.code(),
)
} else {
let (closure_span, found) = found_did
@@ -1008,7 +1306,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(uv) => {
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+ bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+ };
let mut err =
self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
let const_span = self.tcx.def_span(uv.def.did);
@@ -1054,250 +1355,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.emit();
}
-
- /// Given some node representing a fn-like thing in the HIR map,
- /// returns a span and `ArgKind` information that describes the
- /// arguments it expects. This can be supplied to
- /// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
- let sm = self.tcx.sess.source_map();
- let hir = self.tcx.hir();
- Some(match node {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(&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::<Option<Vec<_>>>()?,
- ))
- } else {
- let name = sm.span_to_snippet(arg.pat.span).ok()?;
- Some(ArgKind::Arg(name, "_".to_owned()))
- }
- })
- .collect::<Option<Vec<ArgKind>>>()?,
- ),
- Node::Item(&hir::Item { 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::<Vec<ArgKind>>(),
- ),
- 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<Span>,
- expected_args: Vec<ArgKind>,
- found_args: Vec<ArgKind>,
- 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::<Vec<String>>()
- .join(", ");
- err.span_suggestion_verbose(
- found_span,
- "change the closure to take multiple arguments instead of a single tuple",
- format!("|{}|", sugg),
- Applicability::MachineApplicable,
- );
- }
- }
- if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
- && fields.len() == found_args.len()
- && is_closure
- {
- let sugg = format!(
- "|({}){}|",
- found_args
- .iter()
- .map(|arg| match arg {
- ArgKind::Arg(name, _) => name.to_owned(),
- _ => "_".to_owned(),
- })
- .collect::<Vec<String>>()
- .join(", "),
- // add type annotations if available
- if found_args.iter().any(|arg| match arg {
- ArgKind::Arg(_, ty) => ty != "_",
- _ => false,
- }) {
- format!(
- ": ({})",
- fields
- .iter()
- .map(|(_, ty)| ty.to_owned())
- .collect::<Vec<String>>()
- .join(", ")
- )
- } else {
- String::new()
- },
- );
- err.span_suggestion_verbose(
- found_span,
- "change the closure to accept a tuple instead of individual arguments",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- }
-
- err
- }
-
- 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> {
+trait InferCtxtPrivExt<'tcx> {
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
@@ -1315,6 +1375,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
error: &MismatchedProjectionTypes<'tcx>,
);
+ fn maybe_detailed_projection_msg(
+ &self,
+ pred: ty::ProjectionPredicate<'tcx>,
+ normalized_ty: ty::Term<'tcx>,
+ expected_ty: ty::Term<'tcx>,
+ ) -> Option<String>;
+
fn fuzzy_match_tys(
&self,
a: Ty<'tcx>,
@@ -1371,7 +1438,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
fn predicate_can_apply(
&self,
param_env: ty::ParamEnv<'tcx>,
- pred: ty::PolyTraitRef<'tcx>,
+ pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
@@ -1389,13 +1456,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
predicate: ty::Predicate<'tcx>,
);
- fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>);
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
fn maybe_indirection_for_unsized(
&self,
err: &mut Diagnostic,
- item: &'hir Item<'hir>,
- param: &'hir GenericParam<'hir>,
+ item: &'tcx Item<'tcx>,
+ param: &'tcx GenericParam<'tcx>,
) -> bool;
fn is_recursive_obligation(
@@ -1405,7 +1472,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
) -> bool;
}
-impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, '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 {
@@ -1476,13 +1543,31 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
.emit();
}
FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
- self.report_mismatched_consts(
+ let mut diag = self.report_mismatched_consts(
&error.obligation.cause,
expected_found.expected,
expected_found.found,
err.clone(),
- )
- .emit();
+ );
+ let code = error.obligation.cause.code().peel_derives().peel_match_impls();
+ if let ObligationCauseCode::BindingObligation(..)
+ | ObligationCauseCode::ItemObligation(..)
+ | ObligationCauseCode::ExprBindingObligation(..)
+ | ObligationCauseCode::ExprItemObligation(..) = code
+ {
+ self.note_obligation_cause_code(
+ &mut diag,
+ &error.obligation.predicate,
+ error.obligation.param_env,
+ code,
+ &mut vec![],
+ &mut Default::default(),
+ );
+ }
+ diag.emit();
+ }
+ FulfillmentErrorCode::CodeCycle(ref cycle) => {
+ self.report_overflow_error_cycle(cycle);
}
}
}
@@ -1500,8 +1585,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
self.probe(|_| {
- let err_buf;
- let mut err = &error.err;
+ let mut err = error.err;
let mut values = None;
// try to find the mismatched types to report the error with.
@@ -1534,31 +1618,28 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
obligation.cause.code().peel_derives(),
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
+ | ObligationCauseCode::ExprItemObligation(..)
+ | ObligationCauseCode::ExprBindingObligation(..)
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::OpaqueType
);
- if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
+ if let Err(new_err) = 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;
+ values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
+ err = new_err;
}
}
- let mut diag = struct_span_err!(
- self.tcx.sess,
- obligation.cause.span,
- E0271,
- "type mismatch resolving `{}`",
- predicate
- );
+ let msg = values
+ .and_then(|(predicate, _, normalized_ty, expected_ty)| {
+ self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
+ })
+ .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
+ let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
+
let secondary_span = match predicate.kind().skip_binder() {
ty::PredicateKind::Projection(proj) => self
.tcx
@@ -1584,7 +1665,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
..
})
| hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::TyAlias(ty),
+ kind: hir::ImplItemKind::Type(ty),
..
}),
) => Some((ty.span, format!("type mismatch resolving `{}`", predicate))),
@@ -1596,7 +1677,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
&mut diag,
&obligation.cause,
secondary_span,
- values,
+ values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
+ infer::ValuePairs::Terms(ExpectedFound::new(
+ is_normalized_ty_expected,
+ normalized_ty,
+ term,
+ ))
+ }),
err,
true,
false,
@@ -1606,6 +1693,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
});
}
+ fn maybe_detailed_projection_msg(
+ &self,
+ pred: ty::ProjectionPredicate<'tcx>,
+ normalized_ty: ty::Term<'tcx>,
+ expected_ty: ty::Term<'tcx>,
+ ) -> Option<String> {
+ let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
+ let self_ty = pred.projection_ty.self_ty();
+
+ if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
+ Some(format!(
+ "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
+ fn_kind = self_ty.prefix_string(self.tcx)
+ ))
+ } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+ Some(format!(
+ "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
+ ))
+ } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+ Some(format!(
+ "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
+ ))
+ } else {
+ None
+ }
+ }
+
fn fuzzy_match_tys(
&self,
mut a: Ty<'tcx>,
@@ -1731,13 +1845,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
return false;
}
if candidates.len() == 1 {
+ let ty_desc = match candidates[0].self_ty().kind() {
+ ty::FnPtr(_) => Some("fn pointer"),
+ _ => None,
+ };
+ let the_desc = match ty_desc {
+ Some(desc) => format!(" implemented for {} `", desc),
+ None => " implemented for `".to_string(),
+ };
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),
+ (the_desc, Style::NoStyle),
(candidates[0].self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
]);
@@ -1804,7 +1926,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// types, too.
self.tcx
.visibility(def.did())
- .is_accessible_from(body_id.owner.to_def_id(), self.tcx)
+ .is_accessible_from(body_id.owner.def_id, self.tcx)
} else {
true
}
@@ -1814,16 +1936,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
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,
- }
- })
+ let infcx = self.tcx.infer_ctxt().build();
+ infcx
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .normalize(candidate)
+ .map_or(candidate, |normalized| normalized.value)
};
// Sort impl candidates so that ordering is consistent for UI tests.
@@ -1940,7 +2057,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
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()));
+ debug!(?predicate, obligation.cause.code = ?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.
@@ -1997,7 +2114,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// 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 subst = data.trait_ref.substs.iter().find(|s| s.has_non_region_infer());
let mut err = if let Some(subst) = subst {
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
@@ -2033,13 +2150,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
}
- if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() {
+ if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(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())
+ } else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span)
+ && let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..)
+ = *obligation.cause.code()
{
let generics = self.tcx.generics_of(def_id);
if generics.params.iter().any(|p| p.name != kw::SelfUpper)
@@ -2119,12 +2234,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
&& let [
..,
trait_path_segment @ hir::PathSegment {
- res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)),
+ res: 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)),
+ res: rustc_hir::def::Res::Def(_, item_id),
..
}
] = path.segments
@@ -2169,13 +2284,22 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
trait_impls.non_blanket_impls().len()
)
};
-
+ let mut suggestions = vec![(
+ trait_path_segment.ident.span.shrink_to_lo(),
+ format!("<{} as ", self.tcx.type_of(impl_def_id))
+ )];
+ if let Some(generic_arg) = trait_path_segment.args {
+ let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext);
+ // get rid of :: between Trait and <type>
+ // must be '::' between them, otherwise the parser won't accept the code
+ suggestions.push((between_span, "".to_string(),));
+ suggestions.push((generic_arg.span_ext.shrink_to_hi(), format!(">")));
+ } else {
+ suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), format!(">")));
+ }
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!(">"))
- ],
+ suggestions,
Applicability::MaybeIncorrect
);
}
@@ -2220,7 +2344,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
.substs
.iter()
.chain(Some(data.term.into_arg()))
- .find(|g| g.has_infer_types_or_consts());
+ .find(|g| g.has_non_region_infer());
if let Some(subst) = subst {
let mut err = self.emit_inference_failure_err(
body_id,
@@ -2249,7 +2373,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
- let subst = data.substs.iter().find(|g| g.has_infer_types_or_consts());
+ let subst = data.walk().find(|g| g.is_non_region_infer());
if let Some(subst) = subst {
let err = self.emit_inference_failure_err(
body_id,
@@ -2389,10 +2513,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
fn predicate_can_apply(
&self,
param_env: ty::ParamEnv<'tcx>,
- pred: ty::PolyTraitRef<'tcx>,
+ pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
struct ParamToVarFolder<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
}
@@ -2433,7 +2557,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
- cleaned_pred.without_const().to_predicate(selcx.tcx()),
+ cleaned_pred.to_predicate(selcx.tcx()),
);
self.predicate_may_hold(&obligation)
@@ -2462,15 +2586,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
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;
- };
+ let ty::PredicateKind::Trait(pred) = obligation.predicate.kind().skip_binder() else { return; };
+ let (ObligationCauseCode::BindingObligation(item_def_id, span)
+ | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..))
+ = *obligation.cause.code().peel_derives() else { return; };
debug!(?pred, ?item_def_id, ?span);
let (Some(node), true) = (
@@ -2483,12 +2602,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
#[instrument(level = "debug", skip_all)]
- fn maybe_suggest_unsized_generics<'hir>(
- &self,
- err: &mut Diagnostic,
- span: Span,
- node: Node<'hir>,
- ) {
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) {
let Some(generics) = node.generics() else {
return;
};
@@ -2539,11 +2653,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
);
}
- fn maybe_indirection_for_unsized<'hir>(
+ fn maybe_indirection_for_unsized(
&self,
err: &mut Diagnostic,
- item: &'hir Item<'hir>,
- param: &'hir GenericParam<'hir>,
+ item: &Item<'tcx>,
+ param: &GenericParam<'tcx>,
) -> 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: ?Sized>(T);`
@@ -2643,82 +2757,6 @@ impl<'v> Visitor<'v> for FindTypeParam {
}
}
-pub fn recursive_type_with_infinite_size_error<'tcx>(
- tcx: TyCtxt<'tcx>,
- type_def_id: DefId,
- spans: Vec<(Span, Option<hir::HirId>)>,
-) {
- 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<T>` in a field definition
-fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
- 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 {
@@ -2763,3 +2801,8 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
}
}
}
+
+pub enum DefIdOrName {
+ DefId(DefId),
+ Name(&'static str),
+}
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
index e6907637c..5eef54c63 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -1,17 +1,17 @@
use super::{
ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
};
-use crate::infer::InferCtxt;
+use crate::infer::error_reporting::TypeErrCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, GenericParamDefKind};
use rustc_span::symbol::sym;
use std::iter;
use super::InferCtxtPrivExt;
-pub trait InferCtxtExt<'tcx> {
+pub trait TypeErrCtxtExt<'tcx> {
/*private*/
fn impl_similar_to(
&self,
@@ -29,7 +29,7 @@ pub trait InferCtxtExt<'tcx> {
) -> OnUnimplementedNote;
}
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn impl_similar_to(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
@@ -143,7 +143,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
if let ObligationCauseCode::ItemObligation(item)
- | ObligationCauseCode::BindingObligation(item, _) = *obligation.cause.code()
+ | ObligationCauseCode::BindingObligation(item, _)
+ | ObligationCauseCode::ExprItemObligation(item, ..)
+ | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code()
{
// FIXME: maybe also have some way of handling methods
// from other traits? That would require name resolution,
@@ -162,6 +164,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
}
+ if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+ flags.push((sym::cause, Some("MainFunctionType".to_string())));
+ }
+
// Add all types without trimmed paths.
ty::print::with_no_trimmed_paths!({
let generics = self.tcx.generics_of(def_id);
@@ -254,7 +260,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
}
- if let ty::Dynamic(traits, _) = self_ty.kind() {
+ 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))))
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 219413121..8c41d9d24 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1,5 +1,5 @@
use super::{
- EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+ DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
SelectionContext,
};
@@ -7,6 +7,7 @@ use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
use crate::traits::normalize_to;
+use hir::def::CtorOf;
use hir::HirId;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -20,18 +21,17 @@ 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_infer::infer::error_reporting::TypeErrCtxt;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::LateBoundRegionConversionTime;
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,
+ 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::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::fmt;
@@ -63,7 +63,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
// meet an obligation
fn try_get_upvar_span<F>(
&self,
- infer_context: &InferCtxt<'a, 'tcx>,
+ infer_context: &InferCtxt<'tcx>,
generator_did: DefId,
ty_matches: F,
) -> Option<GeneratorInteriorOrUpvar>
@@ -169,12 +169,12 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
}
// This trait is public to expose the diagnostics methods to clippy.
-pub trait InferCtxtExt<'tcx> {
+pub trait TypeErrCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
&self,
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
- proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+ associated_item: Option<(&'static str, Ty<'tcx>)>,
body_id: hir::HirId,
);
@@ -256,8 +256,15 @@ pub trait InferCtxtExt<'tcx> {
found_span: Option<Span>,
found: ty::PolyTraitRef<'tcx>,
expected: ty::PolyTraitRef<'tcx>,
+ cause: &ObligationCauseCode<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+ fn note_conflicting_closure_bounds(
+ &self,
+ cause: &ObligationCauseCode<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ );
+
fn suggest_fully_qualified_path(
&self,
err: &mut Diagnostic,
@@ -297,8 +304,6 @@ pub trait InferCtxtExt<'tcx> {
) 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,
@@ -462,12 +467,12 @@ fn suggest_restriction<'tcx>(
}
}
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_restricting_param_bound(
&self,
mut err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
- proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+ associated_ty: Option<(&'static str, Ty<'tcx>)>,
body_id: hir::HirId,
) {
let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
@@ -604,21 +609,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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);
-
+ if let Some((name, term)) = associated_ty {
// 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,
+ name,
term
);
} else {
- constraint.push_str(&format!("<{}={}>", item.name, term));
+ constraint.push_str(&format!("<{} = {}>", name, term));
}
}
@@ -648,7 +650,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
..
}) if !param_ty => {
// Missing generic type parameter bound.
- if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
+ if suggest_arbitrary_trait_bound(
+ self.tcx,
+ generics,
+ &mut err,
+ trait_pred,
+ associated_ty,
+ ) {
return;
}
}
@@ -657,7 +665,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
_ => {}
}
- hir_id = self.tcx.hir().local_def_id_to_hir_id(self.tcx.hir().get_parent_item(hir_id));
+ hir_id = self.tcx.hir().get_parent_item(hir_id).into();
}
}
@@ -671,11 +679,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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 ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code()
+ else { return false; };
+ let Some(typeck_results) = &self.typeck_results
+ else { return false; };
+ let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id)
+ else { return false; };
+ let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)
+ else { return false; };
+
let span = obligation.cause.span;
let mut real_trait_pred = trait_pred;
let mut code = obligation.cause.code();
@@ -685,11 +697,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
real_trait_pred = parent_trait_pred;
}
- // Skipping binder here, remapping below
- let real_ty = real_trait_pred.self_ty().skip_binder();
+ let real_ty = real_trait_pred.self_ty();
+ // We `erase_late_bound_regions` here because `make_subregion` does not handle
+ // `ReLateBound`, and we don't particularly care about the regions.
+ if self
+ .can_eq(obligation.param_env, self.tcx.erase_late_bound_regions(real_ty), arg_ty)
+ .is_err()
+ {
+ continue;
+ }
- 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 ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() {
+ let mut autoderef = Autoderef::new(
+ self,
+ obligation.param_env,
+ obligation.cause.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 });
@@ -697,24 +723,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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);
+ let obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.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;
- }
+ // Don't care about `&mut` because `DerefMut` is used less
+ // often and user will not expect autoderef happens.
+ if let Some(hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr),
+ ..
+ })) = self.tcx.hir().find(*arg_hir_id)
+ {
+ let derefs = "*".repeat(steps);
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "consider dereferencing here",
+ derefs,
+ Applicability::MachineApplicable,
+ );
+ return true;
}
}
} else if real_trait_pred != trait_pred {
@@ -724,7 +755,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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,
+ obligation.param_env,
real_trait_pred_and_base_ty,
);
if self.predicate_may_hold(&obligation) {
@@ -750,7 +781,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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) => {
+ hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => {
Some(ident.name)
}
_ => {
@@ -783,75 +814,138 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, '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);
+ if let ty::PredicateKind::Trait(trait_pred) = obligation.predicate.kind().skip_binder()
+ && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
+ {
+ // Don't suggest calling to turn an unsized type into a sized type
+ return false;
+ }
- // "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);
+ // This is duplicated from `extract_callable_info` in typeck, which
+ // relies on autoderef, so we can't use it here.
+ let found = trait_pred.self_ty().skip_binder().peel_refs();
+ let Some((def_id_or_name, output, inputs)) = (match *found.kind()
+ {
+ ty::FnPtr(fn_sig) => {
+ Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
+ }
+ ty::FnDef(def_id, _) => {
+ let fn_sig = found.fn_sig(self.tcx);
+ Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+ }
+ ty::Closure(def_id, substs) => {
+ let fn_sig = substs.as_closure().sig();
+ Some((
+ DefIdOrName::DefId(def_id),
+ fn_sig.output(),
+ fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
+ ))
+ }
+ ty::Opaque(def_id, substs) => {
+ self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+ if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+ && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ // args tuple will always be substs[1]
+ && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+ {
+ Some((
+ DefIdOrName::DefId(def_id),
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ ty::Dynamic(data, _, ty::Dyn) => {
+ data.iter().find_map(|pred| {
+ if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+ && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+ // for existential projection, substs are shifted over by 1
+ && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+ {
+ Some((
+ DefIdOrName::Name("trait object"),
+ pred.rebind(proj.term.ty().unwrap()),
+ pred.rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ ty::Param(_) => {
+ obligation.param_env.caller_bounds().iter().find_map(|pred| {
+ if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+ && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && proj.projection_ty.self_ty() == found
+ // args tuple will always be substs[1]
+ && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+ {
+ Some((
+ DefIdOrName::Name("type parameter"),
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ _ => None,
+ }) else { return false; };
+ let output = self.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ LateBoundRegionConversionTime::FnCall,
+ output,
+ );
+ let inputs = inputs.skip_binder().iter().map(|ty| {
+ self.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ LateBoundRegionConversionTime::FnCall,
+ inputs.rebind(*ty),
+ )
+ });
// Remapping bound vars here
- let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
+ let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
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,
+ if !self.predicate_must_hold_modulo_regions(&new_obligation) {
+ 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::<Vec<_>>().join(", ");
- let sugg = format!("({})", args);
- (format!("{}{}", name, sugg), sugg)
- }
- Some(hir::Node::Item(hir::Item {
- ident,
- kind: hir::ItemKind::Fn(.., body_id),
- ..
- })) => {
- err.span_label(ident.span, "consider calling this function");
- let body = hir.body(*body_id);
- let args = body
- .params
- .iter()
- .map(|arg| match &arg.pat.kind {
- hir::PatKind::Binding(_, _, ident, None)
- // FIXME: provide a better suggestion when encountering `SelfLower`, it
- // should suggest a method call.
- if ident.name != kw::SelfLower => ident.to_string(),
- _ => "_".to_string(),
- })
- .collect::<Vec<_>>()
- .join(", ");
- let sugg = format!("({})", args);
- (format!("{}{}", ident, sugg), sugg)
- }
- _ => return false,
+ let hir = self.tcx.hir();
+
+ let msg = match def_id_or_name {
+ DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
+ DefKind::Ctor(CtorOf::Struct, _) => {
+ "use parentheses to construct this tuple struct".to_string()
+ }
+ DefKind::Ctor(CtorOf::Variant, _) => {
+ "use parentheses to construct this tuple variant".to_string()
+ }
+ kind => format!("use parentheses to call this {}", kind.descr(def_id)),
+ },
+ DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
};
+
+ let args = inputs
+ .map(|ty| {
+ if ty.is_suggestable(self.tcx, false) {
+ format!("/* {ty} */")
+ } else {
+ "/* value */".to_string()
+ }
+ })
+ .collect::<Vec<_>>()
+ .join(", ");
+
if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
+ && obligation.cause.span.can_be_used_for_suggestions()
{
// When the obligation error has been ensured to have been caused by
// an argument, the `obligation.cause.span` points at the expression
@@ -860,11 +954,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
obligation.cause.span.shrink_to_hi(),
&msg,
- sugg,
+ format!("({args})"),
Applicability::HasPlaceholders,
);
- } else {
- err.help(&format!("{}: `{}`", msg, snippet));
+ } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
+ let name = match hir.get_if_local(def_id) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { 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;
+ };
+ name.to_string()
+ }
+ Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => {
+ err.span_label(ident.span, "consider calling this function");
+ ident.to_string()
+ }
+ Some(hir::Node::Ctor(..)) => {
+ let name = self.tcx.def_path_str(def_id);
+ err.span_label(
+ self.tcx.def_span(def_id),
+ format!("consider calling the constructor for `{}`", name),
+ );
+ name
+ }
+ _ => return false,
+ };
+ err.help(&format!("{msg}: `{name}({args})`"));
}
true
}
@@ -882,6 +1001,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
obligation.cause.code()
{
&parent_code
+ } else if let ObligationCauseCode::ItemObligation(_)
+ | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code()
+ {
+ obligation.cause.code()
} else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
span.ctxt().outer_expn_data().kind
{
@@ -906,102 +1029,121 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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| {
+ 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_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
+ let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
+
+ let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
+ if let ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code()
+ && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
+ {
(
- trait_pred,
- self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),
+ matches!(mutability, hir::Mutability::Mut),
)
- });
-
- 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)
+ } else {
+ (false, false)
};
- 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,
+
+ if imm_ref_self_ty_satisfies_pred
+ || mut_ref_self_ty_satisfies_pred
+ || ref_inner_ty_satisfies_pred
+ {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // We don't want a borrowing suggestion on the fields in structs,
+ // ```
+ // struct Foo {
+ // the_foos: Vec<Foo>
+ // }
+ // ```
+ if !matches!(
+ span.ctxt().outer_expn_data().kind,
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+ ) {
+ return false;
+ }
+ 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;
+ }
+ // 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)];
+ }
+ err.span_label(
+ span,
+ format!(
+ "the trait `{}` is not implemented for `{}`",
+ old_pred.print_modifiers_and_trait_path(),
+ old_pred.self_ty().skip_binder(),
+ ),
+ );
+
+ if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
+ err.span_suggestions(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ ["&".to_string(), "&mut ".to_string()].into_iter(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
&format!(
- "expected an implementor of trait `{}`",
- old_pred.print_modifiers_and_trait_path(),
+ "consider{} borrowing here",
+ if is_mut { " mutably" } else { "" }
),
+ format!("&{}", if is_mut { "mut " } else { "" }),
+ Applicability::MaybeIncorrect,
);
-
- // 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<Foo>
- // }
- // ```
-
- 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 true;
}
- return false;
- };
+ }
+ return false;
+ };
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
try_borrowing(cause.derived.parent_trait_pred, &[])
} else if let ObligationCauseCode::BindingObligation(_, _)
- | ObligationCauseCode::ItemObligation(_) = code
+ | ObligationCauseCode::ItemObligation(_)
+ | ObligationCauseCode::ExprItemObligation(..)
+ | ObligationCauseCode::ExprBindingObligation(..) = code
{
try_borrowing(poly_trait_pred, &never_suggest_borrow)
} else {
@@ -1017,7 +1159,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
self_ty: Ty<'tcx>,
object_ty: Ty<'tcx>,
) {
- let ty::Dynamic(predicates, _) = object_ty.kind() else { return; };
+ let ty::Dynamic(predicates, _, ty::Dyn) = 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() {
@@ -1110,8 +1252,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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()),
+ err.span_suggestion(
+ span,
"remove the `.await`",
"",
Applicability::MachineApplicable,
@@ -1126,8 +1268,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
&format!("this call returns `{}`", pred.self_ty()),
);
}
- if let Some(typeck_results) =
- self.in_progress_typeck_results.map(|t| t.borrow())
+ if let Some(typeck_results) = &self.typeck_results
&& 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, .. })) =
@@ -1181,7 +1322,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}
let trait_pred = self.resolve_vars_if_possible(trait_pred);
- if trait_pred.has_infer_types_or_consts() {
+ if trait_pred.has_non_region_infer() {
// Do not ICE while trying to find if a reborrow would succeed on a trait with
// unresolved bindings.
return;
@@ -1250,8 +1391,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
&& 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)
+ && let Some(typeck_results) = &self.typeck_results
+ && let Some(ty) = typeck_results.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))
))
@@ -1315,7 +1456,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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, _) => {
+ ty::Dynamic(predicates, _, ty::Dyn) => {
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
predicates
.principal_def_id()
@@ -1340,7 +1481,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
- let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
+ let typeck_results = self.typeck_results.as_ref().unwrap();
let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
let ret_types = visitor
@@ -1375,7 +1516,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut spans_and_needs_box = vec![];
match liberated_sig.output().kind() {
- ty::Dynamic(predicates, _) => {
+ ty::Dynamic(predicates, _, ty::Dyn) => {
let cause = ObligationCause::misc(ret_ty.span, fn_hir_id);
let param_env = ty::ParamEnv::empty();
@@ -1523,7 +1664,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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();
+ let typeck_results = self.typeck_results.as_ref().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);
@@ -1539,34 +1680,41 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
found_span: Option<Span>,
found: ty::PolyTraitRef<'tcx>,
expected: ty::PolyTraitRef<'tcx>,
+ cause: &ObligationCauseCode<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
pub(crate) fn build_fn_sig_ty<'tcx>(
- tcx: TyCtxt<'tcx>,
+ infcx: &InferCtxt<'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() =>
+ if infcx.tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
{
- tcx.mk_fn_sig(
+ infcx.tcx.mk_fn_sig(
inputs.iter(),
- tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+ infcx.next_ty_var(TypeVariableOrigin {
+ span: DUMMY_SP,
+ kind: TypeVariableOriginKind::MiscVariable,
+ }),
false,
hir::Unsafety::Normal,
abi::Abi::Rust,
)
}
- _ => tcx.mk_fn_sig(
+ _ => infcx.tcx.mk_fn_sig(
std::iter::once(inputs),
- tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+ infcx.next_ty_var(TypeVariableOrigin {
+ span: DUMMY_SP,
+ kind: TypeVariableOriginKind::MiscVariable,
+ }),
false,
hir::Unsafety::Normal,
abi::Abi::Rust,
),
};
- tcx.mk_fn_ptr(trait_ref.rebind(sig))
+ infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig))
}
let argument_kind = match expected.skip_binder().self_ty().kind() {
@@ -1586,18 +1734,76 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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 = build_fn_sig_ty(self, expected);
+ let found = build_fn_sig_ty(self, found);
- let (expected_str, found_str) =
- self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found));
+ let (expected_str, found_str) = self.cmp(expected, found);
let signature_kind = format!("{argument_kind} signature");
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
+ self.note_conflicting_closure_bounds(cause, &mut err);
+
err
}
+ // Add a note if there are two `Fn`-family bounds that have conflicting argument
+ // requirements, which will always cause a closure to have a type error.
+ fn note_conflicting_closure_bounds(
+ &self,
+ cause: &ObligationCauseCode<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ ) {
+ // First, look for an `ExprBindingObligation`, which means we can get
+ // the unsubstituted predicate list of the called function. And check
+ // that the predicate that we failed to satisfy is a `Fn`-like trait.
+ if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
+ && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
+ && let Some(pred) = predicates.predicates.get(*idx)
+ && let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder()
+ && ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()).is_some()
+ {
+ let expected_self =
+ self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
+ let expected_substs = self
+ .tcx
+ .anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs));
+
+ // Find another predicate whose self-type is equal to the expected self type,
+ // but whose substs don't match.
+ let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
+ .enumerate()
+ .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(trait_pred)
+ if ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id())
+ .is_some()
+ && other_idx != idx
+ // Make sure that the self type matches
+ // (i.e. constraining this closure)
+ && expected_self
+ == self.tcx.anonymize_late_bound_regions(
+ pred.kind().rebind(trait_pred.self_ty()),
+ )
+ // But the substs don't match (i.e. incompatible args)
+ && expected_substs
+ != self.tcx.anonymize_late_bound_regions(
+ pred.kind().rebind(trait_pred.trait_ref.substs),
+ ) =>
+ {
+ true
+ }
+ _ => false,
+ });
+ // If we found one, then it's very likely the cause of the error.
+ if let Some((_, (_, other_pred_span))) = other_pred {
+ err.span_note(
+ *other_pred_span,
+ "closure inferred to have a different signature due to this bound",
+ );
+ }
+ }
+ }
+
fn suggest_fully_qualified_path(
&self,
err: &mut Diagnostic,
@@ -1786,12 +1992,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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),
+ typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner),
?span,
);
@@ -1846,7 +2051,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+ let generator_data: Option<GeneratorData<'tcx, '_>> = match &self.typeck_results {
Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
Some(GeneratorData::Local(&t))
}
@@ -2201,7 +2406,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::QuestionMark
| ObligationCauseCode::CheckAssociatedTypeBounds { .. }
| ObligationCauseCode::LetElse
- | ObligationCauseCode::BinOp { .. } => {}
+ | ObligationCauseCode::BinOp { .. }
+ | ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
@@ -2223,11 +2429,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
region, object_ty,
));
}
- ObligationCauseCode::ItemObligation(_item_def_id) => {
+ ObligationCauseCode::ItemObligation(_)
+ | ObligationCauseCode::ExprItemObligation(..) => {
// 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) => {
+ ObligationCauseCode::BindingObligation(item_def_id, span)
+ | ObligationCauseCode::ExprBindingObligation(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) {
@@ -2537,9 +2745,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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()
+ "required for `{}` to implement `{}`",
+ parent_trait_pred.skip_binder().self_ty(),
+ parent_trait_pred.print_modifiers_and_trait_path()
);
let mut is_auto_trait = false;
match self.tcx.hir().get_if_local(data.impl_def_id) {
@@ -2608,9 +2816,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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()
+ "required for `{}` to implement `{}`",
+ parent_trait_pred.skip_binder().self_ty(),
+ parent_trait_pred.print_modifiers_and_trait_path()
));
}
// #74711: avoid a stack overflow
@@ -2649,19 +2857,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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 {
+ let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
Some(t) if t.hir_owner == parent_id => t,
- _ => self.tcx.typeck(parent_id),
+ _ => self.tcx.typeck(parent_id.def_id),
};
- let ty = typeck_results.expr_ty_adjusted(expr);
- let span = expr.peel_blocks().span;
+ let expr = expr.peel_blocks();
+ let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
+ let span = expr.span;
if Some(span) != err.span.primary_span() {
err.span_label(
span,
- &if ty.references_error() {
+ if ty.references_error() {
String::new()
} else {
format!("this tail expression is of type `{:?}`", ty)
@@ -2738,19 +2945,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
- 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())
)]
@@ -2832,19 +3026,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
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,
- );
- }
- _ => {}
+ if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind()
+ && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind()
+ {
+ err.span_suggestion_verbose(
+ rhs_span.shrink_to_hi(),
+ "consider using a floating-point literal by writing it with `.0`",
+ ".0",
+ Applicability::MaybeIncorrect,
+ );
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 556ef466c..a417e1440 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -25,10 +25,9 @@ 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 _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// Note that we include both the `ParamEnv` and the `Predicate`,
@@ -103,7 +102,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
}
/// Attempts to select obligations using `selcx`.
- fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select(&mut self, selcx: SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
@@ -135,10 +134,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
/// `SomeTrait` or a where-clause that lets us unify `$0` with
/// something concrete. If this fails, we'll unify `$0` with
/// `projection_ty` again.
- #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))]
+ #[instrument(level = "debug", skip(self, infcx, param_env, cause))]
fn normalize_projection_type(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
@@ -166,7 +165,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) {
// this helps to reduce duplicate errors, as well as making
@@ -183,7 +182,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_where_possible(infcx);
if !errors.is_empty() {
@@ -194,12 +193,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Vec<FulfillmentError<'tcx>> {
- let mut selcx = SelectionContext::new(infcx);
- self.select(&mut selcx)
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ let selcx = SelectionContext::new(infcx);
+ self.select(selcx)
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
@@ -211,8 +207,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
}
}
-struct FulfillProcessor<'a, 'b, 'tcx> {
- selcx: &'a mut SelectionContext<'b, 'tcx>,
+struct FulfillProcessor<'a, 'tcx> {
+ selcx: SelectionContext<'a, 'tcx>,
}
fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
@@ -221,9 +217,10 @@ fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligatio
.collect()
}
-impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
+impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
type Obligation = PendingPredicateObligation<'tcx>;
type Error = FulfillmentErrorCode<'tcx>;
+ type OUT = Outcome<Self::Obligation, Self::Error>;
/// Identifies whether a predicate obligation needs processing.
///
@@ -279,7 +276,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
debug!(?obligation, "pre-resolve");
- if obligation.predicate.has_infer_types_or_consts() {
+ if obligation.predicate.has_non_region_infer() {
obligation.predicate =
self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
}
@@ -291,7 +288,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
if obligation.predicate.has_projections() {
let mut obligations = Vec::new();
let predicate = crate::traits::project::try_normalize_with_depth_to(
- self.selcx,
+ &mut self.selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
@@ -358,7 +355,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
ty::PredicateKind::RegionOutlives(data) => {
- if infcx.considering_regions || data.has_placeholders() {
+ if infcx.considering_regions {
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
}
@@ -427,16 +424,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
obligation.param_env,
Binder::dummy(subtype),
) {
- None => {
+ Err((a, b)) => {
// 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(),
- ];
+ pending_obligation.stalled_on =
+ vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
ProcessResult::Unchanged
}
- Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
- Some(Err(err)) => {
+ Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+ Ok(Err(err)) => {
let expected_found =
ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
@@ -453,16 +448,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
obligation.param_env,
Binder::dummy(coerce),
) {
- None => {
+ Err((a, b)) => {
// 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(),
- ];
+ pending_obligation.stalled_on =
+ vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
ProcessResult::Unchanged
}
- Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
- Some(Err(err)) => {
+ Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+ Ok(Err(err)) => {
let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
expected_found,
@@ -483,9 +476,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend(
- uv.substs
- .iter()
- .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+ uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
ProcessResult::Unchanged
}
@@ -499,23 +490,20 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
ty::PredicateKind::ConstEquate(c1, c2) => {
+ assert!(
+ self.selcx.tcx().features().generic_const_exprs,
+ "`ConstEquate` without a feature gate: {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![]);
- }
+ // 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, b, obligation.param_env) {
+ return ProcessResult::Changed(vec![]);
}
}
@@ -577,7 +565,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ if c1.has_non_region_infer() || c2.has_non_region_infer() {
ProcessResult::Unchanged
} else {
// Two different constants using generic parameters ~> error.
@@ -597,23 +585,26 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
}
+ #[inline(never)]
fn process_backedge<'c, I>(
&mut self,
cycle: I,
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
- ) where
+ ) -> Result<(), FulfillmentErrorCode<'tcx>>
+ where
I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
{
if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
debug!("process_child_obligations: coinductive match");
+ Ok(())
} else {
let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
- self.selcx.infcx().report_overflow_error_cycle(&cycle);
+ Err(FulfillmentErrorCode::CodeCycle(cycle))
}
}
}
-impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
+impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
#[instrument(level = "debug", skip(self, obligation, stalled_on))]
fn process_trait_obligation(
&mut self,
@@ -648,7 +639,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
// information about the types in the trait.
stalled_on.clear();
stalled_on.extend(substs_infer_vars(
- self.selcx,
+ &self.selcx,
trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
));
@@ -700,12 +691,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
}
}
- match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
+ match project::poly_project_and_unify_type(&mut 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,
+ &self.selcx,
project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
));
ProcessResult::Unchanged
@@ -723,7 +714,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
/// Returns the set of inference variables contained in `substs`.
fn substs_infer_vars<'a, 'tcx>(
- selcx: &mut SelectionContext<'a, 'tcx>,
+ selcx: &SelectionContext<'a, 'tcx>,
substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
selcx
@@ -731,11 +722,11 @@ fn substs_infer_vars<'a, 'tcx>(
.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())
+ .filter(|arg| arg.has_non_region_infer())
.flat_map(|arg| {
let mut walker = arg.walk();
while let Some(c) = walker.next() {
- if !c.has_infer_types_or_consts() {
+ if !c.has_non_region_infer() {
walker.visited.remove(&c);
walker.skip_current_subtree();
}
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index dd2769c71..be603c609 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -7,7 +7,7 @@ use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
-use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
@@ -23,66 +23,64 @@ pub fn can_type_implement_copy<'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(()),
+ let infcx = tcx.infer_ctxt().build();
+ 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),
+ ty::Adt(adt, substs) => (adt, substs),
- _ => return Err(CopyImplementationError::NotAnAdt),
- };
+ _ => 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);
- }
- };
+ 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_non_region_param()
+ {
+ parent_cause.clone()
+ } else {
+ ObligationCause::dummy_with_span(span)
+ };
+ match traits::fully_normalize(&infcx, cause, param_env, ty) {
+ Ok(ty) => {
+ if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+ infringing.push((field, ty));
+ }
+ }
+ Err(errors) => {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ };
}
- if !infringing.is_empty() {
- return Err(CopyImplementationError::InfrigingFields(infringing));
- }
- if adt.has_dtor(tcx) {
- return Err(CopyImplementationError::HasDestructor);
- }
+ }
+ if !infringing.is_empty() {
+ return Err(CopyImplementationError::InfrigingFields(infringing));
+ }
+ if adt.has_dtor(tcx) {
+ return Err(CopyImplementationError::HasDestructor);
+ }
- Ok(())
- })
+ Ok(())
}
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 9c6bb0731..0bf54c096 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -13,6 +13,7 @@ mod fulfill;
pub mod misc;
mod object_safety;
mod on_unimplemented;
+pub mod outlives_bounds;
mod project;
pub mod query;
pub(crate) mod relationships;
@@ -22,18 +23,22 @@ mod structural_match;
mod util;
pub mod wf;
+use crate::errors::DumpVTableEntries;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, TyCtxtInferExt};
-use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::error_reporting::TypeErrCtxtExt 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_infer::traits::TraitEngineExt as _;
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_middle::ty::{
+ self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, VtblEntry,
+};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
@@ -113,11 +118,21 @@ pub enum TraitQueryMode {
/// Creates predicate obligations from the generic bounds.
pub fn predicates_for_generics<'tcx>(
- cause: ObligationCause<'tcx>,
+ cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
generic_bounds: ty::InstantiatedPredicates<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
- util::predicates_for_generics(cause, 0, param_env, generic_bounds)
+ let generic_bounds = generic_bounds;
+ debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);
+
+ std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map(
+ move |(idx, (predicate, span))| Obligation {
+ cause: cause(idx, span),
+ recursion_depth: 0,
+ param_env,
+ predicate,
+ },
+ )
}
/// Determines whether the type `ty` is known to meet `bound` and
@@ -125,8 +140,8 @@ pub fn predicates_for_generics<'tcx>(
/// `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>,
+pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
@@ -155,28 +170,26 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
result
);
- if result && ty.has_infer_types_or_consts() {
+ if result && ty.has_non_region_infer() {
// 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 = <dyn TraitEngine<'tcx>>::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);
+ // 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 errors = fully_solve_bound(infcx, cause, param_env, ty, def_id);
// 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() {
+ match &errors[..] {
[] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
@@ -221,56 +234,51 @@ fn do_normalize_predicates<'tcx>(
// 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);
- }
- };
+ let infcx = tcx.infer_ctxt().ignoring_regions().build();
+ let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
+ Ok(predicates) => predicates,
+ Err(errors) => {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
+ };
+
+ debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
- 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);
- // 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:?}"),
+ );
+ }
- // 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(
+ 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,
- format!(
- "failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
- ),
+ "inference variables in normalized parameter environment: {}",
+ fixup_err
);
}
-
- 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 ...
@@ -381,9 +389,9 @@ pub fn normalize_param_env_or_error<'tcx>(
)
}
-pub fn fully_normalize<'a, 'tcx, T>(
- infcx: &InferCtxt<'a, 'tcx>,
- mut fulfill_cx: FulfillmentContext<'tcx>,
+/// Normalize a type and process all resulting obligations, returning any errors
+pub fn fully_normalize<'tcx, T>(
+ infcx: &InferCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: T,
@@ -399,8 +407,10 @@ where
"fully_normalize: normalized_value={:?} obligations={:?}",
normalized_value, obligations
);
+
+ let mut fulfill_cx = FulfillmentContext::new();
for obligation in obligations {
- fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
+ fulfill_cx.register_predicate_obligation(infcx, obligation);
}
debug!("fully_normalize: select_all_or_error start");
@@ -414,6 +424,43 @@ where
Ok(resolved_value)
}
+/// Process an obligation (and any nested obligations that come from it) to
+/// completion, returning any errors
+pub fn fully_solve_obligation<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ obligation: PredicateObligation<'tcx>,
+) -> Vec<FulfillmentError<'tcx>> {
+ let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ engine.register_predicate_obligation(infcx, obligation);
+ engine.select_all_or_error(infcx)
+}
+
+/// Process a set of obligations (and any nested obligations that come from them)
+/// to completion
+pub fn fully_solve_obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+) -> Vec<FulfillmentError<'tcx>> {
+ let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ engine.register_predicate_obligations(infcx, obligations);
+ engine.select_all_or_error(infcx)
+}
+
+/// Process a bound (and any nested obligations that come from it) to completion.
+/// This is a convenience function for traits that have no generic arguments, such
+/// as auto traits, and builtin traits like Copy or Sized.
+pub fn fully_solve_bound<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ bound: DefId,
+) -> Vec<FulfillmentError<'tcx>> {
+ let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ engine.register_bound(infcx, param_env, ty, bound, cause);
+ engine.select_all_or_error(infcx)
+}
+
/// 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.
@@ -423,31 +470,20 @@ pub fn impossible_predicates<'tcx>(
) -> 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);
+ let infcx = tcx.infer_ctxt().build();
+ let param_env = ty::ParamEnv::reveal_all();
+ let ocx = ObligationCtxt::new(&infcx);
+ let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
+ for predicate in predicates {
+ let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+ ocx.register_obligation(obligation);
+ }
+ let errors = ocx.select_all_or_error();
- // Clean up after ourselves
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- !errors.is_empty()
- });
+ let result = !errors.is_empty();
debug!("impossible_predicates = {:?}", result);
result
}
@@ -474,6 +510,82 @@ fn subst_and_check_impossible_predicates<'tcx>(
result
}
+/// Checks whether a trait's method is impossible to call on a given impl.
+///
+/// This only considers predicates that reference the impl's generics, and not
+/// those that reference the method's generics.
+fn is_impossible_method<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (impl_def_id, trait_item_def_id): (DefId, DefId),
+) -> bool {
+ struct ReferencesOnlyParentGenerics<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx ty::Generics,
+ trait_item_def_id: DefId,
+ }
+ impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
+ type BreakTy = ();
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // If this is a parameter from the trait item's own generics, then bail
+ if let ty::Param(param) = t.kind()
+ && let param_def_id = self.generics.type_param(param, self.tcx).def_id
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
+ {
+ return ControlFlow::BREAK;
+ }
+ t.super_visit_with(self)
+ }
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ReEarlyBound(param) = r.kind()
+ && let param_def_id = self.generics.region_param(&param, self.tcx).def_id
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
+ {
+ return ControlFlow::BREAK;
+ }
+ r.super_visit_with(self)
+ }
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ConstKind::Param(param) = ct.kind()
+ && let param_def_id = self.generics.const_param(&param, self.tcx).def_id
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
+ {
+ return ControlFlow::BREAK;
+ }
+ ct.super_visit_with(self)
+ }
+ }
+
+ let generics = tcx.generics_of(trait_item_def_id);
+ let predicates = tcx.predicates_of(trait_item_def_id);
+ let impl_trait_ref =
+ tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
+ let param_env = tcx.param_env(impl_def_id);
+
+ let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
+ let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
+ if pred.visit_with(&mut visitor).is_continue() {
+ Some(Obligation::new(
+ ObligationCause::dummy_with_span(*span),
+ param_env,
+ ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
+ ))
+ } else {
+ None
+ }
+ });
+
+ let infcx = tcx.infer_ctxt().ignoring_regions().build();
+ for obligation in predicates_for_trait {
+ // Ignore overflow error, to be conservative.
+ if let Ok(result) = infcx.evaluate_obligation(&obligation)
+ && !result.may_apply()
+ {
+ return true;
+ }
+ }
+ false
+}
+
#[derive(Clone, Debug)]
enum VtblSegment<'tcx> {
MetadataDSA,
@@ -645,16 +757,16 @@ fn dump_vtable_entries<'tcx>(
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();
+ tcx.sess.emit_err(DumpVTableEntries {
+ span: sp,
+ trait_ref,
+ entries: format!("{:#?}", entries),
+ });
}
-fn own_existential_vtable_entries<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_ref: ty::PolyExistentialTraitRef<'tcx>,
-) -> &'tcx [DefId] {
+fn own_existential_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> &'tcx [DefId] {
let trait_methods = tcx
- .associated_items(trait_ref.def_id())
+ .associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);
// Now list each method's DefId (for within its trait).
@@ -663,7 +775,7 @@ fn own_existential_vtable_entries<'tcx>(
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) {
+ if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) {
debug!("own_existential_vtable_entry: not vtable safe");
return None;
}
@@ -695,7 +807,7 @@ fn vtable_entries<'tcx>(
// Lookup the shape of vtable for the trait.
let own_existential_entries =
- tcx.own_existential_vtable_entries(existential_trait_ref);
+ tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
let own_entries = own_existential_entries.iter().copied().map(|def_id| {
debug!("vtable_entries: trait_method={:?}", def_id);
@@ -831,10 +943,9 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
}),
);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation).unwrap()
- });
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let implsrc = selcx.select(&obligation).unwrap();
let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
bug!();
@@ -849,11 +960,12 @@ pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
- codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
+ codegen_select_candidate: codegen::codegen_select_candidate,
own_existential_vtable_entries,
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
subst_and_check_impossible_predicates,
+ is_impossible_method,
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)
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 612f51309..0bb25a74d 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -8,19 +8,20 @@
//! - not reference the erased type `Self` except for in this receiver;
//! - not have generic type parameters.
-use super::elaborate_predicates;
+use super::{elaborate_predicates, elaborate_trait_ref};
use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
-use rustc_errors::{FatalError, MultiSpan};
+use hir::def::DefKind;
+use rustc_errors::{DelayDm, 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::{GenericArg, InternalSubsts};
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
@@ -163,37 +164,42 @@ fn lint_object_unsafe_trait(
) {
// 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()
- ),
+ tcx.struct_span_lint_hir(
+ WHERE_CLAUSES_OBJECT_SAFETY,
+ hir::CRATE_HIR_ID,
+ span,
+ DelayDm(|| format!("the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id))),
+ |err| {
+ 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 \
+ <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
);
- };
- 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 \
- <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
- );
- if node.is_some() {
- // Only provide the help if its a local trait, otherwise it's not
- violation.solution(&mut err);
- }
- err.emit();
- });
+ if node.is_some() {
+ // Only provide the help if its a local trait, otherwise it's not
+ violation.solution(err);
+ }
+ err
+ },
+ );
}
fn sized_trait_bound_spans<'tcx>(
@@ -431,6 +437,9 @@ fn virtual_call_violation_for_method<'tcx>(
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
return Some(MethodViolationCode::ReferencesSelfOutput);
}
+ if contains_illegal_impl_trait_in_trait(tcx, sig.output()) {
+ return Some(MethodViolationCode::ReferencesImplTraitInTrait);
+ }
// We can't monomorphize things like `fn foo<A>(...)`.
let own_counts = tcx.generics_of(method.def_id).own_counts();
@@ -438,19 +447,6 @@ fn virtual_call_violation_for_method<'tcx>(
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.
@@ -529,6 +525,21 @@ fn virtual_call_violation_for_method<'tcx>(
}
}
+ // NOTE: This check happens last, because it results in a lint, and not a
+ // hard error.
+ 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);
+ }
+
None
}
@@ -556,51 +567,44 @@ fn receiver_for_self_ty<'tcx>(
/// Creates the object type for the current trait. For example,
/// if the current trait is `Deref`, then this will be
/// `dyn Deref<Target = Self::Target> + 'static`.
+#[instrument(level = "trace", skip(tcx), ret)]
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);
+ debug!(?trait_ref);
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::<Vec<_>>();
-
- // existential predicates need to be in a specific order
- associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
-
- let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
- // We *can* get bound lifetimes here in cases like
- // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
- 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,
- })
+ debug!(?trait_predicate);
+
+ let mut elaborated_predicates: Vec<_> = elaborate_trait_ref(tcx, trait_ref)
+ .filter_map(|obligation| {
+ debug!(?obligation);
+ let pred = obligation.predicate.to_opt_poly_projection_pred()?;
+ Some(pred.map_bound(|p| {
+ ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+ item_def_id: p.projection_ty.item_def_id,
+ substs: p.projection_ty.substs,
+ term: p.term,
+ })
+ }))
})
- });
+ .collect();
+ // NOTE: Since #37965, the existential predicates list has depended on the
+ // list of predicates to be sorted. This is mostly to enforce that the primary
+ // predicate comes first.
+ elaborated_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
+ elaborated_predicates.dedup();
let existential_predicates = tcx
- .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
+ .mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates));
+ debug!(?existential_predicates);
- let object_ty = tcx.mk_dynamic(existential_predicates, lifetime);
-
- debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
-
- object_ty
+ tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
}
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
@@ -725,10 +729,9 @@ fn receiver_is_dispatchable<'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)
- })
+ let infcx = tcx.infer_ctxt().build();
+ // 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>>(
@@ -793,6 +796,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
ControlFlow::CONTINUE
}
}
+ ty::Projection(ref data)
+ if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
+ {
+ // We'll deny these later in their own pass
+ ControlFlow::CONTINUE
+ }
ty::Projection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
@@ -828,21 +837,14 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
}
}
- fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
// 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
+ // If `AbstractConst::from_const` 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()) {
+ if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
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),
@@ -851,7 +853,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
}
})
} else {
- ControlFlow::CONTINUE
+ ct.super_visit_with(self)
}
}
}
@@ -861,6 +863,22 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
.is_break()
}
+pub fn contains_illegal_impl_trait_in_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: ty::Binder<'tcx, Ty<'tcx>>,
+) -> bool {
+ // FIXME(RPITIT): Perhaps we should use a visitor here?
+ ty.skip_binder().walk().any(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Projection(proj) = ty.kind()
+ {
+ tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+ } else {
+ false
+ }
+ })
+}
+
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
index 9227bbf01..4a4f34b76 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -8,6 +8,10 @@ use rustc_parse_format::{ParseMode, Parser, Piece, Position};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
+use crate::errors::{
+ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
+
#[derive(Clone, Debug)]
pub struct OnUnimplementedFormatString(Symbol);
@@ -18,7 +22,7 @@ pub struct OnUnimplementedDirective {
pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>,
pub note: Option<OnUnimplementedFormatString>,
- pub enclosing_scope: Option<OnUnimplementedFormatString>,
+ pub parent_label: Option<OnUnimplementedFormatString>,
pub append_const_msg: Option<Option<Symbol>>,
}
@@ -27,7 +31,7 @@ pub struct OnUnimplementedNote {
pub message: Option<String>,
pub label: Option<String>,
pub note: Option<String>,
- pub enclosing_scope: Option<String>,
+ pub parent_label: Option<String>,
/// 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
@@ -35,21 +39,6 @@ pub struct OnUnimplementedNote {
pub append_const_msg: Option<Option<Symbol>>,
}
-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>,
@@ -70,25 +59,9 @@ impl<'tcx> OnUnimplementedDirective {
} 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,
- )
- })?
+ .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
.meta_item()
- .ok_or_else(|| {
- parse_error(
- tcx,
- span,
- "invalid `on`-clause in `#[rustc_on_unimplemented]`",
- "invalid on-clause here",
- None,
- )
- })?;
+ .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
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);
@@ -101,7 +74,7 @@ impl<'tcx> OnUnimplementedDirective {
let mut message = None;
let mut label = None;
let mut note = None;
- let mut enclosing_scope = None;
+ let mut parent_label = None;
let mut subcommands = vec![];
let mut append_const_msg = None;
@@ -121,9 +94,9 @@ impl<'tcx> OnUnimplementedDirective {
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_)?;
+ } else if item.has_name(sym::parent_label) && parent_label.is_none() {
+ if let Some(parent_label_) = item.value_str() {
+ parent_label = parse_value(parent_label_)?;
continue;
}
} else if item.has_name(sym::on)
@@ -150,13 +123,7 @@ impl<'tcx> OnUnimplementedDirective {
}
// 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")]`"#),
- );
+ tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
}
if let Some(reported) = errored {
@@ -168,7 +135,7 @@ impl<'tcx> OnUnimplementedDirective {
message,
label,
note,
- enclosing_scope,
+ parent_label,
append_const_msg,
})
}
@@ -193,7 +160,7 @@ impl<'tcx> OnUnimplementedDirective {
attr.span,
)?),
note: None,
- enclosing_scope: None,
+ parent_label: None,
append_const_msg: None,
}))
} else {
@@ -214,7 +181,7 @@ impl<'tcx> OnUnimplementedDirective {
let mut message = None;
let mut label = None;
let mut note = None;
- let mut enclosing_scope = None;
+ let mut parent_label = None;
let mut append_const_msg = None;
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
@@ -250,8 +217,8 @@ impl<'tcx> OnUnimplementedDirective {
note = Some(note_.clone());
}
- if let Some(ref enclosing_scope_) = command.enclosing_scope {
- enclosing_scope = Some(enclosing_scope_.clone());
+ if let Some(ref parent_label_) = command.parent_label {
+ parent_label = Some(parent_label_.clone());
}
append_const_msg = command.append_const_msg;
@@ -261,7 +228,7 @@ impl<'tcx> OnUnimplementedDirective {
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)),
+ parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
append_const_msg,
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
new file mode 100644
index 000000000..108dae092
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -0,0 +1,115 @@
+use crate::infer::InferCtxt;
+use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
+use crate::traits::query::NoSolution;
+use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_hir::HirId;
+use rustc_middle::ty::{self, ParamEnv, Ty};
+
+pub use rustc_middle::traits::query::OutlivesBound;
+
+type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
+pub trait InferCtxtExt<'a, 'tcx> {
+ fn implied_outlives_bounds(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ ty: Ty<'tcx>,
+ ) -> Vec<OutlivesBound<'tcx>>;
+
+ fn implied_bounds_tys(
+ &'a self,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ tys: FxHashSet<Ty<'tcx>>,
+ ) -> Bounds<'a, 'tcx>;
+}
+
+impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
+ /// Implied bounds are region relationships that we deduce
+ /// automatically. The idea is that (e.g.) a caller must check that a
+ /// function's argument types are well-formed immediately before
+ /// calling that fn, and hence the *callee* can assume that its
+ /// argument types are well-formed. This may imply certain relationships
+ /// between generic parameters. For example:
+ /// ```
+ /// fn foo<'a,T>(x: &'a T) {}
+ /// ```
+ /// can only be called with a `'a` and `T` such that `&'a T` is WF.
+ /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
+ ///
+ /// # Parameters
+ ///
+ /// - `param_env`, the where-clauses in scope
+ /// - `body_id`, the body-id to use when normalizing assoc types.
+ /// Note that this may cause outlives obligations to be injected
+ /// into the inference context with this body-id.
+ /// - `ty`, the type that we are supposed to assume is WF.
+ #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
+ fn implied_outlives_bounds(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ ty: Ty<'tcx>,
+ ) -> Vec<OutlivesBound<'tcx>> {
+ let span = self.tcx.hir().span(body_id);
+ let result = param_env
+ .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
+ .fully_perform(self);
+ let result = match result {
+ Ok(r) => r,
+ Err(NoSolution) => {
+ self.tcx.sess.delay_span_bug(
+ span,
+ "implied_outlives_bounds failed to solve all obligations",
+ );
+ return vec![];
+ }
+ };
+
+ let TypeOpOutput { output, constraints, .. } = result;
+
+ if let Some(constraints) = constraints {
+ debug!(?constraints);
+ // Instantiation may have produced new inference variables and constraints on those
+ // variables. Process these constraints.
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
+ let cause = ObligationCause::misc(span, body_id);
+ for &constraint in &constraints.outlives {
+ let obligation = self.query_outlives_constraint_to_obligation(
+ constraint,
+ cause.clone(),
+ param_env,
+ );
+ fulfill_cx.register_predicate_obligation(self, obligation);
+ }
+ if !constraints.member_constraints.is_empty() {
+ span_bug!(span, "{:#?}", constraints.member_constraints);
+ }
+ let errors = fulfill_cx.select_all_or_error(self);
+ if !errors.is_empty() {
+ self.tcx.sess.delay_span_bug(
+ span,
+ "implied_outlives_bounds failed to solve obligations from instantiation",
+ );
+ }
+ };
+
+ output
+ }
+
+ fn implied_bounds_tys(
+ &'a self,
+ param_env: ParamEnv<'tcx>,
+ body_id: HirId,
+ tys: FxHashSet<Ty<'tcx>>,
+ ) -> Bounds<'a, 'tcx> {
+ tys.into_iter()
+ .map(move |ty| {
+ let ty = self.resolve_vars_if_possible(ty);
+ self.implied_outlives_bounds(param_env, body_id, ty)
+ })
+ .flatten()
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index c4e80e1ba..e4284b9d3 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -18,7 +18,7 @@ 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::error_reporting::TypeErrCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::select::ProjectionMatchesProjection;
use rustc_data_structures::sso::SsoHashSet;
@@ -30,8 +30,8 @@ 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::DefIdTree;
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
@@ -62,7 +62,8 @@ 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 <<A as Trait>::B as Trait2>::C
+ /// From the definition of `Trait` when you have something like
+ /// `<<A as Trait>::B as Trait2>::C`.
TraitDef(ty::PolyProjectionPredicate<'tcx>),
/// Bounds specified on an object type
@@ -70,6 +71,16 @@ enum ProjectionCandidate<'tcx> {
/// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
+
+ ImplTraitInTrait(ImplTraitInTraitCandidate<'tcx>),
+}
+
+#[derive(PartialEq, Eq, Debug)]
+enum ImplTraitInTraitCandidate<'tcx> {
+ // The `impl Trait` from a trait function's default body
+ Trait,
+ // A concrete type provided from a trait's `impl Trait` from an impl
+ Impl(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
}
enum ProjectionCandidateSet<'tcx> {
@@ -231,7 +242,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
/// 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))]
+#[instrument(level = "debug", skip(selcx))]
fn project_and_unify_type<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionObligation<'tcx>,
@@ -253,7 +264,7 @@ fn project_and_unify_type<'cx, 'tcx>(
};
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
+ // For an example where this is necessary 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 } =
@@ -511,7 +522,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
self.param_env,
ty,
);
- self.selcx.infcx().report_overflow_error(&obligation, true);
+ self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
}
let substs = substs.fold_with(self);
@@ -552,7 +563,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
)
.ok()
.flatten()
- .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+ .unwrap_or_else(|| ty.super_fold_with(self).into())
};
debug!(
?self.depth,
@@ -620,19 +631,33 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
#[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 {
+ let tcx = self.selcx.tcx();
+ if tcx.lazy_normalization() {
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)
+ debug!(?constant, ?self.param_env);
+ with_replaced_escaping_bound_vars(
+ self.selcx.infcx(),
+ &mut self.universes,
+ constant,
+ |constant| constant.eval(tcx, self.param_env),
+ )
+ }
+ }
+
+ #[inline]
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+ p.super_fold_with(self)
+ } else {
+ p
}
}
}
pub struct BoundVarReplacer<'me, 'tcx> {
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'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).
@@ -647,11 +672,46 @@ pub struct BoundVarReplacer<'me, 'tcx> {
universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
}
+/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
+/// and then replaces these placeholders with the original bound variables in the result.
+///
+/// In most places, bound variables should be replaced right when entering a binder, making
+/// this function unnecessary. However, normalization currently does not do that, so we have
+/// to do this lazily.
+///
+/// You should not add any additional uses of this function, at least not without first
+/// discussing it with t-types.
+///
+/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
+/// normalization as well, at which point this function will be unnecessary and can be removed.
+pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>(
+ infcx: &'a InferCtxt<'tcx>,
+ universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
+ value: T,
+ f: impl FnOnce(T) -> R,
+) -> R {
+ if value.has_escaping_bound_vars() {
+ let (value, mapped_regions, mapped_types, mapped_consts) =
+ BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
+ let result = f(value);
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ universe_indices,
+ result,
+ )
+ } else {
+ f(value)
+ }
+}
+
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<T: TypeFoldable<'tcx>>(
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
value: T,
) -> (
@@ -771,7 +831,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
pub struct PlaceholderReplacer<'me, 'tcx> {
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
@@ -781,7 +841,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> {
impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
pub fn replace_placeholders<T: TypeFoldable<'tcx>>(
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
@@ -1182,7 +1242,7 @@ impl<'tcx> Progress<'tcx> {
///
/// IMPORTANT:
/// - `obligation` must be fully normalized
-#[tracing::instrument(level = "info", skip(selcx))]
+#[instrument(level = "info", skip(selcx))]
fn project<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
@@ -1201,6 +1261,8 @@ fn project<'cx, 'tcx>(
let mut candidates = ProjectionCandidateSet::None;
+ assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates);
+
// 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.
@@ -1239,6 +1301,63 @@ fn project<'cx, 'tcx>(
}
}
+/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the
+/// corresponding trait ref. If this yields an `impl`, then we're able to project
+/// to a concrete type, since we have an `impl`'s method to provide the RPITIT.
+fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+ let tcx = selcx.tcx();
+ if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+ let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+ // If we are trying to project an RPITIT with trait's default `Self` parameter,
+ // then we must be within a default trait body.
+ if obligation.predicate.self_ty()
+ == ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.item_def_id)
+ .type_at(0)
+ && tcx.associated_item(trait_fn_def_id).defaultness(tcx).has_value()
+ {
+ candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
+ ImplTraitInTraitCandidate::Trait,
+ ));
+ return;
+ }
+
+ let trait_def_id = tcx.parent(trait_fn_def_id);
+ let trait_substs =
+ obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
+ // FIXME(named-returns): Binders
+ let trait_predicate =
+ ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs })
+ .to_poly_trait_predicate();
+
+ let _ =
+ selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
+ Ok(Some(super::ImplSource::UserDefined(data))) => {
+ candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
+ ImplTraitInTraitCandidate::Impl(data),
+ ));
+ Ok(())
+ }
+ Ok(None) => {
+ candidate_set.mark_ambiguous();
+ return Err(());
+ }
+ Ok(Some(_)) => {
+ // Don't know enough about the impl to provide a useful signature
+ return Err(());
+ }
+ Err(e) => {
+ debug!(error = ?e, "selection error");
+ candidate_set.mark_error(e);
+ return Err(());
+ }
+ });
+ }
+}
+
/// 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.
@@ -1257,7 +1376,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
);
}
-/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
+/// In the case of a nested projection like `<<A as Foo>::FooT as Bar>::BarT`, we may find
/// that the definition of `Foo` has some clues:
///
/// ```ignore (illustrative)
@@ -1344,7 +1463,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
);
}
-#[tracing::instrument(
+#[instrument(
level = "debug",
skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
)]
@@ -1378,7 +1497,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
candidate_set.push_candidate(ctor(data));
if potentially_unnormalized_candidates
- && !obligation.predicate.has_infer_types_or_consts()
+ && !obligation.predicate.has_non_region_infer()
{
// HACK: Pick the first trait def candidate for a fully
// inferred predicate. This is to allow duplicates that
@@ -1395,12 +1514,17 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
}
}
-#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))]
+#[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>,
) {
+ // Can't assemble candidate from impl for RPITIT
+ if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+ return;
+ }
+
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
@@ -1676,6 +1800,18 @@ fn confirm_candidate<'cx, 'tcx>(
ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source)
}
+ ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Impl(data)) => {
+ confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
+ }
+ // If we're projecting an RPITIT for a default trait body, that's just
+ // the same def-id, but as an opaque type (with regular RPIT semantics).
+ ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress {
+ term: selcx
+ .tcx()
+ .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .into(),
+ obligations: vec![],
+ },
};
// When checking for cycle during evaluation, we compare predicates with
@@ -2021,15 +2157,15 @@ fn confirm_impl_candidate<'cx, 'tcx>(
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));
+ let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::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() {
+ if !check_substs_compatible(tcx, &assoc_ty.item, substs) {
let err = tcx.ty_error_with_message(
obligation.cause.span,
- "impl item and trait item have different parameter counts",
+ "impl item and trait item have different parameters",
);
Progress { term: err.into(), obligations: nested }
} else {
@@ -2038,10 +2174,125 @@ fn confirm_impl_candidate<'cx, 'tcx>(
}
}
+// Verify that the trait item and its implementation have compatible substs lists
+fn check_substs_compatible<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ assoc_ty: &ty::AssocItem,
+ substs: ty::SubstsRef<'tcx>,
+) -> bool {
+ fn check_substs_compatible_inner<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx ty::Generics,
+ args: &'tcx [ty::GenericArg<'tcx>],
+ ) -> bool {
+ if generics.count() != args.len() {
+ return false;
+ }
+
+ let (parent_args, own_args) = args.split_at(generics.parent_count);
+
+ if let Some(parent) = generics.parent
+ && let parent_generics = tcx.generics_of(parent)
+ && !check_substs_compatible_inner(tcx, parent_generics, parent_args) {
+ return false;
+ }
+
+ for (param, arg) in std::iter::zip(&generics.params, own_args) {
+ match (&param.kind, arg.unpack()) {
+ (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
+ | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
+ | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
+ _ => return false,
+ }
+ }
+
+ true
+ }
+
+ check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
+}
+
+fn confirm_impl_trait_in_trait_candidate<'tcx>(
+ selcx: &mut SelectionContext<'_, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
+ let mut obligations = data.nested;
+
+ let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+ let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else {
+ return Progress { term: tcx.ty_error().into(), obligations };
+ };
+ if !leaf_def.item.defaultness(tcx).has_value() {
+ return Progress { term: tcx.ty_error().into(), obligations };
+ }
+
+ // Use the default `impl Trait` for the trait, e.g., for a default trait body
+ if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
+ return Progress {
+ term: tcx
+ .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .into(),
+ obligations,
+ };
+ }
+
+ let impl_fn_def_id = leaf_def.item.def_id;
+ // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
+ // since `data.substs` are the impl substs.
+ let impl_fn_substs =
+ obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
+
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::ItemObligation(impl_fn_def_id),
+ );
+ let predicates = normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
+ &mut obligations,
+ );
+ obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
+ |(pred, span)| {
+ Obligation::with_depth(
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ if span.is_dummy() {
+ super::ItemObligation(impl_fn_def_id)
+ } else {
+ super::BindingObligation(impl_fn_def_id, span)
+ },
+ ),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ pred,
+ )
+ },
+ ));
+
+ let ty = super::normalize_to(
+ selcx,
+ obligation.param_env,
+ cause.clone(),
+ tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
+ .map_bound(|tys| {
+ tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
+ })
+ .subst(tcx, impl_fn_substs),
+ &mut obligations,
+ );
+
+ Progress { term: ty.into(), obligations }
+}
+
// 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>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 32669e23d..c84f128dd 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -31,7 +31,7 @@ pub trait InferCtxtExt<'tcx> {
) -> EvaluationResult;
}
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// Evaluates whether the predicate can be satisfied (by any means)
/// in the given `ParamEnv`.
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 449d7a7b4..58e4597b7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -5,17 +5,16 @@
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::error_reporting::TypeErrCtxtExt;
+use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
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 rustc_span::DUMMY_SP;
use std::ops::ControlFlow;
@@ -48,10 +47,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
T: TypeFoldable<'tcx>,
{
debug!(
- "normalize::<{}>(value={:?}, param_env={:?})",
+ "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})",
std::any::type_name::<T>(),
value,
self.param_env,
+ self.cause,
);
if !needs_normalization(&value, self.param_env.reveal()) {
return Ok(Normalized { value, obligations: vec![] });
@@ -154,7 +154,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
}
struct QueryNormalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
cause: &'cx ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
@@ -213,7 +213,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
self.param_env,
ty,
);
- self.infcx.report_overflow_error(&obligation, true);
+ self.infcx.err_ctxt().report_overflow_error(&obligation, true);
}
let generic_ty = self.tcx().bound_type_of(def_id);
@@ -254,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
- bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+ // Rustdoc normalizes possibly not well-formed types, so only
+ // treat this as a bug if we're not in rustdoc.
+ if !tcx.sess.opts.actually_rustdoc {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+ );
+ }
+ return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
@@ -266,7 +274,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
- Ok(result.normalized_ty)
+
+ let res = result.normalized_ty;
+ // `tcx.normalize_projection_ty` may normalize to a type that still has
+ // unevaluated consts, so keep normalizing here if that's the case.
+ if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+ Ok(res.try_super_fold_with(self)?)
+ } else {
+ Ok(res)
+ }
}
ty::Projection(data) => {
@@ -275,11 +291,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
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,
- );
+ BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
let data = data.try_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
@@ -293,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
- bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+ // Rustdoc normalizes possibly not well-formed types, so only
+ // treat this as a bug if we're not in rustdoc.
+ if !tcx.sess.opts.actually_rustdoc {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+ );
+ }
+ return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
@@ -305,18 +325,26 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
- Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+ let res = PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.normalized_ty,
- ))
+ );
+ // `tcx.normalize_projection_ty` may normalize to a type that still has
+ // unevaluated consts, so keep normalizing here if that's the case.
+ if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+ Ok(res.try_super_fold_with(self)?)
+ } else {
+ Ok(res)
+ }
}
_ => ty.try_super_fold_with(self),
})()?;
+
self.cache.insert(ty, res);
Ok(res)
}
@@ -326,29 +354,24 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
constant: ty::Const<'tcx>,
) -> Result<ty::Const<'tcx>, Self::Error> {
let constant = constant.try_super_fold_with(self)?;
- Ok(constant.eval(self.infcx.tcx, self.param_env))
+ debug!(?constant, ?self.param_env);
+ Ok(crate::traits::project::with_replaced_escaping_bound_vars(
+ self.infcx,
+ &mut self.universes,
+ constant,
+ |constant| constant.eval(self.infcx.tcx, self.param_env),
+ ))
}
- fn try_fold_mir_const(
+ #[inline]
+ fn try_fold_predicate(
&mut self,
- constant: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, 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)?,
- })
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+ p.try_super_fold_with(self)
+ } else {
+ Ok(p)
+ }
}
}
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
index c99564936..6bf3ed0d0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,11 +1,9 @@
use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk};
-use crate::traits::engine::TraitEngineExt as _;
+use crate::traits;
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;
@@ -18,16 +16,16 @@ pub struct CustomTypeOp<F, G> {
impl<F, G> CustomTypeOp<F, G> {
pub fn new<'tcx, R>(closure: F, description: G) -> Self
where
- F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
+ F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
G: Fn() -> String,
{
CustomTypeOp { closure, description }
}
}
-impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
+impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
where
- F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
+ F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
G: Fn() -> String,
{
type Output = R;
@@ -38,7 +36,7 @@ where
/// 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<TypeOpOutput<'tcx, Self>> {
+ fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
if cfg!(debug_assertions) {
info!("fully_perform({:?})", self);
}
@@ -59,11 +57,9 @@ where
/// 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>,
+ infcx: &InferCtxt<'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::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
@@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
);
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);
+ let errors = traits::fully_solve_obligations(infcx, obligations);
if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
@@ -94,8 +89,8 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
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)),
+ .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()))
+ .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)),
&region_constraint_data,
);
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
index 578e1d00c..29ae8ae6b 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -26,13 +26,13 @@ pub use rustc_middle::traits::query::type_op::*;
/// extract out the resulting region constraints (or an error if it
/// cannot be completed).
pub trait TypeOp<'tcx>: Sized + fmt::Debug {
- type Output;
+ type Output: fmt::Debug;
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<TypeOpOutput<'tcx, Self>>;
+ fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
}
/// The output from performing a type op
@@ -78,7 +78,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
fn fully_perform_into(
query_key: ParamEnvAnd<'tcx, Self>,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
) -> Fallible<(
Self::QueryResponse,
@@ -120,7 +120,7 @@ where
type Output = Q::QueryResponse;
type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
- fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let mut region_constraints = QueryRegionConstraints::default();
let (output, error_info, mut obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index 8148e2b78..8cf500a46 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, ToPredicate};
pub(crate) fn update<'tcx, T>(
engine: &mut T,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>,
) where
T: TraitEngine<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index a60ce0f34..4c5bc3339 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -6,9 +6,10 @@
//!
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
use hir::LangItem;
+use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::ObligationCause;
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;
@@ -28,7 +29,7 @@ use super::SelectionCandidate::{self, *};
use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack};
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub(super) fn candidate_from_obligation<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
@@ -48,7 +49,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let Some(c) =
self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
{
- debug!(candidate = ?c, "CACHE HIT");
+ debug!("CACHE HIT");
return c;
}
@@ -61,7 +62,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let (candidate, dep_node) =
self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
- debug!(?candidate, "CACHE MISS");
+ debug!("CACHE MISS");
self.insert_candidate_cache(
stack.obligation.param_env,
cache_fresh_trait_pred,
@@ -75,7 +76,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
- if let Some(conflict) = self.is_knowable(stack) {
+ if let Err(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");
@@ -173,7 +174,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
- let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
+ let needs_infer = stack.obligation.predicate.has_non_region_infer();
// If there are STILL multiple candidates, we can further
// reduce the list by dropping duplicates -- including
@@ -309,6 +310,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// 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.tuple_trait() == Some(def_id) {
+ self.assemble_candidate_for_tuple(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
@@ -337,7 +340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(candidates)
}
- #[tracing::instrument(level = "debug", skip(self, candidates))]
+ #[instrument(level = "debug", skip(self, candidates))]
fn assemble_candidates_from_projected_tys(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -360,14 +363,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
- candidates.vec.extend(result.into_iter().map(ProjectionCandidate));
+ candidates
+ .vec
+ .extend(result.into_iter().map(|(idx, constness)| ProjectionCandidate(idx, constness)));
}
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
/// supplied to find out whether it is listed among them.
///
/// Never affects the inference environment.
- #[tracing::instrument(level = "debug", skip(self, stack, candidates))]
+ #[instrument(level = "debug", skip(self, stack, candidates))]
fn assemble_candidates_from_caller_bounds<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
@@ -620,7 +625,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- _ => candidates.vec.push(AutoImplCandidate(def_id)),
+ _ => candidates.vec.push(AutoImplCandidate),
}
}
}
@@ -706,8 +711,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn need_migrate_deref_output_trait_object(
&mut self,
ty: Ty<'tcx>,
- cause: &traits::ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
+ cause: &ObligationCause<'tcx>,
) -> Option<(Ty<'tcx>, DefId)> {
let tcx = self.tcx();
if tcx.features().trait_upcasting {
@@ -729,24 +734,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return None;
}
- let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
- let normalized_ty = fulfillcx.normalize_projection_type(
- &self.infcx,
+ let ty = traits::normalize_projection_type(
+ self,
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));
+ 0,
+ // We're *intentionally* throwing these away,
+ // since we don't actually use them.
+ &mut vec![],
+ )
+ .ty()
+ .unwrap();
+
+ if let ty::Dynamic(data, ..) = ty.kind() {
+ Some((ty, data.principal_def_id()?))
+ } else {
+ None
+ }
}
/// Searches for unsizing that might apply to `obligation`.
@@ -809,8 +817,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let Some((deref_output_ty, deref_output_trait_did)) = self
.need_migrate_deref_output_trait_object(
source,
- &obligation.cause,
obligation.param_env,
+ &obligation.cause,
)
{
if deref_output_trait_did == target_trait_did {
@@ -818,13 +826,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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();
- },
+ DelayDm(|| format!(
+ "`{}` implements `Deref` with supertrait `{}` as output",
+ source, deref_output_ty
+ )),
+ |lint| lint,
);
return;
}
@@ -877,17 +883,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
}
- #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ #[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() {
+ if obligation.has_non_region_param() {
return;
}
- if obligation.has_infer_types_or_consts() {
+ if obligation.has_non_region_infer() {
candidates.ambiguous = true;
return;
}
@@ -895,7 +901,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates.vec.push(TransmutabilityCandidate);
}
- #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ #[instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_trait_alias(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -908,13 +914,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let def_id = obligation.predicate.def_id();
if self.tcx().is_trait_alias(def_id) {
- candidates.vec.push(TraitAliasCandidate(def_id));
+ candidates.vec.push(TraitAliasCandidate);
}
}
/// Assembles the trait which are built-in to the language itself:
/// `Copy`, `Clone` and `Sized`.
- #[tracing::instrument(level = "debug", skip(self, candidates))]
+ #[instrument(level = "debug", skip(self, candidates))]
fn assemble_builtin_bound_candidates(
&mut self,
conditions: BuiltinImplConditions<'tcx>,
@@ -1006,4 +1012,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
}
+
+ fn assemble_candidate_for_tuple(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ let self_ty = self.infcx().shallow_resolve(obligation.self_ty().skip_binder());
+ match self_ty.kind() {
+ ty::Tuple(_) => {
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
+ }
+ ty::Infer(ty::TyVar(_)) => {
+ candidates.ambiguous = true;
+ }
+ 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::Projection(_)
+ | ty::Opaque(_, _)
+ | ty::Param(_)
+ | ty::Bound(_, _)
+ | ty::Error(_)
+ | ty::Infer(_)
+ | ty::Placeholder(_) => {}
+ }
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2a1099fc8..ed22058c6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -11,9 +11,10 @@ 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_middle::ty::{
+ self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
+ ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
+};
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@@ -63,15 +64,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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);
+ AutoImplCandidate => {
+ let data = self.confirm_auto_impl_candidate(obligation);
ImplSource::AutoImpl(data)
}
- ProjectionCandidate(idx) => {
+ ProjectionCandidate(idx, constness) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
- // FIXME(jschievink): constness
- ImplSource::Param(obligations, ty::BoundConstness::NotConst)
+ ImplSource::Param(obligations, constness)
}
ObjectCandidate(idx) => {
@@ -100,8 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData),
- TraitAliasCandidate(alias_def_id) => {
- let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
+ TraitAliasCandidate => {
+ let data = self.confirm_trait_alias_candidate(obligation);
ImplSource::TraitAlias(data)
}
@@ -279,29 +279,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);
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),
+ src: p.trait_ref.substs.type_at(1),
});
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 Some(assume) =
+ rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)) else {
+ return Err(Unimplemented);
+ };
let cause = obligation.cause.clone();
@@ -325,13 +315,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_auto_impl_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
- trait_def_id: DefId,
) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
- debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate");
+ debug!(?obligation, "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)
+ self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)
}
/// See `confirm_auto_impl_candidate`.
@@ -629,17 +618,47 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)
.map_bound(|(trait_ref, _)| trait_ref);
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+
+ // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+ // The binder on the Fn obligation is "less" important than the one on
+ // the signature, as evidenced by how we treat it during projection.
+ // The safe thing to do here is to liberate it, though, which should
+ // have no worse effect than skipping the binder here.
+ let liberated_fn_ty =
+ self.infcx.replace_bound_vars_with_placeholders(obligation.predicate.rebind(self_ty));
+ let output_ty = self
+ .infcx
+ .replace_bound_vars_with_placeholders(liberated_fn_ty.fn_sig(self.tcx()).output());
+ let output_ty = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ cause.clone(),
+ obligation.recursion_depth,
+ output_ty,
+ &mut nested,
+ );
+ let tr = ty::Binder::dummy(ty::TraitRef::new(
+ self.tcx().require_lang_item(LangItem::Sized, None),
+ self.tcx().mk_substs_trait(output_ty, &[]),
+ ));
+ nested.push(Obligation::new(
+ cause,
+ obligation.param_env,
+ tr.to_poly_trait_predicate().to_predicate(self.tcx()),
+ ));
+
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");
+ debug!(?obligation, "confirm_trait_alias_candidate");
+ let alias_def_id = obligation.predicate.def_id();
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;
@@ -794,7 +813,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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)) => {
+ (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b))
+ if repr_a == repr_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();
@@ -820,7 +841,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map(ty::Binder::dummy),
);
let existential_predicates = tcx.mk_poly_existential_predicates(iter);
- let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+ let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b);
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
@@ -898,7 +919,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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)) => {
+ (&ty::Dynamic(ref data_a, r_a, ty::Dyn), &ty::Dynamic(ref data_b, r_b, ty::Dyn)) => {
// 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
@@ -917,7 +938,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map(ty::Binder::dummy),
);
let existential_predicates = tcx.mk_poly_existential_predicates(iter);
- let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+ let source_trait = tcx.mk_dynamic(existential_predicates, r_b, ty::Dyn);
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
@@ -944,7 +965,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// `T` -> `Trait`
- (_, &ty::Dynamic(ref data, r)) => {
+ (_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
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));
@@ -1047,9 +1068,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(Unimplemented);
}
- // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
- let source_tail = tail_field_ty.subst(tcx, substs_a);
- let target_tail = tail_field_ty.subst(tcx, substs_b);
+ // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
+ // normalizing in the process, since `type_of` returns something directly from
+ // astconv (which means it's un-normalized).
+ let source_tail = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ tail_field_ty.subst(tcx, substs_a),
+ &mut nested,
+ );
+ let target_tail = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ tail_field_ty.subst(tcx, substs_b),
+ &mut nested,
+ );
// Check that the source struct with the target's
// unsizing parameters is equal to the target.
@@ -1188,6 +1225,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Never
| ty::Foreign(_) => {}
+ // `ManuallyDrop` is trivially drop
+ ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().manually_drop() => {}
+
// 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) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index c01ac1979..9ebff4892 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -20,7 +20,7 @@ use super::{
};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
-use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::project::ProjectAndUnifyResult;
use crate::traits::project::ProjectionCacheKeyExt;
use crate::traits::ProjectionCacheKey;
@@ -35,9 +35,8 @@ 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::SubstsRef;
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_span::symbol::sym;
@@ -94,7 +93,7 @@ impl IntercrateAmbiguityCause {
}
pub struct SelectionContext<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
/// Freshener used specifically for entries on the obligation
/// stack. This ensures that all entries on the stack at one time
@@ -215,7 +214,7 @@ enum BuiltinImplConditions<'tcx> {
}
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
- pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
+ pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
@@ -225,28 +224,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- 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 intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
+ SelectionContext { intercrate: true, ..SelectionContext::new(infcx) }
}
pub fn with_query_mode(
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'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,
- }
+ SelectionContext { query_mode, ..SelectionContext::new(infcx) }
}
/// Enables tracking of intercrate ambiguity causes. See
@@ -266,7 +253,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.intercrate_ambiguity_causes.take().unwrap_or_default()
}
- pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
+ pub fn infcx(&self) -> &'cx InferCtxt<'tcx> {
self.infcx
}
@@ -295,7 +282,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Attempts to satisfy the obligation. If successful, this will affect the surrounding
/// type environment by performing unification.
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub fn select(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -325,10 +312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Err(SelectionError::Overflow(OverflowError::Canonical))
}
Err(e) => Err(e),
- Ok(candidate) => {
- debug!(?candidate, "confirmed");
- Ok(Some(candidate))
- }
+ Ok(candidate) => Ok(Some(candidate)),
}
}
@@ -435,6 +419,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
level = "debug",
skip(self, previous_stack),
fields(previous_stack = ?previous_stack.head())
+ ret,
)]
fn evaluate_predicate_recursively<'o>(
&mut self,
@@ -450,7 +435,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
None => self.check_recursion_limit(&obligation, &obligation)?,
}
- let result = ensure_sufficient_stack(|| {
+ ensure_sufficient_stack(|| {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(t) => {
@@ -464,15 +449,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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, .. })) => {
+ Ok(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),
+ Ok(Err(_)) => Ok(EvaluatedToErr),
+ Err(..) => Ok(EvaluatedToAmbig),
}
}
@@ -480,15 +465,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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, .. })) => {
+ Ok(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),
+ Ok(Err(_)) => Ok(EvaluatedToErr),
+ Err(..) => Ok(EvaluatedToAmbig),
}
}
@@ -691,23 +676,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::ConstEquate(c1, c2) => {
+ assert!(
+ self.tcx().features().generic_const_exprs,
+ "`ConstEquate` without a feature gate: {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);
- }
+ // 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, b, obligation.param_env) {
+ return Ok(EvaluatedToOk);
}
}
@@ -747,7 +730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ if c1.has_non_region_infer() || c2.has_non_region_infer() {
Ok(EvaluatedToAmbig)
} else {
// Two different constants using generic parameters ~> error.
@@ -760,14 +743,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bug!("TypeWellFormedFromEnv is only used for chalk")
}
}
- });
-
- debug!("finished: {:?} from {:?}", result, obligation);
-
- result
+ })
}
- #[instrument(skip(self, previous_stack), level = "debug")]
+ #[instrument(skip(self, previous_stack), level = "debug", ret)]
fn evaluate_trait_predicate_recursively<'o>(
&mut self,
previous_stack: TraitObligationStackList<'o, 'tcx>,
@@ -798,12 +777,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// 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");
+ debug!("CACHE HIT");
return Ok(result);
}
if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
- debug!(?result, "PROVISIONAL CACHE HIT");
+ debug!("PROVISIONAL CACHE HIT");
stack.update_reached_depth(result.reached_depth);
return Ok(result.result);
}
@@ -826,11 +805,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
- debug!(?result, "CACHE MISS");
+ debug!("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!("PROVISIONAL");
debug!(
"caching provisionally because {:?} \
is a cycle participant (at depth {}, reached depth {})",
@@ -849,7 +828,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// must be met of course). One obvious case this comes up is
/// marker traits like `Send`. Think of a linked list:
///
- /// struct List<T> { data: T, next: Option<Box<List<T>>> }
+ /// struct List<T> { data: T, next: Option<Box<List<T>>> }
///
/// `Box<List<T>>` will be `Send` if `T` is `Send` and
/// `Option<Box<List<T>>>` is `Send`, and in turn
@@ -936,38 +915,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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
@@ -1023,7 +970,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
#[instrument(
level = "debug",
skip(self, stack),
- fields(depth = stack.obligation.recursion_depth)
+ fields(depth = stack.obligation.recursion_depth),
+ ret
)]
fn evaluate_candidate<'o>(
&mut self,
@@ -1056,7 +1004,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
result = result.max(EvaluatedToOkModuloRegions);
}
- debug!(?result);
Ok(result)
}
@@ -1150,7 +1097,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ErrorGuaranteed::unchecked_claim_error_was_emitted(),
));
}
- self.infcx.report_overflow_error(error_obligation, true);
+ self.infcx.err_ctxt().report_overflow_error(error_obligation, true);
}
TraitQueryMode::Canonical => {
return Err(OverflowError::Canonical);
@@ -1202,8 +1149,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {}
// const param
ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
+ // const projection
+ ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) => {}
// auto trait impl
- AutoImplCandidate(..) => {}
+ AutoImplCandidate => {}
// generator, this will raise error in other places
// or ignore error with const_async_blocks feature
GeneratorCandidate => {}
@@ -1265,11 +1214,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(Some(candidate))
}
- fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
+ fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
debug!("is_knowable(intercrate={:?})", self.intercrate);
if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
- return None;
+ return Ok(());
}
let obligation = &stack.obligation;
@@ -1405,11 +1354,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// 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))]
+ #[instrument(level = "debug", skip(self), ret)]
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
- ) -> smallvec::SmallVec<[usize; 2]> {
+ ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 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);
@@ -1435,7 +1384,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// unnecessary ambiguity.
let mut distinct_normalized_bounds = FxHashSet::default();
- let matching_bounds = bounds
+ bounds
.iter()
.enumerate()
.filter_map(|(idx, bound)| {
@@ -1457,15 +1406,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => false,
}
}) {
- return Some(idx);
+ return Some((idx, pred.constness));
}
}
None
})
- .collect();
-
- debug!(?matching_bounds);
- matching_bounds
+ .collect()
}
/// Equates the trait in `obligation` with trait bound. If the two traits
@@ -1576,7 +1522,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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)
+ .any(|&p| p.has_non_region_infer() && self.infcx.shallow_resolve(p) != p)
{
ProjectionMatchesProjection::Ambiguous
} else {
@@ -1618,12 +1564,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
- // `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else.
+ // `DiscriminantKindCandidate`, `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(..), _) => {
+ (_, AutoImplCandidate) | (AutoImplCandidate, _) => {
bug!(
"default implementations shouldn't be recorded \
when there are other valid candidates"
@@ -1691,11 +1638,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..)
+ | TraitAliasCandidate
| ObjectCandidate(_)
- | ProjectionCandidate(_),
+ | ProjectionCandidate(..),
) => !is_global(cand),
- (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+ (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(cand)
@@ -1709,7 +1656,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
ParamCandidate(ref cand),
) => {
// Prefer these to a global where-clause bound
@@ -1717,20 +1664,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
is_global(cand) && other.evaluation.must_apply_modulo_regions()
}
- (ProjectionCandidate(i), ProjectionCandidate(j))
+ (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(_)) => {
+ (ObjectCandidate(_), ProjectionCandidate(..))
+ | (ProjectionCandidate(..), ObjectCandidate(_)) => {
bug!("Have both object and projection candidate")
}
// Arbitrarily give projection and object candidates priority.
(
- ObjectCandidate(_) | ProjectionCandidate(_),
+ ObjectCandidate(_) | ProjectionCandidate(..),
ImplCandidate(..)
| ClosureCandidate
| GeneratorCandidate
@@ -1739,7 +1686,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
) => true,
(
@@ -1751,18 +1698,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..),
- ObjectCandidate(_) | ProjectionCandidate(_),
+ | 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`.
+ // While this requires us to know *for sure* that the `other` impl applies
+ // we still use modulo regions here.
//
- // 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.
+ // This is fine as specialization currently assumes that specializing
+ // impls have to be always applicable, meaning that the only allowed
+ // region constraints may be constraints also present on the default impl.
let tcx = self.tcx();
if other.evaluation.must_apply_modulo_regions() {
if tcx.specializes((other_def, victim_def)) {
@@ -1832,7 +1779,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
ImplCandidate(_)
| ClosureCandidate
| GeneratorCandidate
@@ -1841,7 +1788,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
) => false,
}
}
@@ -1871,6 +1818,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Array(..)
| ty::Closure(..)
| ty::Never
+ | ty::Dynamic(_, _, ty::DynStar)
| ty::Error(_) => {
// safe for everything
Where(ty::Binder::dummy(Vec::new()))
@@ -1937,8 +1885,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Dynamic(..)
| ty::Str
| ty::Slice(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Generator(_, _, hir::Movability::Static)
| ty::Foreign(..)
| ty::Ref(_, _, hir::Mutability::Mut) => None,
@@ -1947,6 +1894,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Where(obligation.predicate.rebind(tys.iter().collect()))
}
+ ty::Generator(_, substs, hir::Movability::Movable) => {
+ if self.tcx().features().generator_clone {
+ let resolved_upvars =
+ self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
+ let resolved_witness =
+ self.infcx.shallow_resolve(substs.as_generator().witness());
+ if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
+ // Not yet resolved.
+ Ambiguous
+ } else {
+ let all = substs
+ .as_generator()
+ .upvar_tys()
+ .chain(iter::once(substs.as_generator().witness()))
+ .collect::<Vec<_>>();
+ Where(obligation.predicate.rebind(all))
+ }
+ } else {
+ None
+ }
+ }
+
+ ty::GeneratorWitness(binder) => {
+ let witness_tys = binder.skip_binder();
+ for witness_ty in witness_tys.iter() {
+ let resolved = self.infcx.shallow_resolve(witness_ty);
+ if resolved.is_ty_var() {
+ return Ambiguous;
+ }
+ }
+ // (*) binder moved here
+ let all_vars = self.tcx().mk_bound_variable_kinds(
+ obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()),
+ );
+ Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
+ }
+
ty::Closure(_, substs) => {
// (*) binder moved here
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
@@ -2153,7 +2137,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- #[tracing::instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
fn match_impl(
&mut self,
impl_def_id: DefId,
@@ -2194,17 +2178,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.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))?;
+ .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");
+ debug!("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 })
}
@@ -2335,7 +2318,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// 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))]
+ #[instrument(level = "debug", skip(self, cause, param_env))]
fn impl_or_trait_obligations(
&mut self,
cause: &ObligationCause<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 6223c5ea3..c89165858 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -12,22 +12,21 @@
pub mod specialization_graph;
use specialization_graph::GraphExt;
+use crate::errors::NegativePositiveConflict;
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{
- self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt,
-};
+use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
+use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, ImplSubject, TyCtxt};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
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::util;
use super::SelectionContext;
-use super::{util, FulfillmentContext};
/// Information pertinent to an overlapping impl error.
#[derive(Debug)]
@@ -74,8 +73,8 @@ pub struct OverlapError {
/// 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>,
+pub fn translate_substs<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_impl: DefId,
source_substs: SubstsRef<'tcx>,
@@ -150,14 +149,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
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,
- ) {
+ let infcx = tcx.infer_ctxt().build();
+ let impl1_trait_ref =
+ match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
Ok(impl1_trait_ref) => impl1_trait_ref,
Err(_errors) => {
tcx.sess.delay_span_bug(
@@ -168,9 +162,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
}
};
- // 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 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
@@ -178,8 +171,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
/// 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>,
+fn fulfill_implication<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_trait_ref: ty::TraitRef<'tcx>,
target_impl: DefId,
@@ -211,11 +204,8 @@ fn fulfill_implication<'a, 'tcx>(
// (which are packed up in penv)
infcx.save_and_restore_in_snapshot_flag(|infcx| {
- let mut fulfill_cx = <dyn TraitEngine<'tcx>>::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() {
+ let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
+ match &errors[..] {
[] => {
debug!(
"fulfill_implication: an impl for {:?} specializes {:?}",
@@ -333,35 +323,13 @@ fn report_negative_positive_conflict(
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));
- }
- }
-
+ let mut err = tcx.sess.create_err(NegativePositiveConflict {
+ impl_span: tcx.def_span(local_impl_def_id),
+ trait_desc: &overlap.trait_desc,
+ self_desc: &overlap.self_desc,
+ negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
+ positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
+ });
sg.has_errored = Some(err.emit());
}
@@ -377,26 +345,12 @@ fn report_conflicting_impls(
// 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<G: EmissionGuarantee>(
+ fn decorate<'a, 'b, G: EmissionGuarantee>(
tcx: TyCtxt<'_>,
overlap: OverlapError,
- used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
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);
+ err: &'b mut DiagnosticBuilder<'a, G>,
+ ) -> &'b mut DiagnosticBuilder<'a, G> {
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
@@ -411,7 +365,9 @@ fn report_conflicting_impls(
}
Err(cname) => {
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
- Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
+ Some(s) => {
+ format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
+ }
None => format!("conflicting implementation in crate `{}`", cname),
};
err.note(&msg);
@@ -419,28 +375,33 @@ fn report_conflicting_impls(
}
for cause in &overlap.intercrate_ambiguity_causes {
- cause.add_intercrate_ambiguity_hint(&mut err);
+ cause.add_intercrate_ambiguity_hint(err);
}
if overlap.involves_placeholder {
- coherence::add_placeholder_note(&mut err);
+ coherence::add_placeholder_note(err);
}
- err.emit()
+ err
}
+ let msg = format!(
+ "conflicting implementations of trait `{}`{}{}",
+ overlap.trait_desc,
+ overlap.self_desc.as_deref().map_or_else(String::new, |ty| format!(" for type `{ty}`")),
+ match used_to_be_allowed {
+ Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
+ _ => "",
+ }
+ );
+
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),
- ))
+ let mut err = struct_span_err!(tcx.sess, impl_span, E0119, "{msg}",);
+ decorate(tcx, overlap, impl_span, &mut err);
+ Some(err.emit())
} else {
Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
};
@@ -455,9 +416,8 @@ fn report_conflicting_impls(
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);
- },
+ msg,
+ |err| decorate(tcx, overlap, impl_span, err),
);
}
};
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index fcb73b43f..63f89a33e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -137,9 +137,8 @@ impl ChildrenExt<'_> for Children {
impl_def_id,
traits::SkipLeakCheck::default(),
overlap_mode,
- |_| true,
- || false,
- );
+ )
+ .is_some();
let error = create_overlap_error(overlap);
@@ -162,34 +161,29 @@ impl ChildrenExt<'_> for Children {
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,
- });
- }
+ )
+ .map_or(Ok((false, false)), |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));
+ return Ok((false, false));
+ }
- if le == ge {
- report_overlap_error(overlap, last_lint_mut)
- } else {
- Ok((le, ge))
- }
- },
- || 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)) }
+ })?;
if le && !ge {
debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 5829a0f92..932dbbb81 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -68,7 +68,7 @@ pub fn search_for_adt_const_param_violation<'tcx>(
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
fn type_marked_structural<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
adt_ty: Ty<'tcx>,
cause: ObligationCause<'tcx>,
) -> bool {
@@ -265,9 +265,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
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)
- })
+ let infcx = tcx.infer_ctxt().build();
+ 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
index d25006016..ed47d2f83 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -5,14 +5,12 @@ 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 rustc_middle::ty::{GenericArg, SubstsRef};
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::{self, util::*};
-use std::iter;
-
///////////////////////////////////////////////////////////////////////////
// `TraitAliasExpander` iterator
///////////////////////////////////////////////////////////////////////////
@@ -210,7 +208,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
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);
+ super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates);
let impl_obligations = impl_obligations
.chain(normalization_obligations1.into_iter())
@@ -219,27 +217,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
(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<Item = PredicateObligation<'tcx>> {
- 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>,
@@ -291,10 +268,7 @@ 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()
+ tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
}
/// Given an upcast trait object described by `object`, returns the
@@ -305,15 +279,10 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
object: &super::ImplSourceObjectData<'tcx, N>,
method_def_id: DefId,
) -> Option<usize> {
- 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)
+ .own_existential_vtable_entries(object.upcast_trait_ref.def_id())
.iter()
.copied()
.position(|def_id| def_id == method_def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 414857f0a..fc0a9f690 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -14,8 +14,8 @@ use std::iter;
/// 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>,
+pub fn obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
recursion_depth: usize,
@@ -31,9 +31,9 @@ pub fn obligations<'a, 'tcx>(
if resolved_ty == ty {
// No progress, bail out to prevent "livelock".
return None;
+ } else {
+ resolved_ty
}
-
- resolved_ty
}
_ => ty,
}
@@ -41,16 +41,14 @@ pub fn obligations<'a, 'tcx>(
}
GenericArgKind::Const(ct) => {
match ct.kind() {
- ty::ConstKind::Infer(infer) => {
- let resolved = infcx.shallow_resolve(infer);
- if resolved == infer {
+ ty::ConstKind::Infer(_) => {
+ let resolved = infcx.shallow_resolve(ct);
+ if resolved == ct {
// No progress.
return None;
+ } else {
+ resolved
}
-
- infcx
- .tcx
- .mk_const(ty::ConstS { kind: ty::ConstKind::Infer(resolved), ty: ct.ty() })
}
_ => ct,
}
@@ -81,8 +79,8 @@ pub fn obligations<'a, 'tcx>(
/// well-formed. For example, if there is a trait `Set` defined like
/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
/// if `Bar: Eq`.
-pub fn trait_obligations<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn trait_obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
trait_pred: &ty::TraitPredicate<'tcx>,
@@ -103,8 +101,9 @@ pub fn trait_obligations<'a, 'tcx>(
wf.normalize(infcx)
}
-pub fn predicate_obligations<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+#[instrument(skip(infcx), ret)]
+pub fn predicate_obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
predicate: ty::Predicate<'tcx>,
@@ -131,9 +130,9 @@ pub fn predicate_obligations<'a, 'tcx>(
}
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(),
+ wf.compute(match t.term.unpack() {
+ ty::TermKind::Ty(ty) => ty.into(),
+ ty::TermKind::Const(c) => c.into(),
})
}
ty::PredicateKind::WellFormed(arg) => {
@@ -149,13 +148,8 @@ pub fn predicate_obligations<'a, 'tcx>(
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::ConstEvaluatable(ct) => {
+ wf.compute(ct.into());
}
ty::PredicateKind::ConstEquate(c1, c2) => {
wf.compute(c1.into());
@@ -220,12 +214,14 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
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),
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => {
+ (impl_.items, *owner_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,
+ hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::Type(ty) => ty.span,
_ => impl_item_ref.span,
};
@@ -242,7 +238,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
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)
+ .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
.map(fix_span)
{
cause.span = impl_item_span;
@@ -257,7 +253,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
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)
+ .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
.map(fix_span)
{
cause.span = impl_item_span;
@@ -276,7 +272,7 @@ impl<'tcx> WfPredicates<'tcx> {
traits::ObligationCause::new(self.span, self.body_id, code)
}
- fn normalize(self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
+ fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
let cause = self.cause(traits::WellFormed(None));
let param_env = self.param_env;
let mut obligations = Vec::with_capacity(self.out.len());
@@ -393,7 +389,8 @@ impl<'tcx> WfPredicates<'tcx> {
// `i32: Clone`
// `i32: Copy`
// ]
- let obligations = self.nominal_obligations(data.item_def_id, data.substs);
+ // Projection types do not require const predicates.
+ let obligations = self.nominal_obligations_without_const(data.item_def_id, data.substs);
self.out.extend(obligations);
let tcx = self.tcx();
@@ -436,11 +433,13 @@ impl<'tcx> WfPredicates<'tcx> {
}
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
+ #[instrument(level = "debug", skip(self))]
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() {
+ debug!(?arg, ?self.out);
let ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty,
@@ -448,14 +447,14 @@ impl<'tcx> WfPredicates<'tcx> {
// obligations are handled by the parent (e.g. `ty::Ref`).
GenericArgKind::Lifetime(_) => continue,
- GenericArgKind::Const(constant) => {
- match constant.kind() {
+ GenericArgKind::Const(ct) => {
+ match ct.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()))
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
.to_predicate(self.tcx());
let cause = self.cause(traits::WellFormed(None));
self.out.push(traits::Obligation::with_depth(
@@ -472,7 +471,7 @@ impl<'tcx> WfPredicates<'tcx> {
cause,
self.recursion_depth,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into()))
.to_predicate(self.tcx()),
));
}
@@ -490,6 +489,8 @@ impl<'tcx> WfPredicates<'tcx> {
}
};
+ debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind());
+
match *ty.kind() {
ty::Bool
| ty::Char
@@ -546,7 +547,7 @@ impl<'tcx> WfPredicates<'tcx> {
}
ty::FnDef(did, substs) => {
- let obligations = self.nominal_obligations(did, substs);
+ let obligations = self.nominal_obligations_without_const(did, substs);
self.out.extend(obligations);
}
@@ -636,7 +637,7 @@ impl<'tcx> WfPredicates<'tcx> {
}
}
- ty::Dynamic(data, r) => {
+ ty::Dynamic(data, r, _) => {
// WfObject
//
// Here, we defer WF checking due to higher-ranked
@@ -688,6 +689,8 @@ impl<'tcx> WfPredicates<'tcx> {
));
}
}
+
+ debug!(?self.out);
}
}
@@ -713,7 +716,7 @@ impl<'tcx> WfPredicates<'tcx> {
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
+ traits::ItemObligation(origin_def_id)
} else {
traits::BindingObligation(origin_def_id, span)
};
@@ -843,7 +846,7 @@ pub fn object_region_bounds<'tcx>(
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
-#[instrument(skip(tcx, predicates), level = "debug")]
+#[instrument(skip(tcx, predicates), level = "debug", ret)]
pub(crate) fn required_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
erased_self_ty: Ty<'tcx>,