summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs259
1 files changed, 207 insertions, 52 deletions
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(