From b4d71ea6f8165b326f065c5db8c7c07ad61bafd3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 1 Dec 2017 09:26:13 -0500 Subject: [PATCH] make `fn_sig().subst()` ICE when used with a closure It's inefficient, and the substitution there doesn't account for the extra regions used by NLL inference, so it's a bad thing to encourage. As it happens all callers already know if they have a closure or not, from what I can tell. --- src/librustc/ty/instance.rs | 4 ++-- src/librustc_trans/common.rs | 4 ++-- src/librustc_trans/mir/constant.rs | 5 ++--- src/librustc_trans_utils/monomorphize.rs | 4 ++-- src/librustc_typeck/collect.rs | 26 ++++++++++++++++-------- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 70636f8b6fe..177c25ac5db 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; -use ty::subst::{Kind, Subst}; +use ty::subst::Kind; use traits; use syntax::abi::Abi; use util::ppaux; @@ -311,7 +311,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( let self_ty = tcx.mk_closure_from_closure_substs( closure_did, substs); - let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs); + let sig = substs.closure_sig(closure_did, tcx); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs([ diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 405647af324..762cf7a0055 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -29,7 +29,7 @@ use value::Value; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{HasDataLayout, LayoutOf}; -use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::subst::{Kind, Substs}; use rustc::hir; use libc::{c_uint, c_char}; @@ -393,7 +393,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::TyFnPtr(_) => ty.fn_sig(ccx.tcx()), ty::TyClosure(def_id, substs) => { let tcx = ccx.tcx(); - let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs); + let sig = substs.closure_sig(def_id, tcx); let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); sig.map_bound(|sig| tcx.mk_fn_sig( diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 764021983e9..0799a388a8b 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -20,7 +20,7 @@ use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty::cast::{CastTy, IntTy}; -use rustc::ty::subst::{Kind, Substs, Subst}; +use rustc::ty::subst::{Kind, Substs}; use rustc_apfloat::{ieee, Float, Status}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use base; @@ -658,8 +658,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { .find(|it| it.kind == ty::AssociatedKind::Method) .unwrap().def_id; // Now create its substs [Closure, Tuple] - let input = tcx.fn_sig(def_id) - .subst(tcx, substs.substs).input(0); + let input = substs.closure_sig(def_id, tcx).input(0); let input = tcx.erase_late_bound_regions_and_normalize(&input); let substs = tcx.mk_substs([operand.ty, input] .iter().cloned().map(Kind::from)); diff --git a/src/librustc_trans_utils/monomorphize.rs b/src/librustc_trans_utils/monomorphize.rs index 66833a1a7c2..d586d1ac315 100644 --- a/src/librustc_trans_utils/monomorphize.rs +++ b/src/librustc_trans_utils/monomorphize.rs @@ -12,7 +12,7 @@ use rustc::hir::def_id::DefId; use rustc::middle::lang_items::DropInPlaceFnLangItem; use rustc::traits; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::ty::subst::{Kind, Subst}; +use rustc::ty::subst::Kind; use rustc::ty::{self, Ty, TyCtxt}; pub use rustc::ty::Instance; @@ -34,7 +34,7 @@ fn fn_once_adapter_instance<'a, 'tcx>( let self_ty = tcx.mk_closure_from_closure_substs( closure_did, substs); - let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs); + let sig = substs.closure_sig(closure_did, tcx); let sig = tcx.erase_late_bound_regions_and_normalize(&sig); assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs([ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b754c981b21..88b9f3cfb93 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1268,15 +1268,23 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, )) } - NodeExpr(&hir::Expr { node: hir::ExprClosure(..), hir_id, .. }) => { - let tables = tcx.typeck_tables_of(def_id); - match tables.node_id_to_type(hir_id).sty { - ty::TyClosure(closure_def_id, closure_substs) => { - assert_eq!(def_id, closure_def_id); - return closure_substs.closure_sig(closure_def_id, tcx); - } - ref t => bug!("closure with non-closure type: {:?}", t), - } + NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { + // In order to property accommodate regions during NLL + // inference, `fn_sig` query only works for top-level + // functions. This is because closures often contain erased regions + // in their signatures that are understood by NLL inference but not other + // parts of the system -- these do not appear in the generics and hence + // are not properly substituted away without some care. + // + // To get the signature of a closure, you should use the + // `closure_sig` method on the `ClosureSubsts`: + // + // closure_substs.closure_sig(def_id, tcx) + // + // or, inside of an inference context, you can use + // + // infcx.closure_sig(def_id, closure_substs) + bug!("to get the signature of a closure, use `closure_sig()` not `fn_sig()`"); } x => {