about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-11-25 15:14:39 +0100
committerDavid Wood <david@davidtw.co>2018-12-30 14:30:58 +0100
commitdc41606ff403536afe4eda88a68b8faa8e3f9d55 (patch)
tree8d3cf44d31e1ad92e0b000512c384f14cbe4c90c
parent162dcdc16f9b004b35160c9dd69faab29fc459e4 (diff)
downloadrust-dc41606ff403536afe4eda88a68b8faa8e3f9d55.tar.gz
rust-dc41606ff403536afe4eda88a68b8faa8e3f9d55.zip
Support user type annotations in `ref` bindings.
This commit adds support for user type annotations in variables declared
using `ref` bindings. When a variable declared using a `ref` binding,
then the `LocalDecl` has the type `&T` where the `&` was introduced by
the `ref` binding but the canonicalized type annotation has only a
`T` since the reference is implicit with the `ref` binding.

Therefore, to support type annotations, the canonicalized type
annotation either needs wrapped in a reference, or the `LocalDecl` type
must have a wrapped reference removed for comparison. It is easier to
remove the outer reference from the `LocalDecl` for the purpose of
comparison, so that is the approach this commit takes.
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs14
-rw-r--r--src/librustc_mir/build/block.rs1
-rw-r--r--src/librustc_mir/build/matches/mod.rs17
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs7
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/test/ui/nll/issue-55401.rs8
-rw-r--r--src/test/ui/nll/issue-55401.stderr11
7 files changed, 40 insertions, 20 deletions
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 51ade33f74c..2c49dbd969d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -307,8 +307,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.sanitize_type(local_decl, local_decl.ty);
 
         for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
+            let ty = if !local_decl.is_nonref_binding() {
+                // If we have a binding of the form `let ref x: T = ..` then remove the outermost
+                // reference so we can check the type annotation for the remaining type.
+                if let ty::Ref(_, rty, _) = local_decl.ty.sty {
+                    rty
+                } else {
+                    bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
+                }
+            } else {
+                local_decl.ty
+            };
+
             if let Err(terr) = self.cx.relate_type_and_user_type(
-                local_decl.ty,
+                ty,
                 ty::Variance::Invariant,
                 user_ty,
                 Locations::All(*span),
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index ad4e5a50dcd..41718cfc870 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -141,6 +141,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             None, remainder_span, lint_level, slice::from_ref(&pattern),
                             ArmHasGuard(false), None);
 
+                        debug!("ast_block_stmts: pattern={:?}", pattern);
                         this.visit_bindings(
                             &pattern,
                             &PatternTypeProjections::none(),
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 92642dff3dc..085c58ef5ff 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -409,6 +409,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         );
         let mut scope = self.source_scope;
         let num_patterns = patterns.len();
+        debug!("declare_bindings: patterns={:?}", patterns);
         self.visit_bindings(
             &patterns[0],
             &PatternTypeProjections::none(),
@@ -499,6 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             &PatternTypeProjections<'tcx>,
         ),
     ) {
+        debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
         match *pattern.kind {
             PatternKind::Binding {
                 mutability,
@@ -509,19 +511,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 ref subpattern,
                 ..
             } => {
-                let pattern_ref_binding; // sidestep temp lifetime limitations.
-                let binding_user_ty = match mode {
-                    BindingMode::ByValue => { pattern_user_ty }
-                    BindingMode::ByRef(..) => {
-                        // If this is a `ref` binding (e.g., `let ref
-                        // x: T = ..`), then the type of `x` is not
-                        // `T` but rather `&T`.
-                        pattern_ref_binding = pattern_user_ty.ref_binding();
-                        &pattern_ref_binding
-                    }
-                };
-
-                f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
+                f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
                 if let Some(subpattern) = subpattern.as_ref() {
                     self.visit_bindings(subpattern, pattern_user_ty, f);
                 }
@@ -565,6 +555,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Leaf { ref subpatterns } => {
                 for subpattern in subpatterns {
                     let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
+                    debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
                     self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
                 }
             }
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 00de40d8cff..6d562c69b2d 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -79,11 +79,6 @@ impl<'tcx> PatternTypeProjections<'tcx> {
         PatternTypeProjections { contents: vec![] }
     }
 
-    pub(crate) fn ref_binding(&self) -> Self {
-        // FIXME(#55401): ignore for now
-        PatternTypeProjections { contents: vec![] }
-    }
-
     fn map_projs(&self,
                  mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>)
                  -> Self
@@ -803,7 +798,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         };
 
         if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
-            debug!("lower_variant_or_leaf: user_ty={:?} span={:?}", user_ty, span);
+            debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
             kind = PatternKind::AscribeUserType {
                 subpattern: Pattern {
                     span,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ff4574eb283..36de41ef8a1 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2388,6 +2388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
         let ty = self.to_ty(ast_ty);
+        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
 
         // If the type given by the user has free regions, save it for
         // later, since NLL would like to enforce those. Also pass in
@@ -2398,6 +2399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // already sufficiently enforced with erased regions. =)
         if ty.has_free_regions() || ty.has_projections() {
             let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty));
+            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
             self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
         }
 
diff --git a/src/test/ui/nll/issue-55401.rs b/src/test/ui/nll/issue-55401.rs
new file mode 100644
index 00000000000..2fa23449108
--- /dev/null
+++ b/src/test/ui/nll/issue-55401.rs
@@ -0,0 +1,8 @@
+#![feature(nll)]
+
+fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+    let (ref y, _z): (&'a u32, u32) = (&22, 44);
+    *y //~ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-55401.stderr b/src/test/ui/nll/issue-55401.stderr
new file mode 100644
index 00000000000..9e50db7b604
--- /dev/null
+++ b/src/test/ui/nll/issue-55401.stderr
@@ -0,0 +1,11 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/issue-55401.rs:5:5
+   |
+LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+   |                                               -- lifetime `'a` defined here
+LL |     let (ref y, _z): (&'a u32, u32) = (&22, 44);
+LL |     *y //~ ERROR
+   |     ^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+