]> git.lizzy.rs Git - rust.git/commitdiff
propagate user-ascribes types down onto resulting bindings
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 10 Sep 2018 14:54:31 +0000 (10:54 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 10 Sep 2018 14:58:31 +0000 (10:58 -0400)
But only in very simple cases.

14 files changed:
src/librustc/ich/impls_mir.rs
src/librustc/mir/mod.rs
src/librustc/mir/visit.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/build/block.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/lib.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/util/pretty.rs
src/test/ui/nll/user-annotations/patterns.rs
src/test/ui/nll/user-annotations/patterns.stderr

index 120006b32016c1f1f347d3c9545b8e3a9ca2e255..5f35c9fea0a337248d24634e744a0c6b5427fe99 100644 (file)
@@ -24,6 +24,7 @@
 impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
     mutability,
     ty,
+    user_ty,
     name,
     source_info,
     visibility_scope,
index 3227888ec6abaa04b4c35b838f35cd18eb388919..3450eec8082f37a2bf9885173b7cf438c50c697e 100644 (file)
@@ -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<CanonicalTy<'tcx>>,
+
     /// 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,
index 723ba6332cce16f74a1e2b0b482b921dc2a187db..0beb5ac0a3cb51e42e9e053a2f751b264ae11715 100644 (file)
@@ -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);
             }
index 1d06a1335ceca4099ad2018bad8a3a9deedc5dc0..de96539ec30f106a8e3df51123b22657992f89ce 100644 (file)
@@ -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>) {
index e0c2e3d8eff48cb5de5dd3953707f580c1c07b1a..bfb6daee6041ea80f58e2a80a2bbf5e18ad284ac 100644 (file)
@@ -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);
                         })
index 59ebb7703ff610e8b3783cd7e2f4bd582971cff7..5708ac4e6b50f7dfd58a57a374c9c8c87e366aa0 100644 (file)
@@ -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,
index 09153ca24799a9dada0afd8fa4ced467ce6e6937..42510f5d71c526b55643e9a71dda1e518ea9c712 100644 (file)
@@ -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<F>(&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<CanonicalTy<'tcx>>,
+        f: &mut impl FnMut(
+            &mut Self,
+            Mutability,
+            Name,
+            BindingMode,
+            NodeId,
+            Span,
+            Ty<'tcx>,
+            Option<CanonicalTy<'tcx>>,
+        ),
+    ) {
         match *pattern.kind {
             PatternKind::Binding {
                 mutability,
@@ -484,9 +497,9 @@ pub fn visit_bindings<F>(&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<F>(&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<CanonicalTy<'tcx>>,
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<Place<'tcx>>, 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,
index 322a6977bedd0b925165bdfa9f8e352922c5c5f2..576c91a02b08daed34dd64fb31da5371800ad30a 100644 (file)
@@ -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,
index d4024981c3754cac0e1445afc1c59b0d81730505..f2c011ccee6a5704ffed97ff84204987d05caf1b 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(if_while_or_patterns)]
 #![feature(try_from)]
 #![feature(reverse_bits)]
+#![feature(underscore_imports)]
 
 #![recursion_limit="256"]
 
index 7e7e7cfade6238f2e12100e6e06b4c7ddfdb0db6..a6c0397568578b0de33e84872883ff45a19318cd 100644 (file)
@@ -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,
index dcbf92b57b13a2a895a0ee897fd44b1b20eb4aad..f1f42768ce3248d2ef1483fd1d10a367b3574173 100644 (file)
@@ -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,
index 9f5b5040b09574ae96c704617058a81f8f414ebc..710ccb2053b8492a6a27573026c85d3537fa6c1f 100644 (file)
@@ -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}",
index c4ed72c7482deffa3f605a8dfd61d25b1d5d8c97..94ac455c257afdef9f6ad153be763bfe4ddc4ced 100644 (file)
@@ -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<T> { 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<T> { 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
index e1208bfb5ec97ed6fb7867d0eb7561ef77eeafcc..c7c3df83d46012fbf4dbc698a39144a0fa609679 100644 (file)
@@ -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`.