@@ -325,7 +325,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
325325 _ => None ,
326326 } ;
327327 let adjust_mode = self . calc_adjust_mode ( pat, opt_path_res. map ( |( res, ..) | res) ) ;
328- self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
328+ let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
329+ self . write_ty ( pat. hir_id , ty) ;
330+
331+ // (note_1): In most of the cases where (note_1) is referenced
332+ // (literals and constants being the exception), we relate types
333+ // using strict equality, even though subtyping would be sufficient.
334+ // There are a few reasons for this, some of which are fairly subtle
335+ // and which cost me (nmatsakis) an hour or two debugging to remember,
336+ // so I thought I'd write them down this time.
337+ //
338+ // 1. There is no loss of expressiveness here, though it does
339+ // cause some inconvenience. What we are saying is that the type
340+ // of `x` becomes *exactly* what is expected. This can cause unnecessary
341+ // errors in some cases, such as this one:
342+ //
343+ // ```
344+ // fn foo<'x>(x: &'x i32) {
345+ // let a = 1;
346+ // let mut z = x;
347+ // z = &a;
348+ // }
349+ // ```
350+ //
351+ // The reason we might get an error is that `z` might be
352+ // assigned a type like `&'x i32`, and then we would have
353+ // a problem when we try to assign `&a` to `z`, because
354+ // the lifetime of `&a` (i.e., the enclosing block) is
355+ // shorter than `'x`.
356+ //
357+ // HOWEVER, this code works fine. The reason is that the
358+ // expected type here is whatever type the user wrote, not
359+ // the initializer's type. In this case the user wrote
360+ // nothing, so we are going to create a type variable `Z`.
361+ // Then we will assign the type of the initializer (`&'x i32`)
362+ // as a subtype of `Z`: `&'x i32 <: Z`. And hence we
363+ // will instantiate `Z` as a type `&'0 i32` where `'0` is
364+ // a fresh region variable, with the constraint that `'x : '0`.
365+ // So basically we're all set.
366+ //
367+ // Note that there are two tests to check that this remains true
368+ // (`regions-reassign-{match,let}-bound-pointer.rs`).
369+ //
370+ // 2. An outdated issue related to the old HIR borrowck. See the test
371+ // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
329372 }
330373
331374 // Helper to avoid resolving the same path pattern several times.
@@ -336,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336379 adjust_mode : AdjustMode ,
337380 expected : Ty < ' tcx > ,
338381 pat_info : PatInfo < ' tcx > ,
339- ) {
382+ ) -> Ty < ' tcx > {
340383 let PatInfo { mut binding_mode, mut max_ref_mutbl, current_depth, .. } = pat_info;
341384 #[ cfg( debug_assertions) ]
342385 if binding_mode == ByRef :: Yes ( Mutability :: Mut )
@@ -369,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
369412 decl_origin : old_pat_info. decl_origin ,
370413 } ;
371414
372- let ty = match pat. kind {
415+ match pat. kind {
373416 // Peel off a `&` or `&mut` from the scrutinee type. See the examples in
374417 // `tests/ui/rfcs/rfc-2005-default-binding-mode`.
375418 _ if let AdjustMode :: Peel = adjust_mode
@@ -408,13 +451,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
408451
409452 // Use the old pat info to keep `current_depth` to its old value.
410453 let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info } ;
411- return self . check_pat_inner (
412- pat,
413- opt_path_res,
414- adjust_mode,
415- inner_ty,
416- new_pat_info,
417- ) ;
454+ // Recurse with the new expected type.
455+ self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
418456 }
419457 PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
420458 // We allow any type here; we ensure that the type is uninhabited during match checking.
@@ -465,51 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
465503 PatKind :: Slice ( before, slice, after) => {
466504 self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
467505 }
468- } ;
469-
470- self . write_ty ( pat. hir_id , ty) ;
471-
472- // (note_1): In most of the cases where (note_1) is referenced
473- // (literals and constants being the exception), we relate types
474- // using strict equality, even though subtyping would be sufficient.
475- // There are a few reasons for this, some of which are fairly subtle
476- // and which cost me (nmatsakis) an hour or two debugging to remember,
477- // so I thought I'd write them down this time.
478- //
479- // 1. There is no loss of expressiveness here, though it does
480- // cause some inconvenience. What we are saying is that the type
481- // of `x` becomes *exactly* what is expected. This can cause unnecessary
482- // errors in some cases, such as this one:
483- //
484- // ```
485- // fn foo<'x>(x: &'x i32) {
486- // let a = 1;
487- // let mut z = x;
488- // z = &a;
489- // }
490- // ```
491- //
492- // The reason we might get an error is that `z` might be
493- // assigned a type like `&'x i32`, and then we would have
494- // a problem when we try to assign `&a` to `z`, because
495- // the lifetime of `&a` (i.e., the enclosing block) is
496- // shorter than `'x`.
497- //
498- // HOWEVER, this code works fine. The reason is that the
499- // expected type here is whatever type the user wrote, not
500- // the initializer's type. In this case the user wrote
501- // nothing, so we are going to create a type variable `Z`.
502- // Then we will assign the type of the initializer (`&'x i32`)
503- // as a subtype of `Z`: `&'x i32 <: Z`. And hence we
504- // will instantiate `Z` as a type `&'0 i32` where `'0` is
505- // a fresh region variable, with the constraint that `'x : '0`.
506- // So basically we're all set.
507- //
508- // Note that there are two tests to check that this remains true
509- // (`regions-reassign-{match,let}-bound-pointer.rs`).
510- //
511- // 2. An outdated issue related to the old HIR borrowck. See the test
512- // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
506+ }
513507 }
514508
515509 /// How should the binding mode and expected type be adjusted?
0 commit comments