Rollup merge of #98497 - compiler-errors:span-inference-note, r=lcnr
Improve some inference diagnostics - Properly point out point location where "type must be known at this point", or else omit the note if it's not associated with a useful span. - Fix up some type ambiguity diagnostics, errors shouldn't say "cannot infer type for reference `&'a ()`" when the given type has no inference variables.
This commit is contained in:
commit
b0935b1ddf
52 changed files with 195 additions and 135 deletions
|
@ -313,11 +313,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
pub fn emit_inference_failure_err(
|
||||
&self,
|
||||
body_id: Option<hir::BodyId>,
|
||||
span: Span,
|
||||
failure_span: Span,
|
||||
arg: GenericArg<'tcx>,
|
||||
// FIXME(#94483): Either use this or remove it.
|
||||
_impl_candidates: Vec<ty::TraitRef<'tcx>>,
|
||||
error_code: TypeAnnotationNeeded,
|
||||
should_label_span: bool,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let arg = self.resolve_vars_if_possible(arg);
|
||||
let arg_data = self.extract_inference_diagnostics_data(arg, None);
|
||||
|
@ -326,7 +327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// If we don't have any typeck results we're outside
|
||||
// of a body, so we won't be able to get better info
|
||||
// here.
|
||||
return self.bad_inference_failure_err(span, arg_data, error_code);
|
||||
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
|
||||
};
|
||||
let typeck_results = typeck_results.borrow();
|
||||
let typeck_results = &typeck_results;
|
||||
|
@ -338,7 +339,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let Some(InferSource { span, kind }) = local_visitor.infer_source else {
|
||||
return self.bad_inference_failure_err(span, arg_data, error_code)
|
||||
return self.bad_inference_failure_err(failure_span, arg_data, error_code)
|
||||
};
|
||||
|
||||
let error_code = error_code.into();
|
||||
|
@ -347,6 +348,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
&format!("type annotations needed{}", kind.ty_msg(self)),
|
||||
error_code,
|
||||
);
|
||||
|
||||
if should_label_span && !failure_span.overlaps(span) {
|
||||
err.span_label(failure_span, "type must be known at this point");
|
||||
}
|
||||
|
||||
match kind {
|
||||
InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
|
||||
let suggestion_msg = if let Some(name) = pattern_name {
|
||||
|
|
|
@ -914,9 +914,17 @@ impl<'tcx> Term<'tcx> {
|
|||
pub fn ty(&self) -> Option<Ty<'tcx>> {
|
||||
if let Term::Ty(ty) = self { Some(*ty) } else { None }
|
||||
}
|
||||
|
||||
pub fn ct(&self) -> Option<Const<'tcx>> {
|
||||
if let Term::Const(c) = self { Some(*c) } else { None }
|
||||
}
|
||||
|
||||
pub fn into_arg(self) -> GenericArg<'tcx> {
|
||||
match self {
|
||||
Term::Ty(ty) => ty.into(),
|
||||
Term::Const(c) => c.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This kind of predicate has no *direct* correspondent in the
|
||||
|
|
|
@ -1958,26 +1958,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
|||
if predicate.references_error() {
|
||||
return;
|
||||
}
|
||||
// Typically, this ambiguity should only happen if
|
||||
// there are unresolved type inference variables
|
||||
// (otherwise it would suggest a coherence
|
||||
// failure). But given #21974 that is not necessarily
|
||||
// the case -- we can have multiple where clauses that
|
||||
// are only distinguished by a region, which results
|
||||
// in an ambiguity even when all types are fully
|
||||
// known, since we don't dispatch based on region
|
||||
// relationships.
|
||||
|
||||
// Pick the first substitution that still contains inference variables as the one
|
||||
// we're going to emit an error for. If there are none (see above), fall back to
|
||||
// the substitution for `Self`.
|
||||
let subst = {
|
||||
let substs = data.trait_ref.substs;
|
||||
substs
|
||||
.iter()
|
||||
.find(|s| s.has_infer_types_or_consts())
|
||||
.unwrap_or_else(|| substs[0])
|
||||
};
|
||||
|
||||
// This is kind of a hack: it frequently happens that some earlier
|
||||
// error prevents types from being fully inferred, and then we get
|
||||
|
@ -1999,27 +1979,54 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
|||
self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
subst,
|
||||
trait_ref.self_ty().skip_binder().into(),
|
||||
vec![],
|
||||
ErrorCode::E0282,
|
||||
false,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let impl_candidates = self
|
||||
.find_similar_impl_candidates(trait_ref)
|
||||
.into_iter()
|
||||
.map(|candidate| candidate.trait_ref)
|
||||
.collect();
|
||||
let mut err = self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
subst,
|
||||
impl_candidates,
|
||||
ErrorCode::E0283,
|
||||
);
|
||||
// Typically, this ambiguity should only happen if
|
||||
// there are unresolved type inference variables
|
||||
// (otherwise it would suggest a coherence
|
||||
// failure). But given #21974 that is not necessarily
|
||||
// the case -- we can have multiple where clauses that
|
||||
// are only distinguished by a region, which results
|
||||
// in an ambiguity even when all types are fully
|
||||
// known, since we don't dispatch based on region
|
||||
// relationships.
|
||||
|
||||
// Pick the first substitution that still contains inference variables as the one
|
||||
// we're going to emit an error for. If there are none (see above), fall back to
|
||||
// a more general error.
|
||||
let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts());
|
||||
|
||||
let mut err = if let Some(subst) = subst {
|
||||
let impl_candidates = self
|
||||
.find_similar_impl_candidates(trait_ref)
|
||||
.into_iter()
|
||||
.map(|candidate| candidate.trait_ref)
|
||||
.collect();
|
||||
self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
subst,
|
||||
impl_candidates,
|
||||
ErrorCode::E0283,
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0283,
|
||||
"type annotations needed: cannot satisfy `{}`",
|
||||
predicate,
|
||||
)
|
||||
};
|
||||
|
||||
let obligation = Obligation::new(
|
||||
obligation.cause.clone(),
|
||||
|
@ -2110,7 +2117,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282)
|
||||
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282, false)
|
||||
}
|
||||
|
||||
ty::PredicateKind::Subtype(data) => {
|
||||
|
@ -2124,26 +2131,38 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
|||
let SubtypePredicate { a_is_expected: _, a, b } = data;
|
||||
// both must be type variables, or the other would've been instantiated
|
||||
assert!(a.is_ty_var() && b.is_ty_var());
|
||||
self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
|
||||
self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
a.into(),
|
||||
vec![],
|
||||
ErrorCode::E0282,
|
||||
true,
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::Projection(data) => {
|
||||
let self_ty = data.projection_ty.self_ty();
|
||||
let term = data.term;
|
||||
if predicate.references_error() || self.is_tainted_by_errors() {
|
||||
return;
|
||||
}
|
||||
if self_ty.needs_infer() && term.needs_infer() {
|
||||
// We do this for the `foo.collect()?` case to produce a suggestion.
|
||||
let subst = data
|
||||
.projection_ty
|
||||
.substs
|
||||
.iter()
|
||||
.chain(Some(data.term.into_arg()))
|
||||
.find(|g| g.has_infer_types_or_consts());
|
||||
if let Some(subst) = subst {
|
||||
let mut err = self.emit_inference_failure_err(
|
||||
body_id,
|
||||
span,
|
||||
self_ty.into(),
|
||||
subst,
|
||||
vec![],
|
||||
ErrorCode::E0284,
|
||||
true,
|
||||
);
|
||||
err.note(&format!("cannot satisfy `{}`", predicate));
|
||||
err
|
||||
} else {
|
||||
// If we can't find a substitution, just print a generic error
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
|
|
|
@ -1538,9 +1538,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty
|
||||
} else {
|
||||
if !self.is_tainted_by_errors() {
|
||||
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), vec![], E0282)
|
||||
.note("type must be known at this point")
|
||||
.emit();
|
||||
self.emit_inference_failure_err(
|
||||
(**self).body_id,
|
||||
sp,
|
||||
ty.into(),
|
||||
vec![],
|
||||
E0282,
|
||||
true,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let err = self.tcx.ty_error();
|
||||
self.demand_suptype(sp, err, ty);
|
||||
|
|
|
@ -694,6 +694,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||
t.into(),
|
||||
vec![],
|
||||
E0282,
|
||||
false,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
@ -708,6 +709,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||
c.into(),
|
||||
vec![],
|
||||
E0282,
|
||||
false,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue