12
12
13
13
use super :: FnCtxt ;
14
14
use super :: method:: MethodCallee ;
15
- use rustc:: ty:: { self , Ty , TypeFoldable , PreferMutLvalue , TypeVariants } ;
15
+ use rustc:: ty:: { self , Ty , TypeFoldable , NoPreference , PreferMutLvalue , TypeVariants } ;
16
16
use rustc:: ty:: TypeVariants :: { TyStr , TyRef } ;
17
17
use rustc:: ty:: adjustment:: { Adjustment , Adjust , AutoBorrow } ;
18
18
use rustc:: infer:: type_variable:: TypeVariableOrigin ;
@@ -29,12 +29,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
29
29
lhs_expr : & ' gcx hir:: Expr ,
30
30
rhs_expr : & ' gcx hir:: Expr ) -> Ty < ' tcx >
31
31
{
32
- let lhs_ty = self . check_expr_with_lvalue_pref ( lhs_expr, PreferMutLvalue ) ;
33
-
34
- let lhs_ty = self . resolve_type_vars_with_obligations ( lhs_ty) ;
35
- let ( rhs_ty, return_ty) =
36
- self . check_overloaded_binop ( expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign :: Yes ) ;
37
- let rhs_ty = self . resolve_type_vars_with_obligations ( rhs_ty) ;
32
+ let ( lhs_ty, rhs_ty, return_ty) =
33
+ self . check_overloaded_binop ( expr, lhs_expr, rhs_expr, op, IsAssign :: Yes ) ;
38
34
39
35
let ty = if !lhs_ty. is_ty_var ( ) && !rhs_ty. is_ty_var ( )
40
36
&& is_builtin_binop ( lhs_ty, rhs_ty, op) {
@@ -73,27 +69,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
73
69
lhs_expr,
74
70
rhs_expr) ;
75
71
76
- let lhs_ty = self . check_expr ( lhs_expr) ;
77
- let lhs_ty = self . resolve_type_vars_with_obligations ( lhs_ty) ;
78
-
79
72
match BinOpCategory :: from ( op) {
80
73
BinOpCategory :: Shortcircuit => {
81
74
// && and || are a simple case.
75
+ self . check_expr_coercable_to_type ( lhs_expr, tcx. types . bool ) ;
82
76
let lhs_diverges = self . diverges . get ( ) ;
83
- self . demand_suptype ( lhs_expr. span , tcx. mk_bool ( ) , lhs_ty) ;
84
- self . check_expr_coercable_to_type ( rhs_expr, tcx. mk_bool ( ) ) ;
77
+ self . check_expr_coercable_to_type ( rhs_expr, tcx. types . bool ) ;
85
78
86
79
// Depending on the LHS' value, the RHS can never execute.
87
80
self . diverges . set ( lhs_diverges) ;
88
81
89
- tcx. mk_bool ( )
82
+ tcx. types . bool
90
83
}
91
84
_ => {
92
85
// Otherwise, we always treat operators as if they are
93
86
// overloaded. This is the way to be most flexible w/r/t
94
87
// types that get inferred.
95
- let ( rhs_ty, return_ty) =
96
- self . check_overloaded_binop ( expr, lhs_expr, lhs_ty ,
88
+ let ( lhs_ty , rhs_ty, return_ty) =
89
+ self . check_overloaded_binop ( expr, lhs_expr,
97
90
rhs_expr, op, IsAssign :: No ) ;
98
91
99
92
// Supply type inference hints if relevant. Probably these
@@ -108,7 +101,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
108
101
// deduce that the result type should be `u32`, even
109
102
// though we don't know yet what type 2 has and hence
110
103
// can't pin this down to a specific impl.
111
- let rhs_ty = self . resolve_type_vars_with_obligations ( rhs_ty) ;
112
104
if
113
105
!lhs_ty. is_ty_var ( ) && !rhs_ty. is_ty_var ( ) &&
114
106
is_builtin_binop ( lhs_ty, rhs_ty, op)
@@ -164,17 +156,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
164
156
fn check_overloaded_binop ( & self ,
165
157
expr : & ' gcx hir:: Expr ,
166
158
lhs_expr : & ' gcx hir:: Expr ,
167
- lhs_ty : Ty < ' tcx > ,
168
159
rhs_expr : & ' gcx hir:: Expr ,
169
160
op : hir:: BinOp ,
170
161
is_assign : IsAssign )
171
- -> ( Ty < ' tcx > , Ty < ' tcx > )
162
+ -> ( Ty < ' tcx > , Ty < ' tcx > , Ty < ' tcx > )
172
163
{
173
- debug ! ( "check_overloaded_binop(expr.id={}, lhs_ty ={:?}, is_assign={:?})" ,
164
+ debug ! ( "check_overloaded_binop(expr.id={}, op ={:?}, is_assign={:?})" ,
174
165
expr. id,
175
- lhs_ty ,
166
+ op ,
176
167
is_assign) ;
177
168
169
+ let lhs_pref = match is_assign {
170
+ IsAssign :: Yes => PreferMutLvalue ,
171
+ IsAssign :: No => NoPreference
172
+ } ;
173
+ // Find a suitable supertype of the LHS expression's type, by coercing to
174
+ // a type variable, to pass as the `Self` to the trait, avoiding invariant
175
+ // trait matching creating lifetime constraints that are too strict.
176
+ // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
177
+ // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
178
+ let lhs_ty = self . check_expr_coercable_to_type_with_lvalue_pref ( lhs_expr,
179
+ self . next_ty_var ( TypeVariableOrigin :: MiscVariable ( lhs_expr. span ) ) ,
180
+ lhs_pref) ;
181
+ let lhs_ty = self . resolve_type_vars_with_obligations ( lhs_ty) ;
182
+
178
183
// NB: As we have not yet type-checked the RHS, we don't have the
179
184
// type at hand. Make a variable to represent it. The whole reason
180
185
// for this indirection is so that, below, we can check the expr
@@ -187,6 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
187
192
188
193
// see `NB` above
189
194
let rhs_ty = self . check_expr_coercable_to_type ( rhs_expr, rhs_ty_var) ;
195
+ let rhs_ty = self . resolve_type_vars_with_obligations ( rhs_ty) ;
190
196
191
197
let return_ty = match result {
192
198
Ok ( method) => {
@@ -296,7 +302,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
296
302
}
297
303
} ;
298
304
299
- ( rhs_ty_var , return_ty)
305
+ ( lhs_ty , rhs_ty , return_ty)
300
306
}
301
307
302
308
fn check_str_addition ( & self ,
0 commit comments