mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-29 17:05:41 +00:00
rollup merge of #21817: edwardw/symmetric-binop
For "symmetric" binary operators, meaning the types of two sides 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:
commit
c64b73e520
@ -2858,11 +2858,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
|
||||
@ -5114,6 +5122,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>,
|
||||
@ -5121,19 +5156,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 {
|
||||
|
@ -29,6 +29,6 @@ trait Add<RHS=Self> {
|
||||
|
||||
fn ice<A>(a: A) {
|
||||
let r = loop {};
|
||||
r = r + a; // here the type `r` is not yet inferred, hence `r+a` generates an error.
|
||||
//~^ ERROR type of this value must be known
|
||||
r = r + a;
|
||||
//~^ ERROR binary operation `+` cannot be applied to type `A`
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ impl<A> vec_monad<A> for Vec<A> {
|
||||
fn bind<B, F>(&self, mut f: F) where F: FnMut(A) -> Vec<B> {
|
||||
let mut r = panic!();
|
||||
for elt in self.iter() { r = r + f(*elt); }
|
||||
//~^ ERROR the type of this value must be known
|
||||
//~^ ERROR binary operation `+` cannot be applied to type `collections::vec::Vec<B>`
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
|
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