diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 120006b32016c1f1f347d3c9545b8e3a9ca2e255..5f35c9fea0a337248d24634e744a0c6b5427fe99 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -24,6 +24,7 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, + user_ty, name, source_info, visibility_scope, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3227888ec6abaa04b4c35b838f35cd18eb388919..3450eec8082f37a2bf9885173b7cf438c50c697e 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -640,6 +640,12 @@ pub struct LocalDecl<'tcx> { /// Type of this local. pub ty: Ty<'tcx>, + /// If the user manually ascribed a type to this variable, + /// e.g. via `let x: T`, then we carry that type here. The MIR + /// borrow checker needs this information since it can affect + /// region inference. + pub user_ty: Option>, + /// Name of the local, used in debuginfo and pretty-printing. /// /// Note that function arguments can also have this set to `Some(_)` @@ -802,6 +808,7 @@ fn new_local( LocalDecl { mutability, ty, + user_ty: None, name: None, source_info: SourceInfo { span, @@ -821,6 +828,7 @@ pub fn new_return_place(return_ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability: Mutability::Mut, ty: return_ty, + user_ty: None, source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE, @@ -2613,6 +2621,7 @@ impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { is_user_variable, internal, ty, + user_ty, name, source_info, visibility_scope, diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 723ba6332cce16f74a1e2b0b482b921dc2a187db..0beb5ac0a3cb51e42e9e053a2f751b264ae11715 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -721,6 +721,7 @@ fn super_local_decl(&mut self, let LocalDecl { mutability: _, ref $($mutability)* ty, + ref $($mutability)* user_ty, name: _, ref $($mutability)* source_info, ref $($mutability)* visibility_scope, @@ -732,6 +733,9 @@ fn super_local_decl(&mut self, local, source_info: *source_info, }); + if let Some(user_ty) = user_ty { + self.visit_canonical_ty(user_ty); + } self.visit_source_info(source_info); self.visit_source_scope(visibility_scope); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 1d06a1335ceca4099ad2018bad8a3a9deedc5dc0..de96539ec30f106a8e3df51123b22657992f89ce 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -275,6 +275,25 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { self.super_local_decl(local, local_decl); self.sanitize_type(local_decl, local_decl.ty); + + if let Some(user_ty) = local_decl.user_ty { + if let Err(terr) = self.cx.relate_type_and_user_type( + local_decl.ty, + ty::Variance::Invariant, + user_ty, + Locations::All, + ) { + span_mirbug!( + self, + local, + "bad user type on variable {:?}: {:?} != {:?} ({:?})", + local, + local_decl.ty, + local_decl.user_ty, + terr, + ); + } + } } fn visit_mir(&mut self, mir: &Mir<'tcx>) { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index e0c2e3d8eff48cb5de5dd3953707f580c1c07b1a..bfb6daee6041ea80f58e2a80a2bbf5e18ad284ac 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -143,7 +143,7 @@ fn ast_block_stmts(&mut self, None, remainder_span, lint_level, slice::from_ref(&pattern), ArmHasGuard(false), None); - this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| { + this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| { this.storage_live_binding(block, node, span, OutsideGuard); this.schedule_drop_for_binding(node, span, OutsideGuard); }) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 59ebb7703ff610e8b3783cd7e2f4bd582971cff7..5708ac4e6b50f7dfd58a57a374c9c8c87e366aa0 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -296,6 +296,7 @@ pub fn into_expr( let ptr_temp = this.local_decls.push(LocalDecl { mutability: Mutability::Mut, ty: ptr_ty, + user_ty: None, name: None, source_info, visibility_scope: source_info.scope, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 09153ca24799a9dada0afd8fa4ced467ce6e6937..42510f5d71c526b55643e9a71dda1e518ea9c712 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -399,7 +399,8 @@ pub fn declare_bindings( let num_patterns = patterns.len(); self.visit_bindings( &patterns[0], - &mut |this, mutability, name, mode, var, span, ty| { + None, + &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); @@ -421,6 +422,7 @@ pub fn declare_bindings( num_patterns, var, ty, + user_ty, has_guard, opt_match_place.map(|(x, y)| (x.cloned(), y)), patterns[0].span, @@ -470,10 +472,21 @@ pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span, for_guard: ); } - pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, f: &mut F) - where - F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>), - { + pub fn visit_bindings( + &mut self, + pattern: &Pattern<'tcx>, + pattern_user_ty: Option>, + f: &mut impl FnMut( + &mut Self, + Mutability, + Name, + BindingMode, + NodeId, + Span, + Ty<'tcx>, + Option>, + ), + ) { match *pattern.kind { PatternKind::Binding { mutability, @@ -484,9 +497,9 @@ pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, f: &mut F) ref subpattern, .. } => { - f(self, mutability, name, mode, var, pattern.span, ty); + f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty); if let Some(subpattern) = subpattern.as_ref() { - self.visit_bindings(subpattern, f); + self.visit_bindings(subpattern, pattern_user_ty, f); } } PatternKind::Array { @@ -499,21 +512,34 @@ pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, f: &mut F) ref slice, ref suffix, } => { + // FIXME(#47184): extract or handle `pattern_user_ty` somehow for subpattern in prefix.iter().chain(slice).chain(suffix) { - self.visit_bindings(subpattern, f); + self.visit_bindings(subpattern, None, f); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} - PatternKind::AscribeUserType { ref subpattern, .. } - | PatternKind::Deref { ref subpattern } => { - self.visit_bindings(subpattern, f); + PatternKind::Deref { ref subpattern } => { + // FIXME(#47184): extract or handle `pattern_user_ty` somehow + self.visit_bindings(subpattern, None, f); + } + PatternKind::AscribeUserType { ref subpattern, user_ty } => { + // This corresponds to something like + // + // ``` + // let (p1: T1): T2 = ...; + // ``` + // + // Not presently possible, though maybe someday. + assert!(pattern_user_ty.is_none()); + self.visit_bindings(subpattern, Some(user_ty), f) } PatternKind::Leaf { ref subpatterns } | PatternKind::Variant { ref subpatterns, .. } => { + // FIXME(#47184): extract or handle `pattern_user_ty` somehow for subpattern in subpatterns { - self.visit_bindings(&subpattern.pattern, f); + self.visit_bindings(&subpattern.pattern, None, f); } } } @@ -1375,6 +1401,7 @@ fn declare_binding( num_patterns: usize, var_id: NodeId, var_ty: Ty<'tcx>, + user_var_ty: Option>, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, @@ -1392,7 +1419,8 @@ fn declare_binding( }; let local = LocalDecl::<'tcx> { mutability, - ty: var_ty.clone(), + ty: var_ty, + user_ty: user_var_ty, name: Some(name), source_info, visibility_scope, @@ -1424,6 +1452,7 @@ fn declare_binding( // See previous comment. mutability: Mutability::Not, ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty), + user_ty: None, name: Some(name), source_info, visibility_scope, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 322a6977bedd0b925165bdfa9f8e352922c5c5f2..576c91a02b08daed34dd64fb31da5371800ad30a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -730,6 +730,7 @@ fn args_and_body(&mut self, self.local_decls.push(LocalDecl { mutability: Mutability::Mut, ty, + user_ty: None, source_info, visibility_scope: source_info.scope, name, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index d4024981c3754cac0e1445afc1c59b0d81730505..f2c011ccee6a5704ffed97ff84204987d05caf1b 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -39,6 +39,7 @@ #![feature(if_while_or_patterns)] #![feature(try_from)] #![feature(reverse_bits)] +#![feature(underscore_imports)] #![recursion_limit="256"] diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 7e7e7cfade6238f2e12100e6e06b4c7ddfdb0db6..a6c0397568578b0de33e84872883ff45a19318cd 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -140,7 +140,9 @@ enum CallKind { fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span }; LocalDecl { - mutability, ty, name: None, + mutability, ty, + user_ty: None, + name: None, source_info, visibility_scope: source_info.scope, internal: false, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index dcbf92b57b13a2a895a0ee897fd44b1b20eb4aad..f1f42768ce3248d2ef1483fd1d10a367b3574173 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -303,6 +303,7 @@ fn replace_result_variable<'tcx>( let new_ret = LocalDecl { mutability: Mutability::Mut, ty: ret_ty, + user_ty: None, name: None, source_info, visibility_scope: source_info.scope, @@ -656,6 +657,7 @@ fn create_generator_drop_shim<'a, 'tcx>( mir.local_decls[RETURN_PLACE] = LocalDecl { mutability: Mutability::Mut, ty: tcx.mk_nil(), + user_ty: None, name: None, source_info, visibility_scope: source_info.scope, @@ -672,6 +674,7 @@ fn create_generator_drop_shim<'a, 'tcx>( ty: gen_ty, mutbl: hir::Mutability::MutMutable, }), + user_ty: None, name: None, source_info, visibility_scope: source_info.scope, diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9f5b5040b09574ae96c704617058a81f8f414ebc..710ccb2053b8492a6a27573026c85d3537fa6c1f 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -17,6 +17,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use std::fmt::Display; +use std::fmt::Write as _; use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; @@ -493,14 +494,18 @@ fn write_scope_tree( }; let indent = indent + INDENT.len(); - let indented_var = format!( - "{0:1$}let {2}{3:?}: {4:?};", + let mut indented_var = format!( + "{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, var.ty ); + if let Some(user_ty) = var.user_ty { + write!(indented_var, " as {:?}", user_ty).unwrap(); + } + indented_var.push_str(";"); writeln!( w, "{0:1$} // \"{2}\" in {3}", diff --git a/src/test/ui/nll/user-annotations/patterns.rs b/src/test/ui/nll/user-annotations/patterns.rs index c4ed72c7482deffa3f605a8dfd61d25b1d5d8c97..94ac455c257afdef9f6ad153be763bfe4ddc4ced 100644 --- a/src/test/ui/nll/user-annotations/patterns.rs +++ b/src/test/ui/nll/user-annotations/patterns.rs @@ -3,10 +3,41 @@ #![feature(nll)] fn variable_no_initializer() { - // FIXME: It is unclear to me whether this should be an error or not. - let x = 22; let y: &'static u32; + y = &x; //~ ERROR +} + +fn tuple_no_initializer() { + // FIXME(#47187): We are not propagating ascribed type through tuples. + + let x = 22; + let (y, z): (&'static u32, &'static u32); + y = &x; +} + +fn ref_with_ascribed_static_type() -> u32 { + // Check the behavior in some wacky cases. + let x = 22; + let y = &x; //~ ERROR + let ref z: &'static u32 = y; //~ ERROR + **z +} + +fn ref_with_ascribed_any_type() -> u32 { + let x = 22; + let y = &x; + let ref z: &u32 = y; + **z +} + +struct Single { value: T } + +fn struct_no_initializer() { + // FIXME(#47187): We are not propagating ascribed type through patterns. + + let x = 22; + let Single { value: y }: Single<&'static u32>; y = &x; } @@ -39,8 +70,6 @@ fn pair_variable_with_initializer() { let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR } -struct Single { value: T } - fn struct_single_field_variable_with_initializer() { let x = 22; let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR @@ -73,7 +102,7 @@ fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { } fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { - // FIXME: The fact that this type-checks is perhaps surprising. + // FIXME(#47187): The fact that this type-checks is perhaps surprising. // What happens is that the right-hand side is constrained to have // type `&'a u32`, which is possible, because it has type // `&'static u32`. The variable `y` is then forced to have type diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index e1208bfb5ec97ed6fb7867d0eb7561ef77eeafcc..c7c3df83d46012fbf4dbc698a39144a0fa609679 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -1,5 +1,37 @@ error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:15:27 + --> $DIR/patterns.rs:8:9 + | +LL | y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:22:13 + | +LL | let y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `y` does not live long enough + --> $DIR/patterns.rs:23:9 + | +LL | let ref z: &'static u32 = y; //~ ERROR + | ^^^^^ borrowed value does not live long enough +LL | **z +LL | } + | - `y` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:46:27 | LL | let y: &'static u32 = &x; //~ ERROR | ^^ borrowed value does not live long enough @@ -9,7 +41,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:20:27 + --> $DIR/patterns.rs:51:27 | LL | let _: &'static u32 = &x; //~ ERROR | ^^ borrowed value does not live long enough @@ -20,7 +52,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error[E0597]: borrowed value does not live long enough - --> $DIR/patterns.rs:22:41 + --> $DIR/patterns.rs:53:41 | LL | let _: Vec<&'static String> = vec![&String::new()]; | ^^^^^^^^^^^^^ - temporary value only lives until here @@ -30,7 +62,7 @@ LL | let _: Vec<&'static String> = vec![&String::new()]; = note: borrowed value must be valid for the static lifetime... error[E0597]: borrowed value does not live long enough - --> $DIR/patterns.rs:25:52 + --> $DIR/patterns.rs:56:52 | LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); | ^^^^^^^^^^^^^ - temporary value only lives until here @@ -40,7 +72,7 @@ LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); = note: borrowed value must be valid for the static lifetime... error[E0597]: borrowed value does not live long enough - --> $DIR/patterns.rs:28:53 + --> $DIR/patterns.rs:59:53 | LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); | ^^^^^^^^^^^^^ - temporary value only lives until here @@ -50,7 +82,7 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); = note: borrowed value must be valid for the static lifetime... error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:34:40 + --> $DIR/patterns.rs:65:40 | LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR | ^^ borrowed value does not live long enough @@ -60,7 +92,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:39:40 + --> $DIR/patterns.rs:70:40 | LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR | ^^ borrowed value does not live long enough @@ -70,7 +102,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:46:69 + --> $DIR/patterns.rs:75:69 | LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR | ^^ borrowed value does not live long enough @@ -80,7 +112,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:51:69 + --> $DIR/patterns.rs:80:69 | LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR | ^^ borrowed value does not live long enough @@ -90,7 +122,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:59:17 + --> $DIR/patterns.rs:88:17 | LL | value1: &x, //~ ERROR | ^^ borrowed value does not live long enough @@ -101,7 +133,7 @@ LL | } = note: borrowed value must be valid for the static lifetime... error: unsatisfied lifetime constraints - --> $DIR/patterns.rs:72:5 + --> $DIR/patterns.rs:101:5 | LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here @@ -110,13 +142,13 @@ LL | y //~ ERROR | ^ returning this value requires that `'a` must outlive `'static` error: unsatisfied lifetime constraints - --> $DIR/patterns.rs:88:40 + --> $DIR/patterns.rs:117:40 | LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR | ^^^^^^^ requires that `'a` must outlive `'static` -error: aborting due to 12 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0597`.