Skip to content

Commit

Permalink
Auto merge of #114811 - estebank:impl-ambiguity, r=wesleywiser
Browse files Browse the repository at this point in the history
Show more information when multiple `impl`s apply

- When there are `impl`s without type params, show only those (to avoid showing overly generic `impl`s).
```
error[E0283]: type annotations needed
  --> $DIR/multiple-impl-apply.rs:34:9
   |
LL |     let y = x.into();
   |         ^     ---- type must be known at this point
   |
note: multiple `impl`s satisfying `_: From<Baz>` found
  --> $DIR/multiple-impl-apply.rs:14:1
   |
LL | impl From<Baz> for Bar {
   | ^^^^^^^^^^^^^^^^^^^^^^
...
LL | impl From<Baz> for Foo {
   | ^^^^^^^^^^^^^^^^^^^^^^
   = note: required for `Baz` to implement `Into<_>`
help: consider giving `y` an explicit type
   |
LL |     let y: /* Type */ = x.into();
   |          ++++++++++++
```

- Lower the importance of `T: Sized`, `T: WellFormed` and coercion errors, to prioritize more relevant errors. The pre-existing deduplication logic deals with hiding redundant errors better that way, and we show errors with more metadata that is useful to the user.

- Show `<SelfTy as Trait>::assoc_fn` suggestion in more cases.
```
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
  --> $DIR/cross-return-site-inference.rs:38:16
   |
LL |     return Err(From::from("foo"));
   |                ^^^^^^^^^^ cannot call associated function of trait
   |
help: use a fully-qualified path to a specific available implementation
   |
LL |     return Err(</* self type */ as From>::from("foo"));
   |                +++++++++++++++++++     +
```

Fix #88284.
  • Loading branch information
bors committed Oct 6, 2023
2 parents 31be8cc + 4483ac2 commit 94bc9c7
Show file tree
Hide file tree
Showing 85 changed files with 3,993 additions and 3,825 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ fn check_opaque_type_well_formed<'tcx>(
if errors.is_empty() {
Ok(definition_ty)
} else {
Err(infcx.err_ctxt().report_fulfillment_errors(&errors))
Err(infcx.err_ctxt().report_fulfillment_errors(errors))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {

let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
}

// Attempting to call a trait method?
Expand Down
25 changes: 14 additions & 11 deletions compiler/rustc_error_codes/src/error_codes/E0282.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@ The compiler could not infer a type and asked for a type annotation.
Erroneous code example:

```compile_fail,E0282
let x = "hello".chars().rev().collect();
let x = Vec::new();
```

This error indicates that type inference did not result in one unique possible
type, and extra information is required. In most cases this can be provided
by adding a type annotation. Sometimes you need to specify a generic type
parameter manually.

A common example is the `collect` method on `Iterator`. It has a generic type
parameter with a `FromIterator` bound, which for a `char` iterator is
implemented by `Vec` and `String` among others. Consider the following snippet
that reverses the characters of a string:
In the example above, type `Vec` has a type parameter `T`. When calling
`Vec::new`, barring any other later usage of the variable `x` that allows the
compiler to infer what type `T` is, the compiler needs to be told what it is.

In the first code example, the compiler cannot infer what the type of `x` should
be: `Vec<char>` and `String` are both suitable candidates. To specify which type
to use, you can use a type annotation on `x`:
The type can be specified on the variable:

```
let x: Vec<char> = "hello".chars().rev().collect();
let x: Vec<i32> = Vec::new();
```

It is not necessary to annotate the full type. Once the ambiguity is resolved,
the compiler can infer the rest:
The type can also be specified in the path of the expression:

```
let x = Vec::<i32>::new();
```

In cases with more complex types, it is not necessary to annotate the full
type. Once the ambiguity is resolved, the compiler can infer the rest:

```
let x: Vec<_> = "hello".chars().rev().collect();
Expand Down
46 changes: 45 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0283.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,51 @@
An implementation cannot be chosen unambiguously because of lack of information.
The compiler could not infer a type and asked for a type annotation.

Erroneous code example:

```compile_fail,E0283
let x = "hello".chars().rev().collect();
```

This error indicates that type inference did not result in one unique possible
type, and extra information is required. In most cases this can be provided
by adding a type annotation. Sometimes you need to specify a generic type
parameter manually.

A common example is the `collect` method on `Iterator`. It has a generic type
parameter with a `FromIterator` bound, which for a `char` iterator is
implemented by `Vec` and `String` among others. Consider the following snippet
that reverses the characters of a string:

In the first code example, the compiler cannot infer what the type of `x` should
be: `Vec<char>` and `String` are both suitable candidates. To specify which type
to use, you can use a type annotation on `x`:

```
let x: Vec<char> = "hello".chars().rev().collect();
```

It is not necessary to annotate the full type. Once the ambiguity is resolved,
the compiler can infer the rest:

```
let x: Vec<_> = "hello".chars().rev().collect();
```

Another way to provide the compiler with enough information, is to specify the
generic type parameter:

```
let x = "hello".chars().rev().collect::<Vec<char>>();
```

Again, you need not specify the full type if the compiler can infer it:

```
let x = "hello".chars().rev().collect::<Vec<_>>();
```

We can see a self-contained example below:

```compile_fail,E0283
struct Foo;
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ fn check_opaque_meets_bounds<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let guar = infcx.err_ctxt().report_fulfillment_errors(&errors);
let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(guar);
}
match origin {
Expand Down Expand Up @@ -1512,6 +1512,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let errors = fulfillment_cx.select_all_or_error(&infcx);
debug!(?errors);
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
}
}
12 changes: 6 additions & 6 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ fn compare_method_predicate_entailment<'tcx>(
// FIXME(-Ztrait-solver=next): Not needed when the hack below is removed.
let errors = ocx.select_where_possible();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}

Expand Down Expand Up @@ -394,7 +394,7 @@ fn compare_method_predicate_entailment<'tcx>(
});
}
CheckImpliedWfMode::Skip => {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
}
Expand Down Expand Up @@ -874,7 +874,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// RPITs.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}

Expand Down Expand Up @@ -2050,7 +2050,7 @@ fn compare_const_predicate_entailment<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
return Err(infcx.err_ctxt().report_fulfillment_errors(&errors));
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
}

let outlives_env = OutlivesEnvironment::new(param_env);
Expand Down Expand Up @@ -2143,7 +2143,7 @@ fn compare_type_predicate_entailment<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}

Expand Down Expand Up @@ -2358,7 +2358,7 @@ pub(super) fn check_type_bounds<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
error = true;
}
// now we can take the return type of the given main function
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ pub fn check_function_signature<'tcx>(
Ok(()) => {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
return;
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(

let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
return;
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
}

// Finally, resolve all regions.
Expand Down Expand Up @@ -470,7 +470,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
}

// Finally, resolve all regions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ fn get_impl_args(

let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(guar);
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2958,7 +2958,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// There should be at least one error reported. If not, we
// will still delay a span bug in `report_fulfillment_errors`.
Ok::<_, NoSolution>((
self.err_ctxt().report_fulfillment_errors(&errors),
self.err_ctxt().report_fulfillment_errors(errors),
impl_trait_ref.args.type_at(1),
element_ty,
))
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
self.err_ctxt().report_fulfillment_errors(&errors);
self.err_ctxt().report_fulfillment_errors(errors);
}
}

Expand All @@ -577,7 +577,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
self.err_ctxt().report_fulfillment_errors(&result);
self.err_ctxt().report_fulfillment_errors(result);
}
}

Expand Down Expand Up @@ -1477,7 +1477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
Ok(normalized_ty) => normalized_ty,
Err(errors) => {
let guar = self.err_ctxt().report_fulfillment_errors(&errors);
let guar = self.err_ctxt().report_fulfillment_errors(errors);
return Ty::new_error(self.tcx,guar);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::iter;

pub enum TypeAnnotationNeeded {
/// ```compile_fail,E0282
/// let x = "hello".chars().rev().collect();
/// let x;
/// ```
E0282,
/// An implementation cannot be chosen unambiguously because of lack of information.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2373,7 +2373,7 @@ impl CheckAttrVisitor<'_> {

let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
self.abort.set(true);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/layout_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub fn ensure_wf<'tcx>(
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
false
} else {
// looks WF!
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
def_id: LocalDefId,
) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
self.assumed_wf_types(param_env, def_id)
.map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors))
.map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors))
}

pub fn assumed_wf_types(
Expand Down
Loading

0 comments on commit 94bc9c7

Please sign in to comment.