use crate::structured_errors::StructuredDiagnostic;
use rustc_ast as ast;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan};
+use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
self.set_tainted_by_errors();
let tcx = self.tcx;
+ // Get the argument span in the context of the call span so that
+ // suggestions and labels are (more) correct when an arg is a
+ // macro invocation.
+ let normalize_span = |span: Span| -> Span {
+ let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span);
+ // Sometimes macros mess up the spans, so do not normalize the
+ // arg span to equal the error span, because that's less useful
+ // than pointing out the arg expr in the wrong context.
+ if normalized_span.source_equal(error_span) { span } else { normalized_span }
+ };
+
// Precompute the provided types and spans, since that's all we typically need for below
let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args
.iter()
.borrow()
.expr_ty_adjusted_opt(*expr)
.unwrap_or_else(|| tcx.ty_error());
- (self.resolve_vars_if_possible(ty), expr.span)
+ (self.resolve_vars_if_possible(ty), normalize_span(expr.span))
})
.collect();
let callee_expr = match &call_expr.peel_blocks().kind {
// If so, we might have just forgotten to wrap some args in a tuple.
if let Some(ty::Tuple(tys)) =
formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
+ // If the tuple is unit, we're not actually wrapping any arguments.
+ && !tys.is_empty()
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
{
// Wrap up the N provided arguments starting at this position in a tuple.
// Take some care with spans, so we don't suggest wrapping a macro's
// innards in parenthesis, for example.
if satisfied
- && let Some(lo) =
- provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span)
- && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()]
- .span
- .find_ancestor_inside(error_span)
+ && let Some((_, lo)) =
+ provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx))
+ && let Some((_, hi)) =
+ provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1))
{
let mut err;
if tys.len() == 1 {
// so don't do anything special here.
err = self.report_and_explain_type_error(
TypeTrace::types(
- &self.misc(lo),
+ &self.misc(*lo),
true,
formal_and_expected_inputs[mismatch_idx.into()].1,
provided_arg_tys[mismatch_idx.into()].0,
"argument"
),
potentially_plural_count(provided_args.len(), "argument"),
- if provided_args.len() == 1 { "was" } else { "were" }
+ pluralize!("was", provided_args.len())
),
DiagnosticId::Error(err_code.to_owned()),
);
if c_variadic { "at least " } else { "" },
potentially_plural_count(formal_and_expected_inputs.len(), "argument"),
potentially_plural_count(provided_args.len(), "argument"),
- if provided_args.len() == 1 { "was" } else { "were" }
+ pluralize!("was", provided_args.len())
),
DiagnosticId::Error(err_code.to_owned()),
)
let suggestion_text = if let Some(provided_idx) = provided_idx
&& let (_, provided_span) = provided_arg_tys[*provided_idx]
&& let Ok(arg_text) =
- source_map.span_to_snippet(provided_span.source_callsite())
+ source_map.span_to_snippet(provided_span)
{
arg_text
} else {
let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
if expected_ty.is_unit() {
"()".to_string()
- } else if expected_ty.is_suggestable(tcx) {
+ } else if expected_ty.is_suggestable(tcx, false) {
format!("/* {} */", expected_ty)
} else {
"/* value */".to_string()
.flat_map(|a| a.args.iter())
{
if let hir::GenericArg::Type(hir_ty) = &arg {
- if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
- &hir_ty.kind
- {
- // Avoid ICE with associated types. As this is best
- // effort only, it's ok to ignore the case. It
- // would trigger in `is_send::<T::AssocType>();`
- // from `typeck-default-trait-impl-assoc-type.rs`.
- } else {
- let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
- let ty = self.resolve_vars_if_possible(ty);
- if ty == predicate.self_ty() {
- error.obligation.cause.span = hir_ty.span;
- }
+ let ty = self.resolve_vars_if_possible(
+ self.typeck_results.borrow().node_type(hir_ty.hir_id),
+ );
+ if ty == predicate.self_ty() {
+ error.obligation.cause.span = hir_ty.span;
}
}
}