Skip to content

Show more information when multiple impls apply #114811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 6, 2023
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
@@ -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))
}
}

Original file line number Diff line number Diff line change
@@ -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?
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
@@ -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();
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;

4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
@@ -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 {
@@ -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
@@ -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);
}

@@ -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);
}
}
@@ -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);
}

@@ -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);
@@ -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);
}

@@ -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);
}

2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/entry.rs
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -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;
}

4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
@@ -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.
@@ -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.
Original file line number Diff line number Diff line change
@@ -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);
}

2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
@@ -3010,7 +3010,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,
))
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
@@ -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);
}
}

@@ -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);
}
}

@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/layout_test.rs
Original file line number Diff line number Diff line change
@@ -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!
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/engine.rs
Original file line number Diff line number Diff line change
@@ -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(
Loading