Skip to content

Commit

Permalink
Rollup merge of #98497 - compiler-errors:span-inference-note, r=lcnr
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
GuillaumeGomez authored Jul 1, 2022
2 parents bda659e + 6711313 commit b0935b1
Show file tree
Hide file tree
Showing 52 changed files with 195 additions and 135 deletions.
12 changes: 9 additions & 3 deletions compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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();
Expand All @@ -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 {
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
99 changes: 59 additions & 40 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(),
Expand Down Expand Up @@ -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) => {
Expand All @@ -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,
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/src/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
t.into(),
vec![],
E0282,
false,
)
.emit();
}
Expand All @@ -708,6 +709,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
c.into(),
vec![],
E0282,
false,
)
.emit();
}
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/array-slice-vec/infer_array_len.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ error[E0282]: type annotations needed
LL | let [_, _] = a.into();
| ^^^^^^
|
= note: type must be known at this point
help: consider giving this pattern a type
|
LL | let [_, _]: _ = a.into();
Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ error[E0282]: type annotations needed
|
LL | [] => {}
| ^^ cannot infer type
|
= note: type must be known at this point

error: aborting due to 5 previous errors

Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/cast/issue-85586.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ error[E0282]: type annotations needed
|
LL | let b = (a + 1) as usize;
| ^^^^^^^ cannot infer type
|
= note: type must be known at this point

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/coherence/coherence-overlap-trait-alias.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0283]: type annotations needed
error[E0283]: type annotations needed: cannot satisfy `u32: C`
--> $DIR/coherence-overlap-trait-alias.rs:15:6
|
LL | impl C for u32 {}
| ^ cannot infer type for type `u32`
| ^
|
note: multiple `impl`s satisfying `u32: C` found
--> $DIR/coherence-overlap-trait-alias.rs:14:1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0283]: type annotations needed for `Mask<_, LANES>`
--> $DIR/issue-91614.rs:6:9
|
LL | let y = Mask::<_, _>::splat(false);
| ^
| ^ ------------------- type must be known at this point
|
= note: cannot satisfy `_: MaskElement`
note: required by a bound in `Mask::<T, LANES>::splat`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
= help: const parameters may only be used as standalone arguments, i.e. `J`
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions

error[E0283]: type annotations needed
error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
--> $DIR/issue-72787.rs:21:26
|
LL | IsLessOrEqual<I, 8>: True,
| ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>`
| ^^^^
|
= note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`

error[E0283]: type annotations needed
error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
--> $DIR/issue-72787.rs:21:26
|
LL | IsLessOrEqual<I, 8>: True,
| ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>`
| ^^^^
|
= note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/const-generics/generic_const_exprs/issue-72787.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ struct S<const I: u32, const J: u32>;
impl<const I: u32, const J: u32> S<I, J>
where
IsLessOrEqual<I, 8>: True,
//[min]~^ Error type annotations needed [E0283]
//[min]~| Error type annotations needed [E0283]
//[min]~^ Error type annotations needed
//[min]~| Error type annotations needed
IsLessOrEqual<J, 8>: True,
IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
//[min]~^ Error generic parameters may not be used in const operations
Expand Down
4 changes: 0 additions & 4 deletions src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ error[E0282]: type annotations needed
|
LL | cont.reify_as();
| ^^^^ cannot infer type
|
= note: type must be known at this point

error[E0282]: type annotations needed
--> $DIR/hidden-type-is-opaque-2.rs:18:9
|
LL | cont.reify_as();
| ^^^^ cannot infer type
|
= note: type must be known at this point

error: aborting due to 2 previous errors

Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/inference/cannot-infer-partial-try-return.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
|
LL | let x = || -> Result<_, QualifiedError<_>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | infallible()?;
| ------------- type must be known at this point
|
help: try giving this closure an explicit return type
|
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/inference/erase-type-params-in-label.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>`
--> $DIR/erase-type-params-in-label.rs:2:9
|
LL | let foo = foo(1, "");
| ^^^
| ^^^ --- type must be known at this point
|
= note: cannot satisfy `_: Default`
note: required by a bound in `foo`
Expand All @@ -23,7 +23,7 @@ error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
--> $DIR/erase-type-params-in-label.rs:5:9
|
LL | let bar = bar(1, "");
| ^^^
| ^^^ --- type must be known at this point
|
= note: cannot satisfy `_: Default`
note: required by a bound in `bar`
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/inference/issue-72616.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0283]: type annotations needed
--> $DIR/issue-72616.rs:20:37
|
LL | if String::from("a") == "a".try_into().unwrap() {}
| ^^^^^^^^
| -- ^^^^^^^^
| |
| type must be known at this point
|
= note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
- impl PartialEq for String;
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/inference/issue-72690.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ error[E0283]: type annotations needed for `&T`
--> $DIR/issue-72690.rs:17:9
|
LL | let _ = "x".as_ref();
| ^
| ^ ------ type must be known at this point
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
Expand Down
Loading

0 comments on commit b0935b1

Please sign in to comment.