Skip to content

Commit

Permalink
Allow subtyping of the final expression of a constant
Browse files Browse the repository at this point in the history
Fixes an ICE for the following code:

fn foo(_ : &()) {}
static X: fn(&'static ()) = foo;
  • Loading branch information
matthewjasper committed Apr 24, 2019
1 parent eb37c64 commit ff4d4b2
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
33 changes: 28 additions & 5 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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));

Expand Down
2 changes: 2 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
8 changes: 8 additions & 0 deletions src/librustc_typeck/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-pass/mir/mir_static_subtype.rs
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit ff4d4b2

Please sign in to comment.