@@ -3215,6 +3215,89 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3215
3215
fcx. write_ty( id, if_ty) ;
3216
3216
}
3217
3217
3218
+ // FIXME This is very similar to `look_op_method`. We should try to merge them.
3219
+ fn lookup_binop_method < ' a , ' tcx > ( fcx: & ' a FnCtxt < ' a , ' tcx > ,
3220
+ op_ex: & ast:: Expr ,
3221
+ lhs_ty: Ty < ' tcx > ,
3222
+ opname: ast:: Name ,
3223
+ trait_did: Option < ast:: DefId > ,
3224
+ lhs: & ' a ast:: Expr ,
3225
+ rhs: & P < ast:: Expr > ,
3226
+ unbound_method: ||) -> Ty <' tcx> {
3227
+ let method = match trait_did {
3228
+ Some ( trait_did) => {
3229
+ // We do eager coercions to make using operators
3230
+ // more ergonomic:
3231
+ //
3232
+ // - If the input is of type &'a T (resp. &'a mut T),
3233
+ // then reborrow it to &'b T (resp. &'b mut T) where
3234
+ // 'b <= 'a. This makes things like `x == y`, where
3235
+ // `x` and `y` are both region pointers, work. We
3236
+ // could also solve this with variance or different
3237
+ // traits that don't force left and right to have same
3238
+ // type.
3239
+ let ( adj_ty, adjustment) = match lhs_ty. sty {
3240
+ ty:: ty_rptr( r_in, mt) => {
3241
+ let r_adj = fcx. infcx( ) . next_region_var( infer:: Autoref ( lhs. span) ) ;
3242
+ fcx. mk_subr( infer:: Reborrow ( lhs. span) , r_adj, r_in) ;
3243
+ let adjusted_ty = ty:: mk_rptr( fcx. tcx( ) , r_adj, mt) ;
3244
+ let autoptr = ty:: AutoPtr ( r_adj, mt. mutbl, None ) ;
3245
+ let adjustment = ty:: AutoDerefRef { autoderefs: 1 , autoref: Some ( autoptr) } ;
3246
+ ( adjusted_ty, adjustment)
3247
+ }
3248
+ _ => {
3249
+ ( lhs_ty, ty:: AutoDerefRef { autoderefs : 0 , autoref : None } )
3250
+ }
3251
+ } ;
3252
+
3253
+ debug ! ( "adjusted_ty={} adjustment={}" ,
3254
+ adj_ty. repr( fcx. tcx( ) ) ,
3255
+ adjustment) ;
3256
+
3257
+ method:: lookup_in_trait_adjusted( fcx, op_ex. span, Some ( lhs) , opname,
3258
+ trait_did, adjustment, adj_ty, None )
3259
+ }
3260
+ None => None
3261
+ } ;
3262
+
3263
+ match method {
3264
+ Some ( method) => {
3265
+ let result_ty = {
3266
+ let fty = match method. ty. sty {
3267
+ ty : : ty_bare_fn( ref fty) => fty,
3268
+ _ => unreachable!( ) ,
3269
+ } ;
3270
+
3271
+ // NB We don't call `check_method_argument_types` here to avoid type checking
3272
+ // the `lhs` and `rhs` expressions again
3273
+ match fty. sig. inputs[ 1 ] . sty {
3274
+ ty : : ty_rptr( _, mt) => demand:: coerce( fcx, rhs. span, mt. ty, & * * rhs) ,
3275
+ // So we hit this case when one implements the
3276
+ // operator traits but leaves an argument as
3277
+ // just T instead of &T. We'll catch it in the
3278
+ // mismatch impl/trait method phase no need to
3279
+ // ICE here.
3280
+ // See: #11450
3281
+ _ => { } ,
3282
+ }
3283
+
3284
+ match fty. sig. output {
3285
+ ty : : FnConverging ( result_ty) => result_ty,
3286
+ ty : : FnDiverging => ty:: mk_err( ) ,
3287
+ }
3288
+ } ;
3289
+ // HACK(eddyb) Fully qualified path to work around a resolve bug.
3290
+ let method_call = :: middle:: typeck:: MethodCall :: expr( op_ex. id) ;
3291
+ fcx. inh. method_map. borrow_mut( ) . insert( method_call, method) ;
3292
+ result_ty
3293
+ }
3294
+ None => {
3295
+ unbound_method( ) ;
3296
+ ty:: mk_err( )
3297
+ }
3298
+ }
3299
+ }
3300
+
3218
3301
fn lookup_op_method < ' a , ' tcx > ( fcx: & ' a FnCtxt < ' a , ' tcx > ,
3219
3302
op_ex: & ast:: Expr ,
3220
3303
lhs_ty: Ty < ' tcx > ,
@@ -3310,55 +3393,59 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3310
3393
SimpleBinop => NoPreference
3311
3394
} ;
3312
3395
check_expr_with_lvalue_pref( fcx, & * lhs, lvalue_pref) ;
3396
+ check_expr( fcx, & * * rhs) ;
3313
3397
3314
- // Callee does bot / err checking
3315
- let lhs_t = structurally_resolved_type( fcx, lhs. span,
3316
- fcx. expr_ty( & * lhs) ) ;
3398
+ let lhs_t = try_structurally_resolved_type( fcx, fcx. expr_ty( & * lhs) ) ;
3399
+ let rhs_t = try_structurally_resolved_type( fcx, fcx. expr_ty( & * * rhs) ) ;
3317
3400
3318
- if ty:: type_is_integral( lhs_t) && ast_util:: is_shift_binop( op) {
3319
- // Shift is a special case: rhs must be uint, no matter what lhs is
3320
- check_expr_has_type( fcx, & * * rhs, ty:: mk_uint( ) ) ;
3321
- fcx. write_ty( expr. id, lhs_t) ;
3322
- return ;
3323
- }
3401
+ if let ( Some ( lhs_t) , Some ( rhs_t) ) = ( lhs_t, rhs_t) {
3402
+ if ty:: type_is_integral( lhs_t) && ty:: type_is_integral( rhs_t) &&
3403
+ ast_util:: is_shift_binop( op) {
3404
+ // Integer shift is a special case: rhs must be uint, no matter what lhs is
3405
+ check_expr_has_type( fcx, & * * rhs, ty:: mk_uint( ) ) ;
3406
+ fcx. write_ty( expr. id, lhs_t) ;
3407
+ return ;
3408
+ }
3324
3409
3325
- if ty:: is_binopable( tcx, lhs_t, op) {
3326
- let tvar = fcx. infcx( ) . next_ty_var( ) ;
3327
- demand:: suptype( fcx, expr. span, tvar, lhs_t) ;
3328
- check_expr_has_type( fcx, & * * rhs, tvar) ;
3329
-
3330
- let result_t = match op {
3331
- ast : : BiEq | ast:: BiNe | ast:: BiLt | ast:: BiLe | ast:: BiGe |
3332
- ast:: BiGt => {
3333
- if ty:: type_is_simd( tcx, lhs_t) {
3334
- if ty:: type_is_fp( ty:: simd_type( tcx, lhs_t) ) {
3335
- fcx. type_error_message( expr. span,
3336
- |actual| {
3337
- format ! ( "binary comparison \
3338
- operation `{}` not \
3339
- supported for floating \
3340
- point SIMD vector `{}`",
3341
- ast_util:: binop_to_string( op) ,
3342
- actual)
3343
- } ,
3344
- lhs_t,
3345
- None
3346
- ) ;
3347
- ty:: mk_err( )
3410
+ if ty:: is_builtin_binop( tcx, lhs_t, rhs_t, op) {
3411
+ demand:: suptype( fcx, expr. span, lhs_t, rhs_t) ;
3412
+
3413
+ let result_t = match op {
3414
+ ast : : BiEq | ast:: BiNe | ast:: BiLt | ast:: BiLe | ast:: BiGe |
3415
+ ast:: BiGt => {
3416
+ if ty:: type_is_simd( tcx, lhs_t) {
3417
+ if ty:: type_is_fp( ty:: simd_type( tcx, lhs_t) ) {
3418
+ fcx. type_error_message( expr. span,
3419
+ |actual| {
3420
+ format ! ( "binary comparison \
3421
+ operation `{}` not \
3422
+ supported for floating \
3423
+ point SIMD vector `{}`",
3424
+ ast_util:: binop_to_string( op) ,
3425
+ actual)
3426
+ } ,
3427
+ lhs_t,
3428
+ None
3429
+ ) ;
3430
+ ty:: mk_err( )
3431
+ } else {
3432
+ lhs_t
3433
+ }
3348
3434
} else {
3349
- lhs_t
3435
+ ty :: mk_bool ( )
3350
3436
}
3351
- } else {
3352
- ty:: mk_bool( )
3353
- }
3354
- } ,
3355
- _ => lhs_t,
3356
- } ;
3437
+ } ,
3438
+ _ => lhs_t,
3439
+ } ;
3357
3440
3358
- fcx. write_ty( expr. id, result_t) ;
3359
- return ;
3441
+ fcx. write_ty( expr. id, result_t) ;
3442
+ return ;
3443
+ }
3360
3444
}
3361
3445
3446
+ // NB Use the type of `lhs` for error messages, even if it's not fully resolved
3447
+ let lhs_t = fcx. expr_ty( lhs) ;
3448
+
3362
3449
if op == ast:: BiOr || op == ast:: BiAnd {
3363
3450
// This is an error; one of the operands must have the wrong
3364
3451
// type
@@ -3430,8 +3517,8 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3430
3517
return ty:: mk_err( ) ;
3431
3518
}
3432
3519
} ;
3433
- lookup_op_method ( fcx, ex, lhs_resolved_t, token:: intern( name) ,
3434
- trait_did, lhs_expr, Some ( rhs) , || {
3520
+ lookup_binop_method ( fcx, ex, lhs_resolved_t, token:: intern( name) ,
3521
+ trait_did, lhs_expr, rhs, || {
3435
3522
fcx. type_error_message( ex. span, |actual| {
3436
3523
format ! ( "binary operation `{}` cannot be applied to type `{}`" ,
3437
3524
ast_util:: binop_to_string( op) ,
@@ -5458,6 +5545,24 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
5458
5545
// resolution is possible, then an error is reported.
5459
5546
pub fn structurally_resolved_type < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > , sp : Span ,
5460
5547
mut ty : Ty < ' tcx > ) -> Ty < ' tcx > {
5548
+ match try_structurally_resolved_type ( fcx, ty) {
5549
+ Some ( ty) => ty,
5550
+ None => {
5551
+ fcx. type_error_message ( sp, |_actual| {
5552
+ "the type of this value must be known in this \
5553
+ context". to_string ( )
5554
+ } , ty, None ) ;
5555
+ demand:: suptype ( fcx, sp, ty:: mk_err ( ) , ty) ;
5556
+ ty = ty:: mk_err ( ) ;
5557
+ ty
5558
+ }
5559
+ }
5560
+ }
5561
+
5562
+ // Like `structurally_resolved_type`, but if resolving fails returns `None` instead of raising a
5563
+ // compile error
5564
+ fn try_structurally_resolved_type < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
5565
+ mut ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
5461
5566
// If `ty` is a type variable, see whether we already know what it is.
5462
5567
ty = fcx. infcx ( ) . shallow_resolve ( ty) ;
5463
5568
@@ -5474,15 +5579,10 @@ pub fn structurally_resolved_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
5474
5579
5475
5580
// If not, error.
5476
5581
if ty:: type_is_ty_var ( ty) {
5477
- fcx. type_error_message ( sp, |_actual| {
5478
- "the type of this value must be known in this \
5479
- context". to_string ( )
5480
- } , ty, None ) ;
5481
- demand:: suptype ( fcx, sp, ty:: mk_err ( ) , ty) ;
5482
- ty = ty:: mk_err ( ) ;
5582
+ None
5583
+ } else {
5584
+ Some ( ty)
5483
5585
}
5484
-
5485
- ty
5486
5586
}
5487
5587
5488
5588
// Returns the one-level-deep structure of the given type.
0 commit comments