mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
Make use of a binary operator's RHS type for LHS inference
For "symmetric" binary operators, meaning the types of two side must be equal, if the type of LHS doesn't know yet but RHS does, use that as an hint to infer LHS' type. Closes #21634
This commit is contained in:
parent
474b324eda
commit
1935bbd913
@ -2815,11 +2815,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
BinopAssignment => PreferMutLvalue,
|
||||
SimpleBinop => NoPreference
|
||||
};
|
||||
check_expr_with_lvalue_pref(fcx, &*lhs, lvalue_pref);
|
||||
check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
|
||||
|
||||
// Callee does bot / err checking
|
||||
let lhs_t = structurally_resolved_type(fcx, lhs.span,
|
||||
fcx.expr_ty(&*lhs));
|
||||
let lhs_t =
|
||||
structurally_resolve_type_or_else(fcx, lhs.span, fcx.expr_ty(lhs), || {
|
||||
if ast_util::is_symmetric_binop(op.node) {
|
||||
// Try RHS first
|
||||
check_expr(fcx, &**rhs);
|
||||
fcx.expr_ty(&**rhs)
|
||||
} else {
|
||||
fcx.tcx().types.err
|
||||
}
|
||||
});
|
||||
|
||||
if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op.node) {
|
||||
// Shift is a special case: rhs must be uint, no matter what lhs is
|
||||
@ -5071,6 +5079,33 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
sp: Span,
|
||||
ty: Ty<'tcx>,
|
||||
f: F) -> Ty<'tcx>
|
||||
where F: Fn() -> Ty<'tcx>
|
||||
{
|
||||
let mut ty = fcx.resolve_type_vars_if_possible(ty);
|
||||
|
||||
if ty::type_is_ty_var(ty) {
|
||||
let alternative = f();
|
||||
|
||||
// If not, error.
|
||||
if ty::type_is_ty_var(alternative) || ty::type_is_error(alternative) {
|
||||
fcx.type_error_message(sp, |_actual| {
|
||||
"the type of this value must be known in this context".to_string()
|
||||
}, ty, None);
|
||||
demand::suptype(fcx, sp, fcx.tcx().types.err, ty);
|
||||
ty = fcx.tcx().types.err;
|
||||
} else {
|
||||
demand::suptype(fcx, sp, alternative, ty);
|
||||
ty = alternative;
|
||||
}
|
||||
}
|
||||
|
||||
ty
|
||||
}
|
||||
|
||||
// Resolves `typ` by a single level if `typ` is a type variable. If no
|
||||
// resolution is possible, then an error is reported.
|
||||
pub fn structurally_resolved_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
@ -5078,19 +5113,9 @@ pub fn structurally_resolved_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let mut ty = fcx.resolve_type_vars_if_possible(ty);
|
||||
|
||||
// If not, error.
|
||||
if ty::type_is_ty_var(ty) {
|
||||
fcx.type_error_message(sp, |_actual| {
|
||||
"the type of this value must be known in this \
|
||||
context".to_string()
|
||||
}, ty, None);
|
||||
demand::suptype(fcx, sp, fcx.tcx().types.err, ty);
|
||||
ty = fcx.tcx().types.err;
|
||||
}
|
||||
|
||||
ty
|
||||
structurally_resolve_type_or_else(fcx, sp, ty, || {
|
||||
fcx.tcx().types.err
|
||||
})
|
||||
}
|
||||
|
||||
// Returns true if b contains a break that can exit from b
|
||||
|
@ -102,6 +102,20 @@ pub fn is_by_value_binop(b: BinOp_) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the binary operator is symmetric in the sense that LHS
|
||||
/// and RHS must have the same type. So the type of LHS can serve as an hint
|
||||
/// for the type of RHS and vice versa.
|
||||
pub fn is_symmetric_binop(b: BinOp_) -> bool {
|
||||
match b {
|
||||
BiAdd | BiSub | BiMul | BiDiv | BiRem |
|
||||
BiBitXor | BiBitAnd | BiBitOr |
|
||||
BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => {
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the unary operator takes its argument by value
|
||||
pub fn is_by_value_unop(u: UnOp) -> bool {
|
||||
match u {
|
||||
|
22
src/test/run-pass/issue-21634.rs
Normal file
22
src/test/run-pass/issue-21634.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
fn main() {
|
||||
if let Ok(x) = "3.1415".parse() {
|
||||
assert_eq!(false, x <= 0.0);
|
||||
}
|
||||
if let Ok(x) = "3.1415".parse() {
|
||||
assert_eq!(3.1415, x + 0.0);
|
||||
}
|
||||
if let Ok(mut x) = "3.1415".parse() {
|
||||
assert_eq!(8.1415, { x += 5.0; x });
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user