From 82ab7079dd5de66ece16e35a86336fc7e380302e Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Sat, 14 Nov 2015 12:12:12 -0800 Subject: [PATCH] Consistently normalize fn types after erasing lifetimes. Fixes #23406. Fixes #23958. Fixes #29832. --- src/librustc_trans/trans/attributes.rs | 1 + src/librustc_trans/trans/base.rs | 34 +++++++------------ src/librustc_trans/trans/callee.rs | 25 +++++++++----- src/librustc_trans/trans/closure.rs | 3 ++ .../trans/debuginfo/metadata.rs | 2 ++ src/librustc_trans/trans/debuginfo/mod.rs | 11 ++++-- .../trans/debuginfo/type_names.rs | 2 ++ src/librustc_trans/trans/declare.rs | 8 ++--- src/librustc_trans/trans/intrinsic.rs | 21 +++++------- src/librustc_trans/trans/meth.rs | 2 ++ src/librustc_trans/trans/type_of.rs | 16 +++++---- src/test/run-pass/issue-23406.rs | 23 +++++++++++++ src/test/run-pass/issue-23598.rs | 22 ++++++++++++ 13 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 src/test/run-pass/issue-23406.rs create mode 100644 src/test/run-pass/issue-23598.rs diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index af4c2205e659b..90a649405cddd 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -142,6 +142,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); + let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig); let mut attrs = llvm::AttrBuilder::new(); let ret_ty = fn_sig.output; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 8023f776dde2f..ecd4c75c9d35d 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -38,6 +38,7 @@ use metadata::{csearch, encoder, loader}; use middle::astencode; use middle::cfg; use middle::def_id::DefId; +use middle::infer; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; use middle::pat_util::simple_name; @@ -1905,7 +1906,11 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans_fn(param_substs={:?})", param_substs); let _icx = push_ctxt("trans_fn"); let fn_ty = ccx.tcx().node_id_to_type(id); - let output_type = ccx.tcx().erase_late_bound_regions(&fn_ty.fn_ret()); + let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fn_ty); + let sig = fn_ty.fn_sig(); + let sig = ccx.tcx().erase_late_bound_regions(&sig); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); + let output_type = sig.output; let abi = fn_ty.fn_abi(); trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi, closure::ClosureEnv::NotClosure); @@ -1936,15 +1941,9 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ccx = bcx.fcx.ccx; - let result_ty = match ctor_ty.sty { - ty::TyBareFn(_, ref bft) => { - bcx.tcx().erase_late_bound_regions(&bft.sig.output()).unwrap() - } - _ => ccx.sess().bug( - &format!("trans_enum_variant_constructor: \ - unexpected ctor return type {}", - ctor_ty)) - }; + let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); + let result_ty = sig.output.unwrap(); // Get location to store the result. If the user does not care about // the result, just make a stack slot @@ -2026,15 +2025,10 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx let ctor_ty = ccx.tcx().node_id_to_type(ctor_id); let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty); - let result_ty = match ctor_ty.sty { - ty::TyBareFn(_, ref bft) => { - ccx.tcx().erase_late_bound_regions(&bft.sig.output()) - } - _ => ccx.sess().bug( - &format!("trans_enum_variant_or_tuple_like_struct: \ - unexpected ctor return type {}", - ctor_ty)) - }; + let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); + let arg_tys = sig.inputs; + let result_ty = sig.output; let (arena, fcx): (TypedArena<_>, FunctionContext); arena = TypedArena::new(); @@ -2044,8 +2038,6 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx assert!(!fcx.needs_ret_allocas); - let arg_tys = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_args()); - if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) { let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot"); let repr = adt::represent_type(ccx, result_ty.unwrap()); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index c8525e33e2667..a52c7f94c3a81 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -25,7 +25,7 @@ use llvm::{self, ValueRef, get_params}; use metadata::cstore::LOCAL_CRATE; use middle::def; use middle::def_id::DefId; -use middle::infer::normalize_associated_type; +use middle::infer; use middle::subst; use middle::subst::{Substs}; use rustc::front::map as hir_map; @@ -304,6 +304,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( } }; let sig = tcx.erase_late_bound_regions(sig); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec()); let tuple_fn_ty = tcx.mk_fn(opt_def_id, tcx.mk_bare_fn(ty::BareFnTy { @@ -466,7 +467,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // Type scheme of the function item (may have type params) let fn_type_scheme = tcx.lookup_item_type(def_id); - let fn_type = normalize_associated_type(tcx, &fn_type_scheme.ty); + let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty); // Find the actual function pointer. let mut val = { @@ -605,8 +606,9 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let (abi, ret_ty) = match callee.ty.sty { ty::TyBareFn(_, ref f) => { - let output = bcx.tcx().erase_late_bound_regions(&f.sig.output()); - (f.abi, output) + let sig = bcx.tcx().erase_late_bound_regions(&f.sig); + let sig = infer::normalize_associated_type(bcx.tcx(), &sig); + (f.abi, sig.output) } _ => panic!("expected bare rust fn or closure in trans_call_inner") }; @@ -826,7 +828,9 @@ fn trans_args_under_call_abi<'blk, 'tcx>( ignore_self: bool) -> Block<'blk, 'tcx> { - let args = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_args()); + let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); + let sig = infer::normalize_associated_type(bcx.tcx(), &sig); + let args = sig.inputs; // Translate the `self` argument first. if !ignore_self { @@ -887,7 +891,10 @@ fn trans_overloaded_call_args<'blk, 'tcx>( ignore_self: bool) -> Block<'blk, 'tcx> { // Translate the `self` argument first. - let arg_tys = bcx.tcx().erase_late_bound_regions( &fn_ty.fn_args()); + let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); + let sig = infer::normalize_associated_type(bcx.tcx(), &sig); + let arg_tys = sig.inputs; + if !ignore_self { let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); bcx = trans_arg_datum(bcx, @@ -933,8 +940,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, debug!("trans_args(abi={})", abi); let _icx = push_ctxt("trans_args"); - let arg_tys = cx.tcx().erase_late_bound_regions(&fn_ty.fn_args()); - let variadic = fn_ty.fn_sig().0.variadic; + let sig = cx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); + let arg_tys = sig.inputs; + let variadic = sig.variadic; let mut bcx = cx; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index d3509c2f8133a..04487a6f2d25d 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -210,6 +210,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, tcx.with_freevars(id, |fv| fv.iter().cloned().collect()); let sig = tcx.erase_late_bound_regions(&function_type.sig); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); trans_closure(ccx, decl, @@ -371,6 +372,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let lloncefn = declare::define_internal_rust_fn(ccx, &function_name, llonce_fn_ty); let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); + let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); fcx = new_fn_ctxt(ccx, diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 2e7b1f31ba9bc..addac528aa25c 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -24,6 +24,7 @@ use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; use middle::def_id::DefId; +use middle::infer; use middle::pat_util; use middle::subst::{self, Substs}; use rustc::front::map as hir_map; @@ -262,6 +263,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str(" fn("); let sig = cx.tcx().erase_late_bound_regions(sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); for ¶meter_type in &sig.inputs { let parameter_type_id = diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index a08f33c889994..9e53d72cfb8b9 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -35,6 +35,7 @@ use rustc_front::hir; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; use trans::{monomorphize, type_of}; +use middle::infer; use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; @@ -418,19 +419,23 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Return type -- llvm::DIBuilder wants this at index 0 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); let fn_type = cx.tcx().node_id_to_type(fn_ast_id); + let fn_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &fn_type); let (sig, abi) = match fn_type.sty { ty::TyBareFn(_, ref barefnty) => { - (cx.tcx().erase_late_bound_regions(&barefnty.sig), barefnty.abi) + let sig = cx.tcx().erase_late_bound_regions(&barefnty.sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); + (sig, barefnty.abi) } ty::TyClosure(def_id, ref substs) => { let closure_type = cx.tcx().closure_type(def_id, substs); - (cx.tcx().erase_late_bound_regions(&closure_type.sig), closure_type.abi) + let sig = cx.tcx().erase_late_bound_regions(&closure_type.sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); + (sig, closure_type.abi) } _ => cx.sess().bug("get_function_metdata: Expected a function type!") }; - let sig = monomorphize::apply_param_substs(cx.tcx(), param_substs, &sig); let mut signature = Vec::with_capacity(sig.inputs.len() + 1); diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index 7400ec3cbcd4a..c6b5ce436835f 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -14,6 +14,7 @@ use super::namespace::crate_root_namespace; use trans::common::CrateContext; use middle::def_id::DefId; +use middle::infer; use middle::subst::{self, Substs}; use middle::ty::{self, Ty}; @@ -124,6 +125,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); let sig = cx.tcx().erase_late_bound_regions(sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); if !sig.inputs.is_empty() { for ¶meter_type in &sig.inputs { push_debuginfo_type_name(cx, parameter_type, true, output); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index ce9f3b4b05da1..b9e74beaf55ae 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -103,9 +103,6 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, fn_type: ty::Ty<'tcx>) -> ValueRef { debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); - let fn_type = infer::normalize_associated_type(ccx.tcx(), &fn_type); - debug!("declare_rust_fn (after normalised associated types) fn_type={:?}", - fn_type); let function_type; // placeholder so that the memory ownership works out ok let (sig, abi, env) = match fn_type.sty { @@ -124,14 +121,15 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, _ => ccx.sess().bug("expected closure or fn") }; - let sig = ty::Binder(ccx.tcx().erase_late_bound_regions(sig)); + let sig = ccx.tcx().erase_late_bound_regions(sig); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi); debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty)); // it is ok to directly access sig.0.output because we erased all // late-bound-regions above - let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output); + let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.output); attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn); llfn } diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 773256a17e4ac..98114da851f91 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -15,6 +15,7 @@ use intrinsics::{self, Intrinsic}; use libc; use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; +use middle::infer; use middle::subst; use middle::subst::FnSpace; use trans::adt; @@ -170,13 +171,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_intrinsic_call"); - let (arg_tys, ret_ty) = match callee_ty.sty { - ty::TyBareFn(_, ref f) => { - (bcx.tcx().erase_late_bound_regions(&f.sig.inputs()), - bcx.tcx().erase_late_bound_regions(&f.sig.output())) - } - _ => panic!("expected bare_fn in trans_intrinsic_call") - }; + let sig = ccx.tcx().erase_late_bound_regions(callee_ty.fn_sig()); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); + let arg_tys = sig.inputs; + let ret_ty = sig.output; let foreign_item = tcx.map.expect_foreign_item(node); let name = foreign_item.name.as_str(); @@ -1330,12 +1328,9 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> let tcx = bcx.tcx(); - let arg_tys = match callee_ty.sty { - ty::TyBareFn(_, ref f) => { - bcx.tcx().erase_late_bound_regions(&f.sig.inputs()) - } - _ => unreachable!() - }; + let sig = tcx.erase_late_bound_regions(callee_ty.fn_sig()); + let sig = infer::normalize_associated_type(tcx, &sig); + let arg_tys = sig.inputs; // every intrinsic takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 2b711be5b07cd..ff94e4feda216 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -12,6 +12,7 @@ use arena::TypedArena; use back::link; use llvm::{ValueRef, get_params}; use middle::def_id::DefId; +use middle::infer; use middle::subst::{Subst, Substs}; use middle::subst::VecPerParamSpace; use middle::subst; @@ -522,6 +523,7 @@ fn trans_object_shim<'a, 'tcx>( let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); + let sig = infer::normalize_associated_type(ccx.tcx(), &sig); let empty_substs = tcx.mk_substs(Substs::trans_empty()); let (block_arena, fcx): (TypedArena<_>, FunctionContext); diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 1e9183f309b51..1e371a1697010 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -11,6 +11,7 @@ #![allow(non_camel_case_types)] use middle::def_id::DefId; +use middle::infer; use middle::subst; use trans::adt; use trans::common::*; @@ -89,7 +90,7 @@ pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llenvironment_type: Option, - sig: &ty::Binder>, + sig: &ty::FnSig<'tcx>, abi: abi::Abi) -> Type { @@ -97,16 +98,17 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, sig, abi); - let sig = cx.tcx().erase_late_bound_regions(sig); assert!(!sig.variadic); // rust fns are never variadic let mut atys: Vec = Vec::new(); // First, munge the inputs, if this has the `rust-call` ABI. - let inputs = &if abi == abi::RustCall { - untuple_arguments(cx, &sig.inputs) + let inputs_temp; + let inputs = if abi == abi::RustCall { + inputs_temp = untuple_arguments(cx, &sig.inputs); + &inputs_temp } else { - sig.inputs + &sig.inputs }; // Arg 0: Output pointer. @@ -155,7 +157,9 @@ pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here if f.abi == abi::Rust || f.abi == abi::RustCall { - type_of_rust_fn(cx, None, &f.sig, f.abi) + let sig = cx.tcx().erase_late_bound_regions(&f.sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); + type_of_rust_fn(cx, None, &sig, f.abi) } else { foreign::lltype_for_foreign_fn(cx, fty) } diff --git a/src/test/run-pass/issue-23406.rs b/src/test/run-pass/issue-23406.rs new file mode 100644 index 0000000000000..c3c1b755af833 --- /dev/null +++ b/src/test/run-pass/issue-23406.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Inner { + type T; +} + +impl<'a> Inner for &'a i32 { + type T = i32; +} + +fn f<'a>(x: &'a i32) -> <&'a i32 as Inner>::T { + *x +} + +fn main() {} diff --git a/src/test/run-pass/issue-23598.rs b/src/test/run-pass/issue-23598.rs new file mode 100644 index 0000000000000..5f1c79a3c1542 --- /dev/null +++ b/src/test/run-pass/issue-23598.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Collection where for<'a> &'a Self: IntoIterator { + fn my_iter(&self) -> <&Self as IntoIterator>::IntoIter { + self.into_iter() + } +} + +impl Collection for [T] { } + +fn main() { + let v = [0usize]; + let _ = v.my_iter(); +}