// like when you have two references but one is `usize` and the other
// is `f32`. In those cases we still want to show the `note`. If the
// value from `ef` is `Infer(_)`, then we ignore it.
- if !ef.expected.is_ty_infer() {
+ if !ef.expected.is_ty_or_numeric_infer() {
ef.expected != values.expected
- } else if !ef.found.is_ty_infer() {
+ } else if !ef.found.is_ty_or_numeric_infer() {
ef.found != values.found
} else {
false
(ty::Tuple(fields), _) => {
self.emit_tuple_wrap_err(&mut err, span, found, fields)
}
+ // If a byte was expected and the found expression is a char literal
+ // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+ // specify a byte literal
+ (ty::Uint(ty::UintTy::U8), ty::Char) => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ && code.chars().next().map_or(false, |c| c.is_ascii())
+ {
+ err.span_suggestion(
+ span,
+ "if you meant to write a byte literal, prefix with `b`",
+ format!("b'{}'", escape_literal(code)),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
// specify a character literal (issue #92479)
// suggest adding an explicit lifetime bound to it.
let generics = self.tcx.generics_of(generic_param_scope);
// type_param_span is (span, has_bounds)
+ let mut is_synthetic = false;
+ let mut ast_generics = None;
let type_param_span = match bound_kind {
GenericKind::Param(ref param) => {
// Account for the case where `param` corresponds to `Self`,
// which doesn't have the expected type argument.
if !(generics.has_self && param.index == 0) {
let type_param = generics.type_param(param, self.tcx);
+ is_synthetic = type_param.kind.is_synthetic();
type_param.def_id.as_local().map(|def_id| {
// Get the `hir::Param` to verify whether it already has any bounds.
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
// instead we suggest `T: 'a + 'b` in that case.
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
+ ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
let bounds =
ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
// `sp` only covers `T`, change it so that it covers
.unwrap_or("'lt".to_string())
};
- let add_lt_sugg = generics
- .params
- .first()
- .and_then(|param| param.def_id.as_local())
- .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt)));
+ let mut add_lt_suggs: Vec<Option<_>> = vec![];
+ if is_synthetic {
+ if let Some(ast_generics) = ast_generics {
+ let named_lifetime_param_exist = ast_generics.params.iter().any(|p| {
+ matches!(
+ p.kind,
+ hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+ )
+ });
+ if named_lifetime_param_exist && let [param, ..] = ast_generics.params
+ {
+ add_lt_suggs.push(Some((
+ self.tcx.def_span(param.def_id).shrink_to_lo(),
+ format!("{new_lt}, "),
+ )));
+ } else {
+ add_lt_suggs
+ .push(Some((ast_generics.span.shrink_to_hi(), format!("<{new_lt}>"))));
+ }
+ }
+ } else {
+ if let [param, ..] = &generics.params[..] && let Some(def_id) = param.def_id.as_local()
+ {
+ add_lt_suggs
+ .push(Some((self.tcx.def_span(def_id).shrink_to_lo(), format!("{new_lt}, "))));
+ }
+ }
+
+ if let Some(ast_generics) = ast_generics {
+ for p in ast_generics.params {
+ if p.is_elided_lifetime() {
+ if self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_prev_source(p.span.shrink_to_hi())
+ .ok()
+ .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&')
+ {
+ add_lt_suggs
+ .push(Some(
+ (
+ p.span.shrink_to_hi(),
+ if let Ok(snip) = self.tcx.sess.source_map().span_to_next_source(p.span)
+ && snip.starts_with(' ')
+ {
+ format!("{new_lt}")
+ } else {
+ format!("{new_lt} ")
+ }
+ )
+ ));
+ } else {
+ add_lt_suggs.push(Some((p.span.shrink_to_hi(), format!("<{new_lt}>"))));
+ }
+ }
+ }
+ }
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
- GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
- GenericKind::Opaque(def_id, substs) => {
- format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
+ GenericKind::Alias(ty::Projection, ref p) => format!("the associated type `{}`", p),
+ GenericKind::Alias(ty::Opaque, ref p) => {
+ format!(
+ "the opaque type `{}`",
+ self.tcx.def_path_str_with_substs(p.def_id, p.substs)
+ )
}
};
);
}
- fn binding_suggestion<S: fmt::Display>(
+ fn binding_suggestion<'tcx, S: fmt::Display>(
err: &mut Diagnostic,
type_param_span: Option<(Span, bool)>,
- bound_kind: GenericKind<'_>,
+ bound_kind: GenericKind<'tcx>,
sub: S,
- add_lt_sugg: Option<(Span, String)>,
+ add_lt_suggs: Vec<Option<(Span, String)>>,
) {
let msg = "consider adding an explicit lifetime bound";
if let Some((sp, has_lifetimes)) = type_param_span {
let suggestion =
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
let mut suggestions = vec![(sp, suggestion)];
- if let Some(add_lt_sugg) = add_lt_sugg {
- suggestions.push(add_lt_sugg);
+ for add_lt_sugg in add_lt_suggs {
+ if let Some(add_lt_sugg) = add_lt_sugg {
+ suggestions.push(add_lt_sugg);
+ }
}
err.multipart_suggestion_verbose(
format!("{msg}..."),
};
let mut sugg =
vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
- if let Some(lt) = add_lt_sugg.clone() {
- sugg.push(lt);
- sugg.rotate_right(1);
+ for add_lt_sugg in add_lt_suggs.clone() {
+ if let Some(lt) = add_lt_sugg {
+ sugg.push(lt);
+ sugg.rotate_right(1);
+ }
}
// `MaybeIncorrect` due to issue #41966.
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
// for the bound is not suitable for suggestions when `-Zverbose` is set because it
// uses `Debug` output, so we handle it specially here so that suggestions are
// always correct.
- binding_suggestion(&mut err, type_param_span, bound_kind, name, None);
+ binding_suggestion(&mut err, type_param_span, bound_kind, name, vec![]);
err
}
"{} may not live long enough",
labeled_user_string
);
- binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None);
+ binding_suggestion(&mut err, type_param_span, bound_kind, "'static", vec![]);
err
}
type_param_span,
bound_kind,
new_lt,
- add_lt_sugg,
+ add_lt_suggs,
);
}
}