summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_trait_selection/src/traits
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs250
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs42
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs117
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs503
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs44
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs39
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs83
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs1
22 files changed, 751 insertions, 447 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index ba5000da6..8096d7969 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -793,7 +793,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
span: tcx.def_span(unevaluated.def),
unevaluated: unevaluated,
});
- Err(ErrorHandled::Reported(reported.into()))
+ Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
}
Err(err) => Err(err),
}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 5746781ae..acab4498a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,9 +6,15 @@
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::InferOk;
+use crate::solve::inspect;
+use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::traits::engine::TraitEngineExt;
use crate::traits::outlives_bounds::InferCtxtExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
+use crate::traits::structural_normalize::StructurallyNormalizeExt;
use crate::traits::util::impl_subject_and_oblig;
+use crate::traits::NormalizeExt;
use crate::traits::SkipLeakCheck;
use crate::traits::{
self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
@@ -18,10 +24,13 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::util;
+use rustc_infer::traits::{util, TraitEngine};
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::solve::{Certainty, Goal};
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE;
@@ -31,9 +40,6 @@ use std::fmt::Debug;
use std::iter;
use std::ops::ControlFlow;
-use super::query::evaluate_obligation::InferCtxtExt;
-use super::NormalizeExt;
-
/// Whether we do the orphan check relative to this crate or
/// to some remote crate.
#[derive(Copy, Clone, Debug)]
@@ -152,16 +158,14 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
.predicates_of(impl_def_id)
.instantiate(tcx, impl_args)
.iter()
- .map(|(c, s)| (c.as_predicate(), s))
+ .map(|(c, _)| c.as_predicate())
.collect(),
};
- let InferOk { value: mut header, obligations } = selcx
- .infcx
- .at(&ObligationCause::dummy_with_span(tcx.def_span(impl_def_id)), param_env)
- .normalize(header);
+ let InferOk { value: mut header, obligations } =
+ selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
- header.predicates.extend(obligations.into_iter().map(|o| (o.predicate, o.cause.span)));
+ header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
header
}
@@ -207,19 +211,19 @@ fn overlap<'tcx>(
// Equate the headers to find their intersection (the general type, with infer vars,
// that may apply both impls).
- let equate_obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
+ let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded");
+ obligations.extend(
+ [&impl1_header.predicates, &impl2_header.predicates].into_iter().flatten().map(
+ |&predicate| Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate),
+ ),
+ );
+
if overlap_mode.use_implicit_negative() {
for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] {
if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| {
- impl_intersection_has_impossible_obligation(
- selcx,
- param_env,
- &impl1_header,
- &impl2_header,
- &equate_obligations,
- )
+ impl_intersection_has_impossible_obligation(selcx, &obligations)
}) {
if matches!(mode, TreatInductiveCycleAs::Recur) {
let first_local_impl = impl1_header
@@ -261,17 +265,11 @@ fn overlap<'tcx>(
infcx.tcx.def_span(impl2_header.impl_def_id),
"the second impl is here",
);
- if !failing_obligation.cause.span.is_dummy() {
- lint.span_label(
- failing_obligation.cause.span,
- format!(
- "`{}` may be considered to hold in future releases, \
- causing the impls to overlap",
- infcx
- .resolve_vars_if_possible(failing_obligation.predicate)
- ),
- );
- }
+ lint.note(format!(
+ "`{}` may be considered to hold in future releases, \
+ causing the impls to overlap",
+ infcx.resolve_vars_if_possible(failing_obligation.predicate)
+ ));
lint
},
);
@@ -289,7 +287,14 @@ fn overlap<'tcx>(
return None;
}
- let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+ let intercrate_ambiguity_causes = if !overlap_mode.use_implicit_negative() {
+ Default::default()
+ } else if infcx.next_trait_solver() {
+ compute_intercrate_ambiguity_causes(&infcx, &obligations)
+ } else {
+ selcx.take_intercrate_ambiguity_causes()
+ };
+
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
let involves_placeholder = infcx
.inner
@@ -343,34 +348,24 @@ fn equate_impl_headers<'tcx>(
/// of the two impls above to be empty.
///
/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
-fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
+fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- impl1_header: &ty::ImplHeader<'tcx>,
- impl2_header: &ty::ImplHeader<'tcx>,
- obligations: &PredicateObligations<'tcx>,
-) -> Option<PredicateObligation<'tcx>> {
+ obligations: &'a [PredicateObligation<'tcx>],
+) -> Option<&'a PredicateObligation<'tcx>> {
let infcx = selcx.infcx;
- [&impl1_header.predicates, &impl2_header.predicates]
- .into_iter()
- .flatten()
- .map(|&(predicate, span)| {
- Obligation::new(infcx.tcx, ObligationCause::dummy_with_span(span), param_env, predicate)
- })
- .chain(obligations.into_iter().cloned())
- .find(|obligation: &PredicateObligation<'tcx>| {
- if infcx.next_trait_solver() {
- infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
- } else {
- // We use `evaluate_root_obligation` to correctly track intercrate
- // ambiguity clauses. We cannot use this in the new solver.
- selcx.evaluate_root_obligation(obligation).map_or(
- false, // Overflow has occurred, and treat the obligation as possibly holding.
- |result| !result.may_apply(),
- )
- }
- })
+ obligations.iter().find(|obligation| {
+ if infcx.next_trait_solver() {
+ infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
+ } else {
+ // We use `evaluate_root_obligation` to correctly track intercrate
+ // ambiguity clauses. We cannot use this in the new solver.
+ selcx.evaluate_root_obligation(obligation).map_or(
+ false, // Overflow has occurred, and treat the obligation as possibly holding.
+ |result| !result.may_apply(),
+ )
+ }
+ })
}
/// Check if both impls can be satisfied by a common type by considering whether
@@ -832,9 +827,7 @@ where
// This should only be created when checking whether we have to check whether some
// auto trait impl applies. There will never be multiple impls, so we can just
// act as if it were a local type here.
- ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => {
- ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
- }
+ ty::GeneratorWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
ty::Alias(ty::Opaque, ..) => {
// This merits some explanation.
// Normally, opaque types are not involved when performing
@@ -890,3 +883,144 @@ where
ControlFlow::Continue(())
}
}
+
+/// Compute the `intercrate_ambiguity_causes` for the new solver using
+/// "proof trees".
+///
+/// This is a bit scuffed but seems to be good enough, at least
+/// when looking at UI tests. Given that it is only used to improve
+/// diagnostics this is good enough. We can always improve it once there
+/// are test cases where it is currently not enough.
+fn compute_intercrate_ambiguity_causes<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ obligations: &[PredicateObligation<'tcx>],
+) -> FxIndexSet<IntercrateAmbiguityCause> {
+ let mut causes: FxIndexSet<IntercrateAmbiguityCause> = Default::default();
+
+ for obligation in obligations {
+ search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes);
+ }
+
+ causes
+}
+
+struct AmbiguityCausesVisitor<'a> {
+ causes: &'a mut FxIndexSet<IntercrateAmbiguityCause>,
+}
+
+impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
+ type BreakTy = !;
+ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy> {
+ let infcx = goal.infcx();
+ for cand in goal.candidates() {
+ cand.visit_nested(self)?;
+ }
+ // When searching for intercrate ambiguity causes, we only need to look
+ // at ambiguous goals, as for others the coherence unknowable candidate
+ // was irrelevant.
+ match goal.result() {
+ Ok(Certainty::Maybe(_)) => {}
+ Ok(Certainty::Yes) | Err(NoSolution) => return ControlFlow::Continue(()),
+ }
+
+ let Goal { param_env, predicate } = goal.goal();
+
+ // For bound predicates we simply call `infcx.replace_bound_vars_with_placeholders`
+ // and then prove the resulting predicate as a nested goal.
+ let trait_ref = match predicate.kind().no_bound_vars() {
+ Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
+ Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => {
+ proj.projection_ty.trait_ref(infcx.tcx)
+ }
+ _ => return ControlFlow::Continue(()),
+ };
+
+ let mut ambiguity_cause = None;
+ for cand in goal.candidates() {
+ // FIXME: boiiii, using string comparisions here sure is scuffed.
+ if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } =
+ cand.kind()
+ {
+ let lazily_normalize_ty = |ty: Ty<'tcx>| {
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx);
+ if matches!(ty.kind(), ty::Alias(..)) {
+ // FIXME(-Ztrait-solver=next-coherence): we currently don't
+ // normalize opaque types here, resulting in diverging behavior
+ // for TAITs.
+ match infcx
+ .at(&ObligationCause::dummy(), param_env)
+ .structurally_normalize(ty, &mut *fulfill_cx)
+ {
+ Ok(ty) => Ok(ty),
+ Err(_errs) => Err(()),
+ }
+ } else {
+ Ok(ty)
+ }
+ };
+
+ infcx.probe(|_| {
+ match trait_ref_is_knowable(infcx.tcx, trait_ref, lazily_normalize_ty) {
+ Err(()) => {}
+ Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
+ Ok(Err(conflict)) => {
+ if !trait_ref.references_error() {
+ let self_ty = trait_ref.self_ty();
+ let (trait_desc, self_desc) = with_no_trimmed_paths!({
+ let trait_desc = trait_ref.print_only_trait_path().to_string();
+ let self_desc = self_ty
+ .has_concrete_skeleton()
+ .then(|| self_ty.to_string());
+ (trait_desc, self_desc)
+ });
+ ambiguity_cause = Some(match conflict {
+ Conflict::Upstream => {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate {
+ trait_desc,
+ self_desc,
+ }
+ }
+ Conflict::Downstream => {
+ IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc,
+ self_desc,
+ }
+ }
+ });
+ }
+ }
+ }
+ })
+ } else {
+ match cand.result() {
+ // We only add an ambiguity cause if the goal would otherwise
+ // result in an error.
+ //
+ // FIXME: While this matches the behavior of the
+ // old solver, it is not the only way in which the unknowable
+ // candidates *weaken* coherence, they can also force otherwise
+ // sucessful normalization to be ambiguous.
+ Ok(Certainty::Maybe(_) | Certainty::Yes) => {
+ ambiguity_cause = None;
+ break;
+ }
+ Err(NoSolution) => continue,
+ }
+ }
+ }
+
+ if let Some(ambiguity_cause) = ambiguity_cause {
+ self.causes.insert(ambiguity_cause);
+ }
+
+ ControlFlow::Continue(())
+ }
+}
+
+fn search_ambiguity_causes<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ goal: Goal<'tcx, ty::Predicate<'tcx>>,
+ causes: &mut FxIndexSet<IntercrateAmbiguityCause>,
+) {
+ infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes });
+}
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 3d0d3812d..62ab1e104 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -73,13 +73,13 @@ pub fn is_const_evaluatable<'tcx>(
ty::ConstKind::Unevaluated(uv) => {
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
match concrete {
- Err(ErrorHandled::TooGeneric) => {
+ Err(ErrorHandled::TooGeneric(_)) => {
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
span,
"Missing value for constant, but no error reported?",
)))
}
- Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
+ Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()),
}
}
@@ -132,7 +132,7 @@ pub fn is_const_evaluatable<'tcx>(
.emit()
}
- Err(ErrorHandled::TooGeneric) => {
+ Err(ErrorHandled::TooGeneric(_)) => {
let err = if uv.has_non_region_infer() {
NotConstEvaluatable::MentionsInfer
} else if uv.has_non_region_param() {
@@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>(
Err(err)
}
- Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
+ Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()),
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 820973dc0..015e38b2a 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -23,6 +23,7 @@ use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::Variance;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::TraitSolver;
@@ -156,6 +157,20 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
+ pub fn relate<T: ToTrace<'tcx>>(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ variance: Variance,
+ expected: T,
+ actual: T,
+ ) -> Result<(), TypeError<'tcx>> {
+ self.infcx
+ .at(cause, param_env)
+ .relate(DefineOpaqueTypes::Yes, expected, variance, actual)
+ .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
+ }
+
/// Checks whether `expected` is a supertype of `actual`: `expected :> actual`.
pub fn sup<T: ToTrace<'tcx>>(
&self,
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 457d5420c..2a586f810 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -986,6 +986,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
+ self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
+ self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
+
// Return early if the trait is Debug or Display and the invocation
// originates within a standard library macro, because the output
// is otherwise overwhelming and unhelpful (see #85844 for an
@@ -1844,7 +1847,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
- ty::GeneratorWitnessMIR(..) => Some(21),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
@@ -2054,7 +2056,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
tcx: self.tcx,
ty_op: |ty| ty,
lt_op: |lt| lt,
- ct_op: |ct| ct.eval(self.tcx, ty::ParamEnv::empty()),
+ ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
});
cand
})
@@ -2920,6 +2922,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
rustc_transmute::Reason::DstIsTooBig => {
format!("The size of `{src}` is smaller than the size of `{dst}`")
}
+ rustc_transmute::Reason::SrcSizeOverflow => {
+ format!(
+ "values of the type `{src}` are too big for the current architecture"
+ )
+ }
+ rustc_transmute::Reason::DstSizeOverflow => {
+ format!(
+ "values of the type `{dst}` are too big for the current architecture"
+ )
+ }
rustc_transmute::Reason::DstHasStricterAlignment {
src_min_align,
dst_min_align,
@@ -2999,10 +3011,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, '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().polarity,
- )
+ obligation.param_env,
+ trait_ref.self_ty(),
+ trait_predicate.skip_binder().polarity,
+ )
{
self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
} else if !trait_ref.has_non_region_infer()
@@ -3021,6 +3033,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
None,
obligation.cause.body_id,
);
+ } else if trait_ref.def_id().is_local()
+ && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
+ && !self.tcx.trait_is_auto(trait_ref.def_id())
+ && !self.tcx.trait_is_alias(trait_ref.def_id())
+ {
+ err.span_help(
+ self.tcx.def_span(trait_ref.def_id()),
+ crate::fluent_generated::trait_selection_trait_has_no_impls,
+ );
} 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);
@@ -3031,7 +3052,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err,
true,
) {
- self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+ self.report_similar_impl_candidates_for_root_obligation(
+ &obligation,
+ *trait_predicate,
+ body_def_id,
+ err,
+ );
}
self.suggest_convert_to_slice(
@@ -3185,7 +3211,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
- format!("opaque type")
+ "opaque type".to_string()
}
hir::OpaqueTyOrigin::TyAlias { .. } => {
format!("`{}`", self.tcx.def_path_debug_str(def_id))
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 0e73bad19..d645dc033 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
@@ -9,6 +9,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use std::iter;
@@ -103,7 +104,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
self.describe_generator(*body_id).or_else(|| {
Some(match sig.header {
- hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function",
+ hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => {
+ "an async function"
+ }
_ => "a function",
})
})
@@ -117,7 +120,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
..
}) => self.describe_generator(*body_id).or_else(|| {
Some(match sig.header {
- hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method",
+ hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method",
_ => "a method",
})
}),
@@ -257,7 +260,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_string())));
- let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
+ let len = len.try_to_valtree().and_then(|v| v.try_to_target_usize(self.tcx));
flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
if let Some(n) = len {
flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
@@ -336,6 +339,10 @@ pub enum AppendConstMessage {
Custom(Symbol),
}
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_malformed_on_unimplemented_attr)]
+pub struct NoValueInOnUnimplementedLint;
+
impl<'tcx> OnUnimplementedDirective {
fn parse(
tcx: TyCtxt<'tcx>,
@@ -343,7 +350,8 @@ impl<'tcx> OnUnimplementedDirective {
items: &[NestedMetaItem],
span: Span,
is_root: bool,
- ) -> Result<Self, ErrorGuaranteed> {
+ is_diagnostic_namespace_variant: bool,
+ ) -> Result<Option<Self>, ErrorGuaranteed> {
let mut errored = None;
let mut item_iter = items.iter();
@@ -391,7 +399,10 @@ impl<'tcx> OnUnimplementedDirective {
note = parse_value(note_)?;
continue;
}
- } else if item.has_name(sym::parent_label) && parent_label.is_none() {
+ } else if item.has_name(sym::parent_label)
+ && parent_label.is_none()
+ && !is_diagnostic_namespace_variant
+ {
if let Some(parent_label_) = item.value_str() {
parent_label = parse_value(parent_label_)?;
continue;
@@ -401,15 +412,30 @@ impl<'tcx> OnUnimplementedDirective {
&& message.is_none()
&& label.is_none()
&& note.is_none()
+ && !is_diagnostic_namespace_variant
+ // FIXME(diagnostic_namespace): disallow filters for now
{
if let Some(items) = item.meta_item_list() {
- match Self::parse(tcx, item_def_id, &items, item.span(), false) {
- Ok(subcommand) => subcommands.push(subcommand),
+ match Self::parse(
+ tcx,
+ item_def_id,
+ &items,
+ item.span(),
+ false,
+ is_diagnostic_namespace_variant,
+ ) {
+ Ok(Some(subcommand)) => subcommands.push(subcommand),
+ Ok(None) => bug!(
+ "This cannot happen for now as we only reach that if `is_diagnostic_namespace_variant` is false"
+ ),
Err(reported) => errored = Some(reported),
};
continue;
}
- } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+ } else if item.has_name(sym::append_const_msg)
+ && append_const_msg.is_none()
+ && !is_diagnostic_namespace_variant
+ {
if let Some(msg) = item.value_str() {
append_const_msg = Some(AppendConstMessage::Custom(msg));
continue;
@@ -419,14 +445,23 @@ impl<'tcx> OnUnimplementedDirective {
}
}
- // nothing found
- tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+ if is_diagnostic_namespace_variant {
+ tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ vec![item.span()],
+ NoValueInOnUnimplementedLint,
+ );
+ } else {
+ // nothing found
+ tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+ }
}
if let Some(reported) = errored {
- Err(reported)
+ if is_diagnostic_namespace_variant { Ok(None) } else { Err(reported) }
} else {
- Ok(OnUnimplementedDirective {
+ Ok(Some(OnUnimplementedDirective {
condition,
subcommands,
message,
@@ -434,32 +469,58 @@ impl<'tcx> OnUnimplementedDirective {
note,
parent_label,
append_const_msg,
- })
+ }))
}
}
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
- let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
+ let mut is_diagnostic_namespace_variant = false;
+ let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| {
+ if tcx.features().diagnostic_namespace {
+ is_diagnostic_namespace_variant = true;
+ tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next()
+ } else {
+ None
+ }
+ }) else {
return Ok(None);
};
let result = if let Some(items) = attr.meta_item_list() {
- Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
+ Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
} else if let Some(value) = attr.value_str() {
- Ok(Some(OnUnimplementedDirective {
- condition: None,
- message: None,
- subcommands: vec![],
- label: Some(OnUnimplementedFormatString::try_parse(
- tcx,
- item_def_id,
- value,
+ if !is_diagnostic_namespace_variant {
+ Ok(Some(OnUnimplementedDirective {
+ condition: None,
+ message: None,
+ subcommands: vec![],
+ label: Some(OnUnimplementedFormatString::try_parse(
+ tcx,
+ item_def_id,
+ value,
+ attr.span,
+ )?),
+ note: None,
+ parent_label: None,
+ append_const_msg: None,
+ }))
+ } else {
+ tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
attr.span,
- )?),
- note: None,
- parent_label: None,
- append_const_msg: None,
- }))
+ NoValueInOnUnimplementedLint,
+ );
+ Ok(None)
+ }
+ } else if is_diagnostic_namespace_variant {
+ tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ attr.span,
+ NoValueInOnUnimplementedLint,
+ );
+ Ok(None)
} else {
let reported =
tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
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 611ec6b00..15f2ba809 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -30,10 +30,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTi
use rustc_middle::hir::map;
use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::{
- self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
- GeneratorDiagnosticData, GeneratorInteriorTypeCause, GenericArgs, InferTy, IsSuggestable,
- ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
- TypeVisitableExt, TypeckResults,
+ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
+ InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
+ TypeSuperFoldable, TypeVisitableExt, TypeckResults,
};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident, Symbol};
@@ -50,7 +49,7 @@ use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
#[derive(Debug)]
pub enum GeneratorInteriorOrUpvar {
// span of interior type
- Interior(Span, Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>),
+ Interior(Span, Option<(Span, Option<Span>)>),
// span of upvar
Upvar(Span),
}
@@ -58,15 +57,12 @@ pub enum GeneratorInteriorOrUpvar {
// This type provides a uniform interface to retrieve data on generators, whether it originated from
// the local crate being compiled or from a foreign crate.
#[derive(Debug)]
-pub enum GeneratorData<'tcx, 'a> {
- Local(&'a TypeckResults<'tcx>),
- Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
-}
+struct GeneratorData<'tcx, 'a>(&'a TypeckResults<'tcx>);
impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
- // Try to get information about variables captured by the generator that matches a type we are
- // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
- // meet an obligation
+ /// Try to get information about variables captured by the generator that matches a type we are
+ /// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
+ /// meet an obligation
fn try_get_upvar_span<F>(
&self,
infer_context: &InferCtxt<'tcx>,
@@ -76,27 +72,21 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
where
F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
{
- match self {
- GeneratorData::Local(typeck_results) => {
- infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
- upvars.iter().find_map(|(upvar_id, upvar)| {
- let upvar_ty = typeck_results.node_type(*upvar_id);
- let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
- ty_matches(ty::Binder::dummy(upvar_ty))
- .then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span))
- })
- })
- }
- GeneratorData::Foreign(_) => None,
- }
+ infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+ upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = self.0.node_type(*upvar_id);
+ let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
+ ty_matches(ty::Binder::dummy(upvar_ty))
+ .then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ })
+ })
}
- // Try to get the span of a type being awaited on that matches the type we are looking with the
- // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
- // obligation
+ /// Try to get the span of a type being awaited on that matches the type we are looking with the
+ /// `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
+ /// obligation
fn get_from_await_ty<F>(
&self,
- tcx: TyCtxt<'tcx>,
visitor: AwaitsVisitor,
hir: map::Map<'tcx>,
ty_matches: F,
@@ -104,69 +94,12 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
where
F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
{
- match self {
- GeneratorData::Local(typeck_results) => visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
- })
- .map(|expr| expr.span),
- GeneratorData::Foreign(generator_diagnostic_data) => visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- ty_matches(ty::Binder::dummy(
- generator_diagnostic_data
- .adjustments
- .get(&await_expr.hir_id.local_id)
- .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
- .last()
- .map_or_else::<Ty<'tcx>, _, _>(
- || {
- generator_diagnostic_data
- .nodes_types
- .get(&await_expr.hir_id.local_id)
- .cloned()
- .unwrap_or_else(|| {
- bug!(
- "node_type: no type for node {}",
- tcx.hir().node_to_string(await_expr.hir_id)
- )
- })
- },
- |adj| adj.target,
- ),
- ))
- })
- .map(|expr| expr.span),
- }
- }
-
- /// Get the type, expression, span and optional scope span of all types
- /// that are live across the yield of this generator
- fn get_generator_interior_types(
- &self,
- ) -> ty::Binder<'tcx, &[GeneratorInteriorTypeCause<'tcx>]> {
- match self {
- GeneratorData::Local(typeck_result) => {
- typeck_result.generator_interior_types.as_deref()
- }
- GeneratorData::Foreign(generator_diagnostic_data) => {
- generator_diagnostic_data.generator_interior_types.as_deref()
- }
- }
- }
-
- // Used to get the source of the data, note we don't have as much information for generators
- // originated from foreign crates
- fn is_foreign(&self) -> bool {
- match self {
- GeneratorData::Local(_) => false,
- GeneratorData::Foreign(_) => true,
- }
+ visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(&await_expr))))
+ .map(|expr| expr.span)
}
}
@@ -316,7 +249,6 @@ pub trait TypeErrCtxtExt<'tcx> {
outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
);
@@ -406,6 +338,20 @@ pub trait TypeErrCtxtExt<'tcx> {
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
);
+
+ fn explain_hrtb_projection(
+ &self,
+ diag: &mut Diagnostic,
+ pred: ty::PolyTraitPredicate<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ );
+
+ fn suggest_desugaring_async_fn_in_trait(
+ &self,
+ err: &mut Diagnostic,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ );
}
fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
@@ -838,7 +784,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
obligation.param_env,
real_trait_pred_and_base_ty,
);
- if self.predicate_may_hold(&obligation) {
+ let sized_obligation = Obligation::new(
+ self.tcx,
+ obligation.cause.clone(),
+ obligation.param_env,
+ ty::TraitRef::from_lang_item(
+ self.tcx,
+ hir::LangItem::Sized,
+ obligation.cause.span,
+ [base_ty],
+ ),
+ );
+ if self.predicate_may_hold(&obligation)
+ && self.predicate_must_hold_modulo_regions(&sized_obligation)
+ {
let call_node = self.tcx.hir().get(*call_hir_id);
let msg = "consider dereferencing here";
let is_receiver = matches!(
@@ -1792,7 +1751,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
} else {
err.note(format!(
- "`{}` is implemented for `{:?}`, but not for `{:?}`",
+ "`{}` is implemented for `{}`, but not for `{}`",
trait_pred.print_modifiers_and_trait_path(),
suggested_ty,
trait_pred.skip_binder().self_ty(),
@@ -2213,11 +2172,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
match *ty.kind() {
- ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => {
+ ty::Generator(did, ..) | ty::GeneratorWitness(did, _) => {
generator = generator.or(Some(did));
outer_generator = Some(did);
}
- ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself,
@@ -2243,11 +2201,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
match *ty.kind() {
- ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => {
+ ty::Generator(did, ..) | ty::GeneratorWitness(did, ..) => {
generator = generator.or(Some(did));
outer_generator = Some(did);
}
- ty::GeneratorWitness(..) => {}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
// of a generator, the first non-generator item is now the tuple itself,
@@ -2324,12 +2281,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// 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 = match &self.typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData::Local(&t),
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData(&t),
_ if generator_did.is_local() => {
- GeneratorData::Local(self.tcx.typeck(generator_did.expect_local()))
- }
- _ if let Some(generator_diag_data) = self.tcx.generator_diagnostic_data(generator_did) => {
- GeneratorData::Foreign(generator_diag_data)
+ GeneratorData(self.tcx.typeck(generator_did.expect_local()))
}
_ => return false,
};
@@ -2341,30 +2295,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut interior_or_upvar_span = None;
- let from_awaited_ty = generator_data.get_from_await_ty(self.tcx, visitor, hir, ty_matches);
+ let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
debug!(?from_awaited_ty);
- // The generator interior types share the same binders
- if let Some(cause) =
- generator_data.get_generator_interior_types().skip_binder().iter().find(
- |ty::GeneratorInteriorTypeCause { ty, .. }| {
- ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
- },
- )
- {
- let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
-
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
- *span,
- Some((*scope_span, *yield_span, *expr, from_awaited_ty)),
- ));
-
- if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None));
- }
- } else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir
- // Avoid disclosing internal information to downstream crates.
- && generator_did.is_local()
+ // Avoid disclosing internal information to downstream crates.
+ if generator_did.is_local()
// Try to avoid cycles.
&& !generator_within_in_progress_typeck
&& let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
@@ -2380,7 +2315,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
decl.source_info.span,
- Some((None, source_info.span, None, from_awaited_ty)),
+ Some((source_info.span, from_awaited_ty)),
));
break 'find_source;
}
@@ -2393,17 +2328,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
}
- if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+ if interior_or_upvar_span.is_none() && !generator_did.is_local() {
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span, None));
}
debug!(?interior_or_upvar_span);
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
let is_async = self.tcx.generator_is_async(generator_did);
- let typeck_results = match generator_data {
- GeneratorData::Local(typeck_results) => Some(typeck_results),
- GeneratorData::Foreign(_) => None,
- };
self.note_obligation_cause_for_async_await(
err,
interior_or_upvar_span,
@@ -2411,7 +2342,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
outer_generator,
trait_ref,
target_ty,
- typeck_results,
obligation,
next_code,
);
@@ -2432,7 +2362,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
) {
@@ -2490,9 +2419,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
};
- let mut explain_yield = |interior_span: Span,
- yield_span: Span,
- scope_span: Option<Span>| {
+ let mut explain_yield = |interior_span: Span, yield_span: Span| {
let mut span = MultiSpan::from_span(yield_span);
let snippet = match source_map.span_to_snippet(interior_span) {
// #70935: If snippet contains newlines, display "the value" instead
@@ -2524,22 +2451,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
interior_span,
format!("has type `{target_ty}` which {trait_explanation}"),
);
- if let Some(scope_span) = scope_span {
- let scope_span = source_map.end_point(scope_span);
-
- let msg = format!("{snippet} is later dropped here");
- span.push_span_label(scope_span, msg);
- }
err.span_note(
- span,
- format!(
- "{future_or_generator} {trait_explanation} as this value is used across {an_await_or_yield}"
- ),
- );
+ span,
+ format!("{future_or_generator} {trait_explanation} as this value is used across {an_await_or_yield}"),
+ );
};
match interior_or_upvar_span {
GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
- if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
+ if let Some((yield_span, from_awaited_ty)) = interior_extra_info {
if let Some(await_span) = from_awaited_ty {
// The type causing this obligation is one being awaited at await_span.
let mut span = MultiSpan::from_span(await_span);
@@ -2557,62 +2476,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
} else {
// Look at the last interior type to get a span for the `.await`.
- debug!(
- generator_interior_types = ?format_args!(
- "{:#?}", typeck_results.as_ref().map(|t| &t.generator_interior_types)
- ),
- );
- explain_yield(interior_span, yield_span, scope_span);
- }
-
- if let Some(expr_id) = expr {
- let expr = hir.expect_expr(expr_id);
- debug!("target_ty evaluated from {:?}", expr);
-
- let parent = hir.parent_id(expr_id);
- if let Some(hir::Node::Expr(e)) = hir.find(parent) {
- let parent_span = hir.span(parent);
- let parent_did = parent.owner.to_def_id();
- // ```rust
- // impl T {
- // fn foo(&self) -> i32 {}
- // }
- // T.foo();
- // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
- // ```
- //
- let is_region_borrow = if let Some(typeck_results) = typeck_results {
- typeck_results
- .expr_adjustments(expr)
- .iter()
- .any(|adj| adj.is_region_borrow())
- } else {
- false
- };
-
- // ```rust
- // struct Foo(*const u8);
- // bar(Foo(std::ptr::null())).await;
- // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
- // ```
- debug!(parent_def_kind = ?self.tcx.def_kind(parent_did));
- let is_raw_borrow_inside_fn_like_call =
- match self.tcx.def_kind(parent_did) {
- DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
- _ => false,
- };
- if let Some(typeck_results) = typeck_results {
- if (typeck_results.is_method_call(e) && is_region_borrow)
- || is_raw_borrow_inside_fn_like_call
- {
- err.span_help(
- parent_span,
- "consider moving this into a `let` \
- binding to create a shorter lived borrow",
- );
- }
- }
- }
+ explain_yield(interior_span, yield_span);
}
}
}
@@ -2690,6 +2554,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::IfExpressionWithNoElse
| ObligationCauseCode::MainFunctionType
| ObligationCauseCode::StartFunctionType
+ | ObligationCauseCode::LangFunctionType(_)
| ObligationCauseCode::IntrinsicType
| ObligationCauseCode::MethodReceiver
| ObligationCauseCode::ReturnNoExpression
@@ -2979,6 +2844,24 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ObligationCauseCode::InlineAsmSized => {
err.note("all inline asm arguments must have a statically known size");
}
+ ObligationCauseCode::SizedClosureCapture(closure_def_id) => {
+ err.note("all values captured by value by a closure must have a statically known size");
+ let hir::ExprKind::Closure(closure) = self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind else {
+ bug!("expected closure in SizedClosureCapture obligation");
+ };
+ if let hir::CaptureBy::Value = closure.capture_clause
+ && let Some(span) = closure.fn_arg_span
+ {
+ err.span_label(span, "this closure captures all values by move");
+ }
+ }
+ ObligationCauseCode::SizedGeneratorInterior(generator_def_id) => {
+ let what = match self.tcx.generator_kind(generator_def_id) {
+ None | Some(hir::GeneratorKind::Gen) => "yield",
+ Some(hir::GeneratorKind::Async(..)) => "await",
+ };
+ err.note(format!("all values live across `{what}` must have a statically known size"));
+ }
ObligationCauseCode::ConstPatternStructural => {
err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
}
@@ -3044,20 +2927,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.span_note(self.tcx.def_span(def_id), msg)
}
- ty::GeneratorWitness(bound_tys) => {
- use std::fmt::Write;
-
- // FIXME: this is kind of an unusual format for rustc, can we make it more clear?
- // Maybe we should just remove this note altogether?
- // FIXME: only print types which don't meet the trait requirement
- let mut msg =
- "required because it captures the following types: ".to_owned();
- for ty in bound_tys.skip_binder() {
- with_forced_trimmed_paths!(write!(msg, "`{ty}`, ").unwrap());
- }
- err.note(msg.trim_end_matches(", ").to_string())
- }
- ty::GeneratorWitnessMIR(def_id, args) => {
+ ty::GeneratorWitness(def_id, args) => {
use std::fmt::Write;
// FIXME: this is kind of an unusual format for rustc, can we make it more clear?
@@ -4014,6 +3884,201 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
}
+
+ fn explain_hrtb_projection(
+ &self,
+ diag: &mut Diagnostic,
+ pred: ty::PolyTraitPredicate<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ ) {
+ if pred.skip_binder().has_escaping_bound_vars() && pred.skip_binder().has_non_region_infer()
+ {
+ self.probe(|_| {
+ let ocx = ObligationCtxt::new(self);
+ let pred = self.instantiate_binder_with_placeholders(pred);
+ let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
+ ocx.register_obligation(Obligation::new(
+ self.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ pred,
+ ));
+ if !ocx.select_where_possible().is_empty() {
+ // encountered errors.
+ return;
+ }
+
+ if let ObligationCauseCode::FunctionArgumentObligation {
+ call_hir_id,
+ arg_hir_id,
+ parent_code: _,
+ } = cause.code()
+ {
+ let arg_span = self.tcx.hir().span(*arg_hir_id);
+ let mut sp: MultiSpan = arg_span.into();
+
+ sp.push_span_label(
+ arg_span,
+ "the trait solver is unable to infer the \
+ generic types that should be inferred from this argument",
+ );
+ sp.push_span_label(
+ self.tcx.hir().span(*call_hir_id),
+ "add turbofish arguments to this call to \
+ specify the types manually, even if it's redundant",
+ );
+ diag.span_note(
+ sp,
+ "this is a known limitation of the trait solver that \
+ will be lifted in the future",
+ );
+ } else {
+ let mut sp: MultiSpan = cause.span.into();
+ sp.push_span_label(
+ cause.span,
+ "try adding turbofish arguments to this expression to \
+ specify the types manually, even if it's redundant",
+ );
+ diag.span_note(
+ sp,
+ "this is a known limitation of the trait solver that \
+ will be lifted in the future",
+ );
+ }
+ });
+ }
+ }
+
+ fn suggest_desugaring_async_fn_in_trait(
+ &self,
+ err: &mut Diagnostic,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ ) {
+ // Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
+ if self.tcx.features().return_type_notation {
+ return;
+ }
+
+ let trait_def_id = trait_ref.def_id();
+
+ // Only suggest specifying auto traits
+ if !self.tcx.trait_is_auto(trait_def_id) {
+ return;
+ }
+
+ // Look for an RPITIT
+ let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else {
+ return;
+ };
+ let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
+ self.tcx.opt_rpitit_info(alias_ty.def_id)
+ else {
+ return;
+ };
+
+ let auto_trait = self.tcx.def_path_str(trait_def_id);
+ // ... which is a local function
+ let Some(fn_def_id) = fn_def_id.as_local() else {
+ // If it's not local, we can at least mention that the method is async, if it is.
+ if self.tcx.asyncness(fn_def_id).is_async() {
+ err.span_note(
+ self.tcx.def_span(fn_def_id),
+ format!(
+ "`{}::{}` is an `async fn` in trait, which does not \
+ automatically imply that its future is `{auto_trait}`",
+ alias_ty.trait_ref(self.tcx),
+ self.tcx.item_name(fn_def_id)
+ ),
+ );
+ }
+ return;
+ };
+ let Some(hir::Node::TraitItem(item)) = self.tcx.hir().find_by_def_id(fn_def_id) else {
+ return;
+ };
+
+ // ... whose signature is `async` (i.e. this is an AFIT)
+ let (sig, body) = item.expect_fn();
+ let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
+ return;
+ };
+ let Ok(async_span) =
+ self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
+ else {
+ return;
+ };
+ let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
+ sig.decl.output
+ else {
+ // This should never happen, but let's not ICE.
+ return;
+ };
+
+ // Check that this is *not* a nested `impl Future` RPIT in an async fn
+ // (i.e. `async fn foo() -> impl Future`)
+ if def.owner_id.to_def_id() != opaque_def_id {
+ return;
+ }
+
+ let future = self.tcx.hir().item(*def).expect_opaque_ty();
+ let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
+ // `async fn` should always lower to a lang item bound... but don't ICE.
+ return;
+ };
+ let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
+ generics.bindings.get(0).map(|binding| binding.kind)
+ else {
+ // Also should never happen.
+ return;
+ };
+
+ let function_name = self.tcx.def_path_str(fn_def_id);
+
+ let mut sugg = if future_output_ty.span.is_empty() {
+ vec![
+ (async_span, String::new()),
+ (
+ future_output_ty.span,
+ format!(" -> impl std::future::Future<Output = ()> + {auto_trait}"),
+ ),
+ ]
+ } else {
+ vec![
+ (
+ future_output_ty.span.shrink_to_lo(),
+ "impl std::future::Future<Output = ".to_owned(),
+ ),
+ (future_output_ty.span.shrink_to_hi(), format!("> + {auto_trait}")),
+ (async_span, String::new()),
+ ]
+ };
+
+ // If there's a body, we also need to wrap it in `async {}`
+ if let hir::TraitFn::Provided(body) = body {
+ let body = self.tcx.hir().body(*body);
+ let body_span = body.value.span;
+ let body_span_without_braces =
+ body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
+ if body_span_without_braces.is_empty() {
+ sugg.push((body_span_without_braces, " async {} ".to_owned()));
+ } else {
+ sugg.extend([
+ (body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
+ (body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
+ ]);
+ }
+ }
+
+ err.multipart_suggestion(
+ format!(
+ "`{auto_trait}` can be made part of the associated future's \
+ guarantees for all implementations of `{function_name}`"
+ ),
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
}
/// Add a hint to add a missing borrow or remove an unnecessary one.
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 3ebf1246a..55b5604b1 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -559,30 +559,31 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
let stalled_on = &mut pending_obligation.stalled_on;
- let mut evaluate =
- |c: Const<'tcx>| {
- if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
- match self.selcx.infcx.try_const_eval_resolve(
- obligation.param_env,
- unevaluated,
- c.ty(),
- Some(obligation.cause.span),
- ) {
- Ok(val) => Ok(val),
- Err(e) => match e {
- ErrorHandled::TooGeneric => {
+ let mut evaluate = |c: Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+ match self.selcx.infcx.try_const_eval_resolve(
+ obligation.param_env,
+ unevaluated,
+ c.ty(),
+ Some(obligation.cause.span),
+ ) {
+ Ok(val) => Ok(val),
+ Err(e) => {
+ match e {
+ ErrorHandled::TooGeneric(..) => {
stalled_on.extend(unevaluated.args.iter().filter_map(
TyOrConstInferVar::maybe_from_generic_arg,
));
- Err(ErrorHandled::TooGeneric)
}
- _ => Err(e),
- },
+ _ => {}
+ }
+ Err(e)
}
- } else {
- Ok(c)
}
- };
+ } else {
+ Ok(c)
+ }
+ };
match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => {
@@ -602,13 +603,14 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
),
}
}
- (Err(ErrorHandled::Reported(reported)), _)
- | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error(
+ (Err(ErrorHandled::Reported(reported, _)), _)
+ | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
CodeSelectionError(SelectionError::NotConstEvaluatable(
NotConstEvaluatable::Error(reported.into()),
)),
),
- (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+ (Err(ErrorHandled::TooGeneric(_)), _)
+ | (_, Err(ErrorHandled::TooGeneric(_))) => {
if c1.has_non_region_infer() || c2.has_non_region_infer() {
ProcessResult::Unchanged
} else {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d2210c6d5..956f8e047 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -288,7 +288,7 @@ pub fn normalize_param_env_or_error<'tcx>(
// should actually be okay since without `feature(generic_const_exprs)` the only
// const arguments that have a non-empty param env are array repeat counts. These
// do not appear in the type system though.
- c.eval(self.0, ty::ParamEnv::empty())
+ c.normalize(self.0, ty::ParamEnv::empty())
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 06a1027e5..f7b4794db 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -659,6 +659,18 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
normalized_ty
}
ty::Weak => {
+ let recursion_limit = self.interner().recursion_limit();
+ if !recursion_limit.value_within_limit(self.depth) {
+ self.selcx.infcx.err_ctxt().report_overflow_error(
+ &ty,
+ self.cause.span,
+ false,
+ |diag| {
+ diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow);
+ },
+ );
+ }
+
let infcx = self.selcx.infcx;
self.obligations.extend(
infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map(
@@ -678,7 +690,14 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
},
),
);
- infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self)
+ self.depth += 1;
+ let res = infcx
+ .tcx
+ .type_of(data.def_id)
+ .instantiate(infcx.tcx, data.args)
+ .fold_with(self);
+ self.depth -= 1;
+ res
}
ty::Inherent if !data.has_escaping_bound_vars() => {
@@ -742,7 +761,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
self.selcx.infcx,
&mut self.universes,
constant,
- |constant| constant.eval(tcx, self.param_env),
+ |constant| constant.normalize(tcx, self.param_env),
)
}
}
@@ -1214,7 +1233,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);
- let result = if projected_term.has_projections() {
+ let mut result = if projected_term.has_projections() {
let mut normalizer = AssocTypeNormalizer::new(
selcx,
param_env,
@@ -1224,14 +1243,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
);
let normalized_ty = normalizer.fold(projected_term);
- let mut deduped = SsoHashSet::with_capacity(projected_obligations.len());
- projected_obligations.retain(|obligation| deduped.insert(obligation.clone()));
-
Normalized { value: normalized_ty, obligations: projected_obligations }
} else {
Normalized { value: projected_term, obligations: projected_obligations }
};
+ let mut deduped = SsoHashSet::with_capacity(result.obligations.len());
+ result.obligations.retain(|obligation| deduped.insert(obligation.clone()));
+
if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
}
@@ -1625,7 +1644,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
let env_predicates = data
.projection_bounds()
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
- .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
+ .map(|p| ty::Clause::from_projection_clause(tcx, p.with_self_ty(tcx, object_ty)));
assemble_candidates_from_predicates(
selcx,
@@ -1794,7 +1813,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Never
| ty::Tuple(..)
// Integers and floats always have `u8` as their discriminant.
@@ -1844,7 +1862,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Never
// Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_)
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 9484a50e3..620b992ee 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -36,7 +36,6 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::FnPtr(_)
| ty::Char
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Str
@@ -134,7 +133,7 @@ pub fn compute_dropck_outlives_inner<'tcx>(
result.overflows.len(),
ty_stack.len()
);
- dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
+ dtorck_constraint_for_ty_inner(tcx, param_env, DUMMY_SP, depth, ty, &mut constraints)?;
// "outlives" represent types/regions that may be touched
// by a destructor.
@@ -186,16 +185,15 @@ pub fn compute_dropck_outlives_inner<'tcx>(
/// Returns a set of constraints that needs to be satisfied in
/// order for `ty` to be valid for destruction.
+#[instrument(level = "debug", skip(tcx, param_env, span, constraints))]
pub fn dtorck_constraint_for_ty_inner<'tcx>(
tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
span: Span,
- for_ty: Ty<'tcx>,
depth: usize,
ty: Ty<'tcx>,
constraints: &mut DropckConstraint<'tcx>,
) -> Result<(), NoSolution> {
- debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
-
if !tcx.recursion_limit().value_within_limit(depth) {
constraints.overflows.push(ty);
return Ok(());
@@ -218,21 +216,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(_)
- | ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..) => {
+ | ty::GeneratorWitness(..) => {
// these types never have a destructor
}
ty::Array(ety, _) | ty::Slice(ety) => {
// single-element containers, behave like their element
rustc_data_structures::stack::ensure_sufficient_stack(|| {
- dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints)
+ dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)
})?;
}
ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in tys.iter() {
- dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
+ dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?;
}
Ok::<_, NoSolution>(())
})?,
@@ -251,7 +248,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
rustc_data_structures::stack::ensure_sufficient_stack(|| {
for ty in args.as_closure().upvar_tys() {
- dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
+ dtorck_constraint_for_ty_inner(
+ tcx,
+ param_env,
+ span,
+ depth + 1,
+ ty,
+ constraints,
+ )?;
}
Ok::<_, NoSolution>(())
})?
@@ -280,8 +284,8 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// only take place through references with lifetimes
// derived from lifetimes attached to the upvars and resume
// argument, and we *do* incorporate those here.
-
- if !args.as_generator().is_valid() {
+ let args = args.as_generator();
+ if !args.is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
tcx.sess.delay_span_bug(
@@ -291,10 +295,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
return Err(NoSolution);
}
- constraints
- .outlives
- .extend(args.as_generator().upvar_tys().iter().map(ty::GenericArg::from));
- constraints.outlives.push(args.as_generator().resume_ty().into());
+ // While we conservatively assume that all coroutines require drop
+ // to avoid query cycles during MIR building, we can check the actual
+ // witness during borrowck to avoid unnecessary liveness constraints.
+ if args.witness().needs_drop(tcx, tcx.erase_regions(param_env)) {
+ constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
+ constraints.outlives.push(args.resume_ty().into());
+ }
}
ty::Adt(def, args) => {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 87beaddc6..f785211c5 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -358,7 +358,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
self.infcx,
&mut self.universes,
constant,
- |constant| constant.eval(self.infcx.tcx, self.param_env),
+ |constant| constant.normalize(self.infcx.tcx, self.param_env),
))
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 979498fb6..e415d7047 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -13,7 +13,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::DUMMY_SP;
use smallvec::{smallvec, SmallVec};
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct ImpliedOutlivesBounds<'tcx> {
pub ty: Ty<'tcx>,
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 59f4a22ac..f2c1243f9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -6,7 +6,7 @@ use crate::traits::ObligationCtxt;
use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct DropckOutlives<'tcx> {
dropped_ty: Ty<'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 e3da87a22..bead8758a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -436,8 +436,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Ref(_, _, _)
| ty::Closure(_, _)
| ty::Generator(_, _, _)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(_, _)
+ | ty::GeneratorWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => return true,
@@ -569,8 +568,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Generator(..)
| ty::Never
| ty::Tuple(_)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(..) => {
+ | ty::GeneratorWitness(..) => {
// Only consider auto impls if there are no manual impls for the root of `self_ty`.
//
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
@@ -946,8 +944,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Closure(..)
| ty::Generator(..)
| ty::Tuple(_)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(..) => {
+ | ty::GeneratorWitness(..) => {
// These are built-in, and cannot have a custom `impl const Destruct`.
candidates.vec.push(ConstDestructCandidate(None));
}
@@ -1020,8 +1017,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::Generator(_, _, _)
- | ty::GeneratorWitness(_)
- | ty::GeneratorWitnessMIR(..)
+ | ty::GeneratorWitness(..)
| ty::Never
| ty::Alias(..)
| ty::Param(_)
@@ -1083,7 +1079,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Never
| ty::Tuple(..)
| ty::Alias(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 88d030033..08ee9c73b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -535,6 +535,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let assoc_types: Vec<_> = tcx
.associated_items(trait_predicate.def_id())
.in_definition_order()
+ // Associated types that require `Self: Sized` do not show up in the built-in
+ // implementation of `Trait for dyn Trait`, and can be dropped here.
+ .filter(|item| !tcx.generics_require_sized_self(item.def_id))
.filter_map(
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
)
@@ -548,7 +551,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.cause.span,
"GATs in trait object shouldn't have been considered",
);
- return Err(SelectionError::Unimplemented);
+ return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id));
}
// This maybe belongs in wf, but that can't (doesn't) handle
@@ -1235,10 +1238,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let generator = args.as_generator();
stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
}
- ty::GeneratorWitness(tys) => {
- stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
- }
- ty::GeneratorWitnessMIR(def_id, args) => {
+ ty::GeneratorWitness(def_id, args) => {
let tcx = self.tcx();
stack.extend(tcx.generator_hidden_types(def_id).map(|bty| {
let ty = bty.instantiate(tcx, args);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 19385e2d7..ec46a6769 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -35,7 +35,8 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitObligation;
-use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
+use rustc_middle::dep_graph::dep_kinds;
+use rustc_middle::dep_graph::DepNodeIndex;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fold::BottomUpFolder;
@@ -988,9 +989,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Err(_) => Ok(EvaluatedToErr),
}
}
- (Err(ErrorHandled::Reported(_)), _)
- | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr),
- (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+ (Err(ErrorHandled::Reported(..)), _)
+ | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr),
+ (Err(ErrorHandled::TooGeneric(..)), _)
+ | (_, Err(ErrorHandled::TooGeneric(..))) => {
if c1.has_non_region_infer() || c2.has_non_region_infer() {
Ok(EvaluatedToAmbig)
} else {
@@ -1415,7 +1417,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
OP: FnOnce(&mut Self) -> R,
{
let (result, dep_node) =
- self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self));
+ self.tcx().dep_graph.with_anon_task(self.tcx(), dep_kinds::TraitSelect, || op(self));
self.tcx().dep_graph.read_index(dep_node);
(result, dep_node)
}
@@ -2110,7 +2112,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Ref(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Array(..)
| ty::Closure(..)
| ty::Never
@@ -2209,22 +2210,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
}
- 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_from_iter(
- obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()),
- );
- Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
- }
-
- ty::GeneratorWitnessMIR(def_id, ref args) => {
+ ty::GeneratorWitness(def_id, ref args) => {
let hidden_types = bind_generator_hidden_types_above(
self.infcx,
def_id,
@@ -2329,12 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
}
- ty::GeneratorWitness(types) => {
- debug_assert!(!types.has_escaping_bound_vars());
- types.map_bound(|types| types.to_vec())
- }
-
- ty::GeneratorWitnessMIR(def_id, ref args) => {
+ ty::GeneratorWitness(def_id, ref args) => {
bind_generator_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
}
@@ -2346,14 +2327,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
- let ty = self.tcx().type_of(def_id);
- if ty.skip_binder().references_error() {
- return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
- }
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
- t.rebind(vec![ty.instantiate(self.tcx(), args)])
+ match self.tcx().type_of_opaque(def_id) {
+ Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
+ Err(_) => {
+ return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
+ }
+ }
}
})
}
@@ -3093,32 +3075,33 @@ fn bind_generator_hidden_types_above<'tcx>(
.generator_hidden_types(def_id)
// Deduplicate tys to avoid repeated work.
.filter(|bty| seen_tys.insert(*bty))
- .map(|bty| {
- let mut ty = bty.instantiate(tcx, args);
-
+ .map(|mut bty| {
// Only remap erased regions if we use them.
if considering_regions {
- ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
- ty::ReErased => {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(None),
- };
- counter += 1;
- ty::Region::new_late_bound(tcx, current_depth, br)
- }
- r => bug!("unexpected region: {r:?}"),
+ bty = bty.map_bound(|ty| {
+ tcx.fold_regions(ty, |r, current_depth| match r.kind() {
+ ty::ReErased => {
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_u32(counter),
+ kind: ty::BrAnon,
+ };
+ counter += 1;
+ ty::Region::new_late_bound(tcx, current_depth, br)
+ }
+ r => bug!("unexpected region: {r:?}"),
+ })
})
}
- ty
+ bty.instantiate(tcx, args)
})
.collect();
if considering_regions {
debug_assert!(!hidden_types.has_erased_regions());
}
- let bound_vars = tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain(
- (num_bound_variables..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon(None))),
- ));
+ let bound_vars =
+ tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain(
+ (num_bound_variables..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon)),
+ ));
ty::Binder::bind_with_vars(hidden_types, bound_vars)
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 729cf2f33..efab29743 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -472,17 +472,11 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
let mut types_without_default_bounds = FxIndexSet::default();
let sized_trait = tcx.lang_items().sized_trait();
- if !args.is_empty() {
+ let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
+ if !arg_names.is_empty() {
types_without_default_bounds.extend(args.types());
w.push('<');
- w.push_str(
- &args
- .iter()
- .map(|k| k.to_string())
- .filter(|k| k != "'_")
- .collect::<Vec<_>>()
- .join(", "),
- );
+ w.push_str(&arg_names.join(", "));
w.push('>');
}
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 0864e4dc8..fc9b42436 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -79,7 +79,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
ty::Closure(..) => {
return ControlFlow::Break(ty);
}
- ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => {
+ ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(ty);
}
ty::FnDef(..) => {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index d3c4dc459..9d6be7689 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -22,9 +22,14 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
assert!(!ty.is_ty_var(), "should have resolved vars before calling");
if self.infcx.next_trait_solver() {
- while let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, projection_ty) =
- *ty.kind()
- {
+ // FIXME(-Ztrait-solver=next): correctly handle
+ // overflow here.
+ for _ in 0..256 {
+ let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, projection_ty) = *ty.kind()
+ else {
+ break;
+ };
+
let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.cause.span,
@@ -49,6 +54,7 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
break;
}
}
+
Ok(ty)
} else {
Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 427ac3684..e41073937 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -152,7 +152,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
segment_visitor(VtblSegment::TraitOwnEntries {
trait_ref: inner_most_trait_ref,
- emit_vptr,
+ emit_vptr: emit_vptr && !tcx.sess.opts.unstable_opts.no_trait_vptr,
})?;
// If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index f26310665..b04008d9e 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -609,7 +609,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
| ty::Error(_)
| ty::Str
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Never
| ty::Param(_)
| ty::Bound(..)