Skip to content

Commit ff4d4b2

Browse files
committed
Allow subtyping of the final expression of a constant
Fixes an ICE for the following code: fn foo(_ : &()) {} static X: fn(&'static ()) = foo;
1 parent eb37c64 commit ff4d4b2

File tree

4 files changed

+46
-5
lines changed

4 files changed

+46
-5
lines changed

src/librustc_mir/build/mod.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,21 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
147147
build::construct_fn(cx, id, arguments, safety, abi,
148148
return_ty, yield_ty, return_ty_span, body)
149149
} else {
150-
build::construct_const(cx, body_id, return_ty_span)
150+
// Get the revealed type of this const. This is *not* the adjusted
151+
// type of its body, which may be a subtype of this type. For
152+
// example:
153+
//
154+
// fn foo(_: &()) {}
155+
// static X: fn(&'static ()) = foo;
156+
//
157+
// The adjusted type of the body of X is `for<'a> fn(&'a ())` which
158+
// is not the same as the type of X. We need the type of the return
159+
// place to be the type of the constant because NLL typeck will
160+
// equate them.
161+
162+
let return_ty = cx.tables().node_type(id);
163+
164+
build::construct_const(cx, body_id, return_ty, return_ty_span)
151165
};
152166

153167
// Convert the Mir to global types.
@@ -730,16 +744,25 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
730744
fn construct_const<'a, 'gcx, 'tcx>(
731745
hir: Cx<'a, 'gcx, 'tcx>,
732746
body_id: hir::BodyId,
733-
ty_span: Span,
747+
const_ty: Ty<'tcx>,
748+
const_ty_span: Span,
734749
) -> Mir<'tcx> {
735750
let tcx = hir.tcx();
736-
let ast_expr = &tcx.hir().body(body_id).value;
737-
let ty = hir.tables().expr_ty_adjusted(ast_expr);
738751
let owner_id = tcx.hir().body_owner(body_id);
739752
let span = tcx.hir().span(owner_id);
740-
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, ty_span, vec![], vec![]);
753+
let mut builder = Builder::new(
754+
hir,
755+
span,
756+
0,
757+
Safety::Safe,
758+
const_ty,
759+
const_ty_span,
760+
vec![],
761+
vec![],
762+
);
741763

742764
let mut block = START_BLOCK;
765+
let ast_expr = &tcx.hir().body(body_id).value;
743766
let expr = builder.hir.mirror(ast_expr);
744767
unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr));
745768

src/librustc_typeck/check/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
866866

867867
fcx.check_expr_coercable_to_type(&body.value, revealed_ty);
868868

869+
fcx.write_ty(id, revealed_ty);
870+
869871
fcx
870872
};
871873

src/librustc_typeck/check/writeback.rs

+8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4242
for arg in &body.arguments {
4343
wbcx.visit_node_id(arg.pat.span, arg.hir_id);
4444
}
45+
// Type only exists for constants and statics, not functions.
46+
match self.tcx.hir().body_owner_kind(item_id) {
47+
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
48+
let item_hir_id = self.tcx.hir().node_to_hir_id(item_id);
49+
wbcx.visit_node_id(body.value.span, item_hir_id);
50+
}
51+
hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
52+
}
4553
wbcx.visit_body(body);
4654
wbcx.visit_upvar_capture_map();
4755
wbcx.visit_upvar_list_map();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Test that subtyping the body of a static doesn't cause an ICE.
2+
3+
fn foo(_ : &()) {}
4+
static X: fn(&'static ()) = foo;
5+
6+
fn main() {
7+
let _ = X;
8+
}

0 commit comments

Comments
 (0)