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

Binary operations involving &1.0 always infer f64 #57447

Open
ExpHP opened this Issue Jan 8, 2019 · 1 comment

Comments

Projects
None yet
4 participants
@ExpHP
Copy link
Contributor

ExpHP commented Jan 8, 2019

Originally posted as a comment on #36549, but in hindsight this may be a different issue. (in that #36549 very clearly looks like a bug, whereas this one is in a potential gray area)

Relevant URLO thread.

let _: f32 = 1. - 1.;   // allowed
let _: f32 = 1. - &1.;  // type error
let _: f32 = &1. - 1.;  // type error
let _: f32 = &1. - &1.; // type error

In the latter 3 cases, the type of &1. is apparently defaulted to &f64:

   Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `<f64 as std::ops::Sub<&f64>>::Output == f32`
 --> src/main.rs:3:21
  |
3 |     let _: f32 = 1. - &1.; // type error
  |                     ^ expected f64, found f32

error[E0271]: type mismatch resolving `<&f64 as std::ops::Sub<f64>>::Output == f32`
 --> src/main.rs:4:22
  |
4 |     let _: f32 = &1. - 1.; // type error
  |                      ^ expected f64, found f32

error[E0271]: type mismatch resolving `<&f64 as std::ops::Sub<&f64>>::Output == f32`
 --> src/main.rs:5:22
  |
5 |     let _: f32 = &1. - &1.; // type error
  |                      ^ expected f64, found f32

To a mortal like me, it seems that the only reason the first line works is because the compiler must have a special case for binary operations between two unconstrained "floating-point flavored" type inference variables. Can the compiler not just special case the latter three examples in the same way it special cases the first?

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jan 10, 2019

OK, it took me a minute to remember this, but indeed there is a built-in rule that favors floating point values:

// Supply type inference hints if relevant. Probably these
// hints should be enforced during select as part of the
// `consider_unification_despite_ambiguity` routine, but this
// more convenient for now.
//
// The basic idea is to help type inference by taking
// advantage of things we know about how the impls for
// scalar types are arranged. This is important in a
// scenario like `1_u32 << 2`, because it lets us quickly
// deduce that the result type should be `u32`, even
// though we don't know yet what type 2 has and hence
// can't pin this down to a specific impl.
if
!lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() &&
is_builtin_binop(lhs_ty, rhs_ty, op)
{
let builtin_return_ty =
self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
self.demand_suptype(expr.span, builtin_return_ty, return_ty);
}

It basically encodes in the inference scheme the idea that x + y has the result type of x so long as x meets certain patterns. In this particular case:

BinOpCategory::Math => {
lhs.references_error() || rhs.references_error() ||
lhs.is_integral() && rhs.is_integral() ||
lhs.is_floating_point() && rhs.is_floating_point()
}

Certainly it is possible that we could generalize this to accept &f32 etc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment