Skip to content

Commit

Permalink
Add naïve mechanism to filter Into suggestions involving math ops
Browse files Browse the repository at this point in the history
```
error[E0284]: type annotations needed
  --> $DIR/issue-70082.rs:7:33
   |
LL |     let y: f64 = 0.01f64 * 1i16.into();
   |                          -      ^^^^
   |                          |
   |                          type must be known at this point
   |
   = note: cannot satisfy `<f64 as Mul<_>>::Output == f64`
help: try using a fully qualified path to specify the expected types
   |
LL |     let y: f64 = 0.01f64 * <i16 as Into<f64>>::into(1i16);
   |                            +++++++++++++++++++++++++    ~
```

Note that we only suggest `Into<f64>`, and not `Into<i32>`, `Into<i64>`, `Into<i128>`, `Into<isize>`, `Into<f32>` or `Into<AtomicI16>`.
  • Loading branch information
estebank committed Aug 5, 2024
1 parent a831d59 commit e302e7f
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 57 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0282,
true,
self.param_env,
None,
)
.emit()
});
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0282,
!raw_ptr_call,
self.param_env,
None,
);
if raw_ptr_call {
err.span_label(span, "cannot call a method on a raw pointer with an unknown pointee type");
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
TypeAnnotationNeeded::E0282,
false,
self.fcx.param_env,
None,
)
.emit()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
error_code: TypeAnnotationNeeded,
should_label_span: bool,
param_env: ty::ParamEnv<'tcx>,
predicate: Option<ty::Predicate<'tcx>>,
) -> Diag<'a> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
Expand Down Expand Up @@ -460,7 +461,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
&& let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
{
paths = self.get_suggestions(ty, def_id, true, param_env, None);
paths = self.get_suggestions(ty, def_id, true, param_env, None, predicate);
}

if paths.is_empty() {
Expand Down Expand Up @@ -587,8 +588,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {

// Look for all the possible implementations to suggest, otherwise we'll show
// just suggest the syntax for the fully qualified path with placeholders.
let paths =
self.get_suggestions(args.type_at(0), def_id, false, param_env, Some(args));
let paths = self.get_suggestions(
args.type_at(0),
def_id,
false,
param_env,
Some(args),
predicate,
);
if paths.len() > 20 || paths.is_empty() {
// This will show the fallback impl, so the expression will have type
// parameter placeholders, but it's better than nothing.
Expand Down Expand Up @@ -667,6 +674,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
target_type: bool,
param_env: ty::ParamEnv<'tcx>,
args: Option<&ty::GenericArgs<'tcx>>,
predicate: Option<ty::Predicate<'tcx>>,
) -> Vec<String> {
let tcx = self.infcx.tcx;
let mut paths = vec![];
Expand Down Expand Up @@ -695,6 +703,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Nope, don't bother.
return;
}

let filter = if let Some(ty::ProjectionPredicate {
projection_term: ty::AliasTerm { def_id, .. },
term,
}) =
predicate.and_then(|p| p.as_projection_clause()).map(|p| p.skip_binder())
&& let ty::TermKind::Ty(assoc_ty) = term.unpack()
&& tcx.item_name(def_id) == sym::Output
{
// If the predicate that failed to be inferred is an associated type called
// "Output" (presumably from one of the math traits), we will only mention the
// `Into` and `From` impls that correspond to the self type as well, so as to
// avoid showing multiple conversion options.
Some(assoc_ty)

This comment has been minimized.

Copy link
@compiler-errors

compiler-errors Aug 5, 2024

Member

I'm mostly concerned about the cases where this is wrong. Presumably it's only correct for types that have reflexive operator impls?

This comment has been minimized.

Copy link
@estebank

estebank Aug 7, 2024

Author Contributor

Yes. We can further check that the parent def id is for one of the std math traits.

} else {
None
};
let assocs = tcx.associated_items(impl_def_id);

if tcx.is_diagnostic_item(sym::blanket_into_impl, impl_def_id)
Expand All @@ -712,6 +737,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return;
};
let target = header.trait_ref.skip_binder().args.type_at(0);
if filter.is_some() && filter != Some(target) {
return;
};
let target = header.trait_ref.skip_binder().args.type_at(0);
let ty = header.trait_ref.skip_binder().args.type_at(1);
if ty == self_ty {
if target_type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0282,
false,
obligation.param_env,
None,
);
return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
}
Expand Down Expand Up @@ -239,6 +240,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0283,
true,
obligation.param_env,
None,
)
} else {
struct_span_code_err!(
Expand Down Expand Up @@ -452,6 +454,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0282,
false,
obligation.param_env,
None,
)
}

Expand All @@ -472,6 +475,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0282,
true,
obligation.param_env,
None,
)
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
Expand Down Expand Up @@ -503,6 +507,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0284,
true,
obligation.param_env,
Some(predicate),
)
.with_note(format!("cannot satisfy `{predicate}`"))
} else {
Expand Down Expand Up @@ -534,6 +539,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0284,
true,
obligation.param_env,
None,
);
err
} else {
Expand All @@ -557,6 +563,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
TypeAnnotationNeeded::E0284,
true,
obligation.param_env,
None,
),
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
if term.is_infer() =>
Expand Down
6 changes: 0 additions & 6 deletions tests/ui/inference/issue-70082.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,4 @@ fn main() {
let y: f64 = 0.01f64 * 1i16.into();
//~^ ERROR type annotations needed
//~| HELP try using a fully qualified path
//~| HELP try using a fully qualified path
//~| HELP try using a fully qualified path
//~| HELP try using a fully qualified path
//~| HELP try using a fully qualified path
//~| HELP try using a fully qualified path
//~| HELP try using a fully qualified path
}
24 changes: 0 additions & 24 deletions tests/ui/inference/issue-70082.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,8 @@ LL | let y: f64 = 0.01f64 * 1i16.into();
= note: cannot satisfy `<f64 as Mul<_>>::Output == f64`
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<i32>>::into(1i16);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<i64>>::into(1i16);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<i128>>::into(1i16);
| ++++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<isize>>::into(1i16);
| +++++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<f32>>::into(1i16);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<f64>>::into(1i16);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | let y: f64 = 0.01f64 * <i16 as Into<AtomicI16>>::into(1i16);
| +++++++++++++++++++++++++++++++ ~

error: aborting due to 1 previous error

Expand Down
24 changes: 0 additions & 24 deletions tests/ui/inference/issue-71584.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,6 @@ help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<u64>>::into(n);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<u128>>::into(n);
| ++++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<i64>>::into(n);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<i128>>::into(n);
| ++++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<f64>>::into(n);
| +++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<Ipv4Addr>>::into(n);
| ++++++++++++++++++++++++++++++ ~
help: try using a fully qualified path to specify the expected types
|
LL | d = d % <u32 as Into<AtomicU32>>::into(n);
| +++++++++++++++++++++++++++++++ ~

error: aborting due to 1 previous error

Expand Down

0 comments on commit e302e7f

Please sign in to comment.