summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/error_reporting
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_trait_selection/src/traits/error_reporting
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/error_reporting')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs518
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs259
4 files changed, 572 insertions, 237 deletions
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 7ab652761..f785c4eaf 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -1,7 +1,7 @@
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
use rustc_infer::traits::util::elaborate;
-use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
+use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation};
use rustc_middle::ty;
use rustc_span::{Span, DUMMY_SP};
@@ -14,13 +14,13 @@ pub enum Ambiguity {
pub fn recompute_applicable_impls<'tcx>(
infcx: &InferCtxt<'tcx>,
- obligation: &TraitObligation<'tcx>,
+ obligation: &PolyTraitObligation<'tcx>,
) -> Vec<Ambiguity> {
let tcx = infcx.tcx;
let param_env = obligation.param_env;
let impl_may_apply = |impl_def_id| {
- let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let ocx = ObligationCtxt::new(infcx);
let placeholder_obligation =
infcx.instantiate_binder_with_placeholders(obligation.predicate);
let obligation_trait_ref =
@@ -45,7 +45,7 @@ pub fn recompute_applicable_impls<'tcx>(
};
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
- let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let ocx = ObligationCtxt::new(infcx);
let placeholder_obligation =
infcx.instantiate_binder_with_placeholders(obligation.predicate);
let obligation_trait_ref =
@@ -84,7 +84,7 @@ pub fn recompute_applicable_impls<'tcx>(
tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
for (pred, span) in elaborate(tcx, predicates.into_iter()) {
let kind = pred.kind();
- if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
+ if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
{
if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index a10ececbb..f34218059 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -5,13 +5,13 @@ pub mod suggestions;
use super::{
FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause,
ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow,
- PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
+ PredicateObligation, SelectionError, TraitNotObjectSafe,
};
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{self, InferCtxt};
+use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::query::normalize::QueryNormalizeExt as _;
use crate::traits::specialize::to_pretty_impl_header;
use crate::traits::NormalizeExt;
use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
@@ -28,21 +28,24 @@ use rustc_hir::{GenericParam, Item, Node};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
-use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch};
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable, TypeVisitableExt,
};
-use rustc_session::config::TraitSolver;
+use rustc_session::config::{DumpSolverProofTree, TraitSolver};
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::sym;
use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use std::borrow::Cow;
use std::fmt;
+use std::io::Write;
use std::iter;
use std::ops::ControlFlow;
use suggestions::TypeErrCtxtExt as _;
@@ -59,12 +62,17 @@ pub enum CandidateSimilarity {
Fuzzy { ignoring_lifetimes: bool },
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ImplCandidate<'tcx> {
pub trait_ref: ty::TraitRef<'tcx>,
pub similarity: CandidateSimilarity,
}
+enum GetSafeTransmuteErrorAndReason {
+ Silent,
+ Error { err_msg: String, safe_transmute_explanation: String },
+}
+
pub trait InferCtxtExt<'tcx> {
/// Given some node representing a fn-like thing in the HIR map,
/// returns a span and `ArgKind` information that describes the
@@ -148,6 +156,12 @@ pub trait TypeErrCtxtExt<'tcx> {
root_obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
);
+
+ fn report_const_param_not_wf(
+ &self,
+ ty: Ty<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
}
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -365,7 +379,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
param_env,
ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }),
);
- let ocx = ObligationCtxt::new_in_snapshot(self);
+ let ocx = ObligationCtxt::new(self);
ocx.register_obligation(obligation);
if ocx.select_all_or_error().is_empty() {
return Ok((
@@ -618,6 +632,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
error: &SelectionError<'tcx>,
) {
let tcx = self.tcx;
+
+ if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == 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(
@@ -640,6 +659,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
span = obligation.cause.span;
}
}
+
if let ObligationCauseCode::CompareImplItemObligation {
impl_item_def_id,
trait_item_def_id,
@@ -656,9 +676,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
+ // Report a const-param specific error
+ if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
+ {
+ self.report_const_param_not_wf(ty, &obligation).emit();
+ return;
+ }
+
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
let trait_predicate = bound_predicate.rebind(trait_predicate);
let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate);
@@ -724,11 +751,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
== self.tcx.lang_items().transmute_trait()
{
// Recompute the safe transmute reason and use that for the error reporting
- self.get_safe_transmute_error_and_reason(
+ match self.get_safe_transmute_error_and_reason(
obligation.clone(),
trait_ref,
span,
- )
+ ) {
+ GetSafeTransmuteErrorAndReason::Silent => return,
+ GetSafeTransmuteErrorAndReason::Error {
+ err_msg,
+ safe_transmute_explanation,
+ } => (err_msg, Some(safe_transmute_explanation)),
+ }
} else {
(err_msg, None)
};
@@ -940,7 +973,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& self.fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|trait_pred| {
- trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit())
+ trait_pred.with_self_ty(self.tcx, Ty::new_unit(self.tcx))
});
let unit_obligation = obligation.with(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
@@ -995,8 +1028,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
}
- ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
- | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => {
span_bug!(
span,
"outlives clauses should not error outside borrowck. obligation: `{:?}`",
@@ -1004,7 +1037,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
- ty::PredicateKind::Clause(ty::Clause::Projection(..)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
span_bug!(
span,
"projection clauses should be implied from elsewhere. obligation: `{:?}`",
@@ -1022,7 +1055,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
}
- ty::PredicateKind::WellFormed(ty) => {
+ 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
@@ -1032,7 +1066,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// (which may fail).
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
}
- TraitSolver::Chalk | TraitSolver::Next => {
+ 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(
@@ -1043,7 +1077,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- ty::PredicateKind::ConstEvaluatable(..) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
// Errors for `ConstEvaluatable` predicates show up as
// `SelectionError::ConstEvalFailure`,
// not `Unimplemented`.
@@ -1067,17 +1101,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
- ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
- span,
- "TypeWellFormedFromEnv predicate should only exist in the environment"
- ),
-
ty::PredicateKind::AliasRelate(..) => span_bug!(
span,
"AliasRelate predicate should never be the predicate cause of a SelectionError"
),
- ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
let mut diag = self.tcx.sess.struct_span_err(
span,
format!("the constant `{}` is not of type `{}`", ct, ty),
@@ -1122,6 +1151,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
+ SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage(
+ &obligation,
+ def_id,
+ ),
+
TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, did, violations)
@@ -1140,16 +1174,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
// Already reported in the query.
- SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => {
- // FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token.
- self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error");
- return;
- }
+ SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
// Already reported.
- Overflow(OverflowError::Error(_)) => {
- self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported");
- return;
- }
+ Overflow(OverflowError::Error(_)) => return,
+
Overflow(_) => {
bug!("overflow should be handled before the `report_selection_error` path");
}
@@ -1162,6 +1190,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit();
}
+
+ fn report_const_param_not_wf(
+ &self,
+ ty: Ty<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let span = obligation.cause.span;
+
+ let mut diag = match ty.kind() {
+ _ if ty.has_param() => {
+ span_bug!(span, "const param tys cannot mention other generic parameters");
+ }
+ ty::Float(_) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "`{ty}` is forbidden as the type of a const generic parameter",
+ )
+ }
+ ty::FnPtr(_) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "using function pointers as const generic parameters is forbidden",
+ )
+ }
+ ty::RawPtr(_) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "using raw pointers as const generic parameters is forbidden",
+ )
+ }
+ ty::Adt(def, _) => {
+ // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...
+ let mut diag = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
+ );
+ // Only suggest derive if this isn't a derived obligation,
+ // and the struct is local.
+ if let Some(span) = self.tcx.hir().span_if_local(def.did())
+ && obligation.cause.code().parent().is_none()
+ {
+ if ty.is_structural_eq_shallow(self.tcx) {
+ diag.span_suggestion(
+ span,
+ "add `#[derive(ConstParamTy)]` to the struct",
+ "#[derive(ConstParamTy)]\n",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // FIXME(adt_const_params): We should check there's not already an
+ // overlapping `Eq`/`PartialEq` impl.
+ diag.span_suggestion(
+ span,
+ "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct",
+ "#[derive(ConstParamTy, PartialEq, Eq)]\n",
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ diag
+ }
+ _ => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "`{ty}` can't be used as a const parameter type",
+ )
+ }
+ };
+
+ let mut code = obligation.cause.code();
+ let mut pred = obligation.predicate.to_opt_poly_trait_pred();
+ while let Some((next_code, next_pred)) = code.parent() {
+ if let Some(pred) = pred {
+ let pred = self.instantiate_binder_with_placeholders(pred);
+ diag.note(format!(
+ "`{}` must implement `{}`, but it does not",
+ pred.self_ty(),
+ pred.print_modifiers_and_trait_path()
+ ));
+ }
+ code = next_code;
+ pred = next_pred;
+ }
+
+ diag
+ }
}
trait InferCtxtPrivExt<'tcx> {
@@ -1292,7 +1416,7 @@ trait InferCtxtPrivExt<'tcx> {
obligation: PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
- ) -> (String, Option<String>);
+ ) -> GetSafeTransmuteErrorAndReason;
fn add_tuple_trait_message(
&self,
@@ -1345,6 +1469,12 @@ trait InferCtxtPrivExt<'tcx> {
terr: TypeError<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+ fn report_opaque_type_auto_trait_leakage(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ def_id: DefId,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
fn report_type_parameter_mismatch_error(
&self,
obligation: &PredicateObligation<'tcx>,
@@ -1372,8 +1502,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let bound_error = error.kind();
let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
(
- ty::PredicateKind::Clause(ty::Clause::Trait(..)),
- ty::PredicateKind::Clause(ty::Clause::Trait(error)),
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)),
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(error)),
) => (cond, bound_error.rebind(error)),
_ => {
// FIXME: make this work in other cases too.
@@ -1383,7 +1513,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for pred in super::elaborate(self.tcx, std::iter::once(cond)) {
let bound_predicate = pred.kind();
- if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) =
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(implication)) =
bound_predicate.skip_binder()
{
let error = error.to_poly_trait_ref();
@@ -1404,6 +1534,10 @@ 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 {
+ dump_proof_tree(&error.root_obligation, self.infcx);
+ }
+
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
self.report_selection_error(
@@ -1474,14 +1608,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
self.probe(|_| {
- let ocx = ObligationCtxt::new_in_snapshot(self);
+ let ocx = ObligationCtxt::new(self);
// try to find the mismatched types to report the error with.
//
// this can fail if the problem was higher-ranked, in which
// cause I have no idea for a good error message.
let bound_predicate = predicate.kind();
- let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
+ let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
bound_predicate.skip_binder()
{
let data = self.instantiate_binder_with_fresh_vars(
@@ -1490,20 +1624,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
bound_predicate.rebind(data),
);
let unnormalized_term = match data.term.unpack() {
- ty::TermKind::Ty(_) => self
- .tcx
- .mk_projection(data.projection_ty.def_id, data.projection_ty.substs)
- .into(),
- ty::TermKind::Const(ct) => self
- .tcx
- .mk_const(
- ty::UnevaluatedConst {
- def: data.projection_ty.def_id,
- substs: data.projection_ty.substs,
- },
- ct.ty(),
- )
- .into(),
+ ty::TermKind::Ty(_) => Ty::new_projection(
+ self.tcx,
+ data.projection_ty.def_id,
+ data.projection_ty.substs,
+ )
+ .into(),
+ ty::TermKind::Const(ct) => ty::Const::new_unevaluated(
+ self.tcx,
+ ty::UnevaluatedConst {
+ def: data.projection_ty.def_id,
+ substs: data.projection_ty.substs,
+ },
+ ct.ty(),
+ )
+ .into(),
};
let normalized_term =
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
@@ -1564,7 +1699,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
let secondary_span = (|| {
- let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
+ let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
predicate.kind().skip_binder()
else {
return None;
@@ -1602,7 +1737,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}),
) => Some((
ty.span,
- with_forced_trimmed_paths!(format!(
+ with_forced_trimmed_paths!(Cow::from(format!(
"type mismatch resolving `{}`",
self.resolve_vars_if_possible(predicate)
.print(FmtPrinter::new_with_limit(
@@ -1612,7 +1747,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
))
.unwrap()
.into_buffer()
- )),
+ ))),
)),
_ => None,
}
@@ -1702,12 +1837,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Alias(ty::Projection, ..) => Some(12),
ty::Alias(ty::Inherent, ..) => Some(13),
ty::Alias(ty::Opaque, ..) => Some(14),
- ty::Never => Some(15),
- ty::Adt(..) => Some(16),
- ty::Generator(..) => Some(17),
- ty::Foreign(..) => Some(18),
- ty::GeneratorWitness(..) => Some(19),
- ty::GeneratorWitnessMIR(..) => Some(20),
+ ty::Alias(ty::Weak, ..) => Some(15),
+ ty::Never => Some(16),
+ ty::Adt(..) => Some(17),
+ ty::Generator(..) => Some(18),
+ ty::Foreign(..) => Some(19),
+ ty::GeneratorWitness(..) => Some(20),
+ ty::GeneratorWitnessMIR(..) => Some(21),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
@@ -1775,6 +1911,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|| !trait_pred
.skip_binder()
.is_constness_satisfied_by(self.tcx.constness(def_id))
+ || !self.tcx.is_user_visible_dep(def_id.krate)
{
return None;
}
@@ -1803,10 +1940,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
other: bool,
) -> bool {
let other = if other { "other " } else { "" };
- let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
- candidates.sort();
- candidates.dedup();
- let len = candidates.len();
+ let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
if candidates.is_empty() {
return false;
}
@@ -1835,11 +1969,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect();
traits.sort();
traits.dedup();
+ // FIXME: this could use a better heuristic, like just checking
+ // that substs[1..] is the same.
+ let all_traits_equal = traits.len() == 1;
- let mut candidates: Vec<String> = candidates
+ let candidates: Vec<String> = candidates
.into_iter()
.map(|c| {
- if traits.len() == 1 {
+ if all_traits_equal {
format!("\n {}", c.self_ty())
} else {
format!("\n {}", c)
@@ -1847,14 +1984,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
})
.collect();
- candidates.sort();
- candidates.dedup();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(format!(
"the following {other}types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
candidates[..end].join(""),
- if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
+ if candidates.len() > 9 {
+ format!("\nand {} others", candidates.len() - 8)
+ } else {
+ String::new()
+ }
));
true
};
@@ -1868,7 +2007,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
return false;
}
- let normalized_impl_candidates: Vec<_> = self
+ let mut impl_candidates: Vec<_> = self
.tcx
.all_impls(def_id)
// Ignore automatically derived impls and `!Trait` impls.
@@ -1895,7 +2034,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
})
.collect();
- return report(normalized_impl_candidates, err);
+
+ impl_candidates.sort();
+ impl_candidates.dedup();
+ return report(impl_candidates, err);
}
// Sort impl candidates so that ordering is consistent for UI tests.
@@ -1904,27 +2046,25 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
//
// Prefer more similar candidates first, then sort lexicographically
// by their normalized string representation.
- let mut normalized_impl_candidates_and_similarities = impl_candidates
+ let mut impl_candidates: Vec<_> = impl_candidates
.iter()
- .copied()
- .map(|ImplCandidate { trait_ref, similarity }| {
- // FIXME(compiler-errors): This should be using `NormalizeExt::normalize`
- let normalized = self
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .query_normalize(trait_ref)
- .map_or(trait_ref, |normalized| normalized.value);
- (similarity, normalized)
+ .cloned()
+ .map(|mut cand| {
+ // Fold the consts so that they shows up as, e.g., `10`
+ // instead of `core::::array::{impl#30}::{constant#0}`.
+ cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder {
+ tcx: self.tcx,
+ ty_op: |ty| ty,
+ lt_op: |lt| lt,
+ ct_op: |ct| ct.eval(self.tcx, ty::ParamEnv::empty()),
+ });
+ cand
})
- .collect::<Vec<_>>();
- normalized_impl_candidates_and_similarities.sort();
- normalized_impl_candidates_and_similarities.dedup();
-
- let normalized_impl_candidates = normalized_impl_candidates_and_similarities
- .into_iter()
- .map(|(_, normalized)| normalized)
- .collect::<Vec<_>>();
+ .collect();
+ impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref));
+ impl_candidates.dedup();
- report(normalized_impl_candidates, err)
+ report(impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(), err)
}
fn report_similar_impl_candidates_for_root_obligation(
@@ -2075,7 +2215,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
let trait_ref = bound_predicate.rebind(data.trait_ref);
debug!(?trait_ref);
@@ -2145,55 +2285,40 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
};
- let obligation = obligation.with(self.tcx, trait_ref);
- let mut selcx = SelectionContext::new(&self);
- match selcx.select_from_obligation(&obligation) {
- Ok(None) => {
- let ambiguities =
- ambiguity::recompute_applicable_impls(self.infcx, &obligation);
- let has_non_region_infer = trait_ref
- .skip_binder()
- .substs
- .types()
- .any(|t| !t.is_ty_or_numeric_infer());
- // It doesn't make sense to talk about applicable impls if there are more
- // than a handful of them.
- if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
- if self.tainted_by_errors().is_some() && subst.is_none() {
- // If `subst.is_none()`, then this is probably two param-env
- // candidates or impl candidates that are equal modulo lifetimes.
- // Therefore, if we've already emitted an error, just skip this
- // one, since it's not particularly actionable.
- err.cancel();
- return;
- }
- self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
- } else {
- if self.tainted_by_errors().is_some() {
- err.cancel();
- return;
- }
- err.note(format!("cannot satisfy `{}`", predicate));
- let impl_candidates = self.find_similar_impl_candidates(
- predicate.to_opt_poly_trait_pred().unwrap(),
- );
- if impl_candidates.len() < 10 {
- self.report_similar_impl_candidates(
- impl_candidates.as_slice(),
- trait_ref,
- obligation.cause.body_id,
- &mut err,
- false,
- );
- }
- }
+ let ambiguities = ambiguity::recompute_applicable_impls(
+ self.infcx,
+ &obligation.with(self.tcx, trait_ref),
+ );
+ let has_non_region_infer =
+ trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_or_numeric_infer());
+ // It doesn't make sense to talk about applicable impls if there are more
+ // than a handful of them.
+ if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+ if self.tainted_by_errors().is_some() && subst.is_none() {
+ // If `subst.is_none()`, then this is probably two param-env
+ // candidates or impl candidates that are equal modulo lifetimes.
+ // Therefore, if we've already emitted an error, just skip this
+ // one, since it's not particularly actionable.
+ err.cancel();
+ return;
}
- _ => {
- if self.tainted_by_errors().is_some() {
- err.cancel();
- return;
- }
- err.note(format!("cannot satisfy `{}`", predicate));
+ self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
+ } else {
+ if self.tainted_by_errors().is_some() {
+ err.cancel();
+ return;
+ }
+ err.note(format!("cannot satisfy `{}`", predicate));
+ let impl_candidates = self
+ .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
+ if impl_candidates.len() < 10 {
+ self.report_similar_impl_candidates(
+ impl_candidates.as_slice(),
+ trait_ref,
+ obligation.cause.body_id,
+ &mut err,
+ false,
+ );
}
}
@@ -2258,17 +2383,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
{
let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
- let message = if non_blanket_impl_count == 1 {
- "use the fully-qualified path to the only available implementation".to_string()
- } else {
+ // If there is only one implementation of the trait, suggest using it.
+ // Otherwise, use a placeholder comment for the implementation.
+ let (message, impl_suggestion) = if non_blanket_impl_count == 1 {(
+ "use the fully-qualified path to the only available implementation".to_string(),
+ format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity())
+ )} else {(
format!(
"use a fully-qualified path to a specific available implementation ({} found)",
non_blanket_impl_count
- )
- };
+ ),
+ "</* self type */ as ".to_string()
+ )};
let mut suggestions = vec![(
path.span.shrink_to_lo(),
- format!("<{} as ", self.tcx.type_of(impl_def_id).subst_identity())
+ impl_suggestion
)];
if let Some(generic_arg) = trait_path_segment.args {
let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext);
@@ -2291,7 +2420,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err
}
- ty::PredicateKind::WellFormed(arg) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
if arg.references_error()
@@ -2329,7 +2458,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
true,
)
}
- ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
if predicate.references_error() || self.tainted_by_errors().is_some() {
return;
}
@@ -2363,7 +2492,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- ty::PredicateKind::ConstEvaluatable(data) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
if predicate.references_error() || self.tainted_by_errors().is_some() {
return;
}
@@ -2526,11 +2655,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
+ if let ty::Param(_) = *ty.kind() {
let infcx = self.infcx;
*self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
+ kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
})
})
@@ -2577,7 +2706,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
obligation: &PredicateObligation<'tcx>,
) {
- let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; };
+ let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = obligation.predicate.kind().skip_binder() else { return; };
let (ObligationCauseCode::BindingObligation(item_def_id, span)
| ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..))
= *obligation.cause.code().peel_derives() else { return; };
@@ -2738,7 +2867,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
obligation: PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
- ) -> (String, Option<String>) {
+ ) -> GetSafeTransmuteErrorAndReason {
+ 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));
@@ -2751,19 +2882,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
};
+
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
obligation.cause,
src_and_dst,
scope,
assume,
) {
- rustc_transmute::Answer::No(reason) => {
+ Answer::No(reason) => {
let dst = trait_ref.substs.type_at(0);
let src = trait_ref.substs.type_at(1);
- let custom_err_msg = format!(
+ let err_msg = format!(
"`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
);
- let reason_msg = match reason {
+ let safe_transmute_explanation = match reason {
rustc_transmute::Reason::SrcIsUnspecified => {
format!("`{src}` does not have a well-specified layout")
}
@@ -2779,19 +2911,39 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
rustc_transmute::Reason::DstIsPrivate => format!(
"`{dst}` is or contains a type or field that is not visible in that scope"
),
- // FIXME(bryangarza): Include the number of bytes of src and dst
rustc_transmute::Reason::DstIsTooBig => {
format!("The size of `{src}` is smaller than the size of `{dst}`")
}
+ rustc_transmute::Reason::DstHasStricterAlignment {
+ src_min_align,
+ dst_min_align,
+ } => {
+ format!(
+ "The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
+ )
+ }
+ rustc_transmute::Reason::DstIsMoreUnique => {
+ format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
+ }
+ // Already reported by rustc
+ rustc_transmute::Reason::TypeError => {
+ return GetSafeTransmuteErrorAndReason::Silent;
+ }
+ rustc_transmute::Reason::SrcLayoutUnknown => {
+ format!("`{src}` has an unknown layout")
+ }
+ rustc_transmute::Reason::DstLayoutUnknown => {
+ format!("`{dst}` has an unknown layout")
+ }
};
- (custom_err_msg, Some(reason_msg))
+ GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation }
}
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
- rustc_transmute::Answer::Yes => span_bug!(
+ Answer::Yes => span_bug!(
span,
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
),
- _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
+ other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"),
}
}
@@ -3049,6 +3201,39 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
+ fn report_opaque_type_auto_trait_leakage(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ def_id: DefId,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
+ hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
+ format!("opaque type")
+ }
+ hir::OpaqueTyOrigin::TyAlias { .. } => {
+ format!("`{}`", self.tcx.def_path_debug_str(def_id))
+ }
+ };
+ let mut err = self.tcx.sess.struct_span_err(
+ obligation.cause.span,
+ format!("cannot check whether the hidden type of {name} satisfies auto traits"),
+ );
+ err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
+ match self.defining_use_anchor {
+ DefiningAnchor::Bubble | DefiningAnchor::Error => {}
+ DefiningAnchor::Bind(bind) => {
+ err.span_note(
+ self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
+ "this item depends on auto traits of the hidden type, \
+ but may also be registering the hidden type. \
+ This is not supported right now. \
+ You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
+ );
+ }
+ };
+ err
+ }
+
fn report_type_parameter_mismatch_error(
&self,
obligation: &PredicateObligation<'tcx>,
@@ -3178,7 +3363,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(ct) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
};
@@ -3360,3 +3545,16 @@ pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
}
+
+pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: &InferCtxt<'tcx>) {
+ infcx.probe(|_| {
+ let goal = Goal { predicate: o.predicate, param_env: o.param_env };
+ let tree = infcx
+ .evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No))
+ .1
+ .expect("proof tree should have been generated");
+ let mut lock = std::io::stdout().lock();
+ let _ = lock.write_fmt(format_args!("{tree:?}"));
+ let _ = lock.flush();
+ });
+}
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 10bd027b6..b16d2eb5f 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
@@ -41,7 +41,6 @@ pub trait TypeErrCtxtExt<'tcx> {
static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
kw::SelfUpper,
sym::ItemContext,
- sym::from_method,
sym::from_desugaring,
sym::direct,
sym::cause,
@@ -172,23 +171,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- if let ObligationCauseCode::ItemObligation(item)
- | ObligationCauseCode::BindingObligation(item, _)
- | ObligationCauseCode::ExprItemObligation(item, ..)
- | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code()
- {
- // FIXME: maybe also have some way of handling methods
- // from other traits? That would require name resolution,
- // which we might want to be some sort of hygienic.
- //
- // Currently I'm leaving it for what I need for `try`.
- if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
- let method = self.tcx.item_name(item);
- flags.push((sym::from_method, None));
- flags.push((sym::from_method, Some(method.to_string())));
- }
- }
-
if let Some(k) = obligation.cause.span.desugaring_kind() {
flags.push((sym::from_desugaring, None));
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
@@ -278,7 +260,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_string())));
- let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
+ let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
if let Some(n) = len {
flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
@@ -672,7 +654,7 @@ impl<'tcx> OnUnimplementedFormatString {
None => {
if let Some(val) = options.get(&s) {
val
- } else if s == sym::from_desugaring || s == sym::from_method {
+ } else if s == sym::from_desugaring {
// don't break messages using these two arguments incorrectly
&empty_string
} else if s == sym::ItemContext {
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 82bad96ea..9ac1ba027 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
- ErrorGuaranteed, MultiSpan, Style,
+ ErrorGuaranteed, MultiSpan, Style, SuggestionStyle,
};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@@ -38,6 +38,7 @@ use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
+use std::borrow::Cow;
use std::iter;
use std::ops::Deref;
@@ -186,7 +187,12 @@ pub trait TypeErrCtxtExt<'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
- fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol>;
+ fn get_closure_name(
+ &self,
+ def_id: DefId,
+ err: &mut Diagnostic,
+ msg: Cow<'static, str>,
+ ) -> Option<Symbol>;
fn suggest_fn_call(
&self,
@@ -356,6 +362,15 @@ pub trait TypeErrCtxtExt<'tcx> {
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
);
+
+ fn suggest_option_method_if_applicable(
+ &self,
+ failed_pred: ty::Predicate<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ );
+
fn note_function_argument_obligation(
&self,
body_id: LocalDefId,
@@ -771,7 +786,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let Some(steps) =
autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
// Re-add the `&`
- let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+ let ty = Ty::new_ref(self.tcx, region, TypeAndMut { ty, mutbl });
// Remapping bound vars here
let real_trait_pred_and_ty =
@@ -857,7 +872,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
/// Given a closure's `DefId`, return the given name of the closure.
///
/// This doesn't account for reassignments, but it's only used for suggestions.
- fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol> {
+ fn get_closure_name(
+ &self,
+ def_id: DefId,
+ err: &mut Diagnostic,
+ msg: Cow<'static, str>,
+ ) -> Option<Symbol> {
let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option<Symbol> {
// Get the local name of this closure. This can be inaccurate because
// of the possibility of reassignment, but this should be good enough.
@@ -900,7 +920,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return false;
}
- if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder()
&& Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
{
// Don't suggest calling to turn an unsized type into a sized type
@@ -934,17 +954,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let msg = match def_id_or_name {
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
DefKind::Ctor(CtorOf::Struct, _) => {
- "use parentheses to construct this tuple struct".to_string()
+ Cow::from("use parentheses to construct this tuple struct")
}
DefKind::Ctor(CtorOf::Variant, _) => {
- "use parentheses to construct this tuple variant".to_string()
+ Cow::from("use parentheses to construct this tuple variant")
}
- kind => format!(
+ kind => Cow::from(format!(
"use parentheses to call this {}",
self.tcx.def_kind_descr(kind, def_id)
- ),
+ )),
},
- DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
+ DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")),
};
let args = inputs
@@ -979,7 +999,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
..
})) => {
err.span_label(*fn_decl_span, "consider calling this closure");
- let Some(name) = self.get_closure_name(def_id, err, &msg) else {
+ let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else {
return false;
};
name.to_string()
@@ -1137,7 +1157,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
- if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+ if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
@@ -1181,7 +1201,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
DefIdOrName::Name("type parameter")
};
param_env.caller_bounds().iter().find_map(|pred| {
- if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+ if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be substs[1]
@@ -1278,13 +1298,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
(
trait_pred,
- self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),
)
});
let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
(
trait_pred,
- self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),
)
});
@@ -1341,7 +1361,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note(msg);
} else {
err.message =
- vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
+ vec![(rustc_errors::DiagnosticMessage::from(msg), Style::NoStyle)];
}
err.span_label(
span,
@@ -1445,7 +1465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) {
let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; };
let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; };
- let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
+ let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);
for predicate in predicates.iter() {
if !self.predicate_must_hold_modulo_regions(
@@ -1619,7 +1639,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
// FIXME: account for associated `async fn`s.
if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
obligation.predicate.kind().skip_binder()
{
err.span_label(*span, format!("this call returns `{}`", pred.self_ty()));
@@ -1686,8 +1706,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
{
let suggested_ty = match mutability {
- hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
- hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
+ hir::Mutability::Mut => Ty::new_imm_ref(self.tcx, region, t_type),
+ hir::Mutability::Not => Ty::new_mut_ref(self.tcx, region, t_type),
};
// Remapping bound vars here
@@ -1931,7 +1951,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
),
};
- infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig))
+ Ty::new_fn_ptr(infcx.tcx, trait_ref.rebind(sig))
}
let argument_kind = match expected.skip_binder().self_ty().kind() {
@@ -1981,7 +2001,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
&& let Some(pred) = predicates.predicates.get(*idx)
- && let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder()
+ && let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
&& self.tcx.is_fn_trait(trait_pred.def_id())
{
let expected_self =
@@ -1995,7 +2015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let other_pred = predicates.into_iter()
.enumerate()
.find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
+ ty::ClauseKind::Trait(trait_pred)
if self.tcx.is_fn_trait(trait_pred.def_id())
&& other_idx != idx
// Make sure that the self type matches
@@ -2121,7 +2141,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// bound was introduced. At least one generator should be present for this diagnostic to be
// modified.
let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(p)) => (Some(p), Some(p.self_ty())),
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => (Some(p), Some(p.self_ty())),
_ => (None, None),
};
let mut generator = None;
@@ -2643,8 +2663,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::LetElse
| ObligationCauseCode::BinOp { .. }
| ObligationCauseCode::AscribeUserTypeProvePredicate(..)
- | ObligationCauseCode::RustCall
- | ObligationCauseCode::DropImpl => {}
+ | ObligationCauseCode::DropImpl
+ | ObligationCauseCode::ConstParam(_) => {}
+ ObligationCauseCode::RustCall => {
+ if let Some(pred) = predicate.to_opt_poly_trait_pred()
+ && Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
+ {
+ err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
+ }
+ }
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
@@ -2697,6 +2724,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let msg = format!("required by this bound in `{short_item_name}`");
multispan.push_span_label(span, msg);
err.span_note(multispan, descr);
+ if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
+ && let ty::ClauseKind::Trait(trait_pred) = clause
+ {
+ let def_id = trait_pred.def_id();
+ let visible_item = if let Some(local) = def_id.as_local() {
+ // Check for local traits being reachable.
+ let vis = &self.tcx.resolutions(()).effective_visibilities;
+ // Account for non-`pub` traits in the root of the local crate.
+ let is_locally_reachable = self.tcx.parent(def_id).is_crate_root();
+ vis.is_reachable(local) || is_locally_reachable
+ } else {
+ // Check for foreign traits being reachable.
+ self.tcx.visible_parent_map(()).get(&def_id).is_some()
+ };
+ if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item {
+ // FIXME(estebank): extend this to search for all the types that do
+ // implement this trait and list them.
+ err.note(format!(
+ "`{short_item_name}` is a \"sealed trait\", because to implement \
+ it you also need to implelement `{}`, which is not accessible; \
+ this is usually done to force you to use one of the provided \
+ types that already implement it",
+ with_no_trimmed_paths!(tcx.def_path_str(def_id)),
+ ));
+ }
+ }
} else {
err.span_note(tcx.def_span(item_def_id), descr);
}
@@ -2786,10 +2839,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.help("unsized locals are gated as an unstable feature");
}
}
- ObligationCauseCode::SizedArgumentType(sp) => {
- if let Some(span) = sp {
+ ObligationCauseCode::SizedArgumentType(ty_span) => {
+ if let Some(span) = ty_span {
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
- && let ty::Clause::Trait(trait_pred) = clause
+ && let ty::ClauseKind::Trait(trait_pred) = clause
&& let ty::Dynamic(..) = trait_pred.self_ty().kind()
{
let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
@@ -2958,7 +3011,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
for ty in bound_tys.skip_binder() {
with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap());
}
- err.note(msg.trim_end_matches(", "))
+ err.note(msg.trim_end_matches(", ").to_string())
}
ty::GeneratorWitnessMIR(def_id, substs) => {
use std::fmt::Write;
@@ -2972,7 +3025,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let ty = bty.subst(tcx, substs);
write!(msg, "`{}`, ", ty).unwrap();
}
- err.note(msg.trim_end_matches(", "))
+ err.note(msg.trim_end_matches(", ").to_string())
}
ty::Generator(def_id, _, _) => {
let sp = self.tcx.def_span(def_id);
@@ -3171,6 +3224,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
});
}
+ ObligationCauseCode::TypeAlias(ref nested, span, def_id) => {
+ // #74711: avoid a stack overflow
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ body_id,
+ err,
+ predicate,
+ param_env,
+ nested,
+ obligated_types,
+ seen_requirements,
+ )
+ });
+ let mut multispan = MultiSpan::from(span);
+ multispan.push_span_label(span, "required by this bound");
+ err.span_note(
+ multispan,
+ format!(
+ "required by a bound on the type alias `{}`",
+ self.infcx.tcx.item_name(def_id)
+ ),
+ );
+ }
ObligationCauseCode::FunctionArgumentObligation {
arg_hir_id,
call_hir_id,
@@ -3271,7 +3347,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
// `<T as Future>::Output`
let projection_ty = trait_pred.map_bound(|trait_pred| {
- self.tcx.mk_projection(
+ Ty::new_projection(
+ self.tcx,
item_def_id,
// Future::Output has no substs
[trait_pred.self_ty()],
@@ -3425,7 +3502,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
let expr = expr.peel_blocks();
- let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc());
+ let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx,));
let span = expr.span;
if Some(span) != err.span.primary_span() {
err.span_label(
@@ -3450,7 +3527,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
&& let Some(where_pred) = where_clauses.predicates.get(*idx)
{
- if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
+ if let Some(where_pred) = where_pred.as_trait_clause()
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
{
let where_pred = self.instantiate_binder_with_placeholders(where_pred);
@@ -3473,13 +3550,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
})
};
- } else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
+ } else if let Some(where_pred) = where_pred.as_projection_clause()
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
&& let Some(found) = failed_pred.skip_binder().term.ty()
{
type_diffs = vec![
Sorts(ty::error::ExpectedFound {
- expected: self.tcx.mk_alias(ty::Projection, where_pred.skip_binder().projection_ty),
+ expected: Ty::new_alias(self.tcx,ty::Projection, where_pred.skip_binder().projection_ty),
found,
}),
];
@@ -3509,15 +3586,93 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.replace_span_with(path.ident.span, true);
}
}
- if let Some(Node::Expr(hir::Expr {
- kind:
- hir::ExprKind::Call(hir::Expr { span, .. }, _)
- | hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..),
- ..
- })) = hir.find(call_hir_id)
+
+ if let Some(Node::Expr(expr)) = hir.find(call_hir_id) {
+ if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
+ | hir::ExprKind::MethodCall(
+ hir::PathSegment { ident: Ident { span, .. }, .. },
+ ..,
+ ) = expr.kind
+ {
+ if Some(*span) != err.span.primary_span() {
+ err.span_label(*span, "required by a bound introduced by this call");
+ }
+ }
+
+ if let hir::ExprKind::MethodCall(_, expr, ..) = expr.kind {
+ self.suggest_option_method_if_applicable(failed_pred, param_env, err, expr);
+ }
+ }
+ }
+
+ fn suggest_option_method_if_applicable(
+ &self,
+ failed_pred: ty::Predicate<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ ) {
+ let tcx = self.tcx;
+ let infcx = self.infcx;
+ let Some(typeck_results) = self.typeck_results.as_ref() else { return };
+
+ // Make sure we're dealing with the `Option` type.
+ let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else { return };
+ if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) {
+ return;
+ }
+
+ // Given the predicate `fn(&T): FnOnce<(U,)>`, extract `fn(&T)` and `(U,)`,
+ // then suggest `Option::as_deref(_mut)` if `U` can deref to `T`
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, .. }))
+ = failed_pred.kind().skip_binder()
+ && tcx.is_fn_trait(trait_ref.def_id)
+ && let [self_ty, found_ty] = trait_ref.substs.as_slice()
+ && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn())
+ && let fn_sig @ ty::FnSig {
+ abi: abi::Abi::Rust,
+ c_variadic: false,
+ unsafety: hir::Unsafety::Normal,
+ ..
+ } = fn_ty.fn_sig(tcx).skip_binder()
+
+ // Extract first param of fn sig with peeled refs, e.g. `fn(&T)` -> `T`
+ && let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind())
+ && !target_ty.has_escaping_bound_vars()
+
+ // Extract first tuple element out of fn trait, e.g. `FnOnce<(U,)>` -> `U`
+ && let Some(ty::Tuple(tys)) = found_ty.as_type().map(Ty::kind)
+ && let &[found_ty] = tys.as_slice()
+ && !found_ty.has_escaping_bound_vars()
+
+ // Extract `<U as Deref>::Target` assoc type and check that it is `T`
+ && let Some(deref_target_did) = tcx.lang_items().deref_target()
+ && let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
+ && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
+ && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
+ && infcx.can_eq(param_env, deref_target, target_ty)
{
- if Some(*span) != err.span.primary_span() {
- err.span_label(*span, "required by a bound introduced by this call");
+ let help = if let hir::Mutability::Mut = needs_mut
+ && let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
+ && infcx
+ .type_implements_trait(deref_mut_did, iter::once(found_ty), param_env)
+ .must_apply_modulo_regions()
+ {
+ Some(("call `Option::as_deref_mut()` first", ".as_deref_mut()"))
+ } else if let hir::Mutability::Not = needs_mut {
+ Some(("call `Option::as_deref()` first", ".as_deref()"))
+ } else {
+ None
+ };
+
+ if let Some((msg, sugg)) = help {
+ err.span_suggestion_with_style(
+ expr.span.shrink_to_hi(),
+ msg,
+ sugg,
+ Applicability::MaybeIncorrect,
+ SuggestionStyle::ShowAlways
+ );
}
}
}
@@ -3539,7 +3694,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut assocs = vec![];
let mut expr = expr;
let mut prev_ty = self.resolve_vars_if_possible(
- typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()),
+ typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
);
while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
// Point at every method call in the chain with the resulting type.
@@ -3550,7 +3705,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
assocs.push(assocs_in_this_method);
prev_ty = self.resolve_vars_if_possible(
- typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()),
+ typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
);
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -3568,7 +3723,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::Node::Param(param) = parent {
// ...and it is a an fn argument.
let prev_ty = self.resolve_vars_if_possible(
- typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error_misc()),
+ typeck_results.node_type_opt(param.hir_id).unwrap_or(Ty::new_misc_error(tcx,)),
);
let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
if assocs_in_this_method.iter().any(|a| a.is_some()) {
@@ -3671,7 +3826,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
- let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
+ let ocx = ObligationCtxt::new(self.infcx);
let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
for diff in type_diffs {
let Sorts(expected_found) = diff else { continue; };
@@ -3698,12 +3853,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// in. For example, this would be what `Iterator::Item` is here.
let ty_var = self.infcx.next_ty_var(origin);
// This corresponds to `<ExprTy as Iterator>::Item = _`.
- let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
- ty::ProjectionPredicate {
+ let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
+ ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs),
term: ty_var.into(),
- },
- )));
+ }),
+ ));
let body_def_id = self.tcx.hir().enclosing_body_owner(body_id);
// Add `<ExprTy as Iterator>::Item = _` obligation.
ocx.register_obligation(Obligation::misc(