about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-03-30 13:00:41 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2019-04-24 19:37:56 +0100
commitff4d4b277f40b33b02e529d14c462ac11ab059ab (patch)
tree5f8dca8e8012f2be0ad622b0aaf9e076f6fbc1c7 /src
parenteb37c648d7c2b5587182c7d654622cf80542bea9 (diff)
downloadrust-ff4d4b277f40b33b02e529d14c462ac11ab059ab.tar.gz
rust-ff4d4b277f40b33b02e529d14c462ac11ab059ab.zip
Allow subtyping of the final expression of a constant
Fixes an ICE for the following code:

fn foo(_ : &()) {}
static X: fn(&'static ()) = foo;
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/build/mod.rs33
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs8
-rw-r--r--src/test/run-pass/mir/mir_static_subtype.rs8
4 files changed, 46 insertions, 5 deletions
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 79e1d5daae1..16ab233bd2e 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -147,7 +147,21 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
             build::construct_fn(cx, id, arguments, safety, abi,
                                 return_ty, yield_ty, return_ty_span, body)
         } else {
-            build::construct_const(cx, body_id, return_ty_span)
+            // Get the revealed type of this const. This is *not* the adjusted
+            // type of its body, which may be a subtype of this type. For
+            // example:
+            //
+            // fn foo(_: &()) {}
+            // static X: fn(&'static ()) = foo;
+            //
+            // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
+            // is not the same as the type of X. We need the type of the return
+            // place to be the type of the constant because NLL typeck will
+            // equate them.
+
+            let return_ty = cx.tables().node_type(id);
+
+            build::construct_const(cx, body_id, return_ty, return_ty_span)
         };
 
         // Convert the Mir to global types.
@@ -730,16 +744,25 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
 fn construct_const<'a, 'gcx, 'tcx>(
     hir: Cx<'a, 'gcx, 'tcx>,
     body_id: hir::BodyId,
-    ty_span: Span,
+    const_ty: Ty<'tcx>,
+    const_ty_span: Span,
 ) -> Mir<'tcx> {
     let tcx = hir.tcx();
-    let ast_expr = &tcx.hir().body(body_id).value;
-    let ty = hir.tables().expr_ty_adjusted(ast_expr);
     let owner_id = tcx.hir().body_owner(body_id);
     let span = tcx.hir().span(owner_id);
-    let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, ty_span, vec![], vec![]);
+    let mut builder = Builder::new(
+        hir,
+        span,
+        0,
+        Safety::Safe,
+        const_ty,
+        const_ty_span,
+        vec![],
+        vec![],
+    );
 
     let mut block = START_BLOCK;
+    let ast_expr = &tcx.hir().body(body_id).value;
     let expr = builder.hir.mirror(ast_expr);
     unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr));
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 79477b6fea8..bd715df6e9d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -866,6 +866,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             fcx.check_expr_coercable_to_type(&body.value, revealed_ty);
 
+            fcx.write_ty(id, revealed_ty);
+
             fcx
         };
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index efff08f6696..193b17af55e 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -42,6 +42,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         for arg in &body.arguments {
             wbcx.visit_node_id(arg.pat.span, arg.hir_id);
         }
+        // Type only exists for constants and statics, not functions.
+        match self.tcx.hir().body_owner_kind(item_id) {
+            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
+                let item_hir_id = self.tcx.hir().node_to_hir_id(item_id);
+                wbcx.visit_node_id(body.value.span, item_hir_id);
+            }
+            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
+        }
         wbcx.visit_body(body);
         wbcx.visit_upvar_capture_map();
         wbcx.visit_upvar_list_map();
diff --git a/src/test/run-pass/mir/mir_static_subtype.rs b/src/test/run-pass/mir/mir_static_subtype.rs
new file mode 100644
index 00000000000..5b1ccd7ddf6
--- /dev/null
+++ b/src/test/run-pass/mir/mir_static_subtype.rs
@@ -0,0 +1,8 @@
+// Test that subtyping the body of a static doesn't cause an ICE.
+
+fn foo(_ : &()) {}
+static X: fn(&'static ()) = foo;
+
+fn main() {
+    let _ = X;
+}