summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_trait_selection/src
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs6
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs73
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs265
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs94
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs428
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs103
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs45
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs214
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs48
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs13
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/build.rs45
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs105
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs54
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs (renamed from compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs)14
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs (renamed from compiler/rustc_trait_selection/src/solve/project_goals/mod.rs)115
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs (renamed from compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs)25
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs (renamed from compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs)9
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs38
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs46
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs122
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs155
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs263
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs492
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs446
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs58
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs281
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs90
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs135
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs165
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs43
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs65
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs51
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs28
58 files changed, 2512 insertions, 1844 deletions
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index c1fb287d6..b0ec8b3a4 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,6 +1,6 @@
use crate::fluent_generated as fluent;
use rustc_errors::{
- AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
+ AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, ErrorGuaranteed, IntoDiagnostic,
SubdiagnosticMessage,
};
use rustc_macros::Diagnostic;
@@ -61,9 +61,9 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
#[track_caller]
fn into_diagnostic(
self,
- handler: &Handler,
+ dcx: &DiagCtxt,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict);
+ let mut diag = dcx.struct_err(fluent::trait_selection_negative_positive_conflict);
diag.set_arg("trait_desc", self.trait_desc.print_only_trait_path().to_string());
diag.set_arg(
"self_desc",
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 38153cccf..251f0628a 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,8 +1,10 @@
+use crate::solve::FulfillmentCtxt;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::{self, DefiningAnchor, ObligationCtxt};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::{TraitEngine, TraitEngineExt};
use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
use rustc_middle::traits::query::NoSolution;
@@ -27,7 +29,7 @@ pub trait InferCtxtExt<'tcx> {
/// - the parameter environment
///
/// Invokes `evaluate_obligation`, so in the event that evaluating
- /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown)
+ /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent (or EvaluatedToAmbigStackDependent)
/// will be returned.
fn type_implements_trait(
&self,
@@ -35,6 +37,13 @@ pub trait InferCtxtExt<'tcx> {
params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult;
+
+ fn could_impl_trait(
+ &self,
+ trait_def_id: DefId,
+ ty: Ty<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<Vec<traits::FulfillmentError<'tcx>>>;
}
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -76,6 +85,68 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
};
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
}
+
+ fn could_impl_trait(
+ &self,
+ trait_def_id: DefId,
+ ty: Ty<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<Vec<traits::FulfillmentError<'tcx>>> {
+ self.probe(|_snapshot| {
+ if let ty::Adt(def, args) = ty.kind()
+ && let Some((impl_def_id, _)) = self
+ .tcx
+ .all_impls(trait_def_id)
+ .filter_map(|impl_def_id| {
+ self.tcx.impl_trait_ref(impl_def_id).map(|r| (impl_def_id, r))
+ })
+ .map(|(impl_def_id, imp)| (impl_def_id, imp.skip_binder()))
+ .find(|(_, imp)| match imp.self_ty().peel_refs().kind() {
+ ty::Adt(i_def, _) if i_def.did() == def.did() => true,
+ _ => false,
+ })
+ {
+ let mut fulfill_cx = FulfillmentCtxt::new(self);
+ // We get all obligations from the impl to talk about specific
+ // trait bounds.
+ let obligations = self
+ .tcx
+ .predicates_of(impl_def_id)
+ .instantiate(self.tcx, args)
+ .into_iter()
+ .map(|(clause, span)| {
+ traits::Obligation::new(
+ self.tcx,
+ traits::ObligationCause::dummy_with_span(span),
+ param_env,
+ clause,
+ )
+ })
+ .collect::<Vec<_>>();
+ fulfill_cx.register_predicate_obligations(self, obligations);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty]);
+ let obligation = traits::Obligation::new(
+ self.tcx,
+ traits::ObligationCause::dummy(),
+ param_env,
+ trait_ref,
+ );
+ fulfill_cx.register_predicate_obligation(self, obligation);
+ let mut errors = fulfill_cx.select_all_or_error(self);
+ // We remove the last predicate failure, which corresponds to
+ // the top-level obligation, because most of the type we only
+ // care about the other ones, *except* when it is the only one.
+ // This seems to only be relevant for arbitrary self-types.
+ // Look at `tests/ui/moves/move-fn-self-receiver.rs`.
+ if errors.len() > 1 {
+ errors.truncate(errors.len() - 1);
+ }
+ Some(errors)
+ } else {
+ None
+ }
+ })
+ }
}
pub trait InferCtxtBuilderExt<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 5ba29f878..de2577cca 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,9 +11,9 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
+#![allow(internal_features)]
#![feature(associated_type_bounds)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
@@ -21,7 +21,6 @@
#![feature(let_chains)]
#![feature(if_let_guard)]
#![feature(never_type)]
-#![feature(result_option_inspect)]
#![feature(type_alias_impl_trait)]
#![feature(min_specialization)]
#![recursion_limit = "512"] // For rustdoc
@@ -38,12 +37,9 @@ extern crate rustc_middle;
#[macro_use]
extern crate smallvec;
-use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_fluent_macro::fluent_messages;
-
pub mod errors;
pub mod infer;
pub mod solve;
pub mod traits;
-fluent_messages! { "../messages.ftl" }
+rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index f7031c5f4..626569fb4 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -11,18 +11,12 @@
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
//! may apply, then we can compute the "intersection" of both normalizes-to by
//! performing them together. This is used specifically to resolve ambiguities.
-use super::{EvalCtxt, SolverMode};
+use super::{EvalCtxt, GoalSource};
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;
-/// We may need to invert the alias relation direction if dealing an alias on the RHS.
-#[derive(Debug)]
-enum Invert {
- No,
- Yes,
-}
-
impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn compute_alias_relate_goal(
@@ -31,187 +25,128 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> QueryResult<'tcx> {
let tcx = self.tcx();
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
- if lhs.is_infer() || rhs.is_infer() {
- bug!(
- "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
- );
- }
-
- match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
- (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
- // RHS is not a projection, only way this is true is if LHS normalizes-to RHS
- (Some(alias_lhs), None) => self.assemble_normalizes_to_candidate(
- param_env,
- alias_lhs,
- rhs,
- direction,
- Invert::No,
- ),
+ let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
+ return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
+ };
- // LHS is not a projection, only way this is true is if RHS normalizes-to LHS
- (None, Some(alias_rhs)) => self.assemble_normalizes_to_candidate(
- param_env,
- alias_rhs,
- lhs,
- direction,
- Invert::Yes,
- ),
+ let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
+ return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
+ };
- (Some(alias_lhs), Some(alias_rhs)) => {
- debug!("both sides are aliases");
+ let variance = match direction {
+ ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
+ ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
+ };
- let mut candidates = Vec::new();
- // LHS normalizes-to RHS
- candidates.extend(self.assemble_normalizes_to_candidate(
- param_env,
- alias_lhs,
- rhs,
- direction,
- Invert::No,
- ));
- // RHS normalizes-to RHS
- candidates.extend(self.assemble_normalizes_to_candidate(
- param_env,
- alias_rhs,
- lhs,
- direction,
- Invert::Yes,
- ));
- // Relate via args
- candidates.extend(
- self.assemble_subst_relate_candidate(
- param_env, alias_lhs, alias_rhs, direction,
- ),
- );
- debug!(?candidates);
+ match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
+ (None, None) => {
+ self.relate(param_env, lhs, variance, rhs)?;
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
- if let Some(merged) = self.try_merge_responses(&candidates) {
- Ok(merged)
+ (Some(alias), None) => {
+ if rhs.is_infer() {
+ self.relate(param_env, lhs, variance, rhs)?;
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ } else if alias.is_opaque(tcx) {
+ self.define_opaque(param_env, alias, rhs)
} else {
- // When relating two aliases and we have ambiguity, if both
- // aliases can be normalized to something, we prefer
- // "bidirectionally normalizing" both of them within the same
- // candidate.
- //
- // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/25>.
- //
- // As this is incomplete, we must not do so during coherence.
- match self.solver_mode() {
- SolverMode::Normal => {
- if let Ok(bidirectional_normalizes_to_response) = self
- .assemble_bidirectional_normalizes_to_candidate(
- param_env, lhs, rhs, direction,
- )
- {
- Ok(bidirectional_normalizes_to_response)
- } else {
- self.flounder(&candidates)
- }
- }
- SolverMode::Coherence => self.flounder(&candidates),
- }
+ Err(NoSolution)
+ }
+ }
+ (None, Some(alias)) => {
+ if lhs.is_infer() {
+ self.relate(param_env, lhs, variance, rhs)?;
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ } else if alias.is_opaque(tcx) {
+ self.define_opaque(param_env, alias, lhs)
+ } else {
+ Err(NoSolution)
}
}
- }
- }
- #[instrument(level = "debug", skip(self), ret)]
- fn assemble_normalizes_to_candidate(
- &mut self,
- param_env: ty::ParamEnv<'tcx>,
- alias: ty::AliasTy<'tcx>,
- other: ty::Term<'tcx>,
- direction: ty::AliasRelationDirection,
- invert: Invert,
- ) -> QueryResult<'tcx> {
- self.probe_misc_candidate("normalizes-to").enter(|ecx| {
- ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
+ (Some(alias_lhs), Some(alias_rhs)) => {
+ self.relate_rigid_alias_or_opaque(param_env, alias_lhs, variance, alias_rhs)
+ }
+ }
}
- // Computes the normalizes-to branch, with side-effects. This must be performed
- // in a probe in order to not taint the evaluation context.
- fn normalizes_to_inner(
+ /// Normalize the `term` to equate it later. This does not define opaque types.
+ #[instrument(level = "debug", skip(self, param_env), ret)]
+ fn try_normalize_term(
&mut self,
param_env: ty::ParamEnv<'tcx>,
- alias: ty::AliasTy<'tcx>,
- other: ty::Term<'tcx>,
- direction: ty::AliasRelationDirection,
- invert: Invert,
- ) -> Result<(), NoSolution> {
- let other = match direction {
- // This is purely an optimization. No need to instantiate a new
- // infer var and equate the RHS to it.
- ty::AliasRelationDirection::Equate => other,
-
- // Instantiate an infer var and subtype our RHS to it, so that we
- // properly represent a subtype relation between the LHS and RHS
- // of the goal.
- ty::AliasRelationDirection::Subtype => {
- let fresh = self.next_term_infer_of_kind(other);
- let (sub, sup) = match invert {
- Invert::No => (fresh, other),
- Invert::Yes => (other, fresh),
- };
- self.sub(param_env, sub, sup)?;
- fresh
+ term: ty::Term<'tcx>,
+ ) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
+ match term.unpack() {
+ ty::TermKind::Ty(ty) => {
+ // We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
+ Ok(self
+ .try_normalize_ty_recur(param_env, DefineOpaqueTypes::No, 0, ty)
+ .map(Into::into))
}
- };
- self.add_goal(Goal::new(
- self.tcx(),
- param_env,
- ty::ProjectionPredicate { projection_ty: alias, term: other },
- ));
-
- Ok(())
+ ty::TermKind::Const(_) => {
+ if let Some(alias) = term.to_alias_ty(self.tcx()) {
+ let term = self.next_term_infer_of_kind(term);
+ self.add_goal(
+ GoalSource::Misc,
+ Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias, term }),
+ );
+ self.try_evaluate_added_goals()?;
+ Ok(Some(self.resolve_vars_if_possible(term)))
+ } else {
+ Ok(Some(term))
+ }
+ }
+ }
}
- fn assemble_subst_relate_candidate(
+ fn define_opaque(
&mut self,
param_env: ty::ParamEnv<'tcx>,
- alias_lhs: ty::AliasTy<'tcx>,
- alias_rhs: ty::AliasTy<'tcx>,
- direction: ty::AliasRelationDirection,
+ opaque: ty::AliasTy<'tcx>,
+ term: ty::Term<'tcx>,
) -> QueryResult<'tcx> {
- self.probe_misc_candidate("args relate").enter(|ecx| {
- match direction {
- ty::AliasRelationDirection::Equate => {
- ecx.eq(param_env, alias_lhs, alias_rhs)?;
- }
- ty::AliasRelationDirection::Subtype => {
- ecx.sub(param_env, alias_lhs, alias_rhs)?;
- }
- }
-
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
+ self.add_goal(
+ GoalSource::Misc,
+ Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
+ );
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
- fn assemble_bidirectional_normalizes_to_candidate(
+ fn relate_rigid_alias_or_opaque(
&mut self,
param_env: ty::ParamEnv<'tcx>,
- lhs: ty::Term<'tcx>,
- rhs: ty::Term<'tcx>,
- direction: ty::AliasRelationDirection,
+ lhs: ty::AliasTy<'tcx>,
+ variance: ty::Variance,
+ rhs: ty::AliasTy<'tcx>,
) -> QueryResult<'tcx> {
- self.probe_misc_candidate("bidir normalizes-to").enter(|ecx| {
- ecx.normalizes_to_inner(
- param_env,
- lhs.to_alias_ty(ecx.tcx()).unwrap(),
- rhs,
- direction,
- Invert::No,
- )?;
- ecx.normalizes_to_inner(
- param_env,
- rhs.to_alias_ty(ecx.tcx()).unwrap(),
- lhs,
- direction,
- Invert::Yes,
- )?;
+ let tcx = self.tcx();
+ let mut candidates = vec![];
+ if lhs.is_opaque(tcx) {
+ candidates.extend(
+ self.probe_misc_candidate("define-lhs-opaque")
+ .enter(|ecx| ecx.define_opaque(param_env, lhs, rhs.to_ty(tcx).into())),
+ );
+ }
+
+ if rhs.is_opaque(tcx) {
+ candidates.extend(
+ self.probe_misc_candidate("define-rhs-opaque")
+ .enter(|ecx| ecx.define_opaque(param_env, rhs, lhs.to_ty(tcx).into())),
+ );
+ }
+
+ candidates.extend(self.probe_misc_candidate("args-relate").enter(|ecx| {
+ ecx.relate(param_env, lhs, variance, rhs)?;
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
+ }));
+
+ if let Some(result) = self.try_merge_responses(&candidates) {
+ Ok(result)
+ } else {
+ self.flounder(&candidates)
+ }
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 27d2bdead..81a766f24 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -1,6 +1,7 @@
//! Code shared by trait and projection goals for candidate assembly.
use super::{EvalCtxt, SolverMode};
+use crate::solve::GoalSource;
use crate::traits::coherence;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
@@ -37,8 +38,6 @@ pub(super) trait GoalKind<'tcx>:
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
- fn polarity(self) -> ty::ImplPolarity;
-
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
@@ -64,7 +63,9 @@ pub(super) trait GoalKind<'tcx>:
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
) -> QueryResult<'tcx> {
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
- ecx.add_goals(requirements);
+ // FIXME(-Znext-solver=coinductive): check whether this should be
+ // `GoalSource::ImplWhereBound` for any caller.
+ ecx.add_goals(GoalSource::Misc, requirements);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -96,12 +97,16 @@ pub(super) trait GoalKind<'tcx>:
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
bug!("expected object type in `consider_object_bound_candidate`");
};
- ecx.add_goals(structural_traits::predicates_for_object_candidate(
- &ecx,
- goal.param_env,
- goal.predicate.trait_ref(tcx),
- bounds,
- ));
+ // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+ ecx.add_goals(
+ GoalSource::Misc,
+ structural_traits::predicates_for_object_candidate(
+ ecx,
+ goal.param_env,
+ goal.predicate.trait_ref(tcx),
+ bounds,
+ ),
+ );
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -110,7 +115,7 @@ pub(super) trait GoalKind<'tcx>:
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
impl_def_id: DefId,
- ) -> QueryResult<'tcx>;
+ ) -> Result<Candidate<'tcx>, NoSolution>;
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
/// errors but still want to emit errors for other trait goals. We have some special
@@ -209,6 +214,11 @@ pub(super) trait GoalKind<'tcx>:
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
+ fn consider_builtin_async_iterator_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx>;
+
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
/// and return types of the coroutine computed during type-checking.
@@ -263,7 +273,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Vec<Candidate<'tcx>> {
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
- return ambig;
+ return vec![ambig];
}
let mut candidates = self.assemble_candidates_via_self_ty(goal, 0);
@@ -288,15 +298,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
fn assemble_self_ty_infer_ambiguity_response<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
- ) -> Option<Vec<Candidate<'tcx>>> {
- goal.predicate.self_ty().is_ty_var().then(|| {
- vec![Candidate {
- source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
- result: self
- .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
- .unwrap(),
- }]
- })
+ ) -> Option<Candidate<'tcx>> {
+ if goal.predicate.self_ty().is_ty_var() {
+ debug!("adding self_ty_infer_ambiguity_response");
+ let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
+ let result = self
+ .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+ .unwrap();
+ let mut dummy_probe = self.inspect.new_probe();
+ dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
+ self.inspect.finish_probe(dummy_probe);
+ Some(Candidate { source, result })
+ } else {
+ None
+ }
}
/// Assemble candidates which apply to the self type. This only looks at candidate which
@@ -310,7 +325,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Vec<Candidate<'tcx>> {
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
- return ambig;
+ return vec![ambig];
}
let mut candidates = Vec::new();
@@ -349,16 +364,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
num_steps: usize,
) {
let tcx = self.tcx();
- let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return };
+ let &ty::Alias(_, alias) = goal.predicate.self_ty().kind() else { return };
candidates.extend(self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
- if num_steps < ecx.local_overflow_limit() {
+ if tcx.recursion_limit().value_within_limit(num_steps) {
let normalized_ty = ecx.next_ty_infer();
- let normalizes_to_goal = goal.with(
- tcx,
- ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
- );
- ecx.add_goal(normalizes_to_goal);
+ let normalizes_to_goal =
+ goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() });
+ ecx.add_goal(GoalSource::Misc, normalizes_to_goal);
if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
debug!("self type normalization failed");
return vec![];
@@ -395,8 +408,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
for &impl_def_id in impls_for_type {
match G::consider_impl_candidate(self, goal, impl_def_id) {
- Ok(result) => candidates
- .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
+ Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
}
@@ -488,6 +500,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
+ #[instrument(level = "debug", skip_all)]
fn assemble_unsize_to_dyn_candidate<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
@@ -505,6 +518,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
+ #[instrument(level = "debug", skip_all)]
fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
@@ -514,8 +528,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
for &impl_def_id in trait_impls.blanket_impls() {
match G::consider_impl_candidate(self, goal, impl_def_id) {
- Ok(result) => candidates
- .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
+ Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
}
@@ -564,6 +577,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
G::consider_builtin_future_candidate(self, goal)
} else if lang_items.iterator_trait() == Some(trait_def_id) {
G::consider_builtin_iterator_candidate(self, goal)
+ } else if lang_items.async_iterator_trait() == Some(trait_def_id) {
+ G::consider_builtin_async_iterator_candidate(self, goal)
} else if lang_items.coroutine_trait() == Some(trait_def_id) {
G::consider_builtin_coroutine_candidate(self, goal)
} else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
@@ -864,23 +879,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
let trait_ref = goal.predicate.trait_ref(tcx);
-
#[derive(Debug)]
- enum FailureKind {
- Overflow,
- NoSolution(NoSolution),
- }
+ struct Overflow;
let lazily_normalize_ty = |ty| match ecx.try_normalize_ty(goal.param_env, ty) {
- Ok(Some(ty)) => Ok(ty),
- Ok(None) => Err(FailureKind::Overflow),
- Err(e) => Err(FailureKind::NoSolution(e)),
+ Some(ty) => Ok(ty),
+ None => Err(Overflow),
};
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty) {
- Err(FailureKind::Overflow) => {
+ Err(Overflow) => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
}
- Err(FailureKind::NoSolution(NoSolution)) | Ok(Ok(())) => Err(NoSolution),
+ Ok(Ok(())) => Err(NoSolution),
Ok(Err(_)) => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 839968b25..f442e2a08 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -50,14 +50,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
- ty::Tuple(ref tys) => {
+ ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
Ok(tys.iter().collect())
}
- ty::Closure(_, ref args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
+ ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
- ty::Coroutine(_, ref args, _) => {
+ ty::Coroutine(_, args, _) => {
let coroutine_args = args.as_coroutine();
Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])
}
@@ -91,13 +91,13 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
) -> ty::Binder<'tcx, Ty<'tcx>> {
- debug_assert!(!ty.has_late_bound_regions());
+ debug_assert!(!ty.has_bound_regions());
let mut counter = 0;
let 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)
+ ty::Region::new_bound(tcx, current_depth, br)
}
// All free regions should be erased here.
r => bug!("unexpected region: {r:?}"),
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
deleted file mode 100644
index 377ae1b4e..000000000
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ /dev/null
@@ -1,428 +0,0 @@
-use std::cmp::Ordering;
-
-use crate::infer::InferCtxt;
-use rustc_middle::infer::canonical::Canonical;
-use rustc_middle::infer::canonical::CanonicalTyVarKind;
-use rustc_middle::infer::canonical::CanonicalVarInfo;
-use rustc_middle::infer::canonical::CanonicalVarInfos;
-use rustc_middle::infer::canonical::CanonicalVarKind;
-use rustc_middle::ty::BoundRegionKind::BrAnon;
-use rustc_middle::ty::BoundTyKind;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty};
-use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-
-/// Whether we're canonicalizing a query input or the query response.
-///
-/// When canonicalizing an input we're in the context of the caller
-/// while canonicalizing the response happens in the context of the
-/// query.
-#[derive(Debug, Clone, Copy)]
-pub enum CanonicalizeMode {
- Input,
- /// FIXME: We currently return region constraints referring to
- /// placeholders and inference variables from a binder instantiated
- /// inside of the query.
- ///
- /// In the long term we should eagerly deal with these constraints
- /// inside of the query and only propagate constraints which are
- /// actually nameable by the caller.
- Response {
- /// The highest universe nameable by the caller.
- ///
- /// All variables in a universe nameable by the caller get mapped
- /// to the root universe in the response and then mapped back to
- /// their correct universe when applying the query response in the
- /// context of the caller.
- ///
- /// This doesn't work for universes created inside of the query so
- /// we do remember their universe in the response.
- max_input_universe: ty::UniverseIndex,
- },
-}
-
-pub struct Canonicalizer<'a, 'tcx> {
- infcx: &'a InferCtxt<'tcx>,
- canonicalize_mode: CanonicalizeMode,
-
- variables: &'a mut Vec<ty::GenericArg<'tcx>>,
- primitive_var_infos: Vec<CanonicalVarInfo<'tcx>>,
- binder_index: ty::DebruijnIndex,
-}
-
-impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
- #[instrument(level = "debug", skip(infcx), ret)]
- pub fn canonicalize<T: TypeFoldable<TyCtxt<'tcx>>>(
- infcx: &'a InferCtxt<'tcx>,
- canonicalize_mode: CanonicalizeMode,
- variables: &'a mut Vec<ty::GenericArg<'tcx>>,
- value: T,
- ) -> Canonical<'tcx, T> {
- let mut canonicalizer = Canonicalizer {
- infcx,
- canonicalize_mode,
-
- variables,
- primitive_var_infos: Vec::new(),
- binder_index: ty::INNERMOST,
- };
-
- let value = value.fold_with(&mut canonicalizer);
- assert!(!value.has_infer());
- assert!(!value.has_placeholders());
-
- let (max_universe, variables) = canonicalizer.finalize();
-
- Canonical { max_universe, variables, value }
- }
-
- fn finalize(self) -> (ty::UniverseIndex, CanonicalVarInfos<'tcx>) {
- let mut var_infos = self.primitive_var_infos;
- // See the rustc-dev-guide section about how we deal with universes
- // during canonicalization in the new solver.
- match self.canonicalize_mode {
- // We try to deduplicate as many query calls as possible and hide
- // all information which should not matter for the solver.
- //
- // For this we compress universes as much as possible.
- CanonicalizeMode::Input => {}
- // When canonicalizing a response we map a universes already entered
- // by the caller to the root universe and only return useful universe
- // information for placeholders and inference variables created inside
- // of the query.
- CanonicalizeMode::Response { max_input_universe } => {
- for var in var_infos.iter_mut() {
- let uv = var.universe();
- let new_uv = ty::UniverseIndex::from(
- uv.index().saturating_sub(max_input_universe.index()),
- );
- *var = var.with_updated_universe(new_uv);
- }
- let max_universe = var_infos
- .iter()
- .map(|info| info.universe())
- .max()
- .unwrap_or(ty::UniverseIndex::ROOT);
-
- let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos);
- return (max_universe, var_infos);
- }
- }
-
- // Given a `var_infos` with existentials `En` and universals `Un` in
- // universes `n`, this algorithm compresses them in place so that:
- //
- // - the new universe indices are as small as possible
- // - we only create a new universe if we would otherwise put a placeholder in
- // the same compressed universe as an existential which cannot name it
- //
- // Let's walk through an example:
- // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
- // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
- // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
- // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
- // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6
- // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: -
- //
- // This algorithm runs in `O(n²)` where `n` is the number of different universe
- // indices in the input. This should be fine as `n` is expected to be small.
- let mut curr_compressed_uv = ty::UniverseIndex::ROOT;
- let mut existential_in_new_uv = false;
- let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
- while let Some(orig_uv) = next_orig_uv.take() {
- let mut update_uv = |var: &mut CanonicalVarInfo<'tcx>, orig_uv, is_existential| {
- let uv = var.universe();
- match uv.cmp(&orig_uv) {
- Ordering::Less => (), // Already updated
- Ordering::Equal => {
- if is_existential {
- existential_in_new_uv = true;
- } else if existential_in_new_uv {
- // `var` is a placeholder from a universe which is not nameable
- // by an existential which we already put into the compressed
- // universe `curr_compressed_uv`. We therefore have to create a
- // new universe for `var`.
- curr_compressed_uv = curr_compressed_uv.next_universe();
- existential_in_new_uv = false;
- }
-
- *var = var.with_updated_universe(curr_compressed_uv);
- }
- Ordering::Greater => {
- // We can ignore this variable in this iteration. We only look at
- // universes which actually occur in the input for performance.
- //
- // For this we set `next_orig_uv` to the next smallest, not yet compressed,
- // universe of the input.
- if next_orig_uv.map_or(true, |curr_next_uv| uv.cannot_name(curr_next_uv)) {
- next_orig_uv = Some(uv);
- }
- }
- }
- };
-
- // For each universe which occurs in the input, we first iterate over all
- // placeholders and then over all inference variables.
- //
- // Whenever we compress the universe of a placeholder, no existential with
- // an already compressed universe can name that placeholder.
- for is_existential in [false, true] {
- for var in var_infos.iter_mut() {
- // We simply put all regions from the input into the highest
- // compressed universe, so we only deal with them at the end.
- if !var.is_region() {
- if is_existential == var.is_existential() {
- update_uv(var, orig_uv, is_existential)
- }
- }
- }
- }
- }
-
- for var in var_infos.iter_mut() {
- if var.is_region() {
- assert!(var.is_existential());
- *var = var.with_updated_universe(curr_compressed_uv);
- }
- }
-
- let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos);
- (curr_compressed_uv, var_infos)
- }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
- fn interner(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
- where
- T: TypeFoldable<TyCtxt<'tcx>>,
- {
- self.binder_index.shift_in(1);
- let t = t.super_fold_with(self);
- self.binder_index.shift_out(1);
- t
- }
-
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if let ty::ReVar(vid) = *r {
- let resolved_region = self
- .infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .opportunistic_resolve_var(self.infcx.tcx, vid);
- assert_eq!(
- r, resolved_region,
- "region var should have been resolved, {r} -> {resolved_region}"
- );
- }
-
- let kind = match *r {
- ty::ReLateBound(..) => return r,
-
- // We may encounter `ReStatic` in item signatures or the hidden type
- // of an opaque. `ReErased` should only be encountered in the hidden
- // type of an opaque for regions that are ignored for the purposes of
- // captures.
- //
- // FIXME: We should investigate the perf implications of not uniquifying
- // `ReErased`. We may be able to short-circuit registering region
- // obligations if we encounter a `ReErased` on one side, for example.
- ty::ReStatic | ty::ReErased => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
- CanonicalizeMode::Response { .. } => return r,
- },
-
- ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
- CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"),
- },
-
- ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
- // We canonicalize placeholder regions as existentials in query inputs.
- CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
- CanonicalizeMode::Response { max_input_universe } => {
- // If we have a placeholder region inside of a query, it must be from
- // a new universe.
- if max_input_universe.can_name(placeholder.universe) {
- bug!("new placeholder in universe {max_input_universe:?}: {r:?}");
- }
- CanonicalVarKind::PlaceholderRegion(placeholder)
- }
- },
-
- ty::ReVar(_) => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
- CanonicalizeMode::Response { .. } => {
- CanonicalVarKind::Region(self.infcx.universe_of_region(r))
- }
- },
-
- ty::ReError(_) => return r,
- };
-
- let existing_bound_var = match self.canonicalize_mode {
- CanonicalizeMode::Input => None,
- CanonicalizeMode::Response { .. } => {
- self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from)
- }
- };
- let var = existing_bound_var.unwrap_or_else(|| {
- let var = ty::BoundVar::from(self.variables.len());
- self.variables.push(r.into());
- self.primitive_var_infos.push(CanonicalVarInfo { kind });
- var
- });
- let br = ty::BoundRegion { var, kind: BrAnon };
- ty::Region::new_late_bound(self.interner(), self.binder_index, br)
- }
-
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- let kind = match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
- assert_eq!(self.infcx.root_var(vid), vid, "ty vid should have been resolved");
- let Err(ui) = self.infcx.probe_ty_var(vid) else {
- bug!("ty var should have been resolved: {t}");
- };
- CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
- }
- ty::Infer(ty::IntVar(vid)) => {
- assert_eq!(self.infcx.opportunistic_resolve_int_var(vid), t);
- CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
- }
- ty::Infer(ty::FloatVar(vid)) => {
- assert_eq!(self.infcx.opportunistic_resolve_float_var(vid), t);
- CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
- }
- ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
- bug!("fresh var during canonicalization: {t:?}")
- }
- ty::Placeholder(placeholder) => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder {
- universe: placeholder.universe,
- bound: ty::BoundTy {
- var: ty::BoundVar::from_usize(self.variables.len()),
- kind: ty::BoundTyKind::Anon,
- },
- }),
- CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder),
- },
- ty::Param(_) => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder {
- universe: ty::UniverseIndex::ROOT,
- bound: ty::BoundTy {
- var: ty::BoundVar::from_usize(self.variables.len()),
- kind: ty::BoundTyKind::Anon,
- },
- }),
- CanonicalizeMode::Response { .. } => bug!("param ty in response: {t:?}"),
- },
- 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::Coroutine(_, _, _)
- | ty::CoroutineWitness(..)
- | ty::Never
- | ty::Tuple(_)
- | ty::Alias(_, _)
- | ty::Bound(_, _)
- | ty::Error(_) => return t.super_fold_with(self),
- };
-
- let var = ty::BoundVar::from(
- self.variables.iter().position(|&v| v == t.into()).unwrap_or_else(|| {
- let var = self.variables.len();
- self.variables.push(t.into());
- self.primitive_var_infos.push(CanonicalVarInfo { kind });
- var
- }),
- );
- let bt = ty::BoundTy { var, kind: BoundTyKind::Anon };
- Ty::new_bound(self.infcx.tcx, self.binder_index, bt)
- }
-
- fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
- let kind = match c.kind() {
- ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
- assert_eq!(
- self.infcx.root_const_var(vid),
- vid,
- "const var should have been resolved"
- );
- let Err(ui) = self.infcx.probe_const_var(vid) else {
- bug!("const var should have been resolved");
- };
- // FIXME: we should fold this ty eventually
- CanonicalVarKind::Const(ui, c.ty())
- }
- ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
- assert_eq!(
- self.infcx.root_effect_var(vid),
- vid,
- "effect var should have been resolved"
- );
- let None = self.infcx.probe_effect_var(vid) else {
- bug!("effect var should have been resolved");
- };
- CanonicalVarKind::Effect
- }
- ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
- bug!("fresh var during canonicalization: {c:?}")
- }
- ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
- ty::Placeholder {
- universe: placeholder.universe,
- bound: ty::BoundVar::from(self.variables.len()),
- },
- c.ty(),
- ),
- CanonicalizeMode::Response { .. } => {
- CanonicalVarKind::PlaceholderConst(placeholder, c.ty())
- }
- },
- ty::ConstKind::Param(_) => match self.canonicalize_mode {
- CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
- ty::Placeholder {
- universe: ty::UniverseIndex::ROOT,
- bound: ty::BoundVar::from(self.variables.len()),
- },
- c.ty(),
- ),
- CanonicalizeMode::Response { .. } => bug!("param ty in response: {c:?}"),
- },
- ty::ConstKind::Bound(_, _)
- | ty::ConstKind::Unevaluated(_)
- | ty::ConstKind::Value(_)
- | ty::ConstKind::Error(_)
- | ty::ConstKind::Expr(_) => return c.super_fold_with(self),
- };
-
- let var = ty::BoundVar::from(
- self.variables.iter().position(|&v| v == c.into()).unwrap_or_else(|| {
- let var = self.variables.len();
- self.variables.push(c.into());
- self.primitive_var_infos.push(CanonicalVarInfo { kind });
- var
- }),
- );
- ty::Const::new_bound(self.infcx.tcx, self.binder_index, var, c.ty())
- }
-}
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index b3f9218d7..ecdae2521 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -9,7 +9,6 @@
//!
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
-use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
use crate::solve::{
inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response,
};
@@ -18,6 +17,7 @@ use rustc_index::IndexVec;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
+use rustc_infer::infer::resolve::EagerResolver;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::traits::query::NoSolution;
@@ -25,10 +25,8 @@ use rustc_middle::traits::solve::{
ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
};
use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{
- self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
- TypeVisitableExt,
-};
+use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
+use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
use rustc_span::DUMMY_SP;
use std::iter;
use std::ops::Deref;
@@ -58,7 +56,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
let (goal, opaque_types) =
- (goal, opaque_types).fold_with(&mut EagerResolver { infcx: self.infcx });
+ (goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx));
let mut orig_values = Default::default();
let canonical_goal = Canonicalizer::canonicalize(
@@ -96,26 +94,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
);
let certainty = certainty.unify_with(goals_certainty);
- if let Certainty::OVERFLOW = certainty {
- // If we have overflow, it's probable that we're substituting a type
- // into itself infinitely and any partial substitutions in the query
- // response are probably not useful anyways, so just return an empty
- // query response.
- //
- // This may prevent us from potentially useful inference, e.g.
- // 2 candidates, one ambiguous and one overflow, which both
- // have the same inference constraints.
- //
- // Changing this to retain some constraints in the future
- // won't be a breaking change, so this is good enough for now.
- return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
- }
let var_values = self.var_values;
let external_constraints = self.compute_external_query_constraints()?;
let (var_values, mut external_constraints) =
- (var_values, external_constraints).fold_with(&mut EagerResolver { infcx: self.infcx });
+ (var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx));
// Remove any trivial region constraints once we've resolved regions
external_constraints
.region_constraints
@@ -262,7 +246,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
GenericArgKind::Lifetime(r) => {
- if let ty::ReLateBound(debruijn, br) = *r {
+ if let ty::ReBound(debruijn, br) = *r {
assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.var] = Some(*original_value);
}
@@ -364,86 +348,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
-/// Resolves ty, region, and const vars to their inferred values or their root vars.
-struct EagerResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
- fn interner(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
- Ok(t) => t.fold_with(self),
- Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
- },
- ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
- ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
- _ => {
- if t.has_infer() {
- t.super_fold_with(self)
- } else {
- t
- }
- }
- }
- }
-
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match *r {
- ty::ReVar(vid) => self
- .infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .opportunistic_resolve_var(self.infcx.tcx, vid),
- _ => r,
- }
- }
-
- fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
- match c.kind() {
- ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
- // FIXME: we need to fold the ty too, I think.
- match self.infcx.probe_const_var(vid) {
- Ok(c) => c.fold_with(self),
- Err(_) => {
- ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
- }
- }
- }
- ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
- debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
- match self.infcx.probe_effect_var(vid) {
- Some(c) => c.as_const(self.infcx.tcx),
- None => ty::Const::new_infer(
- self.infcx.tcx,
- ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
- self.infcx.tcx.types.bool,
- ),
- }
- }
- _ => {
- if c.has_infer() {
- c.super_fold_with(self)
- } else {
- c
- }
- }
- }
- }
-}
-
impl<'tcx> inspect::ProofTreeBuilder<'tcx> {
pub fn make_canonical_state<T: TypeFoldable<TyCtxt<'tcx>>>(
ecx: &EvalCtxt<'_, 'tcx>,
data: T,
) -> inspect::CanonicalState<'tcx, T> {
let state = inspect::State { var_values: ecx.var_values, data };
- let state = state.fold_with(&mut EagerResolver { infcx: ecx.infcx });
+ let state = state.fold_with(&mut EagerResolver::new(ecx.infcx));
Canonicalizer::canonicalize(
ecx.infcx,
CanonicalizeMode::Response { max_input_universe: ecx.max_input_universe },
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs
new file mode 100644
index 000000000..67b680105
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs
@@ -0,0 +1,45 @@
+use super::{EvalCtxt, NestedGoals};
+use crate::solve::inspect;
+use rustc_middle::traits::query::NoSolution;
+
+impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+ pub(in crate::solve) fn commit_if_ok<T>(
+ &mut self,
+ f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> Result<T, NoSolution>,
+ ) -> Result<T, NoSolution> {
+ let mut nested_ecx = EvalCtxt {
+ infcx: self.infcx,
+ variables: self.variables,
+ var_values: self.var_values,
+ predefined_opaques_in_body: self.predefined_opaques_in_body,
+ max_input_universe: self.max_input_universe,
+ search_graph: self.search_graph,
+ nested_goals: NestedGoals::new(),
+ tainted: self.tainted,
+ inspect: self.inspect.new_probe(),
+ };
+
+ let result = nested_ecx.infcx.commit_if_ok(|_| f(&mut nested_ecx));
+ if result.is_ok() {
+ let EvalCtxt {
+ infcx: _,
+ variables: _,
+ var_values: _,
+ predefined_opaques_in_body: _,
+ max_input_universe: _,
+ search_graph: _,
+ nested_goals,
+ tainted,
+ inspect,
+ } = nested_ecx;
+ self.nested_goals.extend(nested_goals);
+ self.tainted = tainted;
+ self.inspect.integrate_snapshot(inspect);
+ } else {
+ nested_ecx.inspect.probe_kind(inspect::ProbeKind::CommitIfOk);
+ self.inspect.finish_probe(nested_ecx.inspect);
+ }
+
+ result
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 70235b710..76c50a111 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
- DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
+ BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause;
@@ -23,17 +23,19 @@ use rustc_middle::ty::{
use rustc_session::config::DumpSolverProofTree;
use rustc_span::DUMMY_SP;
use std::io::Write;
+use std::iter;
use std::ops::ControlFlow;
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
use super::inspect::ProofTreeBuilder;
-use super::SolverMode;
use super::{search_graph, GoalEvaluationKind};
use super::{search_graph::SearchGraph, Goal};
+use super::{GoalSource, SolverMode};
pub use select::InferCtxtSelectExt;
mod canonical;
+mod commit_if_ok;
mod probe;
mod select;
@@ -102,12 +104,12 @@ pub(super) struct NestedGoals<'tcx> {
/// with a fresh inference variable when we evaluate this goal. That can result
/// in a trait solver cycle. This would currently result in overflow but can be
/// can be unsound with more powerful coinduction in the future.
- pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::ProjectionPredicate<'tcx>>>,
+ pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::NormalizesTo<'tcx>>>,
/// The rest of the goals which have not yet processed or remain ambiguous.
- pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+ pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
}
-impl NestedGoals<'_> {
+impl<'tcx> NestedGoals<'tcx> {
pub(super) fn new() -> Self {
Self { normalizes_to_hack_goal: None, goals: Vec::new() }
}
@@ -115,6 +117,11 @@ impl NestedGoals<'_> {
pub(super) fn is_empty(&self) -> bool {
self.normalizes_to_hack_goal.is_none() && self.goals.is_empty()
}
+
+ pub(super) fn extend(&mut self, other: NestedGoals<'tcx>) {
+ assert_eq!(other.normalizes_to_hack_goal, None);
+ self.goals.extend(other.goals)
+ }
}
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
@@ -140,7 +147,7 @@ pub trait InferCtxtEvalExt<'tcx> {
}
impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
- #[instrument(level = "debug", skip(self), ret)]
+ #[instrument(level = "debug", skip(self))]
fn evaluate_root_goal(
&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
@@ -150,7 +157,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
Option<inspect::GoalEvaluation<'tcx>>,
) {
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
- ecx.evaluate_goal(GoalEvaluationKind::Root, goal)
+ ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
})
}
}
@@ -194,9 +201,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let result = f(&mut ecx);
let tree = ecx.inspect.finalize();
- if let (Some(tree), DumpSolverProofTree::Always) =
- (&tree, infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree)
- {
+ if let (Some(tree), DumpSolverProofTree::Always) = (
+ &tree,
+ infcx.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default(),
+ ) {
let mut lock = std::io::stdout().lock();
let _ = lock.write_fmt(format_args!("{tree:?}\n"));
let _ = lock.flush();
@@ -327,12 +335,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
fn evaluate_goal(
&mut self,
goal_evaluation_kind: GoalEvaluationKind,
+ source: GoalSource,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
let mut goal_evaluation =
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
- let encountered_overflow = self.search_graph.encountered_overflow();
let canonical_response = EvalCtxt::evaluate_canonical_goal(
self.tcx(),
self.search_graph,
@@ -347,13 +355,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
Ok(response) => response,
};
- let has_changed = !canonical_response.value.var_values.is_identity_modulo_regions()
- || !canonical_response.value.external_constraints.opaque_types.is_empty();
- let (certainty, nested_goals) = match self.instantiate_and_apply_query_response(
- goal.param_env,
- orig_values,
- canonical_response,
- ) {
+ let (certainty, has_changed, nested_goals) = match self
+ .instantiate_response_discarding_overflow(
+ goal.param_env,
+ source,
+ orig_values,
+ canonical_response,
+ ) {
Err(e) => {
self.inspect.goal_evaluation(goal_evaluation);
return Err(e);
@@ -367,72 +375,54 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
bug!("an unchanged goal shouldn't have any side-effects on instantiation");
}
- // Check that rerunning this query with its inference constraints applied
- // doesn't result in new inference constraints and has the same result.
+ // FIXME: We previously had an assert here that checked that recomputing
+ // a goal after applying its constraints did not change its response.
//
- // If we have projection goals like `<T as Trait>::Assoc == u32` we recursively
- // call `exists<U> <T as Trait>::Assoc == U` to enable better caching. This goal
- // could constrain `U` to `u32` which would cause this check to result in a
- // solver cycle.
- if cfg!(debug_assertions)
- && has_changed
- && !matches!(
- goal_evaluation_kind,
- GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }
- )
- && !self.search_graph.in_cycle()
- {
- // The nested evaluation has to happen with the original state
- // of `encountered_overflow`.
- let from_original_evaluation =
- self.search_graph.reset_encountered_overflow(encountered_overflow);
- self.check_evaluate_goal_stable_result(goal, canonical_goal, canonical_response);
- // In case the evaluation was unstable, we manually make sure that this
- // debug check does not influence the result of the parent goal.
- self.search_graph.reset_encountered_overflow(from_original_evaluation);
- }
+ // This assert was removed as it did not hold for goals constraining
+ // an inference variable to a recursive alias, e.g. in
+ // tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs.
+ //
+ // Once we have decided on how to handle trait-system-refactor-initiative#75,
+ // we should re-add an assert here.
Ok((has_changed, certainty, nested_goals))
}
- fn check_evaluate_goal_stable_result(
+ fn instantiate_response_discarding_overflow(
&mut self,
- goal: Goal<'tcx, ty::Predicate<'tcx>>,
- original_input: CanonicalInput<'tcx>,
- original_result: CanonicalResponse<'tcx>,
- ) {
- let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
- let result = EvalCtxt::evaluate_canonical_goal(
- self.tcx(),
- self.search_graph,
- canonical_goal,
- // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal`
- &mut ProofTreeBuilder::new_noop(),
- );
+ param_env: ty::ParamEnv<'tcx>,
+ source: GoalSource,
+ original_values: Vec<ty::GenericArg<'tcx>>,
+ response: CanonicalResponse<'tcx>,
+ ) -> Result<(Certainty, bool, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
+ // The old solver did not evaluate nested goals when normalizing.
+ // It returned the selection constraints allowing a `Projection`
+ // obligation to not hold in coherence while avoiding the fatal error
+ // from overflow.
+ //
+ // We match this behavior here by considering all constraints
+ // from nested goals which are not from where-bounds. We will already
+ // need to track which nested goals are required by impl where-bounds
+ // for coinductive cycles, so we simply reuse that here.
+ //
+ // While we could consider overflow constraints in more cases, this should
+ // not be necessary for backcompat and results in better perf. It also
+ // avoids a potential inconsistency which would otherwise require some
+ // tracking for root goals as well. See #119071 for an example.
+ let keep_overflow_constraints = || {
+ self.search_graph.current_goal_is_normalizes_to()
+ && source != GoalSource::ImplWhereBound
+ };
- macro_rules! fail {
- ($msg:expr) => {{
- let msg = $msg;
- warn!(
- "unstable result: {msg}\n\
- original goal: {original_input:?},\n\
- original result: {original_result:?}\n\
- re-canonicalized goal: {canonical_goal:?}\n\
- second response: {result:?}"
- );
- return;
- }};
- }
+ if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
+ Ok((Certainty::OVERFLOW, false, Vec::new()))
+ } else {
+ let has_changed = !response.value.var_values.is_identity_modulo_regions()
+ || !response.value.external_constraints.opaque_types.is_empty();
- let Ok(new_canonical_response) = result else { fail!("second response was error") };
- // We only check for modulo regions as we convert all regions in
- // the input to new existentials, even if they're expected to be
- // `'static` or a placeholder region.
- if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
- fail!("additional constraints from second response")
- }
- if original_result.value.certainty != new_canonical_response.value.certainty {
- fail!("unstable certainty")
+ let (certainty, nested_goals) =
+ self.instantiate_and_apply_query_response(param_env, original_values, response)?;
+ Ok((certainty, has_changed, nested_goals))
}
}
@@ -462,8 +452,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
ty::PredicateKind::Coerce(predicate) => {
self.compute_coerce_goal(Goal { param_env, predicate })
}
- ty::PredicateKind::ClosureKind(def_id, args, kind) => self
- .compute_closure_kind_goal(Goal { param_env, predicate: (def_id, args, kind) }),
ty::PredicateKind::ObjectSafe(trait_def_id) => {
self.compute_object_safe_goal(trait_def_id)
}
@@ -474,7 +462,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
}
ty::PredicateKind::ConstEquate(_, _) => {
- bug!("ConstEquate should not be emitted when `-Ztrait-solver=next` is active")
+ bug!("ConstEquate should not be emitted when `-Znext-solver` is active")
+ }
+ ty::PredicateKind::NormalizesTo(predicate) => {
+ self.compute_normalizes_to_goal(Goal { param_env, predicate })
}
ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
.compute_alias_relate_goal(Goal {
@@ -488,7 +479,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
} else {
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
- self.add_goal(goal);
+ self.add_goal(GoalSource::Misc, goal);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
@@ -537,6 +528,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new());
self.inspect.evaluate_added_goals_loop_start();
+
+ fn with_misc_source<'tcx>(
+ it: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+ ) -> impl Iterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)> {
+ iter::zip(iter::repeat(GoalSource::Misc), it)
+ }
+
// If this loop did not result in any progress, what's our final certainty.
let mut unchanged_certainty = Some(Certainty::Yes);
if let Some(goal) = goals.normalizes_to_hack_goal.take() {
@@ -545,17 +543,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term);
let unconstrained_goal = goal.with(
tcx,
- ty::ProjectionPredicate {
- projection_ty: goal.predicate.projection_ty,
- term: unconstrained_rhs,
- },
+ ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs },
);
let (_, certainty, instantiate_goals) = self.evaluate_goal(
GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes },
+ GoalSource::Misc,
unconstrained_goal,
)?;
- self.nested_goals.goals.extend(instantiate_goals);
+ self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
// Finally, equate the goal's RHS with the unconstrained var.
// We put the nested goals from this into goals instead of
@@ -564,15 +560,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
// matters in practice, though.
let eq_goals =
self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?;
- goals.goals.extend(eq_goals);
+ goals.goals.extend(with_misc_source(eq_goals));
// We only look at the `projection_ty` part here rather than
// looking at the "has changed" return from evaluate_goal,
// because we expect the `unconstrained_rhs` part of the predicate
// to have changed -- that means we actually normalized successfully!
- if goal.predicate.projection_ty
- != self.resolve_vars_if_possible(goal.predicate.projection_ty)
- {
+ if goal.predicate.alias != self.resolve_vars_if_possible(goal.predicate.alias) {
unchanged_certainty = None;
}
@@ -587,12 +581,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
}
}
- for goal in goals.goals.drain(..) {
+ for (source, goal) in goals.goals.drain(..) {
let (has_changed, certainty, instantiate_goals) = self.evaluate_goal(
GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No },
+ source,
goal,
)?;
- self.nested_goals.goals.extend(instantiate_goals);
+ self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
if has_changed {
unchanged_certainty = None;
}
@@ -600,7 +595,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
match certainty {
Certainty::Yes => {}
Certainty::Maybe(_) => {
- self.nested_goals.goals.push(goal);
+ self.nested_goals.goals.push((source, goal));
unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
}
}
@@ -642,9 +637,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
///
/// This is the case if the `term` is an inference variable in the innermost universe
/// and does not occur in any other part of the predicate.
+ #[instrument(level = "debug", skip(self), ret)]
pub(super) fn term_is_fully_unconstrained(
&self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> bool {
let term_is_infer = match goal.predicate.term.unpack() {
ty::TermKind::Ty(ty) => {
@@ -708,7 +704,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let mut visitor = ContainsTerm { infcx: self.infcx, term: goal.predicate.term };
term_is_infer
- && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue()
+ && goal.predicate.alias.visit_with(&mut visitor).is_continue()
&& goal.param_env.visit_with(&mut visitor).is_continue()
}
@@ -723,7 +719,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
.at(&ObligationCause::dummy(), param_env)
.eq(DefineOpaqueTypes::No, lhs, rhs)
.map(|InferOk { value: (), obligations }| {
- self.add_goals(obligations.into_iter().map(|o| o.into()));
+ self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
})
.map_err(|e| {
debug!(?e, "failed to equate");
@@ -742,7 +738,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
.at(&ObligationCause::dummy(), param_env)
.sub(DefineOpaqueTypes::No, sub, sup)
.map(|InferOk { value: (), obligations }| {
- self.add_goals(obligations.into_iter().map(|o| o.into()));
+ self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
})
.map_err(|e| {
debug!(?e, "failed to subtype");
@@ -750,6 +746,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
})
}
+ #[instrument(level = "debug", skip(self, param_env), ret)]
+ pub(super) fn relate<T: ToTrace<'tcx>>(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ lhs: T,
+ variance: ty::Variance,
+ rhs: T,
+ ) -> Result<(), NoSolution> {
+ self.infcx
+ .at(&ObligationCause::dummy(), param_env)
+ .relate(DefineOpaqueTypes::No, lhs, variance, rhs)
+ .map(|InferOk { value: (), obligations }| {
+ self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
+ })
+ .map_err(|e| {
+ debug!(?e, "failed to relate");
+ NoSolution
+ })
+ }
+
/// Equates two values returning the nested goals without adding them
/// to the nested goals of the `EvalCtxt`.
///
@@ -780,7 +796,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> T {
self.infcx.instantiate_binder_with_fresh_vars(
DUMMY_SP,
- LateBoundRegionConversionTime::HigherRankedType,
+ BoundRegionConversionTime::HigherRankedType,
value,
)
}
@@ -875,7 +891,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
true,
&mut obligations,
)?;
- self.add_goals(obligations.into_iter().map(|o| o.into()));
+ self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
Ok(())
}
@@ -895,7 +911,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
hidden_ty,
&mut obligations,
);
- self.add_goals(obligations.into_iter().map(|o| o.into()));
+ self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
}
// Do something for each opaque/hidden pair defined with `def_id` in the
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index 6087b9167..91fd48807 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -1,5 +1,10 @@
+use crate::solve::assembly::Candidate;
+
use super::EvalCtxt;
-use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
+use rustc_middle::traits::{
+ query::NoSolution,
+ solve::{inspect, CandidateSource, QueryResult},
+};
use std::marker::PhantomData;
pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
@@ -36,6 +41,23 @@ where
}
}
+pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
+ cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
+ source: CandidateSource,
+}
+
+impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
+where
+ F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
+{
+ pub(in crate::solve) fn enter(
+ self,
+ f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+ ) -> Result<Candidate<'tcx>, NoSolution> {
+ self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
+ }
+}
+
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
/// `probe_kind` is only called when proof tree building is enabled so it can be
/// as expensive as necessary to output the desired information.
@@ -69,20 +91,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
pub(in crate::solve) fn probe_trait_candidate(
&mut self,
source: CandidateSource,
- ) -> ProbeCtxt<
- '_,
- 'a,
- 'tcx,
- impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
- QueryResult<'tcx>,
- > {
- ProbeCtxt {
- ecx: self,
- probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
- source,
- result: *result,
+ ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
+ {
+ TraitProbeCtxt {
+ cx: ProbeCtxt {
+ ecx: self,
+ probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
+ source,
+ result: *result,
+ },
+ _result: PhantomData,
},
- _result: PhantomData,
+ source,
}
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index f1d309122..2139210b8 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -108,6 +108,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
MismatchedProjectionTypes { err: TypeError::Mismatch },
)
}
+ ty::PredicateKind::NormalizesTo(..) => {
+ FulfillmentErrorCode::CodeProjectionError(
+ MismatchedProjectionTypes { err: TypeError::Mismatch },
+ )
+ }
ty::PredicateKind::AliasRelate(_, _, _) => {
FulfillmentErrorCode::CodeProjectionError(
MismatchedProjectionTypes { err: TypeError::Mismatch },
@@ -135,7 +140,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
}
ty::PredicateKind::Clause(_)
| ty::PredicateKind::ObjectSafe(_)
- | ty::PredicateKind::ClosureKind(_, _, _)
| ty::PredicateKind::Ambiguous => {
FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented,
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 69bfdd468..6db53d6dd 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -58,7 +58,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
visitor: &mut V,
) -> ControlFlow<V::BreakTy> {
// HACK: An arbitrary cutoff to avoid dealing with overflow and cycles.
- if self.goal.depth >= 10 {
+ if self.goal.depth <= 10 {
let infcx = self.goal.infcx;
infcx.probe(|_| {
let mut instantiated_goals = vec![];
@@ -119,8 +119,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
) {
for step in &probe.steps {
match step {
- &inspect::ProbeStep::AddGoal(goal) => nested_goals.push(goal),
- inspect::ProbeStep::EvaluateGoals(_) => (),
+ &inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
inspect::ProbeStep::NestedProbe(ref probe) => {
// Nested probes have to prove goals added in their parent
// but do not leak them, so we truncate the added goals
@@ -129,13 +128,17 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
self.candidates_recur(candidates, nested_goals, probe);
nested_goals.truncate(num_goals);
}
+ inspect::ProbeStep::EvaluateGoals(_)
+ | inspect::ProbeStep::CommitIfOkStart
+ | inspect::ProbeStep::CommitIfOkSuccess => (),
}
}
match probe.kind {
inspect::ProbeKind::NormalizedSelfTyAssembly
| inspect::ProbeKind::UnsizeAssembly
- | inspect::ProbeKind::UpcastProjectionCompatibility => (),
+ | inspect::ProbeKind::UpcastProjectionCompatibility
+ | inspect::ProbeKind::CommitIfOk => (),
// We add a candidate for the root evaluation if there
// is only one way to prove a given goal, e.g. for `WellFormed`.
//
@@ -172,7 +175,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
warn!("unexpected root evaluation: {:?}", self.evaluation);
return vec![];
}
- inspect::CanonicalGoalEvaluationKind::Evaluation { ref revisions } => {
+ inspect::CanonicalGoalEvaluationKind::Evaluation { revisions } => {
if let Some(last) = revisions.last() {
last
} else {
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 088455b38..d8caef5b0 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -7,7 +7,7 @@ use std::mem;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{
- CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult,
+ CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack, QueryInput, QueryResult,
};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::DumpSolverProofTree;
@@ -216,17 +216,21 @@ impl<'tcx> WipProbe<'tcx> {
#[derive(Eq, PartialEq, Debug)]
enum WipProbeStep<'tcx> {
- AddGoal(inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+ AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
NestedProbe(WipProbe<'tcx>),
+ CommitIfOkStart,
+ CommitIfOkSuccess,
}
impl<'tcx> WipProbeStep<'tcx> {
fn finalize(self) -> inspect::ProbeStep<'tcx> {
match self {
- WipProbeStep::AddGoal(goal) => inspect::ProbeStep::AddGoal(goal),
+ WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
+ WipProbeStep::CommitIfOkStart => inspect::ProbeStep::CommitIfOkStart,
+ WipProbeStep::CommitIfOkSuccess => inspect::ProbeStep::CommitIfOkSuccess,
}
}
}
@@ -261,7 +265,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
GenerateProofTree::Never => ProofTreeBuilder::new_noop(),
GenerateProofTree::IfEnabled => {
let opts = &tcx.sess.opts.unstable_opts;
- match opts.dump_solver_proof_tree {
+ match opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() {
DumpSolverProofTree::Always => ProofTreeBuilder::new_root(),
// `OnError` is handled by reevaluating goals in error
// reporting with `GenerateProofTree::Yes`.
@@ -424,7 +428,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
}
- pub fn add_goal(ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+ pub fn add_goal(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ source: GoalSource,
+ goal: Goal<'tcx, ty::Predicate<'tcx>>,
+ ) {
// Can't use `if let Some(this) = ecx.inspect.as_mut()` here because
// we have to immutably use the `EvalCtxt` for `make_canonical_state`.
if ecx.inspect.is_noop() {
@@ -438,7 +446,9 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
evaluation: WipProbe { steps, .. },
..
})
- | DebugSolver::Probe(WipProbe { steps, .. }) => steps.push(WipProbeStep::AddGoal(goal)),
+ | DebugSolver::Probe(WipProbe { steps, .. }) => {
+ steps.push(WipProbeStep::AddGoal(source, goal))
+ }
s => unreachable!("tried to add {goal:?} to {s:?}"),
}
}
@@ -459,6 +469,29 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
}
+ /// Used by `EvalCtxt::commit_if_ok` to flatten the work done inside
+ /// of the probe into the parent.
+ pub fn integrate_snapshot(&mut self, probe: ProofTreeBuilder<'tcx>) {
+ if let Some(this) = self.as_mut() {
+ match (this, *probe.state.unwrap()) {
+ (
+ DebugSolver::Probe(WipProbe { steps, .. })
+ | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
+ evaluation: WipProbe { steps, .. },
+ ..
+ }),
+ DebugSolver::Probe(probe),
+ ) => {
+ steps.push(WipProbeStep::CommitIfOkStart);
+ assert_eq!(probe.kind, None);
+ steps.extend(probe.steps);
+ steps.push(WipProbeStep::CommitIfOkSuccess);
+ }
+ _ => unreachable!(),
+ }
+ }
+ }
+
pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> {
self.nested(|| WipAddedGoalsEvaluation { evaluations: vec![], result: None })
}
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index dba5369fa..2f3111a24 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -1,7 +1,6 @@
//! The next-generation trait solver, currently still WIP.
//!
-//! As a user of rust, you can use `-Ztrait-solver=next` or `next-coherence`
-//! to enable the new trait solver always, or just within coherence, respectively.
+//! As a user of rust, you can use `-Znext-solver` to enable the new trait solver.
//!
//! As a developer of rustc, you shouldn't be using the new trait
//! solver without asking the trait-system-refactor-initiative, but it can
@@ -16,31 +15,33 @@
//! about it on zulip.
use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::infer::canonical::CanonicalVarInfos;
use rustc_middle::traits::solve::{
- CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult,
- Response,
+ CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
+ QueryResult, Response,
};
-use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
};
mod alias_relate;
mod assembly;
-mod canonicalize;
mod eval_ctxt;
mod fulfill;
pub mod inspect;
mod normalize;
+mod normalizes_to;
mod project_goals;
mod search_graph;
mod trait_goals;
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
pub use fulfill::FulfillmentCtxt;
-pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
+pub(crate) use normalize::deeply_normalize_for_diagnostics;
+pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
#[derive(Debug, Clone, Copy)]
enum SolverMode {
@@ -63,8 +64,6 @@ enum GoalEvaluationKind {
trait CanonicalResponseExt {
fn has_no_inference_or_external_constraints(&self) -> bool;
-
- fn has_only_region_constraints(&self) -> bool;
}
impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
@@ -73,11 +72,6 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
&& self.value.var_values.is_identity()
&& self.value.external_constraints.opaque_types.is_empty()
}
-
- fn has_only_region_constraints(&self) -> bool {
- self.value.var_values.is_identity_modulo_regions()
- && self.value.external_constraints.opaque_types.is_empty()
- }
}
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
@@ -163,7 +157,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
) -> QueryResult<'tcx> {
match self.well_formed_goals(goal.param_env, goal.predicate) {
Some(goals) => {
- self.add_goals(goals);
+ self.add_goals(GoalSource::Misc, goals);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS),
@@ -220,7 +214,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self))]
- fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) {
+ fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
assert!(
self.nested_goals.normalizes_to_hack_goal.is_none(),
"attempted to set the projection eq hack goal when one already exists"
@@ -229,15 +223,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
#[instrument(level = "debug", skip(self))]
- fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
- inspect::ProofTreeBuilder::add_goal(self, goal);
- self.nested_goals.goals.push(goal);
+ fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+ inspect::ProofTreeBuilder::add_goal(self, source, goal);
+ self.nested_goals.goals.push((source, goal));
}
#[instrument(level = "debug", skip(self, goals))]
- fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
+ fn add_goals(
+ &mut self,
+ source: GoalSource,
+ goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+ ) {
for goal in goals {
- self.add_goal(goal);
+ self.add_goal(source, goal);
}
}
@@ -253,7 +251,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return None;
}
- // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with
+ // FIXME(-Znext-solver): We should instead try to find a `Certainty::Yes` response with
// a subset of the constraints that all the other responses have.
let one = responses[0];
if responses[1..].iter().all(|&resp| resp == one) {
@@ -294,28 +292,61 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
/// in [`EvalCtxt::assemble_candidates_via_self_ty`] does not have to normalize
/// the self type. It is required when structurally matching on any other
/// arguments of a trait goal, e.g. when assembling builtin unsize candidates.
+ #[instrument(level = "debug", skip(self), ret)]
fn try_normalize_ty(
&mut self,
param_env: ty::ParamEnv<'tcx>,
- mut ty: Ty<'tcx>,
- ) -> Result<Option<Ty<'tcx>>, NoSolution> {
- for _ in 0..self.local_overflow_limit() {
- let ty::Alias(_, projection_ty) = *ty.kind() else {
- return Ok(Some(ty));
- };
-
- let normalized_ty = self.next_ty_infer();
+ ty: Ty<'tcx>,
+ ) -> Option<Ty<'tcx>> {
+ self.try_normalize_ty_recur(param_env, DefineOpaqueTypes::Yes, 0, ty)
+ }
+
+ fn try_normalize_ty_recur(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ define_opaque_types: DefineOpaqueTypes,
+ depth: usize,
+ ty: Ty<'tcx>,
+ ) -> Option<Ty<'tcx>> {
+ if !self.tcx().recursion_limit().value_within_limit(depth) {
+ return None;
+ }
+
+ let ty::Alias(kind, alias) = *ty.kind() else {
+ return Some(ty);
+ };
+
+ // We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
+ if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
+ if let Some(def_id) = alias.def_id.as_local() {
+ if self
+ .unify_existing_opaque_tys(
+ param_env,
+ OpaqueTypeKey { def_id, args: alias.args },
+ self.next_ty_infer(),
+ )
+ .is_empty()
+ {
+ return Some(ty);
+ }
+ }
+ }
+
+ match self.commit_if_ok(|this| {
+ let normalized_ty = this.next_ty_infer();
let normalizes_to_goal = Goal::new(
- self.tcx(),
+ this.tcx(),
param_env,
- ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
+ ty::NormalizesTo { alias, term: normalized_ty.into() },
);
- self.add_goal(normalizes_to_goal);
- self.try_evaluate_added_goals()?;
- ty = self.resolve_vars_if_possible(normalized_ty);
+ this.add_goal(GoalSource::Misc, normalizes_to_goal);
+ this.try_evaluate_added_goals()?;
+ let ty = this.resolve_vars_if_possible(normalized_ty);
+ Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty))
+ }) {
+ Ok(ty) => ty,
+ Err(NoSolution) => Some(ty),
}
-
- Ok(None)
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index b0a348985..55b79e6fc 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -4,19 +4,20 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::at::At;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::TraitEngineExt;
use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::Reveal;
+use rustc_middle::traits::{ObligationCause, Reveal};
use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
-use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
use super::FulfillmentCtxt;
/// Deeply normalize all aliases in `value`. This does not handle inference and expects
/// its input to be already fully resolved.
-pub(crate) fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+pub fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
at: At<'_, 'tcx>,
value: T,
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
@@ -30,7 +31,7 @@ pub(crate) fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
/// Additionally takes a list of universes which represents the binders which have been
/// entered before passing `value` to the function. This is currently needed for
/// `normalize_erasing_regions`, which skips binders as it walks through a type.
-pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+pub fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
at: At<'_, 'tcx>,
value: T,
universes: Vec<Option<UniverseIndex>>,
@@ -75,7 +76,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
tcx,
self.at.cause.clone(),
self.at.param_env,
- ty::ProjectionPredicate { projection_ty: alias, term: new_infer_ty.into() },
+ ty::NormalizesTo { alias, term: new_infer_ty.into() },
);
// Do not emit an error if normalization is known to fail but instead
@@ -128,8 +129,8 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
tcx,
self.at.cause.clone(),
self.at.param_env,
- ty::ProjectionPredicate {
- projection_ty: AliasTy::new(tcx, uv.def, uv.args),
+ ty::NormalizesTo {
+ alias: AliasTy::new(tcx, uv.def, uv.args),
term: new_infer_ct.into(),
},
);
@@ -230,3 +231,42 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
}
}
}
+
+// Deeply normalize a value and return it
+pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+ infcx: &InferCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ t: T,
+) -> T {
+ t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
+ at: infcx.at(&ObligationCause::dummy(), param_env),
+ })
+}
+
+struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
+ at: At<'a, 'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
+ fn interner(&self) -> TyCtxt<'tcx> {
+ self.at.infcx.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ deeply_normalize_with_skipped_universes(
+ self.at,
+ ty,
+ vec![None; ty.outer_exclusive_binder().as_usize()],
+ )
+ .unwrap_or_else(|_| ty.super_fold_with(self))
+ }
+
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ deeply_normalize_with_skipped_universes(
+ self.at,
+ ct,
+ vec![None; ct.outer_exclusive_binder().as_usize()],
+ )
+ .unwrap_or_else(|_| ct.super_fold_with(self))
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
index 28fe59b7f..b2dff9b48 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
@@ -4,18 +4,18 @@
//! 1. instantiate substs,
//! 2. equate the self type, and
//! 3. instantiate and register where clauses.
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;
-use super::EvalCtxt;
+use crate::solve::EvalCtxt;
impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_inherent_associated_type(
&mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
- let inherent = goal.predicate.projection_ty;
+ let inherent = goal.predicate.alias;
let expected = goal.predicate.term.ty().expect("inherent consts are treated separately");
let impl_def_id = tcx.parent(inherent.def_id);
@@ -38,7 +38,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
.expect("expected goal term to be fully unconstrained");
// Check both where clauses on the impl and IAT
+ //
+ // FIXME(-Znext-solver=coinductive): I think this should be split
+ // and we tag the impl bounds with `GoalSource::ImplWhereBound`?
+ // Right not this includes both the impl and the assoc item where bounds,
+ // and I don't think the assoc item where-bounds are allowed to be coinductive.
self.add_goals(
+ GoalSource::Misc,
tcx.predicates_of(inherent.def_id)
.instantiate(tcx, inherent_substs)
.into_iter()
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 240141065..0e9656a1e 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -1,7 +1,7 @@
use crate::traits::{check_args_compatible, specialization_graph};
-use super::assembly::{self, structural_traits};
-use super::EvalCtxt;
+use super::assembly::{self, structural_traits, Candidate};
+use super::{EvalCtxt, GoalSource};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
@@ -13,20 +13,20 @@ use rustc_middle::traits::solve::{
};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::ProjectionPredicate;
+use rustc_middle::ty::NormalizesTo;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
-mod inherent_projection;
+mod inherent;
mod opaques;
mod weak_types;
impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
- pub(super) fn compute_projection_goal(
+ pub(super) fn compute_normalizes_to_goal(
&mut self,
- goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
let def_id = goal.predicate.def_id();
match self.tcx().def_kind(def_id) {
@@ -71,16 +71,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
fn normalize_anon_const(
&mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
if let Some(normalized_const) = self.try_const_eval_resolve(
goal.param_env,
- ty::UnevaluatedConst::new(
- goal.predicate.projection_ty.def_id,
- goal.predicate.projection_ty.args,
- ),
+ ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
self.tcx()
- .type_of(goal.predicate.projection_ty.def_id)
+ .type_of(goal.predicate.alias.def_id)
.no_bound_vars()
.expect("const ty should not rely on other generics"),
) {
@@ -92,17 +89,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
-impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
+impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
fn self_ty(self) -> Ty<'tcx> {
self.self_ty()
}
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
- self.projection_ty.trait_ref(tcx)
- }
-
- fn polarity(self) -> ty::ImplPolarity {
- ty::ImplPolarity::Positive
+ self.alias.trait_ref(tcx)
}
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
@@ -127,7 +120,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ecx.instantiate_binder_with_infer(projection_pred);
ecx.eq(
goal.param_env,
- goal.predicate.projection_ty,
+ goal.predicate.alias,
assumption_projection_pred.projection_ty,
)?;
ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
@@ -135,8 +128,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
// Add GAT where clauses from the trait's definition
ecx.add_goals(
+ GoalSource::Misc,
tcx.predicates_of(goal.predicate.def_id())
- .instantiate_own(tcx, goal.predicate.projection_ty.args)
+ .instantiate_own(tcx, goal.predicate.alias.args)
.map(|(pred, _)| goal.with(tcx, pred)),
);
@@ -152,15 +146,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, NormalizesTo<'tcx>>,
impl_def_id: DefId,
- ) -> QueryResult<'tcx> {
+ ) -> Result<Candidate<'tcx>, NoSolution> {
let tcx = ecx.tcx();
- let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
+ let goal_trait_ref = goal.predicate.alias.trait_ref(tcx);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
- if !drcx.args_refs_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args) {
+ if !drcx.args_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args) {
return Err(NoSolution);
}
@@ -176,12 +170,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
.predicates
.into_iter()
.map(|pred| goal.with(tcx, pred));
- ecx.add_goals(where_clause_bounds);
+ ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
// Add GAT where clauses from the trait's definition
ecx.add_goals(
+ GoalSource::Misc,
tcx.predicates_of(goal.predicate.def_id())
- .instantiate_own(tcx, goal.predicate.projection_ty.args)
+ .instantiate_own(tcx, goal.predicate.alias.args)
.map(|(pred, _)| goal.with(tcx, pred)),
);
@@ -200,17 +195,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
};
let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| {
- let guar = tcx.sess.delay_span_bug(tcx.def_span(assoc_def.item.def_id), reason);
+ let guar = tcx.sess.span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
let error_term = match assoc_def.item.kind {
ty::AssocKind::Const => ty::Const::new_error(
tcx,
guar,
tcx.type_of(goal.predicate.def_id())
- .instantiate(tcx, goal.predicate.projection_ty.args),
+ .instantiate(tcx, goal.predicate.alias.args),
)
.into(),
ty::AssocKind::Type => Ty::new_error(tcx, guar).into(),
- ty::AssocKind::Fn => unreachable!(),
+ // This makes no sense...
+ ty::AssocKind::Fn => span_bug!(
+ tcx.def_span(assoc_def.item.def_id),
+ "cannot project to an associated function"
+ ),
};
ecx.eq(goal.param_env, goal.predicate.term, error_term)
.expect("expected goal term to be fully unconstrained");
@@ -231,11 +230,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
//
// And then map these args to the args of the defining impl of `Assoc`, going
// from `[u32, u64]` to `[u32, i32, u64]`.
- let impl_args_with_gat = goal.predicate.projection_ty.args.rebase_onto(
- tcx,
- goal_trait_ref.def_id,
- impl_args,
- );
+ let impl_args_with_gat =
+ goal.predicate.alias.args.rebase_onto(tcx, goal_trait_ref.def_id, impl_args);
let args = ecx.translate_args(
goal.param_env,
impl_def_id,
@@ -290,7 +286,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
- ecx.tcx().sess.delay_span_bug(
+ ecx.tcx().sess.span_delayed_bug(
ecx.tcx().def_span(goal.predicate.def_id()),
"associated types not allowed on auto traits",
);
@@ -419,7 +415,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
DUMMY_SP,
[ty::GenericArg::from(goal.predicate.self_ty())],
);
- ecx.add_goal(goal.with(tcx, sized_predicate));
+ // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+ ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate));
tcx.types.unit
}
@@ -427,7 +424,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
None => tcx.types.unit,
Some(field_def) => {
let self_ty = field_def.ty(tcx, args);
- ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
+ // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+ ecx.add_goal(
+ GoalSource::Misc,
+ goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
+ );
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
@@ -437,7 +438,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ty::Tuple(elements) => match elements.last() {
None => tcx.types.unit,
Some(&self_ty) => {
- ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
+ // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+ ecx.add_goal(
+ GoalSource::Misc,
+ goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
+ );
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
@@ -520,6 +525,40 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
)
}
+ fn consider_builtin_async_iterator_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx> {
+ let self_ty = goal.predicate.self_ty();
+ let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+ return Err(NoSolution);
+ };
+
+ // Coroutines are not AsyncIterators unless they come from `gen` desugaring
+ let tcx = ecx.tcx();
+ if !tcx.coroutine_is_async_gen(def_id) {
+ return Err(NoSolution);
+ }
+
+ ecx.probe_misc_candidate("builtin AsyncIterator kind").enter(|ecx| {
+ // Take `AsyncIterator<Item = I>` and turn it into the corresponding
+ // coroutine yield ty `Poll<Option<I>>`.
+ let expected_ty = Ty::new_adt(
+ tcx,
+ tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)),
+ tcx.mk_args(&[Ty::new_adt(
+ tcx,
+ tcx.adt_def(tcx.require_lang_item(LangItem::Option, None)),
+ tcx.mk_args(&[goal.predicate.term.into()]),
+ )
+ .into()]),
+ );
+ let yield_ty = args.as_coroutine().yield_ty();
+ ecx.eq(goal.param_env, expected_ty, yield_ty)?;
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ })
+ }
+
fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs
index ebd129f32..b5d1aa06e 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs
@@ -12,10 +12,10 @@ use crate::solve::{EvalCtxt, SolverMode};
impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_opaque_type(
&mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
- let opaque_ty = goal.predicate.projection_ty;
+ let opaque_ty = goal.predicate.alias;
let expected = goal.predicate.term.ty().expect("no such thing as an opaque const");
match (goal.param_env.reveal(), self.solver_mode()) {
@@ -44,6 +44,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// Prefer opaques registered already.
let opaque_type_key =
ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args };
+ // FIXME: This also unifies the previous hidden type with the expected.
+ //
+ // If that fails, we insert `expected` as a new hidden type instead of
+ // eagerly emitting an error.
let matches =
self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected);
if !matches.is_empty() {
@@ -53,6 +57,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return self.flounder(&matches);
}
}
+
+ let expected = match self.try_normalize_ty(goal.param_env, expected) {
+ Some(ty) => {
+ if ty.is_ty_var() {
+ return self.evaluate_added_goals_and_make_canonical_response(
+ Certainty::AMBIGUOUS,
+ );
+ } else {
+ ty
+ }
+ }
+ None => {
+ return self
+ .evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
+ }
+ };
+
// Otherwise, define a new opaque type
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
self.add_item_bounds_for_hidden_type(
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
index 54de32cf6..6d5728797 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
@@ -3,18 +3,18 @@
//!
//! Since a weak alias is not ambiguous, this just computes the `type_of` of
//! the alias and registers the where-clauses of the type alias.
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;
-use super::EvalCtxt;
+use crate::solve::EvalCtxt;
impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_weak_type(
&mut self,
- goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+ goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
- let weak_ty = goal.predicate.projection_ty;
+ let weak_ty = goal.predicate.alias;
let expected = goal.predicate.term.ty().expect("no such thing as a const alias");
let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
@@ -22,6 +22,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// Check where clauses
self.add_goals(
+ GoalSource::Misc,
tcx.predicates_of(weak_ty.def_id)
.instantiate(tcx, weak_ty.args)
.predicates
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
new file mode 100644
index 000000000..30ae385a8
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -0,0 +1,38 @@
+use crate::solve::GoalSource;
+
+use super::EvalCtxt;
+use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::ty::{self, ProjectionPredicate};
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+ #[instrument(level = "debug", skip(self), ret)]
+ pub(super) fn compute_projection_goal(
+ &mut self,
+ goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
+ ) -> QueryResult<'tcx> {
+ let tcx = self.tcx();
+ let projection_term = match goal.predicate.term.unpack() {
+ ty::TermKind::Ty(_) => goal.predicate.projection_ty.to_ty(tcx).into(),
+ ty::TermKind::Const(_) => ty::Const::new_unevaluated(
+ tcx,
+ ty::UnevaluatedConst::new(
+ goal.predicate.projection_ty.def_id,
+ goal.predicate.projection_ty.args,
+ ),
+ tcx.type_of(goal.predicate.projection_ty.def_id)
+ .instantiate(tcx, goal.predicate.projection_ty.args),
+ )
+ .into(),
+ };
+ let goal = goal.with(
+ tcx,
+ ty::PredicateKind::AliasRelate(
+ projection_term,
+ goal.predicate.term,
+ ty::AliasRelationDirection::Equate,
+ ),
+ );
+ self.add_goal(GoalSource::Misc, goal);
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 7ffa1d7d3..2a161c2d9 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -8,11 +8,13 @@ use rustc_index::IndexVec;
use rustc_middle::dep_graph::dep_kinds;
use rustc_middle::traits::solve::CacheData;
use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
+use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_session::Limit;
use std::collections::hash_map::Entry;
rustc_index::newtype_index! {
+ #[orderable]
pub struct StackDepth {}
}
@@ -37,7 +39,7 @@ struct StackEntry<'tcx> {
/// If we were to use that result when later trying to prove another cycle
/// participant, we can end up with unstable query results.
///
- /// See tests/ui/new-solver/coinduction/incompleteness-unstable-result.rs for
+ /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
/// an example of where this is needed.
cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
}
@@ -110,37 +112,13 @@ impl<'tcx> SearchGraph<'tcx> {
self.stack.is_empty()
}
- /// Whether we're currently in a cycle. This should only be used
- /// for debug assertions.
- pub(super) fn in_cycle(&self) -> bool {
- if let Some(stack_depth) = self.stack.last_index() {
- // Either the current goal on the stack is the root of a cycle
- // or it depends on a goal with a lower depth.
- self.stack[stack_depth].has_been_used
- || self.stack[stack_depth].cycle_root_depth != stack_depth
- } else {
- false
- }
- }
-
- /// Fetches whether the current goal encountered overflow.
- ///
- /// This should only be used for the check in `evaluate_goal`.
- pub(super) fn encountered_overflow(&self) -> bool {
- if let Some(last) = self.stack.raw.last() { last.encountered_overflow } else { false }
- }
-
- /// Resets `encountered_overflow` of the current goal.
- ///
- /// This should only be used for the check in `evaluate_goal`.
- pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) -> bool {
- if let Some(last) = self.stack.raw.last_mut() {
- let prev = last.encountered_overflow;
- last.encountered_overflow = encountered_overflow;
- prev
- } else {
- false
- }
+ pub(super) fn current_goal_is_normalizes_to(&self) -> bool {
+ self.stack.raw.last().map_or(false, |e| {
+ matches!(
+ e.input.value.goal.predicate.kind().skip_binder(),
+ ty::PredicateKind::NormalizesTo(..)
+ )
+ })
}
/// Returns the remaining depth allowed for nested goals.
@@ -269,7 +247,7 @@ impl<'tcx> SearchGraph<'tcx> {
// in unstable results due to incompleteness.
//
// However, a test for this would be an even more complex version of
- // tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs.
+ // tests/ui/traits/next-solver/coinduction/incompleteness-unstable-result.rs.
// I did not bother to write such a test and we have no regression test
// for this. It would be good to have such a test :)
#[allow(rustc::potential_query_instability)]
@@ -280,7 +258,7 @@ impl<'tcx> SearchGraph<'tcx> {
// until we reach a fixpoint. It is not enough to simply retry the
// `root` goal of this cycle.
//
- // See tests/ui/traits/new-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
+ // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
// for an example.
self.stack[stack_depth].has_been_used = true;
return if let Some(result) = self.stack[stack_depth].provisional_result {
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index a0e2ad6e2..ac3ffd2d6 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1,12 +1,14 @@
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
-use super::assembly::{self, structural_traits};
-use super::{EvalCtxt, SolverMode};
+use super::assembly::{self, structural_traits, Candidate};
+use super::{EvalCtxt, GoalSource, SolverMode};
use rustc_hir::def_id::DefId;
use rustc_hir::{LangItem, Movability};
use rustc_infer::traits::query::NoSolution;
use rustc_middle::traits::solve::inspect::ProbeKind;
-use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{
+ CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
+};
use rustc_middle::traits::{BuiltinImplSource, Reveal};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -22,10 +24,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
self.trait_ref
}
- fn polarity(self) -> ty::ImplPolarity {
- self.polarity
- }
-
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
self.with_self_ty(tcx, self_ty)
}
@@ -38,14 +36,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, TraitPredicate<'tcx>>,
impl_def_id: DefId,
- ) -> QueryResult<'tcx> {
+ ) -> Result<Candidate<'tcx>, NoSolution> {
let tcx = ecx.tcx();
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
- if !drcx
- .args_refs_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
- {
+ if !drcx.args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) {
return Err(NoSolution);
}
@@ -65,7 +61,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
},
};
- ecx.probe_misc_candidate("impl").enter(|ecx| {
+ ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
let impl_args = ecx.fresh_args_for_item(impl_def_id);
let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
@@ -76,7 +72,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
.predicates
.into_iter()
.map(|pred| goal.with(tcx, pred));
- ecx.add_goals(where_clause_bounds);
+ ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
})
@@ -176,7 +172,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let nested_obligations = tcx
.predicates_of(goal.predicate.def_id())
.instantiate(tcx, goal.predicate.trait_ref.args);
- ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
+ // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+ ecx.add_goals(
+ GoalSource::Misc,
+ nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)),
+ );
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -260,7 +260,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
Err(NoSolution)
}
}
- ty::ImplPolarity::Reservation => bug!(),
+ // FIXME: Goal polarity should be split from impl polarity
+ ty::ImplPolarity::Reservation => {
+ bug!("we never expect a `Reservation` polarity in a trait goal")
+ }
}
}
@@ -374,6 +377,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
+ fn consider_builtin_async_iterator_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
+ let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+ return Err(NoSolution);
+ };
+
+ // Coroutines are not iterators unless they come from `gen` desugaring
+ let tcx = ecx.tcx();
+ if !tcx.coroutine_is_async_gen(def_id) {
+ return Err(NoSolution);
+ }
+
+ // Gen coroutines unconditionally implement `Iterator`
+ // Technically, we need to check that the iterator output type is Sized,
+ // but that's already proven by the coroutines being WF.
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+
fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
@@ -425,7 +452,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
return Err(NoSolution);
}
- // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver
+ // FIXME(-Znext-solver): Implement this when we get const working in the new solver
// `Destruct` is automatically implemented for every type in
// non-const environments.
@@ -471,7 +498,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let a_ty = goal.predicate.self_ty();
// We need to normalize the b_ty since it's destructured as a `dyn Trait`.
let Some(b_ty) =
- ecx.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1))?
+ ecx.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1))
else {
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
};
@@ -489,17 +516,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
// Check that the type implements all of the predicates of the trait object.
// (i.e. the principal, all of the associated types match, and any auto traits)
- ecx.add_goals(b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))));
+ ecx.add_goals(
+ GoalSource::ImplWhereBound,
+ b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
+ );
// The type must be `Sized` to be unsized.
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
- ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
+ ecx.add_goal(
+ GoalSource::ImplWhereBound,
+ goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
+ );
} else {
return Err(NoSolution);
}
// The type must outlive the lifetime of the `dyn` we're unsizing into.
- ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
+ ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -538,9 +571,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let b_ty = match ecx
.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1))
{
- Ok(Some(b_ty)) => b_ty,
- Ok(None) => return vec![misc_candidate(ecx, Certainty::OVERFLOW)],
- Err(_) => return vec![],
+ Some(b_ty) => b_ty,
+ None => return vec![misc_candidate(ecx, Certainty::OVERFLOW)],
};
let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
@@ -727,11 +759,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
// Also require that a_ty's lifetime outlives b_ty's lifetime.
- self.add_goal(Goal::new(
- self.tcx(),
- param_env,
- ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
- ));
+ self.add_goal(
+ GoalSource::ImplWhereBound,
+ Goal::new(
+ self.tcx(),
+ param_env,
+ ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
+ ),
+ );
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -804,14 +839,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
// types.
self.eq(goal.param_env, unsized_a_ty, b_ty)?;
- self.add_goal(goal.with(
- tcx,
- ty::TraitRef::new(
+ self.add_goal(
+ GoalSource::ImplWhereBound,
+ goal.with(
tcx,
- tcx.lang_items().unsize_trait().unwrap(),
- [a_tail_ty, b_tail_ty],
+ ty::TraitRef::new(
+ tcx,
+ tcx.lang_items().unsize_trait().unwrap(),
+ [a_tail_ty, b_tail_ty],
+ ),
),
- ));
+ );
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -843,14 +881,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.eq(goal.param_env, unsized_a_ty, b_ty)?;
// Similar to ADTs, require that we can unsize the tail.
- self.add_goal(goal.with(
- tcx,
- ty::TraitRef::new(
+ self.add_goal(
+ GoalSource::ImplWhereBound,
+ goal.with(
tcx,
- tcx.lang_items().unsize_trait().unwrap(),
- [a_last_ty, b_last_ty],
+ ty::TraitRef::new(
+ tcx,
+ tcx.lang_items().unsize_trait().unwrap(),
+ [a_last_ty, b_last_ty],
+ ),
),
- ));
+ );
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -959,6 +1000,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> QueryResult<'tcx> {
self.probe_misc_candidate("constituent tys").enter(|ecx| {
ecx.add_goals(
+ GoalSource::ImplWhereBound,
constituent_tys(ecx, goal.predicate.self_ty())?
.into_iter()
.map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)))
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 8096d7969..13a09917c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -5,11 +5,9 @@ use super::*;
use crate::errors::UnableToConstructConstantValue;
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::infer::InferCtxt;
use crate::traits::project::ProjectAndUnifyResult;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{ImplPolarity, Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
@@ -252,7 +250,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
fresh_preds.insert(self.clean_pred(infcx, predicate.as_predicate()));
}
- let mut select = SelectionContext::new(&infcx);
+ let mut select = SelectionContext::new(infcx);
let mut already_visited = FxHashSet::default();
let mut predicates = VecDeque::new();
@@ -410,11 +408,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
iter::zip(new_args.regions(), old_args.regions())
{
match (*new_region, *old_region) {
- // If both predicates have an `ReLateBound` (a HRTB) in the
+ // If both predicates have an `ReBound` (a HRTB) in the
// same spot, we do nothing.
- (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {}
+ (ty::ReBound(_, _), ty::ReBound(_, _)) => {}
- (ty::ReLateBound(_, _), _) | (_, ty::ReVar(_)) => {
+ (ty::ReBound(_, _), _) | (_, ty::ReVar(_)) => {
// One of these is true:
// The new predicate has a HRTB in a spot where the old
// predicate does not (if they both had a HRTB, the previous
@@ -440,7 +438,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// `user_computed_preds`.
return false;
}
- (_, ty::ReLateBound(_, _)) | (ty::ReVar(_), _) => {
+ (_, ty::ReBound(_, _)) | (ty::ReVar(_), _) => {
// This is the opposite situation as the previous arm.
// One of these is true:
//
@@ -820,9 +818,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// the `ParamEnv`.
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
+ | ty::PredicateKind::NormalizesTo(..)
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
// FIXME(generic_const_exprs): you can absolutely add this as a where clauses
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index dcf5fd869..533fe32f7 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,8 +6,8 @@
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::InferOk;
-use crate::solve::inspect;
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::solve::{deeply_normalize_for_diagnostics, inspect};
use crate::traits::engine::TraitEngineExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
@@ -20,15 +20,15 @@ use crate::traits::{
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, TraitEngine};
use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{Certainty, Goal};
+use rustc_middle::traits::solve::{CandidateSource, 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, TypeSuperVisitable, TypeVisitor};
use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE;
@@ -53,7 +53,7 @@ pub enum Conflict {
pub struct OverlapResult<'tcx> {
pub impl_header: ty::ImplHeader<'tcx>,
- pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
+ pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
/// `true` if the overlap might've been permitted before the shift
/// to universes.
@@ -100,7 +100,7 @@ pub fn overlapping_impls(
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
- (Some(a), Some(b)) => drcx.args_refs_may_unify(a.skip_binder().args, b.skip_binder().args),
+ (Some(a), Some(b)) => drcx.args_may_unify(a.skip_binder().args, b.skip_binder().args),
(None, None) => {
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
@@ -245,7 +245,7 @@ fn overlap<'tcx>(
let trait_ref = infcx.resolve_vars_if_possible(trait_ref);
format!(
"of `{}` for `{}`",
- trait_ref.print_only_trait_path(),
+ trait_ref.print_trait_sugared(),
trait_ref.self_ty()
)
}
@@ -273,7 +273,6 @@ fn overlap<'tcx>(
causing the impls to overlap",
infcx.resolve_vars_if_possible(failing_obligation.predicate)
));
- lint
},
);
}
@@ -308,7 +307,13 @@ fn overlap<'tcx>(
.iter()
.any(|c| c.0.involves_placeholders());
- let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header);
+ let mut impl_header = infcx.resolve_vars_if_possible(impl1_header);
+
+ // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails.
+ if infcx.next_trait_solver() {
+ impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
+ }
+
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
}
@@ -329,7 +334,7 @@ fn equate_impl_headers<'tcx>(
impl1.self_ty,
impl2.self_ty,
),
- _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
+ _ => bug!("equate_impl_headers given mismatched impl kinds"),
};
result.map(|infer_ok| infer_ok.obligations).ok()
@@ -360,15 +365,23 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
let infcx = selcx.infcx;
obligations.iter().find(|obligation| {
- if infcx.next_trait_solver() {
- infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
+ let evaluation_result = if infcx.next_trait_solver() {
+ infcx.evaluate_obligation(obligation)
} 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(),
- )
+ selcx.evaluate_root_obligation(obligation)
+ };
+
+ match evaluation_result {
+ Ok(result) => !result.may_apply(),
+ // If overflow occurs, we need to conservatively treat the goal as possibly holding,
+ // since there can be instantiations of this goal that don't overflow and result in
+ // success. This isn't much of a problem in the old solver, since we treat overflow
+ // fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
+ // but in the new solver, this is very important for correctness, since overflow
+ // *must* be treated as ambiguity for completeness.
+ Err(_overflow) => false,
}
})
}
@@ -396,8 +409,11 @@ fn impl_intersection_has_negative_obligation(
) -> bool {
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
+ // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates
+ // do not need intercrate mode enabled.
let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
- let universe = infcx.universe();
+ let root_universe = infcx.universe();
+ assert_eq!(root_universe, ty::UniverseIndex::ROOT);
let impl1_header = fresh_impl_header(infcx, impl1_def_id);
let param_env =
@@ -407,13 +423,25 @@ fn impl_intersection_has_negative_obligation(
// Equate the headers to find their intersection (the general type, with infer vars,
// that may apply both impls).
- let Some(_equate_obligations) =
+ let Some(equate_obligations) =
equate_impl_headers(infcx, param_env, &impl1_header, &impl2_header)
else {
return false;
};
- plug_infer_with_placeholders(infcx, universe, (impl1_header.impl_args, impl2_header.impl_args));
+ // FIXME(with_negative_coherence): the infcx has constraints from equating
+ // the impl headers. We should use these constraints as assumptions, not as
+ // requirements, when proving the negated where clauses below.
+ drop(equate_obligations);
+ drop(infcx.take_registered_region_obligations());
+ drop(infcx.take_and_reset_region_constraints());
+
+ plug_infer_with_placeholders(
+ infcx,
+ root_universe,
+ (impl1_header.impl_args, impl2_header.impl_args),
+ );
+ let param_env = infcx.resolve_vars_if_possible(param_env);
util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args))
.any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env))
@@ -458,7 +486,7 @@ fn plug_infer_with_placeholders<'tcx>(
),
)
else {
- bug!()
+ bug!("we always expect to be able to plug an infer var with placeholder")
};
assert_eq!(obligations, &[]);
ControlFlow::Continue(())
@@ -481,7 +509,7 @@ fn plug_infer_with_placeholders<'tcx>(
),
)
else {
- bug!()
+ bug!("we always expect to be able to plug an infer var with placeholder")
};
assert_eq!(obligations, &[]);
ControlFlow::Continue(())
@@ -515,7 +543,7 @@ fn plug_infer_with_placeholders<'tcx>(
),
)
else {
- bug!()
+ bug!("we always expect to be able to plug an infer var with placeholder")
};
assert_eq!(obligations, &[]);
}
@@ -540,15 +568,11 @@ fn try_prove_negated_where_clause<'tcx>(
return false;
};
- // FIXME(with_negative_coherence): the infcx has region contraints from equating
- // the impl headers as requirements. Given that the only region constraints we
- // get are involving inference regions in the root, it shouldn't matter, but
- // still sus.
- //
- // We probably should just throw away the region obligations registered up until
- // now, or ideally use them as assumptions when proving the region obligations
- // that we get from proving the negative predicate below.
- let ref infcx = root_infcx.fork();
+ // N.B. We don't need to use intercrate mode here because we're trying to prove
+ // the *existence* of a negative goal, not the non-existence of a positive goal.
+ // Without this, we over-eagerly register coherence ambiguity candidates when
+ // impl candidates do exist.
+ let ref infcx = root_infcx.fork_with_intercrate(false);
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligation(Obligation::new(
@@ -830,7 +854,7 @@ where
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- // Need to lazily normalize here in with `-Ztrait-solver=next-coherence`.
+ // Need to lazily normalize here in with `-Znext-solver=coherence`.
let ty = match (self.lazily_normalize_ty)(ty) {
Ok(ty) => ty,
Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)),
@@ -967,8 +991,8 @@ where
fn compute_intercrate_ambiguity_causes<'tcx>(
infcx: &InferCtxt<'tcx>,
obligations: &[PredicateObligation<'tcx>],
-) -> FxIndexSet<IntercrateAmbiguityCause> {
- let mut causes: FxIndexSet<IntercrateAmbiguityCause> = Default::default();
+) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
+ let mut causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>> = Default::default();
for obligation in obligations {
search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes);
@@ -977,11 +1001,11 @@ fn compute_intercrate_ambiguity_causes<'tcx>(
causes
}
-struct AmbiguityCausesVisitor<'a> {
- causes: &'a mut FxIndexSet<IntercrateAmbiguityCause>,
+struct AmbiguityCausesVisitor<'a, 'tcx> {
+ causes: &'a mut FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
}
-impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
+impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
type BreakTy = !;
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy> {
let infcx = goal.infcx();
@@ -998,26 +1022,53 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
let Goal { param_env, predicate } = goal.goal();
- // For bound predicates we simply call `infcx.replace_bound_vars_with_placeholders`
+ // For bound predicates we simply call `infcx.instantiate_binder_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))) => {
+ Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
+ if matches!(
+ infcx.tcx.def_kind(proj.projection_ty.def_id),
+ DefKind::AssocTy | DefKind::AssocConst
+ ) =>
+ {
proj.projection_ty.trait_ref(infcx.tcx)
}
_ => return ControlFlow::Continue(()),
};
+ // Add ambiguity causes for reservation impls.
+ for cand in goal.candidates() {
+ if let inspect::ProbeKind::TraitCandidate {
+ source: CandidateSource::Impl(def_id),
+ result: Ok(_),
+ } = cand.kind()
+ {
+ if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) {
+ let message = infcx
+ .tcx
+ .get_attr(def_id, sym::rustc_reservation_impl)
+ .and_then(|a| a.value_str());
+ if let Some(message) = message {
+ self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { message });
+ }
+ }
+ }
+ }
+
+ // Add ambiguity causes for unknowable goals.
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()
+ if let inspect::ProbeKind::MiscCandidate {
+ name: "coherence unknowable",
+ result: Ok(_),
+ } = 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
+ // FIXME(-Znext-solver=coherence): we currently don't
// normalize opaque types here, resulting in diverging behavior
// for TAITs.
match infcx
@@ -1038,25 +1089,23 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
Ok(Err(conflict)) => {
if !trait_ref.references_error() {
+ // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
+ let trait_ref =
+ deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
+
let self_ty = trait_ref.self_ty();
- let (trait_desc, self_desc) = with_no_trimmed_paths!({
- let trait_desc = trait_ref.print_only_trait_path().to_string();
- let self_desc = self_ty
- .has_concrete_skeleton()
- .then(|| self_ty.to_string());
- (trait_desc, self_desc)
- });
+ let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
ambiguity_cause = Some(match conflict {
Conflict::Upstream => {
IntercrateAmbiguityCause::UpstreamCrateUpdate {
- trait_desc,
- self_desc,
+ trait_ref,
+ self_ty,
}
}
Conflict::Downstream => {
IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc,
- self_desc,
+ trait_ref,
+ self_ty,
}
}
});
@@ -1093,7 +1142,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
fn search_ambiguity_causes<'tcx>(
infcx: &InferCtxt<'tcx>,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
- causes: &mut FxIndexSet<IntercrateAmbiguityCause>,
+ causes: &mut FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
) {
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 62ab1e104..aee513207 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -65,7 +65,7 @@ pub fn is_const_evaluatable<'tcx>(
// FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
// currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
// is evaluatable or not. For now we just ICE until this is implemented.
- Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug(
+ Err(NotConstEvaluatable::Error(tcx.sess.span_delayed_bug(
span,
"evaluating `ConstKind::Expr` is not currently supported",
)))
@@ -74,7 +74,7 @@ pub fn is_const_evaluatable<'tcx>(
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(
+ Err(NotConstEvaluatable::Error(infcx.tcx.sess.span_delayed_bug(
span,
"Missing value for constant, but no error reported?",
)))
@@ -138,10 +138,10 @@ pub fn is_const_evaluatable<'tcx>(
} else if uv.has_non_region_param() {
NotConstEvaluatable::MentionsParam
} else {
- let guar = infcx
- .tcx
- .sess
- .delay_span_bug(span, "Missing value for constant, but no error reported?");
+ let guar = infcx.tcx.sess.span_delayed_bug(
+ span,
+ "Missing value for constant, but no error reported?",
+ );
NotConstEvaluatable::Error(guar)
};
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index d9a1a9819..013a50f9f 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -25,7 +25,6 @@ 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;
pub trait TraitEngineExt<'tcx> {
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
@@ -33,18 +32,16 @@ pub trait TraitEngineExt<'tcx> {
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
- match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) {
- (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => {
- Box::new(FulfillmentContext::new(infcx))
- }
- (TraitSolver::Classic | TraitSolver::Next | TraitSolver::NextCoherence, true) => {
- Box::new(NextFulfillmentCtxt::new(infcx))
- }
- (TraitSolver::Next, false) => bug!(
- "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})",
- infcx.tcx.sess.opts.unstable_opts.trait_solver,
- infcx.next_trait_solver()
- ),
+ if infcx.next_trait_solver() {
+ Box::new(NextFulfillmentCtxt::new(infcx))
+ } else {
+ let new_solver_globally =
+ infcx.tcx.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally);
+ assert!(
+ !new_solver_globally,
+ "using old solver even though new solver is enabled globally"
+ );
+ Box::new(FulfillmentContext::new(infcx))
}
}
}
@@ -108,7 +105,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
value: T,
) -> T {
- let infer_ok = self.infcx.at(&cause, param_env).normalize(value);
+ let infer_ok = self.infcx.at(cause, param_env).normalize(value);
self.register_infer_ok_obligations(infer_ok)
}
@@ -204,7 +201,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
generic_param_scope: LocalDefId,
outlives_env: &OutlivesEnvironment<'tcx>,
) -> Result<(), ErrorGuaranteed> {
- let errors = self.infcx.resolve_regions(&outlives_env);
+ let errors = self.infcx.resolve_regions(outlives_env);
if errors.is_empty() {
Ok(())
} else {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 5bc5a12a8..b246e476b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -1,5 +1,5 @@
use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
+use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
use rustc_infer::traits::util::elaborate;
use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation};
use rustc_middle::ty;
@@ -53,7 +53,7 @@ pub fn recompute_applicable_impls<'tcx>(
let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
DUMMY_SP,
- LateBoundRegionConversionTime::HigherRankedType,
+ BoundRegionConversionTime::HigherRankedType,
poly_trait_predicate,
);
let param_env_trait_ref =
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
index b4835b011..0190d5ab4 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
@@ -61,8 +61,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
.params
.iter()
.map(|arg| {
- if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
- *arg.pat
+ if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat
{
Some(ArgKind::Tuple(
Some(span),
@@ -92,7 +91,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
.inputs
.iter()
.map(|arg| match arg.kind {
- hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
+ hir::TyKind::Tup(tys) => ArgKind::Tuple(
Some(arg.span),
vec![("_".to_owned(), "_".to_owned()); tys.len()],
),
@@ -100,7 +99,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
})
.collect::<Vec<ArgKind>>(),
),
- Node::Ctor(ref variant_data) => {
+ Node::Ctor(variant_data) => {
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
(span, None, vec![ArgKind::empty(); variant_data.fields().len()])
}
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 5fbfedd3e..61e97dde5 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
@@ -103,7 +103,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
/// to be the enclosing (async) block/function/closure
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
let hir = self.tcx.hir();
- let node = hir.find(hir_id)?;
+ let node = self.tcx.opt_hir_node(hir_id)?;
match &node {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
self.describe_coroutine(*body_id).or_else(|| {
@@ -184,18 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
flags.push((sym::cause, Some("MainFunctionType".to_string())));
}
- if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id)
- && let ty::Tuple(args) = trait_ref.args.type_at(1).kind()
- {
- let args = args
- .iter()
- .map(|ty| ty.to_string())
- .collect::<Vec<_>>()
- .join(", ");
- flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str()))));
- } else {
- flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string())));
- }
+ flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string())));
// Add all types without trimmed paths or visible paths, ensuring they end up with
// their "canonical" def path.
@@ -325,7 +314,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
#[derive(Clone, Debug)]
-pub struct OnUnimplementedFormatString(Symbol);
+pub struct OnUnimplementedFormatString {
+ symbol: Symbol,
+ span: Span,
+ is_diagnostic_namespace_variant: bool,
+}
#[derive(Debug)]
pub struct OnUnimplementedDirective {
@@ -354,7 +347,7 @@ pub struct OnUnimplementedNote {
pub enum AppendConstMessage {
#[default]
Default,
- Custom(Symbol),
+ Custom(Symbol, Span),
}
#[derive(LintDiagnostic)]
@@ -376,6 +369,43 @@ impl MalformedOnUnimplementedAttrLint {
#[help]
pub struct MissingOptionsForOnUnimplementedAttr;
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_ignored_diagnostic_option)]
+pub struct IgnoredDiagnosticOption {
+ pub option_name: &'static str,
+ #[label]
+ pub span: Span,
+ #[label(trait_selection_other_label)]
+ pub prev_span: Span,
+}
+
+impl IgnoredDiagnosticOption {
+ fn maybe_emit_warning<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ new: Option<Span>,
+ old: Option<Span>,
+ option_name: &'static str,
+ ) {
+ if let (Some(new_item), Some(old_item)) = (new, old) {
+ tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+ new_item,
+ IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
+ );
+ }
+ }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)]
+#[help]
+pub struct UnknownFormatParameterForOnUnimplementedAttr {
+ argument_name: Symbol,
+ trait_name: Symbol,
+}
+
impl<'tcx> OnUnimplementedDirective {
fn parse(
tcx: TyCtxt<'tcx>,
@@ -388,8 +418,15 @@ impl<'tcx> OnUnimplementedDirective {
let mut errored = None;
let mut item_iter = items.iter();
- let parse_value = |value_str| {
- OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
+ let parse_value = |value_str, value_span| {
+ OnUnimplementedFormatString::try_parse(
+ tcx,
+ item_def_id,
+ value_str,
+ value_span,
+ is_diagnostic_namespace_variant,
+ )
+ .map(Some)
};
let condition = if is_root {
@@ -402,7 +439,7 @@ impl<'tcx> OnUnimplementedDirective {
.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)
+ && let Err(guar) = parse_value(value, cfg.span)
{
errored = Some(guar);
}
@@ -421,17 +458,17 @@ impl<'tcx> OnUnimplementedDirective {
for item in item_iter {
if item.has_name(sym::message) && message.is_none() {
if let Some(message_) = item.value_str() {
- message = parse_value(message_)?;
+ message = parse_value(message_, item.span())?;
continue;
}
} else if item.has_name(sym::label) && label.is_none() {
if let Some(label_) = item.value_str() {
- label = parse_value(label_)?;
+ label = parse_value(label_, item.span())?;
continue;
}
} else if item.has_name(sym::note) {
if let Some(note_) = item.value_str() {
- if let Some(note) = parse_value(note_)? {
+ if let Some(note) = parse_value(note_, item.span())? {
notes.push(note);
continue;
}
@@ -441,7 +478,7 @@ impl<'tcx> OnUnimplementedDirective {
&& !is_diagnostic_namespace_variant
{
if let Some(parent_label_) = item.value_str() {
- parent_label = parse_value(parent_label_)?;
+ parent_label = parse_value(parent_label_, item.span())?;
continue;
}
} else if item.has_name(sym::on)
@@ -456,7 +493,7 @@ impl<'tcx> OnUnimplementedDirective {
match Self::parse(
tcx,
item_def_id,
- &items,
+ items,
item.span(),
false,
is_diagnostic_namespace_variant,
@@ -474,7 +511,7 @@ impl<'tcx> OnUnimplementedDirective {
&& !is_diagnostic_namespace_variant
{
if let Some(msg) = item.value_str() {
- append_const_msg = Some(AppendConstMessage::Custom(msg));
+ append_const_msg = Some(AppendConstMessage::Custom(msg, item.span()));
continue;
} else if item.is_word() {
append_const_msg = Some(AppendConstMessage::Default);
@@ -485,7 +522,7 @@ impl<'tcx> OnUnimplementedDirective {
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()),
+ tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
vec![item.span()],
MalformedOnUnimplementedAttrLint::new(item.span()),
);
@@ -523,6 +560,54 @@ impl<'tcx> OnUnimplementedDirective {
subcommands.extend(directive.subcommands);
let mut notes = aggr.notes;
notes.extend(directive.notes);
+ IgnoredDiagnosticOption::maybe_emit_warning(
+ tcx,
+ item_def_id,
+ directive.message.as_ref().map(|f| f.span),
+ aggr.message.as_ref().map(|f| f.span),
+ "message",
+ );
+ IgnoredDiagnosticOption::maybe_emit_warning(
+ tcx,
+ item_def_id,
+ directive.label.as_ref().map(|f| f.span),
+ aggr.label.as_ref().map(|f| f.span),
+ "label",
+ );
+ IgnoredDiagnosticOption::maybe_emit_warning(
+ tcx,
+ item_def_id,
+ directive.condition.as_ref().map(|i| i.span),
+ aggr.condition.as_ref().map(|i| i.span),
+ "condition",
+ );
+ IgnoredDiagnosticOption::maybe_emit_warning(
+ tcx,
+ item_def_id,
+ directive.parent_label.as_ref().map(|f| f.span),
+ aggr.parent_label.as_ref().map(|f| f.span),
+ "parent_label",
+ );
+ IgnoredDiagnosticOption::maybe_emit_warning(
+ tcx,
+ item_def_id,
+ directive.append_const_msg.as_ref().and_then(|c| {
+ if let AppendConstMessage::Custom(_, s) = c {
+ Some(*s)
+ } else {
+ None
+ }
+ }),
+ aggr.append_const_msg.as_ref().and_then(|c| {
+ if let AppendConstMessage::Custom(_, s) = c {
+ Some(*s)
+ } else {
+ None
+ }
+ }),
+ "append_const_msg",
+ );
+
Ok(Some(Self {
condition: aggr.condition.or(directive.condition),
subcommands,
@@ -560,6 +645,7 @@ impl<'tcx> OnUnimplementedDirective {
item_def_id,
value,
attr.span,
+ is_diagnostic_namespace_variant,
)?),
notes: Vec::new(),
parent_label: None,
@@ -576,7 +662,7 @@ impl<'tcx> OnUnimplementedDirective {
tcx.emit_spanned_lint(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
report_span,
MalformedOnUnimplementedAttrLint::new(report_span),
);
@@ -587,14 +673,14 @@ impl<'tcx> OnUnimplementedDirective {
AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
tcx.emit_spanned_lint(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
attr.span,
MalformedOnUnimplementedAttrLint::new(attr.span),
);
}
_ => tcx.emit_spanned_lint(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
attr.span,
MissingOptionsForOnUnimplementedAttr,
),
@@ -602,8 +688,9 @@ impl<'tcx> OnUnimplementedDirective {
Ok(None)
} else {
- let reported =
- tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
+ let reported = tcx
+ .sess
+ .span_delayed_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
return Err(reported);
};
debug!("of_item({:?}) = {:?}", item_def_id, result);
@@ -636,7 +723,18 @@ impl<'tcx> OnUnimplementedDirective {
let value = cfg.value.map(|v| {
// `with_no_visible_paths` is also used when generating the options,
// so we need to match it here.
- ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map))
+ ty::print::with_no_visible_paths!(
+ OnUnimplementedFormatString {
+ symbol: v,
+ span: cfg.span,
+ is_diagnostic_namespace_variant: false
+ }
+ .format(
+ tcx,
+ trait_ref,
+ &options_map
+ )
+ )
});
options.contains(&(cfg.name, value))
@@ -679,19 +777,19 @@ impl<'tcx> OnUnimplementedFormatString {
tcx: TyCtxt<'tcx>,
item_def_id: DefId,
from: Symbol,
- err_sp: Span,
+ value_span: Span,
+ is_diagnostic_namespace_variant: bool,
) -> Result<Self, ErrorGuaranteed> {
- let result = OnUnimplementedFormatString(from);
- result.verify(tcx, item_def_id, err_sp)?;
+ let result = OnUnimplementedFormatString {
+ symbol: from,
+ span: value_span,
+ is_diagnostic_namespace_variant,
+ };
+ result.verify(tcx, item_def_id)?;
Ok(result)
}
- fn verify(
- &self,
- tcx: TyCtxt<'tcx>,
- item_def_id: DefId,
- span: Span,
- ) -> Result<(), ErrorGuaranteed> {
+ fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> {
let trait_def_id = if tcx.is_trait(item_def_id) {
item_def_id
} else {
@@ -700,7 +798,7 @@ impl<'tcx> OnUnimplementedFormatString {
};
let trait_name = tcx.item_name(trait_def_id);
let generics = tcx.generics_of(item_def_id);
- let s = self.0.as_str();
+ let s = self.symbol.as_str();
let parser = Parser::new(s, None, None, false, ParseMode::Format);
let mut result = Ok(());
for token in parser {
@@ -710,24 +808,40 @@ impl<'tcx> OnUnimplementedFormatString {
Position::ArgumentNamed(s) => {
match Symbol::intern(s) {
// `{ThisTraitsName}` is allowed
- s if s == trait_name => (),
- s if ALLOWED_FORMAT_SYMBOLS.contains(&s) => (),
+ s if s == trait_name && !self.is_diagnostic_namespace_variant => (),
+ s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
+ && !self.is_diagnostic_namespace_variant =>
+ {
+ ()
+ }
// So is `{A}` if A is a type parameter
s if generics.params.iter().any(|param| param.name == s) => (),
s => {
- result = Err(struct_span_err!(
- tcx.sess,
- span,
- E0230,
- "there is no parameter `{}` on {}",
- s,
- if trait_def_id == item_def_id {
- format!("trait `{trait_name}`")
- } else {
- "impl".to_string()
- }
- )
- .emit());
+ if self.is_diagnostic_namespace_variant {
+ tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+ self.span,
+ UnknownFormatParameterForOnUnimplementedAttr {
+ argument_name: s,
+ trait_name,
+ },
+ );
+ } else {
+ result = Err(struct_span_err!(
+ tcx.sess,
+ self.span,
+ E0230,
+ "there is no parameter `{}` on {}",
+ s,
+ if trait_def_id == item_def_id {
+ format!("trait `{trait_name}`")
+ } else {
+ "impl".to_string()
+ }
+ )
+ .emit());
+ }
}
}
}
@@ -735,7 +849,7 @@ impl<'tcx> OnUnimplementedFormatString {
Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
let reported = struct_span_err!(
tcx.sess,
- span,
+ self.span,
E0231,
"only named substitution parameters are allowed"
)
@@ -774,37 +888,42 @@ impl<'tcx> OnUnimplementedFormatString {
.collect::<FxHashMap<Symbol, String>>();
let empty_string = String::new();
- let s = self.0.as_str();
+ let s = self.symbol.as_str();
let parser = Parser::new(s, None, None, false, ParseMode::Format);
let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
parser
.map(|p| match p {
- Piece::String(s) => s,
+ Piece::String(s) => s.to_owned(),
Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s) => {
- let s = Symbol::intern(s);
+ Position::ArgumentNamed(arg) => {
+ let s = Symbol::intern(arg);
match generic_map.get(&s) {
- Some(val) => val,
- None if s == name => &trait_str,
+ Some(val) => val.to_string(),
+ None if self.is_diagnostic_namespace_variant => {
+ format!("{{{arg}}}")
+ }
+ None if s == name => trait_str.clone(),
None => {
if let Some(val) = options.get(&s) {
- val
+ val.clone()
} else if s == sym::from_desugaring {
// don't break messages using these two arguments incorrectly
- &empty_string
- } else if s == sym::ItemContext {
- &item_context
+ String::new()
+ } else if s == sym::ItemContext
+ && !self.is_diagnostic_namespace_variant
+ {
+ item_context.clone()
} else if s == sym::integral {
- "{integral}"
+ String::from("{integral}")
} else if s == sym::integer_ {
- "{integer}"
+ String::from("{integer}")
} else if s == sym::float {
- "{float}"
+ String::from("{float}")
} else {
bug!(
"broken on_unimplemented {:?} for {:?}: \
no argument matching {:?}",
- self.0,
+ self.symbol,
trait_ref,
s
)
@@ -812,7 +931,7 @@ impl<'tcx> OnUnimplementedFormatString {
}
}
}
- _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
+ _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol),
},
})
.collect()
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 6b09bc898..a1b896d22 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -17,7 +17,7 @@ use rustc_errors::{
ErrorGuaranteed, MultiSpan, Style, SuggestionStyle,
};
use rustc_hir as hir;
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::is_range_literal;
@@ -26,7 +26,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, Node};
use rustc_hir::{Expr, HirId};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
+use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
use rustc_middle::hir::map;
use rustc_middle::traits::IsConstable;
use rustc_middle::ty::error::TypeError::{self, Sorts};
@@ -36,7 +36,7 @@ use rustc_middle::ty::{
TypeSuperFoldable, TypeVisitableExt, TypeckResults,
};
use rustc_span::def_id::LocalDefId;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::borrow::Cow;
@@ -99,7 +99,7 @@ impl<'tcx, 'a> CoroutineData<'tcx, 'a> {
.awaits
.into_iter()
.map(|id| hir.expect_expr(id))
- .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(&await_expr))))
+ .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr))))
.map(|expr| expr.span)
}
}
@@ -222,6 +222,15 @@ pub trait TypeErrCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+ fn note_conflicting_fn_args(
+ &self,
+ err: &mut Diagnostic,
+ cause: &ObligationCauseCode<'tcx>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ );
+
fn note_conflicting_closure_bounds(
&self,
cause: &ObligationCauseCode<'tcx>,
@@ -501,7 +510,7 @@ pub fn suggest_restriction<'tcx>(
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_restricting_param_bound(
&self,
- mut err: &mut Diagnostic,
+ err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
associated_ty: Option<(&'static str, Ty<'tcx>)>,
mut body_id: LocalDefId,
@@ -521,7 +530,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
// don't suggest `T: Sized + ?Sized`.
- while let Some(node) = self.tcx.hir().find_by_def_id(body_id) {
+ while let Some(node) = self.tcx.opt_hir_node_by_def_id(body_id) {
match node {
hir::Node::Item(hir::Item {
ident,
@@ -533,7 +542,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
suggest_restriction(
self.tcx,
body_id,
- &generics,
+ generics,
"`Self`",
err,
None,
@@ -552,7 +561,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
assert!(param_ty);
// Restricting `Self` for a single method.
suggest_restriction(
- self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred,
+ self.tcx, body_id, generics, "`Self`", err, None, projection, trait_pred,
None,
);
return;
@@ -575,7 +584,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
suggest_restriction(
self.tcx,
body_id,
- &generics,
+ generics,
"the associated type",
err,
Some(fn_sig),
@@ -595,7 +604,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
suggest_restriction(
self.tcx,
body_id,
- &generics,
+ generics,
"the associated type",
err,
None,
@@ -662,7 +671,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if suggest_constraining_type_param(
self.tcx,
generics,
- &mut err,
+ err,
&param_name,
&constraint,
Some(trait_pred.def_id()),
@@ -690,7 +699,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if suggest_arbitrary_trait_bound(
self.tcx,
generics,
- &mut err,
+ err,
trait_pred,
associated_ty,
) {
@@ -723,7 +732,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let Some(typeck_results) = &self.typeck_results else {
return false;
};
- let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) else {
+ let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id) else {
return false;
};
let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) else {
@@ -739,9 +748,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
real_trait_pred = parent_trait_pred;
}
- // We `erase_late_bound_regions` here because `make_subregion` does not handle
- // `ReLateBound`, and we don't particularly care about the regions.
- let real_ty = self.tcx.erase_late_bound_regions(real_trait_pred.self_ty());
+ // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle
+ // `ReBound`, and we don't particularly care about the regions.
+ let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());
if !self.can_eq(obligation.param_env, real_ty, arg_ty) {
continue;
}
@@ -776,7 +785,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
kind:
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr),
..
- })) = self.tcx.hir().find(*arg_hir_id)
+ })) = self.tcx.opt_hir_node(*arg_hir_id)
{
let derefs = "*".repeat(steps);
err.span_suggestion_verbose(
@@ -812,7 +821,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
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 call_node = self.tcx.hir_node(*call_hir_id);
let msg = "consider dereferencing here";
let is_receiver = matches!(
call_node,
@@ -871,7 +880,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
};
let hir = self.tcx.hir();
- let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?);
+ let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);
match hir.find_parent(hir_id) {
Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
get_name(err, &local.pat.kind)
@@ -908,7 +917,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let self_ty = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
trait_pred.self_ty(),
);
@@ -1034,10 +1043,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {
return;
};
- let hir::def::Res::Local(hir_id) = path.res else {
+ let Res::Local(hir_id) = path.res else {
return;
};
- let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
+ let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(hir_id) else {
return;
};
let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) =
@@ -1097,7 +1106,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
else {
return false;
};
- let arg_node = self.tcx.hir().get(*arg_hir_id);
+ let arg_node = self.tcx.hir_node(*arg_hir_id);
let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { return false };
let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
@@ -1237,7 +1246,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let output = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
output,
);
let inputs = inputs
@@ -1246,7 +1255,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.map(|ty| {
self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
inputs.rebind(*ty),
)
})
@@ -1273,7 +1282,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
obligation.cause.code()
{
- &parent_code
+ parent_code
} else if let ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code()
{
@@ -1378,14 +1387,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.message =
vec![(rustc_errors::DiagnosticMessage::from(msg), Style::NoStyle)];
}
+ let mut file = None;
err.span_label(
span,
format!(
"the trait `{}` is not implemented for `{}`",
old_pred.print_modifiers_and_trait_path(),
- old_pred.self_ty().skip_binder(),
+ self.tcx.short_ty_string(old_pred.self_ty().skip_binder(), &mut file),
),
);
+ if let Some(file) = file {
+ err.note(format!(
+ "the full type name has been written to '{}'",
+ file.display()
+ ));
+ }
if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
err.span_suggestions(
@@ -1618,8 +1634,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
- && let hir::def::Res::Local(hir_id) = path.res
- && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
+ && let Res::Local(hir_id) = path.res
+ && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(hir_id)
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id)
&& let None = local.ty
&& let Some(binding_expr) = local.init
@@ -1634,9 +1650,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
let hir = self.tcx.hir();
- if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) =
- obligation.cause.code().peel_derives()
- && let hir::Node::Expr(expr) = hir.get(*hir_id)
+ if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives()
+ && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)
{
// FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
// and if not maybe suggest doing something else? If we kept the expression around we
@@ -1786,7 +1801,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
let hir = self.tcx.hir();
- let node = hir.find_by_def_id(obligation.cause.body_id);
+ let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id);
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
&& let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
&& sig.decl.output.span().overlaps(span)
@@ -1821,9 +1836,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
- let hir = self.tcx.hir();
let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) =
- hir.find_by_def_id(obligation.cause.body_id)
+ self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id)
else {
return None;
};
@@ -1867,7 +1881,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id));
let mut visitor = ReturnsVisitor::default();
- visitor.visit_body(&body);
+ visitor.visit_body(body);
let mut sugg =
vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
@@ -1915,14 +1929,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
let hir = self.tcx.hir();
- let node = hir.find_by_def_id(obligation.cause.body_id);
+ let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id);
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
node
{
let body = hir.body(*body_id);
// Point at all the `return`s in the function as they have failed trait bounds.
let mut visitor = ReturnsVisitor::default();
- visitor.visit_body(&body);
+ visitor.visit_body(body);
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) {
@@ -2006,6 +2020,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let signature_kind = format!("{argument_kind} signature");
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
+ self.note_conflicting_fn_args(&mut err, cause, expected, found, param_env);
self.note_conflicting_closure_bounds(cause, &mut err);
if let Some(found_node) = found_node {
@@ -2015,6 +2030,158 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err
}
+ fn note_conflicting_fn_args(
+ &self,
+ err: &mut Diagnostic,
+ cause: &ObligationCauseCode<'tcx>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) {
+ let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = cause else {
+ return;
+ };
+ let ty::FnPtr(expected) = expected.kind() else {
+ return;
+ };
+ let ty::FnPtr(found) = found.kind() else {
+ return;
+ };
+ let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id) else {
+ return;
+ };
+ let hir::ExprKind::Path(path) = arg.kind else {
+ return;
+ };
+ let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(*expected).inputs();
+ let found_inputs = self.tcx.instantiate_bound_regions_with_erased(*found).inputs();
+ let both_tys = expected_inputs.iter().copied().zip(found_inputs.iter().copied());
+
+ let arg_expr = |infcx: &InferCtxt<'tcx>, name, expected: Ty<'tcx>, found: Ty<'tcx>| {
+ let (expected_ty, expected_refs) = get_deref_type_and_refs(expected);
+ let (found_ty, found_refs) = get_deref_type_and_refs(found);
+
+ if infcx.can_eq(param_env, found_ty, expected_ty) {
+ if found_refs.len() == expected_refs.len()
+ && found_refs.iter().eq(expected_refs.iter())
+ {
+ name
+ } else if found_refs.len() > expected_refs.len() {
+ let refs = &found_refs[..found_refs.len() - expected_refs.len()];
+ if found_refs[..expected_refs.len()].iter().eq(expected_refs.iter()) {
+ format!(
+ "{}{name}",
+ refs.iter()
+ .map(|mutbl| format!("&{}", mutbl.prefix_str()))
+ .collect::<Vec<_>>()
+ .join(""),
+ )
+ } else {
+ // The refs have different mutability.
+ format!(
+ "{}*{name}",
+ refs.iter()
+ .map(|mutbl| format!("&{}", mutbl.prefix_str()))
+ .collect::<Vec<_>>()
+ .join(""),
+ )
+ }
+ } else if expected_refs.len() > found_refs.len() {
+ format!(
+ "{}{name}",
+ (0..(expected_refs.len() - found_refs.len()))
+ .map(|_| "*")
+ .collect::<Vec<_>>()
+ .join(""),
+ )
+ } else {
+ format!(
+ "{}{name}",
+ found_refs
+ .iter()
+ .map(|mutbl| format!("&{}", mutbl.prefix_str()))
+ .chain(found_refs.iter().map(|_| "*".to_string()))
+ .collect::<Vec<_>>()
+ .join(""),
+ )
+ }
+ } else {
+ format!("/* {found} */")
+ }
+ };
+ let args_have_same_underlying_type = both_tys.clone().all(|(expected, found)| {
+ let (expected_ty, _) = get_deref_type_and_refs(expected);
+ let (found_ty, _) = get_deref_type_and_refs(found);
+ self.can_eq(param_env, found_ty, expected_ty)
+ });
+ let (closure_names, call_names): (Vec<_>, Vec<_>) = if args_have_same_underlying_type
+ && !expected_inputs.is_empty()
+ && expected_inputs.len() == found_inputs.len()
+ && let Some(typeck) = &self.typeck_results
+ && let Res::Def(res_kind, fn_def_id) = typeck.qpath_res(&path, *arg_hir_id)
+ && res_kind.is_fn_like()
+ {
+ let closure: Vec<_> = self
+ .tcx
+ .fn_arg_names(fn_def_id)
+ .iter()
+ .enumerate()
+ .map(|(i, ident)| {
+ if ident.name.is_empty() || ident.name == kw::SelfLower {
+ format!("arg{i}")
+ } else {
+ format!("{ident}")
+ }
+ })
+ .collect();
+ let args = closure
+ .iter()
+ .zip(both_tys)
+ .map(|(name, (expected, found))| {
+ arg_expr(self.infcx, name.to_owned(), expected, found)
+ })
+ .collect();
+ (closure, args)
+ } else {
+ let closure_args = expected_inputs
+ .iter()
+ .enumerate()
+ .map(|(i, _)| format!("arg{i}"))
+ .collect::<Vec<_>>();
+ let call_args = both_tys
+ .enumerate()
+ .map(|(i, (expected, found))| {
+ arg_expr(self.infcx, format!("arg{i}"), expected, found)
+ })
+ .collect::<Vec<_>>();
+ (closure_args, call_args)
+ };
+ let closure_names: Vec<_> = closure_names
+ .into_iter()
+ .zip(expected_inputs.iter())
+ .map(|(name, ty)| {
+ format!(
+ "{name}{}",
+ if ty.has_infer_types() {
+ String::new()
+ } else if ty.references_error() {
+ ": /* type */".to_string()
+ } else {
+ format!(": {ty}")
+ }
+ )
+ })
+ .collect();
+ err.multipart_suggestion(
+ "consider wrapping the function in a closure",
+ vec![
+ (arg.span.shrink_to_lo(), format!("|{}| ", closure_names.join(", "))),
+ (arg.span.shrink_to_hi(), format!("({})", call_names.join(", "))),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+
// 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(
@@ -2287,8 +2454,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// represent regions that are part of the suspended
// coroutine frame. Bound regions are preserved by
// `erase_regions` and so we must also call
- // `erase_late_bound_regions`.
- let ty_erased = self.tcx.erase_late_bound_regions(ty);
+ // `instantiate_bound_regions_with_erased`.
+ let ty_erased = self.tcx.instantiate_bound_regions_with_erased(ty);
let ty_erased = self.tcx.erase_regions(ty_erased);
let eq = ty_erased == target_ty_erased;
debug!(?ty_erased, ?target_ty_erased, ?eq);
@@ -2300,7 +2467,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// cycles. If we can't use resolved types because the coroutine comes from another crate,
// we still provide a targeted error but without all the relevant spans.
let coroutine_data = match &self.typeck_results {
- Some(t) if t.hir_owner.to_def_id() == coroutine_did_root => CoroutineData(&t),
+ Some(t) if t.hir_owner.to_def_id() == coroutine_did_root => CoroutineData(t),
_ if coroutine_did.is_local() => {
CoroutineData(self.tcx.typeck(coroutine_did.expect_local()))
}
@@ -2344,7 +2511,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if interior_or_upvar_span.is_none() {
interior_or_upvar_span =
- coroutine_data.try_get_upvar_span(&self, coroutine_did, ty_matches);
+ coroutine_data.try_get_upvar_span(self, coroutine_did, ty_matches);
}
if interior_or_upvar_span.is_none() && !coroutine_did.is_local() {
@@ -2415,7 +2582,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.tcx
.parent(coroutine_did)
.as_local()
- .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
+ .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
.and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
.map(|name| {
format!("future returned by `{name}` is not {trait_name}")
@@ -2426,11 +2593,28 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
CoroutineKind::Async(CoroutineSource::Closure) => {
format!("future created by async closure is not {trait_name}")
}
+ CoroutineKind::AsyncGen(CoroutineSource::Fn) => self
+ .tcx
+ .parent(coroutine_did)
+ .as_local()
+ .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
+ .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
+ .map(|name| {
+ format!("async iterator returned by `{name}` is not {trait_name}")
+ })?,
+ CoroutineKind::AsyncGen(CoroutineSource::Block) => {
+ format!("async iterator created by async gen block is not {trait_name}")
+ }
+ CoroutineKind::AsyncGen(CoroutineSource::Closure) => {
+ format!(
+ "async iterator created by async gen closure is not {trait_name}"
+ )
+ }
CoroutineKind::Gen(CoroutineSource::Fn) => self
.tcx
.parent(coroutine_did)
.as_local()
- .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
+ .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
.and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
.map(|name| {
format!("iterator returned by `{name}` is not {trait_name}")
@@ -2517,7 +2701,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
CoroutineInteriorOrUpvar::Upvar(upvar_span) => {
// `Some((ref_ty, is_mut))` if `target_ty` is `&T` or `&mut T` and fails to impl `Send`
let non_send = match target_ty.kind() {
- ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(&obligation) {
+ ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(obligation) {
Ok(eval) if !eval.may_apply() => Some((ref_ty, mutability.is_mut())),
_ => None,
},
@@ -2593,11 +2777,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::MethodReceiver
| ObligationCauseCode::ReturnNoExpression
| ObligationCauseCode::UnifyReceiver(..)
- | ObligationCauseCode::OpaqueType
| ObligationCauseCode::MiscObligation
| ObligationCauseCode::WellFormed(..)
| ObligationCauseCode::MatchImpl(..)
- | ObligationCauseCode::ReturnType
| ObligationCauseCode::ReturnValue(_)
| ObligationCauseCode::BlockTailExpression(..)
| ObligationCauseCode::AwaitableExpr(_)
@@ -2608,7 +2790,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::BinOp { .. }
| ObligationCauseCode::AscribeUserTypeProvePredicate(..)
| ObligationCauseCode::DropImpl
- | ObligationCauseCode::ConstParam(_) => {}
+ | ObligationCauseCode::ConstParam(_)
+ | ObligationCauseCode::ReferenceOutlivesReferent(..)
+ | ObligationCauseCode::ObjectTypeBound(..) => {}
ObligationCauseCode::RustCall => {
if let Some(pred) = predicate.to_opt_poly_trait_pred()
&& Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
@@ -2622,19 +2806,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ObligationCauseCode::TupleElem => {
err.note("only the last element of a tuple may have a dynamically sized type");
}
- ObligationCauseCode::ProjectionWf(data) => {
- err.note(format!("required so that the projection `{data}` is well-formed"));
- }
- ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
- err.note(format!(
- "required so that reference `{ref_ty}` does not outlive its referent"
- ));
- }
- ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
- err.note(format!(
- "required so that the lifetime bound of `{region}` for `{object_ty}` is satisfied",
- ));
- }
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::ExprItemObligation(..) => {
// We hold the `DefId` of the item introducing the obligation, but displaying it
@@ -2723,11 +2894,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.collect::<Vec<_>>();
if !impls.is_empty() {
let len = impls.len();
- let mut types = impls.iter()
- .map(|t| with_no_trimmed_paths!(format!(
- " {}",
- tcx.type_of(*t).instantiate_identity(),
- )))
+ let mut types = impls
+ .iter()
+ .map(|t| {
+ with_no_trimmed_paths!(format!(
+ " {}",
+ tcx.type_of(*t).instantiate_identity(),
+ ))
+ })
.collect::<Vec<_>>();
let post = if types.len() > 9 {
types.truncate(8);
@@ -2749,50 +2923,62 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
ObligationCauseCode::Coercion { source, target } => {
- let (source, source_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(source));
- let (target, target_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(target));
+ let mut file = None;
+ let source =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
+ let target =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
err.note(with_forced_trimmed_paths!(format!(
"required for the cast from `{source}` to `{target}`",
)));
- if let Some(file) = source_file {
- err.note(format!(
- "the full name for the source type has been written to '{}'",
- file.display(),
- ));
- }
- if let Some(file) = target_file {
+ if let Some(file) = file {
err.note(format!(
- "the full name for the target type has been written to '{}'",
+ "the full name for the type has been written to '{}'",
file.display(),
));
}
}
- ObligationCauseCode::RepeatElementCopy { is_constable, elt_type, elt_span, elt_stmt_span } => {
+ ObligationCauseCode::RepeatElementCopy {
+ is_constable,
+ elt_type,
+ elt_span,
+ elt_stmt_span,
+ } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
);
let value_kind = match is_constable {
IsConstable::Fn => Some("the result of the function call"),
IsConstable::Ctor => Some("the result of the constructor"),
- _ => None
+ _ => None,
};
let sm = tcx.sess.source_map();
- if let Some(value_kind) = value_kind &&
- let Ok(snip) = sm.span_to_snippet(elt_span)
+ if let Some(value_kind) = value_kind
+ && let Ok(snip) = sm.span_to_snippet(elt_span)
{
let help_msg = format!(
"consider creating a new `const` item and initializing it with {value_kind} \
- to be used in the repeat position");
+ to be used in the repeat position"
+ );
let indentation = sm.indentation_before(elt_stmt_span).unwrap_or_default();
- err.multipart_suggestion(help_msg, vec![
- (elt_stmt_span.shrink_to_lo(), format!("const ARRAY_REPEAT_VALUE: {elt_type} = {snip};\n{indentation}")),
- (elt_span, "ARRAY_REPEAT_VALUE".to_string())
- ], Applicability::MachineApplicable);
+ err.multipart_suggestion(
+ help_msg,
+ vec![
+ (
+ elt_stmt_span.shrink_to_lo(),
+ format!(
+ "const ARRAY_REPEAT_VALUE: {elt_type} = {snip};\n{indentation}"
+ ),
+ ),
+ (elt_span, "ARRAY_REPEAT_VALUE".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
}
- if self.tcx.sess.is_nightly_build() && matches!(is_constable, IsConstable::Fn|IsConstable::Ctor) {
+ if self.tcx.sess.is_nightly_build()
+ && matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
+ {
err.help(
"create an inline `const` block, see RFC #2920 \
<https://github.com/rust-lang/rfcs/pull/2920> for more information",
@@ -2801,7 +2987,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
ObligationCauseCode::VariableType(hir_id) => {
let parent_node = self.tcx.hir().parent_id(hir_id);
- match self.tcx.hir().find(parent_node) {
+ match self.tcx.opt_hir_node(parent_node) {
Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
err.span_suggestion_verbose(
ty.span.shrink_to_lo(),
@@ -2945,7 +3131,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"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
+ self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
else {
bug!("expected closure in SizedClosureCapture obligation");
};
@@ -2957,16 +3143,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
let what = match self.tcx.coroutine_kind(coroutine_def_id) {
- None | Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) => "yield",
+ None
+ | Some(hir::CoroutineKind::Coroutine)
+ | Some(hir::CoroutineKind::Gen(_)) => "yield",
Some(hir::CoroutineKind::Async(..)) => "await",
+ Some(hir::CoroutineKind::AsyncGen(_)) => "yield`/`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`");
- }
ObligationCauseCode::SharedStatic => {
err.note("shared static variables must have a type that implements `Sync`");
}
@@ -3000,9 +3186,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Don't print the tuple of capture types
'print: {
if !is_upvar_tys_infer_tuple {
- let msg = with_forced_trimmed_paths!(format!(
- "required because it appears within the type `{ty}`",
- ));
+ let mut file = None;
+ let ty_str = self.tcx.short_ty_string(ty, &mut file);
+ let msg = format!("required because it appears within the type `{ty_str}`");
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
Some(ident) => err.span_note(ident.span, msg),
@@ -3099,8 +3285,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut parent_trait_pred =
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
let parent_def_id = parent_trait_pred.def_id();
- let (self_ty, file) =
- self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty());
+ let mut file = None;
+ let self_ty =
+ self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
let msg = format!(
"required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path()
@@ -3197,8 +3384,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
count,
pluralize!(count)
));
- let (self_ty, file) =
- self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty());
+ let mut file = None;
+ let self_ty = self
+ .tcx
+ .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
err.note(format!(
"required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path()
@@ -3283,7 +3472,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err,
predicate,
param_env,
- &parent_code,
+ parent_code,
obligated_types,
seen_requirements,
)
@@ -3352,7 +3541,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
let impls_future = self.type_implements_trait(
future_trait,
- [self.tcx.erase_late_bound_regions(self_ty)],
+ [self.tcx.instantiate_bound_regions_with_erased(self_ty)],
obligation.param_env,
);
if !impls_future.must_apply_modulo_regions() {
@@ -3443,17 +3632,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
is_derivable_trait &&
// Ensure all fields impl the trait.
adt.all_fields().all(|field| {
- let field_ty = field.ty(self.tcx, args);
+ let field_ty = ty::GenericArg::from(field.ty(self.tcx, args));
let trait_args = match diagnostic_name {
sym::PartialEq | sym::PartialOrd => {
Some(field_ty)
}
_ => None,
};
+ // Also add host param, if present
+ let host = self.tcx.generics_of(trait_pred.def_id()).host_effect_index.map(|idx| trait_pred.skip_binder().trait_ref.args[idx]);
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
trait_ref: ty::TraitRef::new(self.tcx,
trait_pred.def_id(),
- [field_ty].into_iter().chain(trait_args),
+ [field_ty].into_iter().chain(trait_args).chain(host),
),
..*tr
});
@@ -3474,6 +3665,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_pred.skip_binder().self_ty(),
diagnostic_name,
),
+ // FIXME(effects, const_trait_impl) derive_const as suggestion?
format!("#[derive({diagnostic_name})]\n"),
Applicability::MaybeIncorrect,
);
@@ -3513,13 +3705,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
call_hir_id: HirId,
) {
let tcx = self.tcx;
- let hir = tcx.hir();
- if let Some(Node::Expr(expr)) = hir.find(arg_hir_id)
+ if let Some(Node::Expr(expr)) = tcx.opt_hir_node(arg_hir_id)
&& let Some(typeck_results) = &self.typeck_results
{
if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
let inner_expr = expr.peel_blocks();
- let ty = typeck_results.expr_ty_adjusted_opt(inner_expr)
+ let ty = typeck_results
+ .expr_ty_adjusted_opt(inner_expr)
.unwrap_or(Ty::new_misc_error(tcx));
let span = inner_expr.span;
if Some(span) != err.span.primary_span() {
@@ -3538,16 +3730,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
tcx.lang_items().fn_once_trait(),
tcx.lang_items().fn_mut_trait(),
tcx.lang_items().fn_trait(),
- ].contains(&Some(pred.def_id()))
+ ]
+ .contains(&Some(pred.def_id()))
{
if let [stmt, ..] = block.stmts
&& let hir::StmtKind::Semi(value) = stmt.kind
&& let hir::ExprKind::Closure(hir::Closure {
- body,
- fn_decl_span,
- ..
+ body, fn_decl_span, ..
}) = value.kind
- && let body = hir.body(*body)
+ && let body = tcx.hir().body(*body)
&& !matches!(body.value.kind, hir::ExprKind::Block(..))
{
// Check if the failed predicate was an expectation of a closure type
@@ -3568,9 +3759,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"you might have meant to create the closure instead of a block",
format!(
"|{}| ",
- (0..pred.trait_ref.args.len() - 1).map(|_| "_")
+ (0..pred.trait_ref.args.len() - 1)
+ .map(|_| "_")
.collect::<Vec<_>>()
- .join(", ")),
+ .join(", ")
+ ),
Applicability::MaybeIncorrect,
);
}
@@ -3595,7 +3788,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let where_pred = self.instantiate_binder_with_placeholders(where_pred);
let failed_pred = self.instantiate_binder_with_fresh_vars(
expr.span,
- LateBoundRegionConversionTime::FnCall,
+ BoundRegionConversionTime::FnCall,
failed_pred,
);
@@ -3627,21 +3820,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
- && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
- && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
+ && let hir::Path { res: Res::Local(hir_id), .. } = path
+ && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id)
&& let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id)
- && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
+ && let Some(hir::Node::Local(local)) = self.tcx.opt_hir_node(parent_hir_id)
&& let Some(binding_expr) = local.init
{
// If the expression we're calling on is a binding, we want to point at the
// `let` when talking about the type. Otherwise we'll point at every part
// of the method chain with the type.
- self.point_at_chain(binding_expr, &typeck_results, type_diffs, param_env, err);
+ self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err);
} else {
- self.point_at_chain(expr, &typeck_results, type_diffs, param_env, err);
+ self.point_at_chain(expr, typeck_results, type_diffs, param_env, err);
}
}
- let call_node = hir.find(call_hir_id);
+ let call_node = tcx.opt_hir_node(call_hir_id);
if let Some(Node::Expr(hir::Expr {
kind: hir::ExprKind::MethodCall(path, rcvr, ..), ..
})) = call_node
@@ -3651,7 +3844,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- if let Some(Node::Expr(expr)) = hir.find(call_hir_id) {
+ if let Some(Node::Expr(expr)) = tcx.opt_hir_node(call_hir_id) {
if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
| hir::ExprKind::MethodCall(
hir::PathSegment { ident: Ident { span, .. }, .. },
@@ -3812,7 +4005,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
continue;
};
let hir = tcx.hir();
- let node = hir.get_by_def_id(hir.get_parent_item(expr.hir_id).def_id);
+ let node = tcx.hir_node_by_def_id(hir.get_parent_item(expr.hir_id).def_id);
let pred = ty::Binder::dummy(ty::TraitPredicate {
trait_ref: ty::TraitRef::from_lang_item(
@@ -3832,7 +4025,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
suggest_restriction(
tcx,
hir.body_owner_def_id(body_id),
- &generics,
+ generics,
&format!("type parameter `{ty}`"),
err,
node.fn_sig(),
@@ -3887,8 +4080,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
- && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
- && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
+ && let hir::Path { res: Res::Local(hir_id), .. } = path
+ && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id)
&& let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
{
// We've reached the root of the method call chain...
@@ -4267,7 +4460,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
return;
};
- let Some(hir::Node::TraitItem(item)) = self.tcx.hir().find_by_def_id(fn_def_id) else {
+ let Some(hir::Node::TraitItem(item)) = self.tcx.opt_hir_node_by_def_id(fn_def_id) else {
return;
};
@@ -4342,17 +4535,6 @@ fn hint_missing_borrow<'tcx>(
let args = fn_decl.inputs.iter();
- fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
- let mut refs = vec![];
-
- while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
- ty = *new_ty;
- refs.push(*mutbl);
- }
-
- (ty, refs)
- }
-
let mut to_borrow = Vec::new();
let mut remove_borrow = Vec::new();
@@ -4483,7 +4665,7 @@ pub trait NextTypeParamName {
impl NextTypeParamName for &[hir::GenericParam<'_>] {
fn next_type_param_name(&self, name: Option<&str>) -> String {
// This is the list of possible parameter names that we might suggest.
- let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase());
+ let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
let name = name.as_deref();
let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
let used_names = self
@@ -4512,7 +4694,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
if let hir::TyKind::Path(hir::QPath::Resolved(
None,
- hir::Path { res: hir::def::Res::Def(_, segment_did), .. },
+ hir::Path { res: Res::Def(_, segment_did), .. },
)) = t.kind
{
if self.param_did == *segment_did {
@@ -4530,6 +4712,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
}
pub(super) fn get_explanation_based_on_obligation<'tcx>(
+ tcx: TyCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
@@ -4550,13 +4733,13 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
pre_message,
trait_predicate.print_modifiers_and_trait_path(),
desc,
- trait_ref.skip_binder().self_ty(),
+ tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None),
),
None => format!(
"{}the trait `{}` is not implemented for `{}`",
pre_message,
trait_predicate.print_modifiers_and_trait_path(),
- trait_ref.skip_binder().self_ty(),
+ tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None),
),
}
}
@@ -4599,9 +4782,15 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
return None;
};
- let future = tcx.hir().get_by_def_id(opaque_def_id).expect_item().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.
+ let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+ let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else {
+ // `async fn` should always lower to a single bound... but don't ICE.
+ return None;
+ };
+ let Some(hir::PathSegment { args: Some(generics), .. }) =
+ trait_ref.trait_ref.path.segments.last()
+ else {
+ // desugaring to a single path segment for `Future<...>`.
return None;
};
let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
@@ -4645,3 +4834,14 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
Some(sugg)
}
+
+fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
+ let mut refs = vec![];
+
+ while let ty::Ref(_, new_ty, mutbl) = ty.kind() {
+ ty = *new_ty;
+ refs.push(*mutbl);
+ }
+
+ (ty, refs)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index ba2e3d1ae..9ee091bbd 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -3,6 +3,7 @@ use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as
use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::InferCtxtExt as _;
use crate::infer::{self, InferCtxt};
use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt;
use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*};
@@ -36,11 +37,11 @@ use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable, TypeVisitableExt,
};
-use rustc_session::config::{DumpSolverProofTree, TraitSolver};
+use rustc_session::config::DumpSolverProofTree;
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::iter;
@@ -98,8 +99,21 @@ pub trait TypeErrCtxtExt<'tcx> {
error: &SelectionError<'tcx>,
);
+ fn emit_specialized_closure_kind_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Option<ErrorGuaranteed>;
+
fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
+ fn try_conversion_context(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ err: &mut Diagnostic,
+ ) -> bool;
+
fn report_const_param_not_wf(
&self,
ty: Ty<'tcx>,
@@ -212,7 +226,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors")
+ self.tcx.sess.span_delayed_bug(DUMMY_SP, "expected fulfillment errors")
}
/// Reports that an overflow has occurred and halts compilation. We
@@ -236,7 +250,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.emit();
self.tcx.sess.abort_if_errors();
- bug!();
+ // FIXME: this should be something like `build_overflow_error_fatal`, which returns
+ // `DiagnosticBuilder<', !>`. Then we don't even need anything after that `emit()`.
+ unreachable!(
+ "did not expect compilation to continue after `abort_if_errors`, \
+ since an error was definitely emitted!"
+ );
}
fn build_overflow_error<T>(
@@ -356,14 +375,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) {
let tcx = self.tcx;
- if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
+ if tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
+ == DumpSolverProofTree::OnError
+ {
dump_proof_tree(root_obligation, self.infcx);
}
let mut span = obligation.cause.span;
// FIXME: statically guarantee this by tainting after the diagnostic is emitted
self.set_tainted_by_errors(
- tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"),
+ tcx.sess.span_delayed_bug(span, "`report_selection_error` did not emit an error"),
);
let mut err = match *error {
@@ -411,6 +432,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
let trait_predicate = bound_predicate.rebind(trait_predicate);
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+ let trait_ref = trait_predicate.to_poly_trait_ref();
+
+ if let Some(_guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
+ return;
+ }
// FIXME(effects)
let predicate_is_const = false;
@@ -425,22 +451,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// reported on the binding definition (#56607).
return;
}
- let trait_ref = trait_predicate.to_poly_trait_ref();
- let (post_message, pre_message, type_def, file_note) = self
+ let mut file = None;
+ let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| {
- let (t, file) = self.tcx.short_ty_string(t);
+ let t = self.tcx.short_ty_string(t, &mut file);
(
format!(" in `{t}`"),
format!("within `{t}`, "),
s.map(|s| (format!("within this `{t}`"), s)),
- file.map(|file| format!(
- "the full trait has been written to '{}'",
- file.display(),
- ))
)
})
.unwrap_or_default();
+ let file_note = file.map(|file| format!(
+ "the full trait has been written to '{}'",
+ file.display(),
+ ));
let OnUnimplementedNote {
message,
@@ -499,6 +525,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg);
+ let mut suggested = false;
+ if is_try_conversion {
+ suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err);
+ }
+
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
@@ -511,7 +542,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
self.add_tuple_trait_message(
- &obligation.cause.code().peel_derives(),
+ obligation.cause.code().peel_derives(),
&mut err,
);
}
@@ -524,6 +555,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
let explanation = get_explanation_based_on_obligation(
+ self.tcx,
&obligation,
trait_ref,
&trait_predicate,
@@ -569,7 +601,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
self.suggest_borrowing_for_object_cast(
&mut err,
- &root_obligation,
+ root_obligation,
source,
target,
);
@@ -599,8 +631,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
- let mut suggested =
- self.suggest_dereferences(&obligation, &mut err, trait_predicate);
+ suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate);
suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
suggested = if let &[cand] = &impl_candidates[..] {
@@ -612,7 +643,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
span.shrink_to_hi(),
format!(
"the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
- cand.print_only_trait_path(),
+ cand.print_trait_sugared(),
cand.self_ty(),
),
format!(" as {}", cand.self_ty()),
@@ -786,30 +817,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
report_object_safety_error(self.tcx, span, trait_def_id, violations)
}
- ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
- let found_kind = self.closure_kind(closure_args).unwrap();
- self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
- }
-
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
let ty = self.resolve_vars_if_possible(ty);
- match self.tcx.sess.opts.unstable_opts.trait_solver {
- TraitSolver::Classic => {
- // WF predicates cannot themselves make
- // errors. They can only block due to
- // ambiguity; otherwise, they always
- // degenerate into other obligations
- // (which may fail).
- span_bug!(span, "WF predicate not satisfied for {:?}", ty);
- }
- TraitSolver::Next | TraitSolver::NextCoherence => {
- // FIXME: we'll need a better message which takes into account
- // which bounds actually failed to hold.
- self.tcx.sess.struct_span_err(
- span,
- format!("the type `{ty}` is not well-formed"),
- )
- }
+ if self.next_trait_solver() {
+ // FIXME: we'll need a better message which takes into account
+ // which bounds actually failed to hold.
+ self.tcx.sess.struct_span_err(
+ span,
+ format!("the type `{ty}` is not well-formed"),
+ )
+ } else {
+ // WF predicates cannot themselves make
+ // errors. They can only block due to
+ // ambiguity; otherwise, they always
+ // degenerate into other obligations
+ // (which may fail).
+ span_bug!(span, "WF predicate not satisfied for {:?}", ty);
}
}
@@ -837,6 +860,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
+ ty::PredicateKind::NormalizesTo(..) => span_bug!(
+ span,
+ "NormalizesTo predicate should never be the predicate cause of a SelectionError"
+ ),
+
ty::PredicateKind::AliasRelate(..) => span_bug!(
span,
"AliasRelate predicate should never be the predicate cause of a SelectionError"
@@ -927,18 +955,48 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.emit();
}
+ fn emit_specialized_closure_kind_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Option<ErrorGuaranteed> {
+ if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind()
+ && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
+ && let Some(found_kind) = self.closure_kind(closure_args)
+ && !found_kind.extends(expected_kind)
+ && let sig = closure_args.as_closure().sig()
+ && self.can_sub(
+ obligation.param_env,
+ trait_ref,
+ sig.map_bound(|sig| {
+ ty::TraitRef::new(
+ self.tcx,
+ trait_ref.def_id(),
+ [trait_ref.self_ty().skip_binder(), sig.inputs()[0]],
+ )
+ }),
+ )
+ {
+ let mut err =
+ self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind);
+ self.note_obligation_cause(&mut err, &obligation);
+ self.point_at_returns_when_relevant(&mut err, &obligation);
+ Some(err.emit())
+ } else {
+ None
+ }
+ }
+
fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool {
- if let ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id,
- ..
- } = obligation.cause.code()
- && let Some(Node::Expr(arg)) = self.tcx.hir().find(*arg_hir_id)
+ if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
+ obligation.cause.code()
+ && let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id)
&& let arg = arg.peel_borrows()
&& let hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Local(hir_id), .. },
)) = arg.kind
- && let Some(Node::Pat(pat)) = self.tcx.hir().find(*hir_id)
+ && let Some(Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id)
&& let Some(preds) = self.reported_trait_errors.borrow().get(&pat.span)
&& preds.contains(&obligation.predicate)
{
@@ -947,6 +1005,223 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
false
}
+ /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
+ /// identify thoe method chain sub-expressions that could or could not have been annotated
+ /// with `?`.
+ fn try_conversion_context(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ err: &mut Diagnostic,
+ ) -> bool {
+ let span = obligation.cause.span;
+ struct V<'v> {
+ search_span: Span,
+ found: Option<&'v hir::Expr<'v>>,
+ }
+ impl<'v> Visitor<'v> for V<'v> {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind
+ {
+ if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) {
+ if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind {
+ self.found = Some(expr);
+ return;
+ }
+ }
+ }
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+ let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
+ let body_id = match self.tcx.opt_hir_node(hir_id) {
+ Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
+ body_id
+ }
+ _ => return false,
+ };
+ let mut v = V { search_span: span, found: None };
+ v.visit_body(self.tcx.hir().body(*body_id));
+ let Some(expr) = v.found else {
+ return false;
+ };
+ let Some(typeck) = &self.typeck_results else {
+ return false;
+ };
+ let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
+ else {
+ return false;
+ };
+ if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
+ return false;
+ }
+ let self_ty = trait_ref.self_ty();
+ let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type());
+
+ let mut prev_ty = self.resolve_vars_if_possible(
+ typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
+ );
+
+ // We always look at the `E` type, because that's the only one affected by `?`. If the
+ // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
+ // expression, after the `?` has "unwrapped" the `T`.
+ let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> {
+ let ty::Adt(def, args) = prev_ty.kind() else {
+ return None;
+ };
+ let Some(arg) = args.get(1) else {
+ return None;
+ };
+ if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {
+ return None;
+ }
+ arg.as_type()
+ };
+
+ let mut suggested = false;
+ let mut chain = vec![];
+
+ // The following logic is simlar to `point_at_chain`, but that's focused on associated types
+ let mut expr = expr;
+ while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
+ // Point at every method call in the chain with the `Result` type.
+ // let foo = bar.iter().map(mapper)?;
+ // ------ -----------
+ expr = rcvr_expr;
+ chain.push((span, prev_ty));
+
+ let next_ty = self.resolve_vars_if_possible(
+ typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
+ );
+
+ let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| {
+ let ty::Adt(def, _) = ty.kind() else {
+ return false;
+ };
+ self.tcx.is_diagnostic_item(symbol, def.did())
+ };
+ // For each method in the chain, see if this is `Result::map_err` or
+ // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect
+ // trailing `;`.
+ if let Some(ty) = get_e_type(prev_ty)
+ && let Some(found_ty) = found_ty
+ // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%
+ // accurate check, but we are in the wrong stage to do that and looking for
+ // `Result::map_err` by checking the Self type and the path segment is enough.
+ // sym::ok_or_else
+ && (
+ ( // Result::map_err
+ path_segment.ident.name == sym::map_err
+ && is_diagnostic_item(sym::Result, next_ty)
+ ) || ( // Option::ok_or_else
+ path_segment.ident.name == sym::ok_or_else
+ && is_diagnostic_item(sym::Option, next_ty)
+ )
+ )
+ // Found `Result<_, ()>?`
+ && let ty::Tuple(tys) = found_ty.kind()
+ && tys.is_empty()
+ // The current method call returns `Result<_, ()>`
+ && self.can_eq(obligation.param_env, ty, found_ty)
+ // There's a single argument in the method call and it is a closure
+ && args.len() == 1
+ && let Some(arg) = args.get(0)
+ && let hir::ExprKind::Closure(closure) = arg.kind
+ // The closure has a block for its body with no tail expression
+ && let body = self.tcx.hir().body(closure.body)
+ && let hir::ExprKind::Block(block, _) = body.value.kind
+ && let None = block.expr
+ // The last statement is of a type that can be converted to the return error type
+ && let [.., stmt] = block.stmts
+ && let hir::StmtKind::Semi(expr) = stmt.kind
+ && let expr_ty = self.resolve_vars_if_possible(
+ typeck.expr_ty_adjusted_opt(expr)
+ .unwrap_or(Ty::new_misc_error(self.tcx)),
+ )
+ && self
+ .infcx
+ .type_implements_trait(
+ self.tcx.get_diagnostic_item(sym::From).unwrap(),
+ [self_ty, expr_ty],
+ obligation.param_env,
+ )
+ .must_apply_modulo_regions()
+ {
+ suggested = true;
+ err.span_suggestion_short(
+ stmt.span.with_lo(expr.span.hi()),
+ "remove this semicolon",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ prev_ty = next_ty;
+
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
+ && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
+ && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id)
+ && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
+ {
+ // We've reached the root of the method call chain...
+ if let hir::Node::Local(local) = parent
+ && let Some(binding_expr) = local.init
+ {
+ // ...and it is a binding. Get the binding creation and continue the chain.
+ expr = binding_expr;
+ }
+ if let hir::Node::Param(_param) = parent {
+ // ...and it is a an fn argument.
+ break;
+ }
+ }
+ }
+ // `expr` is now the "root" expression of the method call chain, which can be any
+ // expression kind, like a method call or a path. If this expression is `Result<T, E>` as
+ // well, then we also point at it.
+ prev_ty = self.resolve_vars_if_possible(
+ typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
+ );
+ chain.push((expr.span, prev_ty));
+
+ let mut prev = None;
+ for (span, err_ty) in chain.into_iter().rev() {
+ let err_ty = get_e_type(err_ty);
+ let err_ty = match (err_ty, prev) {
+ (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {
+ err_ty
+ }
+ (Some(err_ty), None) => err_ty,
+ _ => {
+ prev = err_ty;
+ continue;
+ }
+ };
+ if self
+ .infcx
+ .type_implements_trait(
+ self.tcx.get_diagnostic_item(sym::From).unwrap(),
+ [self_ty, err_ty],
+ obligation.param_env,
+ )
+ .must_apply_modulo_regions()
+ {
+ if !suggested {
+ err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
+ }
+ } else {
+ err.span_label(
+ span,
+ format!(
+ "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`",
+ ),
+ );
+ }
+ prev = Some(err_ty);
+ }
+ suggested
+ }
+
fn report_const_param_not_wf(
&self,
ty: Ty<'tcx>,
@@ -1291,7 +1566,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
- if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
+ if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
+ == DumpSolverProofTree::OnError
+ {
dump_proof_tree(&error.root_obligation, self.infcx);
}
@@ -1377,7 +1654,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
let data = self.instantiate_binder_with_fresh_vars(
obligation.cause.span,
- infer::LateBoundRegionConversionTime::HigherRankedType,
+ infer::BoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
let unnormalized_term = match data.term.unpack() {
@@ -1397,7 +1674,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
.into(),
};
- // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice
+ // FIXME(-Znext-solver): For diagnostic purposes, it would be nice
// to deeply normalize this type.
let normalized_term =
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
@@ -1413,7 +1690,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::ExprItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
| ObligationCauseCode::Coercion { .. }
- | ObligationCauseCode::OpaqueType
);
// constrain inference variables a bit more to nested obligations from normalize so
@@ -1653,6 +1929,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block",
hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function",
hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure",
+ hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Block) => "an async gen block",
+ hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Fn) => "an async gen function",
+ hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Closure) => "an async gen closure",
hir::CoroutineKind::Gen(hir::CoroutineSource::Block) => "a gen block",
hir::CoroutineKind::Gen(hir::CoroutineSource::Fn) => "a gen function",
hir::CoroutineKind::Gen(hir::CoroutineSource::Closure) => "a gen closure",
@@ -1751,7 +2030,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
});
err.highlighted_help(vec![
- (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
+ (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
("is".to_string(), Style::Highlight),
(" implemented for `".to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight),
@@ -1787,7 +2066,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => (" implemented for `", ""),
};
err.highlighted_help(vec![
- (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
+ (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
("is".to_string(), Style::Highlight),
(desc.to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight),
@@ -1820,7 +2099,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(format!(
"the following {other}types implement trait `{}`:{}{}",
- trait_ref.print_only_trait_path(),
+ trait_ref.print_trait_sugared(),
candidates[..end].join(""),
if candidates.len() > 9 {
format!("\nand {} others", candidates.len() - 8)
@@ -1967,7 +2246,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
- self.get_parent_trait_ref(&parent_code)
+ self.get_parent_trait_ref(parent_code)
}
_ => None,
}
@@ -2182,7 +2461,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
{
let mut expr_finder = FindExprBySpan::new(span);
- expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
+ expr_finder.visit_expr(self.tcx.hir().body(body_id).value);
if let Some(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
@@ -2228,7 +2507,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ident: trait_name,
kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
..
- })) = self.tcx.hir().find_by_def_id(local_def_id)
+ })) = self.tcx.opt_hir_node_by_def_id(local_def_id)
&& let Some(method_ref) = trait_item_refs
.iter()
.find(|item_ref| item_ref.ident == *assoc_item_name)
@@ -2731,7 +3010,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Some(format!("{cannot_do_this} in const contexts"))
}
// overridden post message
- (true, Some(AppendConstMessage::Custom(custom_msg))) => {
+ (true, Some(AppendConstMessage::Custom(custom_msg, _))) => {
Some(format!("{cannot_do_this}{custom_msg}"))
}
// fallback to generic message
@@ -2752,7 +3031,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
use rustc_transmute::Answer;
// Erase regions because layout code doesn't particularly care about regions.
- let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
+ let trait_ref =
+ self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
let src_and_dst = rustc_transmute::Types {
dst: trait_ref.args.type_at(0),
@@ -2933,7 +3213,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
obligation.param_env,
) {
self.report_similar_impl_candidates_for_root_obligation(
- &obligation,
+ obligation,
*trait_predicate,
body_def_id,
err,
@@ -3040,18 +3320,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Additional context information explaining why the closure only implements
// a particular trait.
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 hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id.expect_local());
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
(ty::ClosureKind::FnOnce, Some((span, place))) => {
err.fn_once_label = Some(ClosureFnOnceLabel {
span: *span,
- place: ty::place_to_string_for_capture(self.tcx, &place),
+ place: ty::place_to_string_for_capture(self.tcx, place),
})
}
(ty::ClosureKind::FnMut, Some((span, place))) => {
err.fn_mut_label = Some(ClosureFnMutLabel {
span: *span,
- place: ty::place_to_string_for_capture(self.tcx, &place),
+ place: ty::place_to_string_for_capture(self.tcx, place),
})
}
_ => {}
@@ -3115,7 +3395,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
};
if let Some(diag) =
- self.tcx.sess.diagnostic().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
+ self.tcx.sess.dcx().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
{
diag.cancel();
}
@@ -3163,7 +3443,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut not_tupled = false;
let found = match found_trait_ref.skip_binder().args.type_at(1).kind() {
- ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+ ty::Tuple(tys) => vec![ArgKind::empty(); tys.len()],
_ => {
not_tupled = true;
vec![ArgKind::empty()]
@@ -3172,7 +3452,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let expected_ty = expected_trait_ref.skip_binder().args.type_at(1);
let expected = match expected_ty.kind() {
- ty::Tuple(ref tys) => {
+ ty::Tuple(tys) => {
tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
}
_ => {
@@ -3253,20 +3533,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
- let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => match ct.kind() {
+ ty::ConstKind::Unevaluated(uv) => {
+ let mut err =
+ self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+ let const_span = self.tcx.def_span(uv.def);
+ match self.tcx.sess.source_map().span_to_snippet(const_span) {
+ Ok(snippet) => err.help(format!(
+ "try adding a `where` bound using this expression: `where [(); {snippet}]:`"
+ )),
+ _ => err.help("consider adding a `where` bound using this expression"),
+ };
+ Some(err)
+ }
+ ty::ConstKind::Expr(_) => {
+ let err = self
+ .tcx
+ .sess
+ .struct_span_err(span, format!("unconstrained generic constant `{ct}`"));
+ Some(err)
+ }
+ _ => {
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);
- match self.tcx.sess.source_map().span_to_snippet(const_span) {
- Ok(snippet) => err.help(format!(
- "try adding a `where` bound using this expression: `where [(); {snippet}]:`"
- )),
- _ => err.help("consider adding a `where` bound using this expression"),
- };
- Some(err)
- }
+ }
+ },
_ => {
span_bug!(
span,
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index fb9cf51b5..045d7e444 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,4 +1,5 @@
use crate::infer::{InferCtxt, TyOrConstInferVar};
+use crate::traits::error_reporting::TypeErrCtxtExt;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
@@ -115,12 +116,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn register_predicate_obligation(
&mut self,
infcx: &InferCtxt<'tcx>,
- obligation: PredicateObligation<'tcx>,
+ mut obligation: PredicateObligation<'tcx>,
) {
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
// this helps to reduce duplicate errors, as well as making
// debug output much nicer to read and so on.
- let obligation = infcx.resolve_vars_if_possible(obligation);
+ debug_assert!(!obligation.param_env.has_non_region_infer());
+ obligation.predicate = infcx.resolve_vars_if_possible(obligation.predicate);
debug!(?obligation, "register_predicate_obligation");
@@ -350,7 +352,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
| ty::PredicateKind::ObjectSafe(_)
- | ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
@@ -360,8 +361,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
}
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
+ ty::PredicateKind::NormalizesTo(..) => {
+ bug!("NormalizesTo is only used by the new solver")
+ }
ty::PredicateKind::AliasRelate(..) => {
- bug!("AliasRelate is only used for new solver")
+ bug!("AliasRelate is only used by the new solver")
}
},
Some(pred) => match pred {
@@ -411,17 +415,30 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
}
- ty::PredicateKind::ClosureKind(_, closure_args, kind) => {
- match self.selcx.infcx.closure_kind(closure_args) {
- Some(closure_kind) => {
- if closure_kind.extends(kind) {
- ProcessResult::Changed(vec![])
- } else {
- ProcessResult::Error(CodeSelectionError(Unimplemented))
- }
- }
- None => ProcessResult::Unchanged,
- }
+ ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
+ ty::PredicateKind::NormalizesTo(..) => {
+ bug!("NormalizesTo is only used by the new solver")
+ }
+ ty::PredicateKind::AliasRelate(..) => {
+ bug!("AliasRelate is only used by the new solver")
+ }
+
+ // General case overflow check. Allow `process_trait_obligation`
+ // and `process_projection_obligation` to handle checking for
+ // the recursion limit themselves. Also don't check some
+ // predicate kinds that don't give further obligations.
+ _ if !self
+ .selcx
+ .tcx()
+ .recursion_limit()
+ .value_within_limit(obligation.recursion_depth) =>
+ {
+ self.selcx.infcx.err_ctxt().report_overflow_error(
+ &obligation.predicate,
+ obligation.cause.span,
+ false,
+ |_| {},
+ );
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
@@ -454,7 +471,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
ProcessResult::Unchanged
}
- Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+ Ok(Ok(mut ok)) => {
+ for subobligation in &mut ok.obligations {
+ subobligation.set_depth_from_parent(obligation.recursion_depth);
+ }
+ ProcessResult::Changed(mk_pending(ok.obligations))
+ }
Ok(Err(err)) => {
let expected_found =
ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
@@ -625,10 +647,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
}
}
- ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
- ty::PredicateKind::AliasRelate(..) => {
- bug!("AliasRelate is only used for new solver")
- }
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
DefineOpaqueTypes::No,
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index ab07b10c6..cf4fa2337 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -9,7 +9,7 @@ use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
-use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use super::outlives_bounds::InferCtxtExt;
@@ -173,7 +173,7 @@ pub fn all_fields_implement_trait<'tcx>(
// between expected and found const-generic types. Don't report an
// additional copy error here, since it's not typically useful.
if !normalization_errors.is_empty() || ty.references_error() {
- tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
+ tcx.sess.span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
continue;
}
@@ -209,10 +209,10 @@ pub fn all_fields_implement_trait<'tcx>(
pub fn check_tys_might_be_eq<'tcx>(
tcx: TyCtxt<'tcx>,
- canonical: Canonical<'tcx, (ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>,
+ canonical: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>,
) -> Result<(), NoSolution> {
- let (infcx, (param_env, ty_a, ty_b), _) =
- tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical);
+ let (infcx, key, _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical);
+ let (param_env, (ty_a, ty_b)) = key.into_parts();
let ocx = ObligationCtxt::new(&infcx);
let result = ocx.eq(&ObligationCause::dummy(), param_env, ty_a, ty_b);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index fff5510bb..8c5f1e907 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -215,7 +215,7 @@ fn do_normalize_predicates<'tcx>(
// the normalized predicates.
let errors = infcx.resolve_regions(&outlives_env);
if !errors.is_empty() {
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
span,
format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
);
@@ -315,7 +315,7 @@ pub fn normalize_param_env_or_error<'tcx>(
// We do not normalize types here as there is no backwards compatibility requirement
// for us to do so.
//
- // FIXME(-Ztrait-solver=next): remove this hack since we have deferred projection equality
+ // FIXME(-Znext-solver): remove this hack since we have deferred projection equality
predicate.fold_with(&mut ConstNormalizer(tcx))
}),
)
@@ -386,7 +386,7 @@ pub fn normalize_param_env_or_error<'tcx>(
/// Normalize a type and process all resulting obligations, returning any errors.
///
-/// FIXME(-Ztrait-solver=next): This should be replaced by `At::deeply_normalize`
+/// FIXME(-Znext-solver): This should be replaced by `At::deeply_normalize`
/// which has the same behavior with the new solver. Because using a separate
/// fulfillment context worsens caching in the old solver, `At::deeply_normalize`
/// is still lazy with the old solver as it otherwise negatively impacts perf.
@@ -484,7 +484,7 @@ fn is_impossible_associated_item(
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::ReEarlyBound(param) = r.kind()
+ if let ty::ReEarlyParam(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
{
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 17c7f94ee..7ac37315f 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -84,7 +84,7 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
span,
) = violation
{
- lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
+ lint_object_unsafe_trait(tcx, *span, trait_def_id, violation);
}
}
return true;
@@ -192,9 +192,8 @@ fn lint_object_unsafe_trait(
);
if node.is_some() {
// Only provide the help if its a local trait, otherwise it's not
- violation.solution(err);
+ violation.solution().add_to(err);
}
- err
},
);
}
@@ -329,7 +328,7 @@ fn super_predicates_have_non_lifetime_binders(
tcx.super_predicates_of(trait_def_id)
.predicates
.iter()
- .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span))
+ .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(*span))
.collect()
}
@@ -345,7 +344,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Search for a predicate like `Self : Sized` amongst the trait bounds.
let predicates = tcx.predicates_of(def_id);
let predicates = predicates.instantiate_identity(tcx).predicates;
- elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() {
+ elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() {
ty::ClauseKind::Trait(ref trait_pred) => {
trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
}
@@ -509,7 +508,7 @@ fn virtual_call_violations_for_method<'tcx>(
Ok(layout) => Some(layout.abi),
Err(err) => {
// #78372
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
tcx.def_span(method.def_id),
format!("error: {err}\n while computing layout for type {ty:?}"),
);
@@ -525,7 +524,7 @@ fn virtual_call_violations_for_method<'tcx>(
match abi_of_ty(unit_receiver_ty) {
Some(Abi::Scalar(..)) => (),
abi => {
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
tcx.def_span(method.def_id),
format!(
"receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
@@ -543,7 +542,7 @@ fn virtual_call_violations_for_method<'tcx>(
match abi_of_ty(trait_object_receiver) {
Some(Abi::ScalarPair(..)) => (),
abi => {
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
tcx.def_span(method.def_id),
format!(
"receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
@@ -595,9 +594,7 @@ fn virtual_call_violations_for_method<'tcx>(
// would already have reported an error at the definition of the
// auto trait.
if pred_trait_ref.args.len() != 1 {
- tcx.sess
- .diagnostic()
- .delay_span_bug(span, "auto traits cannot have generic parameters");
+ tcx.sess.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters");
}
return false;
}
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 32bbd626d..7513f88cf 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -72,7 +72,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
};
let mut constraints = QueryRegionConstraints::default();
- let Ok(InferOk { value, obligations }) = self
+ let Ok(InferOk { value: mut bounds, obligations }) = self
.instantiate_nll_query_response_and_region_obligations(
&ObligationCause::dummy(),
param_env,
@@ -85,6 +85,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
};
assert_eq!(&obligations, &[]);
+ // Because of #109628, we may have unexpected placeholders. Ignore them!
+ // FIXME(#109628): panic in this case once the issue is fixed.
+ bounds.retain(|bound| !bound.has_placeholders());
+
if !constraints.is_empty() {
let span = self.tcx.def_span(body_id);
@@ -107,14 +111,14 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- self.tcx.sess.delay_span_bug(
+ self.tcx.sess.span_delayed_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
);
}
};
- value
+ bounds
}
fn implied_bounds_tys(
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 471d10dbd..a1b0ada0e 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -18,7 +18,7 @@ use rustc_middle::traits::ImplSourceUserDefinedData;
use crate::errors::InherentProjectionNormalizationOverflow;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
+use crate::infer::{BoundRegionConversionTime, InferCtxt, InferOk};
use crate::traits::error_reporting::TypeErrCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::select::ProjectionMatchesProjection;
@@ -67,7 +67,7 @@ pub trait NormalizeExt<'tcx> {
/// same goals in both a temporary and the shared context which negatively impacts
/// performance as these don't share caching.
///
- /// FIXME(-Ztrait-solver=next): This has the same behavior as `traits::fully_normalize`
+ /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize`
/// in the new solver, but because of performance reasons, we currently reuse an
/// existing fulfillment context in the old solver. Once we also eagerly prove goals with
/// the old solver or have removed the old solver, remove `traits::fully_normalize` and
@@ -191,7 +191,9 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
match (current, candidate) {
(ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (),
(ParamEnv(..), _) => return false,
- (_, ParamEnv(..)) => unreachable!(),
+ (_, ParamEnv(..)) => bug!(
+ "should never prefer non-param-env candidates over param-env candidates"
+ ),
(_, _) => convert_to_ambiguous = (),
}
}
@@ -584,7 +586,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
data,
self.cause.clone(),
self.depth,
- &mut self.obligations,
+ self.obligations,
)
} else {
opt_normalize_projection_type(
@@ -593,7 +595,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
data,
self.cause.clone(),
self.depth,
- &mut self.obligations,
+ self.obligations,
)
.ok()
.flatten()
@@ -632,7 +634,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
data,
self.cause.clone(),
self.depth,
- &mut self.obligations,
+ self.obligations,
)
.ok()
.flatten()
@@ -717,7 +719,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
data,
self.cause.clone(),
self.depth,
- &mut self.obligations,
+ self.obligations,
)
}
@@ -732,7 +734,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
data,
self.cause.clone(),
self.depth,
- &mut self.obligations,
+ self.obligations,
);
PlaceholderReplacer::replace_placeholders(
@@ -894,16 +896,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReLateBound(debruijn, _)
- if debruijn.as_usize() + 1
- > self.current_index.as_usize() + self.universe_indices.len() =>
+ ty::ReBound(debruijn, _)
+ if debruijn.as_usize()
+ >= self.current_index.as_usize() + self.universe_indices.len() =>
{
bug!(
"Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
self.universe_indices
);
}
- ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
+ ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderRegion { universe, bound: br };
self.mapped_regions.insert(p, br);
@@ -1001,7 +1003,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
&mut self,
t: ty::Binder<'tcx, T>,
) -> ty::Binder<'tcx, T> {
- if !t.has_placeholders() && !t.has_infer_regions() {
+ if !t.has_placeholders() && !t.has_infer() {
return t;
}
self.current_index.shift_in(1);
@@ -1034,7 +1036,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- ty::Region::new_late_bound(self.interner(), db, *replace_var)
+ ty::Region::new_bound(self.interner(), db, *replace_var)
}
None => r1,
}
@@ -1048,6 +1050,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let ty = self.infcx.shallow_resolve(ty);
match *ty.kind() {
ty::Placeholder(p) => {
let replace_var = self.mapped_types.get(&p);
@@ -1063,16 +1066,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
);
Ty::new_bound(self.infcx.tcx, db, *replace_var)
}
- None => ty,
+ None => {
+ if ty.has_infer() {
+ ty.super_fold_with(self)
+ } else {
+ ty
+ }
+ }
}
}
- _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
+ _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
_ => ty,
}
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ let ct = self.infcx.shallow_resolve(ct);
if let ty::ConstKind::Placeholder(p) = ct.kind() {
let replace_var = self.mapped_consts.get(&p);
match replace_var {
@@ -1087,7 +1097,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
);
ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty())
}
- None => ct,
+ None => {
+ if ct.has_infer() {
+ ct.super_fold_with(self)
+ } else {
+ ct
+ }
+ }
}
} else {
ct.super_fold_with(self)
@@ -1440,11 +1456,22 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
// Infer the generic parameters of the impl by unifying the
// impl type with the self type of the projection.
- let self_ty = alias_ty.self_ty();
+ let mut self_ty = alias_ty.self_ty();
+ if !selcx.infcx.next_trait_solver() {
+ self_ty = normalize_with_depth_to(
+ selcx,
+ param_env,
+ cause.clone(),
+ depth + 1,
+ self_ty,
+ obligations,
+ );
+ }
+
match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
Ok(mut ok) => obligations.append(&mut ok.obligations),
Err(_) => {
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
cause.span,
format!(
"{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
@@ -1798,11 +1825,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let lang_items = selcx.tcx().lang_items();
- if [lang_items.coroutine_trait(), lang_items.future_trait(), lang_items.iterator_trait()].contains(&Some(trait_ref.def_id))
- || selcx.tcx().fn_trait_kind_from_def_id(trait_ref.def_id).is_some()
+ if [
+ lang_items.coroutine_trait(),
+ lang_items.future_trait(),
+ lang_items.iterator_trait(),
+ lang_items.async_iterator_trait(),
+ lang_items.fn_trait(),
+ lang_items.fn_mut_trait(),
+ lang_items.fn_once_trait(),
+ ].contains(&Some(trait_ref.def_id))
{
true
- } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) {
+ }else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) {
match self_ty.kind() {
ty::Bool
| ty::Char
@@ -1949,7 +1983,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
// These traits have no associated types.
- selcx.tcx().sess.delay_span_bug(
+ selcx.tcx().sess.span_delayed_bug(
obligation.cause.span,
format!("Cannot project an associated type from `{impl_source:?}`"),
);
@@ -2017,6 +2051,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
confirm_future_candidate(selcx, obligation, data)
} else if lang_items.iterator_trait() == Some(trait_def_id) {
confirm_iterator_candidate(selcx, obligation, data)
+ } else if lang_items.async_iterator_trait() == Some(trait_def_id) {
+ confirm_async_iterator_candidate(selcx, obligation, data)
} else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() {
if obligation.predicate.self_ty().is_closure() {
confirm_closure_candidate(selcx, obligation, data)
@@ -2046,12 +2082,13 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let ty::Coroutine(_, args, _) =
- selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
- else {
- unreachable!()
+ let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
+ let ty::Coroutine(_, args, _) = self_ty.kind() else {
+ unreachable!(
+ "expected coroutine self type for built-in coroutine candidate, found {self_ty}"
+ )
};
- let coroutine_sig = args.as_coroutine().poly_sig();
+ let coroutine_sig = args.as_coroutine().sig();
let Normalized { value: coroutine_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@@ -2066,29 +2103,31 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None);
- let predicate = super::util::coroutine_trait_ref_and_outputs(
+ let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs(
tcx,
coroutine_def_id,
obligation.predicate.self_ty(),
coroutine_sig,
- )
- .map_bound(|(trait_ref, yield_ty, return_ty)| {
- let name = tcx.associated_item(obligation.predicate.def_id).name;
- let ty = if name == sym::Return {
- return_ty
- } else if name == sym::Yield {
- yield_ty
- } else {
- bug!()
- };
+ );
- ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
- term: ty.into(),
- }
- });
+ let name = tcx.associated_item(obligation.predicate.def_id).name;
+ let ty = if name == sym::Return {
+ return_ty
+ } else if name == sym::Yield {
+ yield_ty
+ } else {
+ span_bug!(
+ tcx.def_span(obligation.predicate.def_id),
+ "unexpected associated type: `Coroutine::{name}`"
+ );
+ };
- confirm_param_env_candidate(selcx, obligation, predicate, false)
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+ term: ty.into(),
+ };
+
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}
@@ -2098,12 +2137,13 @@ fn confirm_future_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let ty::Coroutine(_, args, _) =
- selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
- else {
- unreachable!()
+ let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
+ let ty::Coroutine(_, args, _) = self_ty.kind() else {
+ unreachable!(
+ "expected coroutine self type for built-in async future candidate, found {self_ty}"
+ )
};
- let coroutine_sig = args.as_coroutine().poly_sig();
+ let coroutine_sig = args.as_coroutine().sig();
let Normalized { value: coroutine_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@@ -2117,22 +2157,21 @@ fn confirm_future_candidate<'cx, 'tcx>(
let tcx = selcx.tcx();
let fut_def_id = tcx.require_lang_item(LangItem::Future, None);
- let predicate = super::util::future_trait_ref_and_outputs(
+ let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs(
tcx,
fut_def_id,
obligation.predicate.self_ty(),
coroutine_sig,
- )
- .map_bound(|(trait_ref, return_ty)| {
- debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
+ );
- ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
- term: return_ty.into(),
- }
- });
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
+
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+ term: return_ty.into(),
+ };
- confirm_param_env_candidate(selcx, obligation, predicate, false)
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}
@@ -2142,12 +2181,54 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
+ let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
+ let ty::Coroutine(_, args, _) = self_ty.kind() else {
+ unreachable!("expected coroutine self type for built-in gen candidate, found {self_ty}")
+ };
+ let gen_sig = args.as_coroutine().sig();
+ let Normalized { value: gen_sig, obligations } = normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ gen_sig,
+ );
+
+ debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate");
+
+ let tcx = selcx.tcx();
+ let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None);
+
+ let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs(
+ tcx,
+ iter_def_id,
+ obligation.predicate.self_ty(),
+ gen_sig,
+ );
+
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
+
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+ term: yield_ty.into(),
+ };
+
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+ .with_addl_obligations(nested)
+ .with_addl_obligations(obligations)
+}
+
+fn confirm_async_iterator_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ nested: Vec<PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
let ty::Coroutine(_, args, _) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
- let gen_sig = args.as_coroutine().poly_sig();
+ let gen_sig = args.as_coroutine().sig();
let Normalized { value: gen_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@@ -2156,27 +2237,34 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
- debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate");
+ debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate");
let tcx = selcx.tcx();
- let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None);
+ let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None);
- let predicate = super::util::iterator_trait_ref_and_outputs(
+ let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs(
tcx,
iter_def_id,
obligation.predicate.self_ty(),
gen_sig,
- )
- .map_bound(|(trait_ref, yield_ty)| {
- debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
+ );
- ty::ProjectionPredicate {
- projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
- term: yield_ty.into(),
- }
- });
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
- confirm_param_env_candidate(selcx, obligation, predicate, false)
+ let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
+ bug!();
+ };
+ let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else {
+ bug!();
+ };
+ let item_ty = args.type_at(0);
+
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+ term: item_ty.into(),
+ };
+
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}
@@ -2239,8 +2327,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
- let sig = fn_type.fn_sig(selcx.tcx());
+ let sig = fn_type.fn_sig(tcx);
let Normalized { value: sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@@ -2249,9 +2338,24 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
sig,
);
- confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
- .with_addl_obligations(nested)
- .with_addl_obligations(obligations)
+ let host_effect_param = match *fn_type.kind() {
+ ty::FnDef(def_id, args) => tcx
+ .generics_of(def_id)
+ .host_effect_index
+ .map_or(tcx.consts.true_, |idx| args.const_at(idx)),
+ ty::FnPtr(_) => tcx.consts.true_,
+ _ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"),
+ };
+
+ confirm_callable_candidate(
+ selcx,
+ obligation,
+ sig,
+ util::TupleArgumentsFlag::Yes,
+ host_effect_param,
+ )
+ .with_addl_obligations(nested)
+ .with_addl_obligations(obligations)
}
fn confirm_closure_candidate<'cx, 'tcx>(
@@ -2259,9 +2363,9 @@ fn confirm_closure_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let ty::Closure(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
- else {
- unreachable!()
+ let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
+ let ty::Closure(_, args) = self_ty.kind() else {
+ unreachable!("expected closure self type for closure candidate, found {self_ty}")
};
let closure_sig = args.as_closure().sig();
let Normalized { value: closure_sig, obligations } = normalize_with_depth(
@@ -2274,9 +2378,16 @@ fn confirm_closure_candidate<'cx, 'tcx>(
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
- confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
- .with_addl_obligations(nested)
- .with_addl_obligations(obligations)
+ confirm_callable_candidate(
+ selcx,
+ obligation,
+ closure_sig,
+ util::TupleArgumentsFlag::No,
+ // FIXME(effects): This doesn't handle const closures correctly!
+ selcx.tcx().consts.true_,
+ )
+ .with_addl_obligations(nested)
+ .with_addl_obligations(obligations)
}
fn confirm_callable_candidate<'cx, 'tcx>(
@@ -2284,6 +2395,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
fn_sig: ty::PolyFnSig<'tcx>,
flag: util::TupleArgumentsFlag,
+ fn_host_effect: ty::Const<'tcx>,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
@@ -2298,6 +2410,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
obligation.predicate.self_ty(),
fn_sig,
flag,
+ fn_host_effect,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),
@@ -2319,7 +2432,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
let cache_entry = infcx.instantiate_binder_with_fresh_vars(
cause.span,
- LateBoundRegionConversionTime::HigherRankedType,
+ BoundRegionConversionTime::HigherRankedType,
poly_cache_entry,
);
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 f8efa6a1f..ec80df1d6 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -48,9 +48,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *all* of them are trivial.
ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
- ty::Closure(_, ref args) => {
- trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty())
- }
+ ty::Closure(_, args) => trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()),
ty::Adt(def, _) => {
if Some(def.did()) == tcx.lang_items().manually_drop() {
@@ -239,7 +237,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// By the time this code runs, all type variables ought to
// be fully resolved.
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
span,
format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
);
@@ -288,7 +286,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
if !args.is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
span,
format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",),
);
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 65f32b1c4..d812d537d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -72,7 +72,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self);
fulfill_cx.register_predicate_obligation(self, obligation.clone());
// True errors
- // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
+ // FIXME(-Znext-solver): Overflows are reported as ambig here, is that OK?
if !fulfill_cx.select_where_possible(self).is_empty() {
Ok(EvaluationResult::EvaluatedToErr)
} else if !fulfill_cx.select_all_or_error(self).is_empty() {
@@ -108,7 +108,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
match self.evaluate_obligation(obligation) {
Ok(result) => result,
Err(OverflowError::Canonical) => {
- let mut selcx = SelectionContext::new(&self);
+ let mut selcx = SelectionContext::new(self);
selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
OverflowError::Canonical => {
span_bug!(
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 2e31b560b..ed55533bc 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -150,7 +150,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
#[inline]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
match *r {
- ty::ReLateBound(debruijn, _) if debruijn > self.outer_index => {
+ ty::ReBound(debruijn, _) if debruijn > self.outer_index => {
self.escaping =
self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
}
@@ -160,14 +160,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- match ct.kind() {
- ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
- self.escaping =
- self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
- ControlFlow::Continue(())
- }
- _ => ct.super_visit_with(self),
+ if ct.outer_exclusive_binder() > self.outer_index {
+ self.escaping = self
+ .escaping
+ .max(ct.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
}
+ ControlFlow::Continue(())
}
}
@@ -287,14 +285,14 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
ty::Projection => tcx.normalize_projection_ty(c_data),
ty::Weak => tcx.normalize_weak_ty(c_data),
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
- _ => unreachable!(),
+ kind => unreachable!("did not expect {kind:?} due to match arm above"),
}?;
// We don't expect ambiguity.
if !result.value.is_proven() {
// 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(
+ tcx.sess.span_delayed_bug(
DUMMY_SP,
format!("unexpected ambiguity: {c_data:?} {result:?}"),
);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index 302b6016e..152ceeee8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -26,7 +26,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
tcx.type_op_ascribe_user_type(canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
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 c81bc5790..18bb56ba4 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
@@ -82,13 +82,13 @@ where
let value = infcx.commit_if_ok(|_| {
let ocx = ObligationCtxt::new(infcx);
let value = op(&ocx).map_err(|_| {
- infcx.tcx.sess.delay_span_bug(span, format!("error performing operation: {name}"))
+ infcx.tcx.sess.span_delayed_bug(span, format!("error performing operation: {name}"))
})?;
let errors = ocx.select_all_or_error();
if errors.is_empty() {
Ok(value)
} else {
- Err(infcx.tcx.sess.delay_span_bug(
+ Err(infcx.tcx.sess.span_delayed_bug(
DUMMY_SP,
format!("errors selecting obligation during MIR typeck: {errors:?}"),
))
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
index f65893088..57e649f3e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
@@ -23,7 +23,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
tcx.type_op_eq(canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
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 e345fc39e..ba6ed2987 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
@@ -50,7 +50,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
tcx.implied_outlives_bounds(canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
@@ -123,20 +123,19 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
Some(pred) => pred,
};
match pred {
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
// FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
// if we ever support that
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
- | ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
- | ty::PredicateKind::AliasRelate(..)
- => {}
+ | ty::PredicateKind::NormalizesTo(..)
+ | ty::PredicateKind::AliasRelate(..) => {}
// We need to search through *all* WellFormed predicates
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
@@ -144,10 +143,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
}
// We need to register region relationships
- ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
- r_a,
- r_b,
- ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
+ ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
+ ty::OutlivesPredicate(r_a, r_b),
+ )) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
ty_a,
@@ -186,7 +184,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
push_outlives_components(tcx, ty_a, &mut components);
implied_bounds.extend(implied_bounds_from_components(r_b, components))
}
- ty::GenericArgKind::Const(_) => unreachable!(),
+ ty::GenericArgKind::Const(_) => {
+ unreachable!("consts do not participate in outlives bounds")
+ }
}
}
@@ -208,6 +208,11 @@ fn implied_bounds_from_components<'tcx>(
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
+ Component::Placeholder(_p) => {
+ // FIXME(non_lifetime_binders): Placeholders don't currently
+ // imply anything for outlives, though they could easily.
+ None
+ }
Component::EscapingAlias(_) =>
// If the projection has escaping regions, don't
// try to infer any implied bounds even for its
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 9d7933e23..272f1a54f 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
@@ -89,7 +89,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
/// make sure to feed it predefined opaque types and the defining anchor
/// and that would require duplicating all of the tcx queries. Instead,
/// just perform these ops locally.
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution>;
@@ -149,7 +149,7 @@ where
if infcx.next_trait_solver() {
return Ok(scrape_region_constraints(
infcx,
- |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
+ |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self),
"query type op",
span,
)?
@@ -159,7 +159,7 @@ where
let mut region_constraints = QueryRegionConstraints::default();
let (output, error_info, mut obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
- infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}"))
+ infcx.tcx.sess.span_delayed_bug(span, format!("error performing {self:?}"))
})?;
// Typically, instantiating NLL query results does not
@@ -188,7 +188,7 @@ where
}
}
if !progress {
- return Err(infcx.tcx.sess.delay_span_bug(
+ return Err(infcx.tcx.sess.span_delayed_bug(
span,
format!("ambiguity processing {obligations:?} from {self:?}"),
));
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 9559f5002..3b33f6e61 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -25,11 +25,11 @@ where
T::type_op_method(tcx, canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
- // FIXME(-Ztrait-solver=next): shouldn't be using old normalizer
+ // FIXME(-Znext-solver): shouldn't be using old normalizer
Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value))
}
}
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 f2c1243f9..07587e374 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
@@ -42,7 +42,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
tcx.dropck_outlives(canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 789ef6472..e21ede47f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -40,7 +40,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
tcx.type_op_prove_predicate(canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
index 10976d5cd..ae11b0825 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
@@ -20,7 +20,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
tcx.type_op_subtype(canonicalized)
}
- fn perform_locally_in_new_solver(
+ fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>,
) -> Result<Self::QueryResponse, NoSolution> {
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 f4b6d3bcf..38b1046ac 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -115,6 +115,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_future_candidates(obligation, &mut candidates);
} else if lang_items.iterator_trait() == Some(def_id) {
self.assemble_iterator_candidates(obligation, &mut candidates);
+ } else if lang_items.async_iterator_trait() == Some(def_id) {
+ self.assemble_async_iterator_candidates(obligation, &mut candidates);
}
self.assemble_closure_candidates(obligation, &mut candidates);
@@ -155,10 +157,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
- // FIXME(effects) proper constness needed?
- candidates.vec.extend(
- result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)),
- );
+ candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
}
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
@@ -261,6 +260,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
+ fn assemble_async_iterator_candidates(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ let self_ty = obligation.self_ty().skip_binder();
+ if let ty::Coroutine(did, args, _) = *self_ty.kind() {
+ // gen constructs get lowered to a special kind of coroutine that
+ // should directly `impl AsyncIterator`.
+ if self.tcx().coroutine_is_async_gen(did) {
+ debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
+
+ // Can only confirm this candidate if we have constrained
+ // the `Yield` type to at least `Poll<Option<?0>>`..
+ let ty::Adt(_poll_def, args) = *args.as_coroutine().yield_ty().kind() else {
+ candidates.ambiguous = true;
+ return;
+ };
+ let ty::Adt(_option_def, _) = *args.type_at(0).kind() else {
+ candidates.ambiguous = true;
+ return;
+ };
+
+ candidates.vec.push(AsyncIteratorCandidate);
+ }
+ }
+ }
+
/// Checks for the artificial impl that the compiler will create for an obligation like `X :
/// FnMut<..>` where `X` is a closure type.
///
@@ -291,8 +318,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
None => {
- debug!("assemble_unboxed_candidates: closure_kind not yet known");
- candidates.vec.push(ClosureCandidate { is_const });
+ if kind == ty::ClosureKind::FnOnce {
+ candidates.vec.push(ClosureCandidate { is_const });
+ } else {
+ candidates.ambiguous = true;
+ }
}
}
}
@@ -328,17 +358,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Provide an impl, but only for suitable `fn` pointers.
ty::FnPtr(sig) => {
if sig.is_fn_trait_compatible() {
- candidates.vec.push(FnPointerCandidate { is_const: false });
+ candidates
+ .vec
+ .push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
}
}
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
- ty::FnDef(def_id, _) => {
- if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
- && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
+ ty::FnDef(def_id, args) => {
+ let tcx = self.tcx();
+ if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+ && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
{
- candidates
- .vec
- .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
+ candidates.vec.push(FnPointerCandidate {
+ fn_host_effect: tcx
+ .generics_of(def_id)
+ .host_effect_index
+ .map_or(tcx.consts.true_, |idx| args.const_at(idx)),
+ });
}
}
_ => {}
@@ -375,7 +411,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// consider a "quick reject". This avoids creating more types
// and so forth that we need to.
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
- if !drcx.args_refs_may_unify(obligation_args, impl_trait_ref.skip_binder().args) {
+ if !drcx.args_may_unify(obligation_args, impl_trait_ref.skip_binder().args) {
return;
}
if self.reject_fn_ptr_impls(
@@ -555,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::Alias(ty::Opaque, _) => {
- if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) {
+ if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
// We do not generate an auto impl candidate for `impl Trait`s which already
// reference our auto trait.
//
@@ -634,7 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty = placeholder_trait_predicate.self_ty();
let principal_trait_ref = match self_ty.kind() {
- ty::Dynamic(ref data, ..) => {
+ ty::Dynamic(data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!(
"assemble_candidates_from_object_ty: matched builtin bound, \
@@ -759,10 +795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
- (
- &ty::Dynamic(ref a_data, a_region, ty::Dyn),
- &ty::Dynamic(ref b_data, b_region, ty::Dyn),
- ) => {
+ (&ty::Dynamic(a_data, a_region, ty::Dyn), &ty::Dynamic(b_data, b_region, ty::Dyn)) => {
// Upcast coercions permit several things:
//
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@@ -923,9 +956,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) {
// If the predicate is `~const Destruct` in a non-const environment, we don't actually need
// to check anything. We'll short-circuit checking any obligations in confirmation, too.
- // FIXME(effects)
- if true {
- candidates.vec.push(ConstDestructCandidate(None));
+ let Some(host_effect_index) =
+ self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
+ else {
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
+ return;
+ };
+ // If the obligation has `host = true`, then the obligation is non-const and it's always
+ // trivially implemented.
+ if obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index)
+ == self.tcx().consts.true_
+ {
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
return;
}
@@ -1051,7 +1093,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) {
// The regions of a type don't affect the size of the type
let tcx = self.tcx();
- let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty());
+ let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty());
// We should erase regions from both the param-env and type, since both
// may have infer regions. Specifically, after canonicalizing and instantiating,
// early bound regions turn into region vars in both the new and old solver.
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 4bfa341e3..ce3fc2185 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -9,7 +9,7 @@
use rustc_ast::Mutability;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
+use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch};
use rustc_middle::ty::{
@@ -71,7 +71,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
- ProjectionCandidate(idx, _) => {
+ ProjectionCandidate(idx) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
ImplSource::Param(obligations)
}
@@ -98,8 +98,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
}
- FnPointerCandidate { is_const } => {
- let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
+ AsyncIteratorCandidate => {
+ let vtable_iterator = self.confirm_async_iterator_candidate(obligation)?;
+ ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
+ }
+
+ FnPointerCandidate { fn_host_effect } => {
+ let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
@@ -327,8 +332,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// care about other regions. Erasing late-bound regions is equivalent
// to instantiating the binder with placeholders then erasing those
// placeholder regions.
- let predicate =
- self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate));
+ let predicate = self
+ .tcx()
+ .erase_regions(self.tcx().instantiate_bound_regions_with_erased(obligation.predicate));
let Some(assume) = rustc_transmute::Assume::from_const(
self.infcx.tcx,
@@ -393,7 +399,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.recursion_depth + 1,
obligation.param_env,
trait_def_id,
- &trait_ref.args,
+ trait_ref.args,
obligation.predicate,
);
@@ -454,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
recursion_depth,
param_env,
impl_def_id,
- &args.value,
+ args.value,
parent_trait_pred,
);
@@ -552,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let defs: &ty::Generics = tcx.generics_of(assoc_type);
if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
- tcx.sess.delay_span_bug(
+ tcx.sess.span_delayed_bug(
obligation.cause.span,
"GATs in trait object shouldn't have been considered",
);
@@ -592,7 +598,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
let bound_var = ty::BoundVariableKind::Region(kind);
bound_vars.push(bound_var);
- ty::Region::new_late_bound(
+ ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion {
@@ -647,8 +653,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_fn_pointer_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
- // FIXME(effects)
- _is_const: bool,
+ fn_host_effect: ty::Const<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_fn_pointer_candidate");
@@ -669,6 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
+ fn_host_effect,
)
.map_bound(|(trait_ref, _)| trait_ref);
@@ -707,7 +713,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.recursion_depth,
obligation.param_env,
trait_def_id,
- &args,
+ args,
obligation.predicate,
);
@@ -730,7 +736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate");
- let coroutine_sig = args.as_coroutine().poly_sig();
+ let coroutine_sig = args.as_coroutine().sig();
// NOTE: The self-type is a coroutine type and hence is
// in fact unparameterized (or at least does not reference any
@@ -741,15 +747,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.no_bound_vars()
.expect("unboxed closure type should not capture bound vars from the predicate");
- let trait_ref = super::util::coroutine_trait_ref_and_outputs(
+ let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
self_ty,
coroutine_sig,
- )
- .map_bound(|(trait_ref, ..)| trait_ref);
+ );
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
debug!(?trait_ref, ?nested, "coroutine candidate obligations");
Ok(nested)
@@ -769,17 +774,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate");
- let coroutine_sig = args.as_coroutine().poly_sig();
+ let coroutine_sig = args.as_coroutine().sig();
- let trait_ref = super::util::future_trait_ref_and_outputs(
+ let (trait_ref, _) = super::util::future_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(),
coroutine_sig,
- )
- .map_bound(|(trait_ref, ..)| trait_ref);
+ );
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
debug!(?trait_ref, ?nested, "future candidate obligations");
Ok(nested)
@@ -799,17 +803,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate");
- let gen_sig = args.as_coroutine().poly_sig();
+ let gen_sig = args.as_coroutine().sig();
- let trait_ref = super::util::iterator_trait_ref_and_outputs(
+ let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
gen_sig,
- )
- .map_bound(|(trait_ref, ..)| trait_ref);
+ );
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
+ debug!(?trait_ref, ?nested, "iterator candidate obligations");
+
+ Ok(nested)
+ }
+
+ fn confirm_async_iterator_candidate(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ // Okay to skip binder because the args on coroutine types never
+ // touch bound regions, they just capture the in-scope
+ // type/region parameters.
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+ bug!("closure candidate for non-closure {:?}", obligation);
+ };
+
+ debug!(?obligation, ?coroutine_def_id, ?args, "confirm_async_iterator_candidate");
+
+ let gen_sig = args.as_coroutine().sig();
+
+ let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs(
+ self.tcx(),
+ obligation.predicate.def_id(),
+ obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+ gen_sig,
+ );
+
+ let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?;
debug!(?trait_ref, ?nested, "iterator candidate obligations");
Ok(nested)
@@ -820,11 +852,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- let kind = self
- .tcx()
- .fn_trait_kind_from_def_id(obligation.predicate.def_id())
- .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
-
// Okay to skip binder because the args on closure types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
@@ -833,16 +860,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bug!("closure candidate for non-closure {:?}", obligation);
};
- let trait_ref = self.closure_trait_ref_unnormalized(obligation, args);
- let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let trait_ref =
+ self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_);
+ let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
- nested.push(obligation.with(
- self.tcx(),
- ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, args, kind)),
- ));
-
Ok(nested)
}
@@ -920,8 +943,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let a_ty = self.infcx.shallow_resolve(predicate.self_ty());
let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1));
- let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { bug!() };
- let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { bug!() };
+ let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
+ bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
+ };
+ let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
+ bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
+ };
let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty);
let unnormalized_upcast_principal =
@@ -985,7 +1012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
- (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b))
+ (&ty::Dynamic(data_a, r_a, dyn_a), &ty::Dynamic(data_b, r_b, dyn_b))
if dyn_a == dyn_b =>
{
// See `assemble_candidates_for_unsizing` for more info.
@@ -1030,7 +1057,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// `T` -> `Trait`
- (_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
+ (_, &ty::Dynamic(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.check_is_object_safe(*did)) {
return Err(TraitNotObjectSafe(did));
@@ -1184,11 +1211,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
impl_def_id: Option<DefId>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop`
- // FIXME(effects)
- if true {
- return Ok(vec![]);
- }
+ let Some(host_effect_index) =
+ self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
+ else {
+ bug!()
+ };
+ let host_effect_param: ty::GenericArg<'tcx> =
+ obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index).into();
let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
@@ -1277,7 +1306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx();
stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| {
let ty = bty.instantiate(tcx, args);
- debug_assert!(!ty.has_late_bound_regions());
+ debug_assert!(!ty.has_bound_regions());
ty
}))
}
@@ -1285,7 +1314,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
ty::Alias(ty::Projection | ty::Inherent, ..) => {
- // FIXME(effects) this needs constness
let predicate = normalize_with_depth_to(
self,
obligation.param_env,
@@ -1296,7 +1324,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.tcx(),
LangItem::Destruct,
cause.span,
- [nested_ty],
+ [nested_ty.into(), host_effect_param],
),
polarity: ty::ImplPolarity::Positive,
}),
@@ -1316,13 +1344,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// since it's either not `const Drop` (and we raise an error during selection),
// or it's an ADT (and we need to check for a custom impl during selection)
_ => {
- // FIXME(effects) this needs constness
let predicate = self_ty.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef::from_lang_item(
self.tcx(),
LangItem::Destruct,
cause.span,
- [nested_ty],
+ [nested_ty.into(), host_effect_param],
),
polarity: ty::ImplPolarity::Positive,
});
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 08208cc60..23f7bdd15 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,8 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_infer::infer::BoundRegionConversionTime;
use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitObligation;
use rustc_middle::dep_graph::dep_kinds;
use rustc_middle::dep_graph::DepNodeIndex;
@@ -46,6 +46,7 @@ use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_span::symbol::sym;
+use rustc_span::Symbol;
use std::cell::{Cell, RefCell};
use std::cmp;
@@ -59,13 +60,13 @@ mod candidate_assembly;
mod confirmation;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub enum IntercrateAmbiguityCause {
- DownstreamCrate { trait_desc: String, self_desc: Option<String> },
- UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> },
- ReservationImpl { message: String },
+pub enum IntercrateAmbiguityCause<'tcx> {
+ DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
+ UpstreamCrateUpdate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
+ ReservationImpl { message: Symbol },
}
-impl IntercrateAmbiguityCause {
+impl<'tcx> IntercrateAmbiguityCause<'tcx> {
/// Emits notes when the overlap is caused by complex intercrate ambiguities.
/// See #23980 for details.
pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) {
@@ -73,28 +74,32 @@ impl IntercrateAmbiguityCause {
}
pub fn intercrate_ambiguity_hint(&self) -> String {
- match self {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => {
- let self_desc = if let Some(ty) = self_desc {
- format!(" for type `{ty}`")
- } else {
- String::new()
- };
- format!("downstream crates may implement trait `{trait_desc}`{self_desc}")
+ with_no_trimmed_paths!(match self {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => {
+ format!(
+ "downstream crates may implement trait `{trait_desc}`{self_desc}",
+ trait_desc = trait_ref.print_trait_sugared(),
+ self_desc = if let Some(self_ty) = self_ty {
+ format!(" for type `{self_ty}`")
+ } else {
+ String::new()
+ }
+ )
}
- IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => {
- let self_desc = if let Some(ty) = self_desc {
- format!(" for type `{ty}`")
- } else {
- String::new()
- };
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } => {
format!(
"upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \
- in future versions"
+ in future versions",
+ trait_desc = trait_ref.print_trait_sugared(),
+ self_desc = if let Some(self_ty) = self_ty {
+ format!(" for type `{self_ty}`")
+ } else {
+ String::new()
+ }
)
}
- IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(),
- }
+ IntercrateAmbiguityCause::ReservationImpl { message } => message.to_string(),
+ })
}
}
@@ -114,7 +119,7 @@ pub struct SelectionContext<'cx, 'tcx> {
/// We don't do his until we detect a coherence error because it can
/// lead to false overflow results (#47139) and because always
/// computing it may negatively impact performance.
- intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause>>,
+ intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause<'tcx>>>,
/// The mode that trait queries run in, which informs our error handling
/// policy. In essence, canonicalized queries need their errors propagated
@@ -217,8 +222,8 @@ pub enum TreatInductiveCycleAs {
impl From<TreatInductiveCycleAs> for EvaluationResult {
fn from(treat: TreatInductiveCycleAs) -> EvaluationResult {
match treat {
- TreatInductiveCycleAs::Ambig => EvaluatedToUnknown,
- TreatInductiveCycleAs::Recur => EvaluatedToRecur,
+ TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent,
+ TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent,
}
}
}
@@ -270,7 +275,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Gets the intercrate ambiguity causes collected since tracking
/// was enabled and disables tracking at the same time. If
/// tracking is not enabled, just returns an empty vector.
- pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
+ pub fn take_intercrate_ambiguity_causes(
+ &mut self,
+ ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
assert!(self.is_intercrate());
self.intercrate_ambiguity_causes.take().unwrap_or_default()
}
@@ -367,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug_assert!(!self.infcx.next_trait_solver());
// Watch out for overflow. This intentionally bypasses (and does
// not update) the cache.
- self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
+ self.check_recursion_limit(stack.obligation, stack.obligation)?;
// Check the cache. Note that we freshen the trait-ref
// separately rather than using `stack.fresh_trait_ref` --
@@ -416,7 +423,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut no_candidates_apply = true;
for c in candidate_set.vec.iter() {
- if self.evaluate_candidate(stack, &c)?.may_apply() {
+ if self.evaluate_candidate(stack, c)?.may_apply() {
no_candidates_apply = false;
break;
}
@@ -428,19 +435,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
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)
- });
+ let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
let cause = if let Conflict::Upstream = conflict {
- IntercrateAmbiguityCause::UpstreamCrateUpdate {
- trait_desc,
- self_desc,
- }
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
} else {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
};
debug!(?cause, "evaluate_stack: pushing cause");
self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
@@ -799,7 +798,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// A global type with no free lifetimes or generic parameters
// outlives anything.
if pred.0.has_free_regions()
- || pred.0.has_late_bound_regions()
+ || pred.0.has_bound_regions()
|| pred.0.has_non_region_infer()
|| pred.0.has_non_region_infer()
{
@@ -885,19 +884,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- ty::PredicateKind::ClosureKind(_, closure_args, kind) => {
- match self.infcx.closure_kind(closure_args) {
- Some(closure_kind) => {
- if closure_kind.extends(kind) {
- Ok(EvaluatedToOk)
- } else {
- Ok(EvaluatedToErr)
- }
- }
- None => Ok(EvaluatedToAmbig),
- }
- }
-
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
match const_evaluatable::is_const_evaluatable(
self.infcx,
@@ -1004,8 +990,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
}
+ ty::PredicateKind::NormalizesTo(..) => {
+ bug!("NormalizesTo is only used by the new solver")
+ }
ty::PredicateKind::AliasRelate(..) => {
- bug!("AliasRelate is only used for new solver")
+ bug!("AliasRelate is only used by the new solver")
}
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
@@ -1237,15 +1226,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
- && self.match_fresh_trait_refs(
- stack.fresh_trait_pred,
- prev.fresh_trait_pred,
- prev.obligation.param_env,
- )
+ && self.match_fresh_trait_refs(stack.fresh_trait_pred, prev.fresh_trait_pred)
})
{
debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
- return Ok(EvaluatedToUnknown);
+ return Ok(EvaluatedToAmbigStackDependent);
}
match self.candidate_from_obligation(stack) {
@@ -1464,20 +1449,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ImplCandidate(def_id) = candidate {
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
- let value = tcx
+ let message = tcx
.get_attr(def_id, sym::rustc_reservation_impl)
.and_then(|a| a.value_str());
- if let Some(value) = value {
+ if let Some(message) = message {
debug!(
"filter_reservation_impls: \
reservation impl ambiguity on {:?}",
def_id
);
- intercrate_ambiguity_clauses.insert(
- IntercrateAmbiguityCause::ReservationImpl {
- message: value.to_string(),
- },
- );
+ intercrate_ambiguity_clauses
+ .insert(IntercrateAmbiguityCause::ReservationImpl { message });
}
}
return Ok(None);
@@ -1751,7 +1733,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut nested_obligations = Vec::new();
let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
- LateBoundRegionConversionTime::HigherRankedType,
+ BoundRegionConversionTime::HigherRankedType,
env_predicate,
);
let infer_projection = if potentially_unnormalized_candidates {
@@ -1841,7 +1823,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
let is_global =
- |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_late_bound_vars();
+ |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// `DiscriminantKindCandidate`, `ConstDestructCandidate`
@@ -1879,7 +1861,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
// Drop otherwise equivalent non-const fn pointer candidates
- (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
+ (FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
+ DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
+ }
(
ParamCandidate(ref other_cand),
@@ -1889,6 +1873,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1896,7 +1881,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinCandidate { .. }
| TraitAliasCandidate
| ObjectCandidate(_)
- | ProjectionCandidate(..),
+ | ProjectionCandidate(_),
) => {
// We have a where clause so don't go around looking
// for impls. Arbitrarily give param candidates priority
@@ -1906,7 +1891,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// here (see issue #50825).
DropVictim::drop_if(!is_global(other_cand))
}
- (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
+ (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
@@ -1918,6 +1903,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1933,26 +1919,27 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
)
}
- (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.
DropVictim::drop_if(i < j && !has_non_region_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(..)
| AutoImplCandidate
| ClosureCandidate { .. }
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1968,13 +1955,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate,
- ObjectCandidate(_) | ProjectionCandidate(..),
+ ObjectCandidate(_) | ProjectionCandidate(_),
) => DropVictim::No,
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
@@ -2075,6 +2063,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2086,6 +2075,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| CoroutineCandidate
| FutureCandidate
| IteratorCandidate
+ | AsyncIteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2218,7 +2208,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
}
- ty::CoroutineWitness(def_id, ref args) => {
+ ty::CoroutineWitness(def_id, args) => {
let hidden_types = bind_coroutine_hidden_types_above(
self.infcx,
def_id,
@@ -2307,23 +2297,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
- ty::Tuple(ref tys) => {
+ ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
t.rebind(tys.iter().collect())
}
- ty::Closure(_, ref args) => {
+ ty::Closure(_, args) => {
let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
t.rebind(vec![ty])
}
- ty::Coroutine(_, ref args, _) => {
+ ty::Coroutine(_, args, _) => {
let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
let witness = args.as_coroutine().witness();
t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
}
- ty::CoroutineWitness(def_id, ref args) => {
+ ty::CoroutineWitness(def_id, args) => {
bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
}
@@ -2436,7 +2426,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// the placeholder trait ref may fail due the Generalizer relation
// raising a CyclicalTy error due to a sub_root_var relation
// for a variable being generalized...
- let guar = self.infcx.tcx.sess.delay_span_bug(
+ let guar = self.infcx.tcx.sess.span_delayed_bug(
obligation.cause.span,
format!(
"Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
@@ -2638,9 +2628,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&self,
previous: ty::PolyTraitPredicate<'tcx>,
current: ty::PolyTraitPredicate<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
) -> bool {
- let mut matcher = MatchAgainstFreshVars::new(self.tcx(), param_env);
+ let mut matcher = MatchAgainstFreshVars::new(self.tcx());
matcher.relate(previous, current).is_ok()
}
@@ -2668,6 +2657,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self,
obligation: &PolyTraitObligation<'tcx>,
args: GenericArgsRef<'tcx>,
+ fn_host_effect: ty::Const<'tcx>,
) -> ty::PolyTraitRef<'tcx> {
let closure_sig = args.as_closure().sig();
@@ -2688,6 +2678,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
self_ty,
closure_sig,
util::TupleArgumentsFlag::No,
+ fn_host_effect,
)
.map_bound(|(trait_ref, _)| trait_ref)
}
@@ -3103,7 +3094,7 @@ fn bind_coroutine_hidden_types_above<'tcx>(
kind: ty::BrAnon,
};
counter += 1;
- ty::Region::new_late_bound(tcx, current_depth, br)
+ ty::Region::new_bound(tcx, current_depth, br)
}
r => bug!("unexpected region: {r:?}"),
})
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index efab29743..71a88f5f0 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -37,7 +37,7 @@ pub struct OverlapError<'tcx> {
pub with_impl: DefId,
pub trait_ref: ty::TraitRef<'tcx>,
pub self_ty: Option<Ty<'tcx>>,
- pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
+ pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
pub involves_placeholder: bool,
}
@@ -107,7 +107,7 @@ pub fn translate_args_with_cause<'tcx>(
param_env, source_impl, source_args, target_node
);
let source_trait_ref =
- infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, &source_args);
+ infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, source_args);
// translate the Self and Param parts of the substitution, since those
// vary across impls
@@ -197,25 +197,22 @@ fn fulfill_implication<'tcx>(
param_env, source_trait_ref, target_impl
);
- let source_trait_ref = match traits::fully_normalize(
- &infcx,
- ObligationCause::dummy(),
- param_env,
- source_trait_ref,
- ) {
- Ok(source_trait_ref) => source_trait_ref,
- Err(_errors) => {
- infcx.tcx.sess.delay_span_bug(
- infcx.tcx.def_span(source_impl),
- format!("failed to fully normalize {source_trait_ref}"),
- );
- source_trait_ref
- }
- };
+ let source_trait_ref =
+ match traits::fully_normalize(infcx, ObligationCause::dummy(), param_env, source_trait_ref)
+ {
+ Ok(source_trait_ref) => source_trait_ref,
+ Err(_errors) => {
+ infcx.tcx.sess.span_delayed_bug(
+ infcx.tcx.def_span(source_impl),
+ format!("failed to fully normalize {source_trait_ref}"),
+ );
+ source_trait_ref
+ }
+ };
let source_trait = ImplSubject::Trait(source_trait_ref);
- let selcx = &mut SelectionContext::new(&infcx);
+ let selcx = &mut SelectionContext::new(infcx);
let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
let (target_trait, obligations) =
util::impl_subject_and_oblig(selcx, param_env, target_impl, target_args, error_cause);
@@ -415,7 +412,7 @@ fn report_conflicting_impls<'tcx>(
let msg = DelayDm(|| {
format!(
"conflicting implementations of trait `{}`{}{}",
- overlap.trait_ref.print_only_trait_path(),
+ overlap.trait_ref.print_trait_sugared(),
overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")),
match used_to_be_allowed {
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
@@ -434,7 +431,10 @@ fn report_conflicting_impls<'tcx>(
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"))
+ Some(
+ tcx.sess
+ .span_delayed_bug(impl_span, "impl should have failed the orphan check"),
+ )
};
sg.has_errored = reported;
}
@@ -445,12 +445,11 @@ fn report_conflicting_impls<'tcx>(
};
tcx.struct_span_lint_hir(
lint,
- tcx.hir().local_def_id_to_hir_id(impl_def_id),
+ tcx.local_def_id_to_hir_id(impl_def_id),
impl_span,
msg,
|err| {
decorate(tcx, &overlap, impl_span, err);
- err
},
);
}
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 5960415a8..f8e47cacc 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -135,7 +135,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
bug!("unexpected type during structural-match checking: {:?}", ty);
}
ty::Error(_) => {
- self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check");
+ self.tcx.sess.span_delayed_bug(self.span, "ty::Error in structural-match check");
// We still want to check other types after encountering an error,
// as this may still emit relevant errors.
return ControlFlow::Continue(());
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index 9d6be7689..e0f9fdc38 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -3,7 +3,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::traits::{FulfillmentError, TraitEngine};
use rustc_middle::ty::{self, Ty};
-use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation};
+use crate::traits::{NormalizeExt, Obligation};
pub trait StructurallyNormalizeExt<'tcx> {
fn structurally_normalize(
@@ -16,46 +16,43 @@ pub trait StructurallyNormalizeExt<'tcx> {
impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
fn structurally_normalize(
&self,
- mut ty: Ty<'tcx>,
+ ty: Ty<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
assert!(!ty.is_ty_var(), "should have resolved vars before calling");
if self.infcx.next_trait_solver() {
- // 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,
- });
- let obligation = Obligation::new(
- self.infcx.tcx,
- self.cause.clone(),
- self.param_env,
- ty::Binder::dummy(ty::ProjectionPredicate {
- projection_ty,
- term: new_infer_ty.into(),
- }),
- );
- if self.infcx.predicate_may_hold(&obligation) {
- fulfill_cx.register_predicate_obligation(self.infcx, obligation);
- let errors = fulfill_cx.select_where_possible(self.infcx);
- if !errors.is_empty() {
- return Err(errors);
- }
- ty = self.infcx.resolve_vars_if_possible(new_infer_ty);
- } else {
- break;
- }
+ // FIXME(-Znext-solver): Should we resolve opaques here?
+ let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = *ty.kind() else {
+ return Ok(ty);
+ };
+
+ let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::NormalizeProjectionType,
+ span: self.cause.span,
+ });
+
+ // We simply emit an `alias-eq` goal here, since that will take care of
+ // normalizing the LHS of the projection until it is a rigid projection
+ // (or a not-yet-defined opaque in scope).
+ let obligation = Obligation::new(
+ self.infcx.tcx,
+ self.cause.clone(),
+ self.param_env,
+ ty::PredicateKind::AliasRelate(
+ ty.into(),
+ new_infer_ty.into(),
+ ty::AliasRelationDirection::Equate,
+ ),
+ );
+
+ fulfill_cx.register_predicate_obligation(self.infcx, obligation);
+ let errors = fulfill_cx.select_where_possible(self.infcx);
+ if !errors.is_empty() {
+ return Err(errors);
}
- Ok(ty)
+ Ok(self.infcx.resolve_vars_if_possible(new_infer_ty))
} else {
Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index bbde0c827..19eae93df 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -220,9 +220,8 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
- let impl_obligations = impl_obligations
- .chain(normalization_obligations1.into_iter())
- .chain(normalization_obligations2.into_iter());
+ let impl_obligations =
+ impl_obligations.chain(normalization_obligations1).chain(normalization_obligations2);
(subject, impl_obligations)
}
@@ -265,13 +264,26 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
self_ty: Ty<'tcx>,
sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag,
+ fn_host_effect: ty::Const<'tcx>,
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
assert!(!self_ty.has_escaping_bound_vars());
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
};
- let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
+ let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() {
+ ty::TraitRef::new(
+ tcx,
+ fn_trait_def_id,
+ [
+ ty::GenericArg::from(self_ty),
+ ty::GenericArg::from(arguments_tuple),
+ ty::GenericArg::from(fn_host_effect),
+ ],
+ )
+ } else {
+ ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple])
+ };
sig.map_bound(|sig| (trait_ref, sig.output()))
}
@@ -279,33 +291,44 @@ pub fn coroutine_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
- sig: ty::PolyGenSig<'tcx>,
-) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
+ sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
- let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]);
- sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty))
+ let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]);
+ (trait_ref, sig.yield_ty, sig.return_ty)
}
pub fn future_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
- sig: ty::PolyGenSig<'tcx>,
-) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
+ sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
- sig.map_bound(|sig| (trait_ref, sig.return_ty))
+ (trait_ref, sig.return_ty)
}
pub fn iterator_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
iterator_def_id: DefId,
self_ty: Ty<'tcx>,
- sig: ty::PolyGenSig<'tcx>,
-) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
+ sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
assert!(!self_ty.has_escaping_bound_vars());
let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
- sig.map_bound(|sig| (trait_ref, sig.yield_ty))
+ (trait_ref, sig.yield_ty)
+}
+
+pub fn async_iterator_trait_ref_and_outputs<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ async_iterator_def_id: DefId,
+ self_ty: Ty<'tcx>,
+ sig: ty::GenSig<'tcx>,
+) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
+ assert!(!self_ty.has_escaping_bound_vars());
+ let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]);
+ (trait_ref, sig.yield_ty)
}
pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index fe5b625e4..0f8d9c6bf 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -624,7 +624,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// Note that we handle the len is implicitly checked while walking `arg`.
}
- ty::Tuple(ref tys) => {
+ ty::Tuple(tys) => {
if let Some((_last, rest)) = tys.split_last() {
for &elem in rest {
self.require_sized(elem, traits::TupleElem);
@@ -761,18 +761,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
if !defer_to_coercion {
- let cause = self.cause(traits::WellFormed(None));
- let component_traits = data.auto_traits().chain(data.principal_def_id());
- let tcx = self.tcx();
- self.out.extend(component_traits.map(|did| {
- traits::Obligation::with_depth(
- tcx,
- cause.clone(),
+ if let Some(principal) = data.principal_def_id() {
+ self.out.push(traits::Obligation::with_depth(
+ self.tcx(),
+ self.cause(traits::WellFormed(None)),
depth,
param_env,
- ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did)),
- )
- }));
+ ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)),
+ ));
+ }
}
}
@@ -913,20 +910,15 @@ pub fn object_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
existential_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> Vec<ty::Region<'tcx>> {
- // Since we don't actually *know* the self type for an object,
- // this "open(err)" serves as a kind of dummy standin -- basically
- // a placeholder type.
- let open_ty = Ty::new_fresh(tcx, 0);
-
let predicates = existential_predicates.iter().filter_map(|predicate| {
if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() {
None
} else {
- Some(predicate.with_self_ty(tcx, open_ty))
+ Some(predicate.with_self_ty(tcx, tcx.types.trait_object_dummy_self))
}
});
- required_region_bounds(tcx, open_ty, predicates)
+ required_region_bounds(tcx, tcx.types.trait_object_dummy_self, predicates)
}
/// Given a set of predicates that apply to an object type, returns