summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/error_reporting
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/error_reporting')
-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
5 files changed, 910 insertions, 302 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 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,