From ff4d4b277f40b33b02e529d14c462ac11ab059ab Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Mar 2019 13:00:41 +0000 Subject: [PATCH] Allow subtyping of the final expression of a constant Fixes an ICE for the following code: fn foo(_ : &()) {} static X: fn(&'static ()) = foo; --- src/librustc_mir/build/mod.rs | 33 +++++++++++++++++---- src/librustc_typeck/check/mod.rs | 2 ++ src/librustc_typeck/check/writeback.rs | 8 +++++ src/test/run-pass/mir/mir_static_subtype.rs | 8 +++++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/mir/mir_static_subtype.rs 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 @@ pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::Type 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; +} -- GitLab