Fix ICE that @steveklabnik encountered in rust-ice. The problems turned out to be that were being very loose with bound regions in trans (we were basically just ignoring and flattening binders). Since binders are significant to subtyping and hence to trait selection, this can cause a lot of problems. So this patch makes us treat them more strictly -- for example, we propagate binders, and avoid skipping past the Binder by writing foo.0.

Fixes #20644.
This commit is contained in:
Niko Matsakis 2015-01-06 05:03:42 -05:00
parent 8efd9901b6
commit 2486d93e5b
23 changed files with 399 additions and 183 deletions

View file

@ -514,7 +514,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
if return_ty == ty::FnDiverging {
if return_ty.diverges() {
self.add_node(ast::DUMMY_NODE_ID, &[])
} else {
ret

View file

@ -864,7 +864,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
None => {}
Some(method_ty) => {
let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
let self_ty = ty::ty_fn_args(method_ty)[0];
// the method call infrastructure should have
// replaced all late-bound regions with variables:
let self_ty = ty::ty_fn_sig(method_ty).input(0);
let self_ty = ty::assert_no_late_bound_regions(self.tcx(), &self_ty);
let (m, r) = match self_ty.sty {
ty::ty_rptr(r, ref m) => (m.mutbl, r),
_ => self.tcx().sess.span_bug(expr.span,

View file

@ -112,6 +112,7 @@ use self::VarKind::*;
use middle::def::*;
use middle::mem_categorization::Typer;
use middle::pat_util;
use middle::region::CodeExtent;
use middle::ty;
use middle::ty::UnboxedClosureTyper;
use lint;
@ -1149,8 +1150,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
ast::ExprCall(ref f, ref args) => {
let diverges = !self.ir.tcx.is_method_call(expr.id) && {
let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f));
t_ret == ty::FnDiverging
ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f)).diverges()
};
let succ = if diverges {
self.s.exit_ln
@ -1164,7 +1164,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
ast::ExprMethodCall(_, _, ref args) => {
let method_call = ty::MethodCall::expr(expr.id);
let method_ty = self.ir.tcx.method_map.borrow().get(&method_call).unwrap().ty;
let diverges = ty::ty_fn_ret(method_ty) == ty::FnDiverging;
let diverges = ty::ty_fn_ret(method_ty).diverges();
let succ = if diverges {
self.s.exit_ln
} else {
@ -1514,11 +1514,11 @@ fn check_fn(_v: &Liveness,
}
impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::FnOutput<'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
match fn_ty.sty {
ty::ty_unboxed_closure(closure_def_id, _, substs) =>
self.ir.tcx.unboxed_closure_type(closure_def_id, substs).sig.0.output,
self.ir.tcx.unboxed_closure_type(closure_def_id, substs).sig.output(),
_ =>
ty::ty_fn_ret(fn_ty),
}
@ -1529,8 +1529,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
sp: Span,
_fk: FnKind,
entry_ln: LiveNode,
body: &ast::Block) {
match self.fn_ret(id) {
body: &ast::Block)
{
// within the fn body, late-bound regions are liberated:
let fn_ret =
ty::liberate_late_bound_regions(
self.ir.tcx,
CodeExtent::from_node_id(body.id),
&self.fn_ret(id));
match fn_ret {
ty::FnConverging(t_ret)
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => {

View file

@ -492,9 +492,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
let method_call = ty::MethodCall::expr(expr.id());
match self.typer.node_method_ty(method_call) {
Some(method_ty) => {
// If this is an index implemented by a method call, then it will
// include an implicit deref of the result.
let ret_ty = ty::ty_fn_ret(method_ty).unwrap();
// If this is an index implemented by a
// method call, then it will include an
// implicit deref of the result.
let ret_ty = self.overloaded_method_return_ty(method_ty);
self.cat_deref(expr,
self.cat_rvalue_node(expr.id(),
expr.span(),
@ -865,7 +866,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
let base_cmt = match method_ty {
Some(method_ty) => {
let ref_ty = ty::ty_fn_ret(method_ty).unwrap();
let ref_ty =
ty::assert_no_late_bound_regions(
self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
}
None => base_cmt
@ -945,9 +948,12 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
let element_ty = match method_ty {
Some(method_ty) => {
let ref_ty = ty::ty_fn_ret(method_ty).unwrap();
let ref_ty = self.overloaded_method_return_ty(method_ty);
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
ty::ty_fn_args(method_ty)[0]
// FIXME(#20649) -- why are we using the `self_ty` as the element type...?
let self_ty = ty::ty_fn_sig(method_ty).input(0);
ty::assert_no_late_bound_regions(self.tcx(), &self_ty)
}
None => {
match ty::array_element_ty(self.tcx(), base_cmt.ty) {
@ -1269,6 +1275,19 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
Ok(())
}
fn overloaded_method_return_ty(&self,
method_ty: Ty<'tcx>)
-> Ty<'tcx>
{
// When we process an overloaded `*` or `[]` etc, we often
// need to extract the return type of the method. These method
// types are generated by method resolution and always have
// all late-bound regions fully instantiated, so we just want
// to skip past the binder.
ty::assert_no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty))
.unwrap() // overloaded ops do not diverge, either
}
}
#[derive(Copy)]

View file

@ -1054,6 +1054,10 @@ pub enum FnOutput<'tcx> {
}
impl<'tcx> FnOutput<'tcx> {
pub fn diverges(&self) -> bool {
*self == FnDiverging
}
pub fn unwrap(self) -> Ty<'tcx> {
match self {
ty::FnConverging(t) => t,
@ -1062,6 +1066,14 @@ impl<'tcx> FnOutput<'tcx> {
}
}
pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
impl<'tcx> PolyFnOutput<'tcx> {
pub fn diverges(&self) -> bool {
self.0.diverges()
}
}
/// Signature of a function type, which I have arbitrarily
/// decided to use to refer to the input/output types.
///
@ -1077,6 +1089,21 @@ pub struct FnSig<'tcx> {
pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
impl<'tcx> PolyFnSig<'tcx> {
pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
ty::Binder(self.0.inputs.clone())
}
pub fn input(&self, index: uint) -> ty::Binder<Ty<'tcx>> {
ty::Binder(self.0.inputs[index])
}
pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
ty::Binder(self.0.output.clone())
}
pub fn variadic(&self) -> bool {
self.0.variadic
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Show)]
pub struct ParamTy {
pub space: subst::ParamSpace,
@ -4145,8 +4172,8 @@ pub fn ty_fn_abi(fty: Ty) -> abi::Abi {
}
// Type accessors for substructures of types
pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> &'tcx [Ty<'tcx>] {
ty_fn_sig(fty).0.inputs.as_slice()
pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> ty::Binder<Vec<Ty<'tcx>>> {
ty_fn_sig(fty).inputs()
}
pub fn ty_closure_store(fty: Ty) -> TraitStore {
@ -4162,9 +4189,9 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore {
}
}
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> {
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> Binder<FnOutput<'tcx>> {
match fty.sty {
ty_bare_fn(_, ref f) => f.sig.0.output,
ty_bare_fn(_, ref f) => f.sig.output(),
ref s => {
panic!("ty_fn_ret() called on non-fn type: {}", s)
}
@ -4319,9 +4346,12 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
let method_call = MethodCall::autoderef(expr_id, i);
match method_type(method_call) {
Some(method_ty) => {
if let ty::FnConverging(result_type) = ty_fn_ret(method_ty) {
adjusted_ty = result_type;
}
// overloaded deref operators have all late-bound
// regions fully instantiated and coverge
let fn_ret =
ty::assert_no_late_bound_regions(cx,
&ty_fn_ret(method_ty));
adjusted_ty = fn_ret.unwrap();
}
None => {}
}
@ -5143,7 +5173,9 @@ impl<'tcx> VariantInfo<'tcx> {
match ast_variant.node.kind {
ast::TupleVariantKind(ref args) => {
let arg_tys = if args.len() > 0 {
ty_fn_args(ctor_ty).iter().map(|a| *a).collect()
// the regions in the argument types come from the
// enum def'n, and hence will all be early bound
ty::assert_no_late_bound_regions(cx, &ty_fn_args(ctor_ty))
} else {
Vec::new()
};
@ -5159,7 +5191,6 @@ impl<'tcx> VariantInfo<'tcx> {
};
},
ast::StructVariantKind(ref struct_def) => {
let fields: &[StructField] = struct_def.fields[];
assert!(fields.len() > 0);
@ -5791,40 +5822,6 @@ pub fn is_binopable<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, op: ast::BinOp) -> bool
return tbl[tycat(cx, ty) as uint ][opcat(op) as uint];
}
/// Returns an equivalent type with all the typedefs and self regions removed.
pub fn normalize_ty<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
let u = TypeNormalizer(cx).fold_ty(ty);
return u;
struct TypeNormalizer<'a, 'tcx: 'a>(&'a ctxt<'tcx>);
impl<'a, 'tcx> TypeFolder<'tcx> for TypeNormalizer<'a, 'tcx> {
fn tcx(&self) -> &ctxt<'tcx> { let TypeNormalizer(c) = *self; c }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
None => {}
Some(u) => return u
}
let t_norm = ty_fold::super_fold_ty(self, ty);
self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
return t_norm;
}
fn fold_region(&mut self, _: ty::Region) -> ty::Region {
ty::ReStatic
}
fn fold_substs(&mut self,
substs: &subst::Substs<'tcx>)
-> subst::Substs<'tcx> {
subst::Substs { regions: subst::ErasedRegions,
types: substs.types.fold_with(self) }
}
}
}
// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
match const_eval::eval_const_expr_partial(tcx, count_expr) {
@ -6204,7 +6201,7 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
mt.mutbl.hash(state);
};
let fn_sig = |&: state: &mut sip::SipState, sig: &Binder<FnSig<'tcx>>| {
let sig = anonymize_late_bound_regions(tcx, sig);
let sig = anonymize_late_bound_regions(tcx, sig).0;
for a in sig.inputs.iter() { helper(tcx, *a, svh, state); }
if let ty::FnConverging(output) = sig.output {
helper(tcx, output, svh, state);
@ -6265,7 +6262,7 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
did(state, data.principal_def_id());
hash!(data.bounds);
let principal = anonymize_late_bound_regions(tcx, &data.principal);
let principal = anonymize_late_bound_regions(tcx, &data.principal).0;
for subty in principal.substs.types.iter() {
helper(tcx, *subty, svh, state);
}
@ -6696,6 +6693,16 @@ pub fn binds_late_bound_regions<'tcx, T>(
count_late_bound_regions(tcx, value) > 0
}
pub fn assert_no_late_bound_regions<'tcx, T>(
tcx: &ty::ctxt<'tcx>,
value: &Binder<T>)
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
{
assert!(!binds_late_bound_regions(tcx, value));
value.0.clone()
}
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
/// method lookup and a few other places where precise region relationships are not required.
pub fn erase_late_bound_regions<'tcx, T>(
@ -6718,14 +6725,14 @@ pub fn erase_late_bound_regions<'tcx, T>(
pub fn anonymize_late_bound_regions<'tcx, T>(
tcx: &ctxt<'tcx>,
sig: &Binder<T>)
-> T
-> Binder<T>
where T : TypeFoldable<'tcx> + Repr<'tcx>,
{
let mut counter = 0;
replace_late_bound_regions(tcx, sig, |_, db| {
ty::Binder(replace_late_bound_regions(tcx, sig, |_, db| {
counter += 1;
ReLateBound(db, BrAnon(counter))
}).0
}).0)
}
/// Replaces the late-bound-regions in `value` that are bound by `value`.

View file

@ -868,6 +868,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
// because whether or not a region is bound affects subtyping,
// we can't erase the bound/free distinction, but we can
// replace all free regions with 'static
match r {
ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
_ => ty::ReStatic

View file

@ -283,35 +283,40 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty);
let (inputs, output, abi, env) = match fn_ty.sty {
let function_type; // placeholder so that the memory ownership works out ok
let (sig, abi, env) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => {
(f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None)
(&f.sig, f.abi, None)
}
ty::ty_unboxed_closure(closure_did, _, substs) => {
let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx());
let function_type = typer.unboxed_closure_type(closure_did, substs);
function_type = typer.unboxed_closure_type(closure_did, substs);
let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty);
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
debug!("decl_rust_fn: function_type={} self_type={}",
function_type.repr(ccx.tcx()),
self_type.repr(ccx.tcx()));
(function_type.sig.0.inputs,
function_type.sig.0.output,
RustCall,
Some(llenvironment_type))
(&function_type.sig, RustCall, Some(llenvironment_type))
}
_ => panic!("expected closure or fn")
};
let llfty = type_of_rust_fn(ccx, env, inputs[], output, abi);
debug!("decl_rust_fn(input count={},type={})",
inputs.len(),
let sig = ty::erase_late_bound_regions(ccx.tcx(), sig);
let sig = ty::Binder(sig);
let llfty = type_of_rust_fn(ccx, env, &sig, abi);
debug!("decl_rust_fn(sig={}, type={})",
sig.repr(ccx.tcx()),
ccx.tn().type_to_string(llfty));
let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, output);
let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output /* (1) */);
let attrs = get_fn_llvm_attributes(ccx, fn_ty);
attrs.apply_llfn(llfn);
// (1) it's ok to directly access sig.0.output because we erased all late-bound-regions above
llfn
}
@ -1938,7 +1943,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
let _icx = push_ctxt("trans_fn");
let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
let output_type = ty::ty_fn_ret(fn_ty);
let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty));
let abi = ty::ty_fn_abi(fn_ty);
trans_closure(ccx,
decl,
@ -1981,7 +1986,9 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let tcx = ccx.tcx();
let result_ty = match ctor_ty.sty {
ty::ty_bare_fn(_, ref bft) => bft.sig.0.output.unwrap(),
ty::ty_bare_fn(_, ref bft) => {
ty::erase_late_bound_regions(bcx.tcx(), &bft.sig.output()).unwrap()
}
_ => ccx.sess().bug(
format!("trans_enum_variant_constructor: \
unexpected ctor return type {}",
@ -2053,7 +2060,9 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
let result_ty = match ctor_ty.sty {
ty::ty_bare_fn(_, ref bft) => bft.sig.0.output,
ty::ty_bare_fn(_, ref bft) => {
ty::erase_late_bound_regions(ccx.tcx(), &bft.sig.output())
}
_ => ccx.sess().bug(
format!("trans_enum_variant_or_tuple_like_struct: \
unexpected ctor return type {}",
@ -2067,7 +2076,9 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
assert!(!fcx.needs_ret_allocas);
let arg_tys = ty::ty_fn_args(ctor_ty);
let arg_tys =
ty::erase_late_bound_regions(
ccx.tcx(), &ty::ty_fn_args(ctor_ty));
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys[]);
@ -2426,25 +2437,28 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>)
-> llvm::AttrBuilder {
-> llvm::AttrBuilder
{
use middle::ty::{BrAnon, ReLateBound};
let function_type;
let (fn_sig, abi, has_env) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => (f.sig.clone(), f.abi, false),
ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, false),
ty::ty_unboxed_closure(closure_did, _, substs) => {
let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx());
let function_type = typer.unboxed_closure_type(closure_did, substs);
(function_type.sig, RustCall, true)
function_type = typer.unboxed_closure_type(closure_did, substs);
(&function_type.sig, RustCall, true)
}
_ => ccx.sess().bug("expected closure or function.")
};
let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig);
// Since index 0 is the return value of the llvm func, we start
// at either 1 or 2 depending on whether there's an env slot or not
let mut first_arg_offset = if has_env { 2 } else { 1 };
let mut attrs = llvm::AttrBuilder::new();
let ret_ty = fn_sig.0.output;
let ret_ty = fn_sig.output;
// These have an odd calling convention, so we need to manually
// unpack the input ty's
@ -2452,15 +2466,15 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
ty::ty_unboxed_closure(_, _, _) => {
assert!(abi == RustCall);
match fn_sig.0.inputs[0].sty {
match fn_sig.inputs[0].sty {
ty::ty_tup(ref inputs) => inputs.clone(),
_ => ccx.sess().bug("expected tuple'd inputs")
}
},
ty::ty_bare_fn(..) if abi == RustCall => {
let mut inputs = vec![fn_sig.0.inputs[0]];
let mut inputs = vec![fn_sig.inputs[0]];
match fn_sig.0.inputs[1].sty {
match fn_sig.inputs[1].sty {
ty::ty_tup(ref t_in) => {
inputs.push_all(t_in[]);
inputs
@ -2468,7 +2482,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
_ => ccx.sess().bug("expected tuple'd inputs")
}
}
_ => fn_sig.0.inputs.clone()
_ => fn_sig.inputs.clone()
};
if let ty::FnConverging(ret_ty) = ret_ty {

View file

@ -265,7 +265,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
let _icx = push_ctxt("trans_fn_pointer_shim");
let tcx = ccx.tcx();
let bare_fn_ty = ty::normalize_ty(tcx, bare_fn_ty);
let bare_fn_ty = normalize_ty(tcx, bare_fn_ty);
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
Some(&llval) => { return llval; }
None => { }
@ -279,16 +279,13 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
// which is the fn pointer, and `args`, which is the arguments tuple.
let (opt_def_id, input_tys, output_ty) =
let (opt_def_id, sig) =
match bare_fn_ty.sty {
ty::ty_bare_fn(opt_def_id,
&ty::BareFnTy { unsafety: ast::Unsafety::Normal,
abi: synabi::Rust,
sig: ty::Binder(ty::FnSig { inputs: ref input_tys,
output: output_ty,
variadic: false })}) =>
{
(opt_def_id, input_tys, output_ty)
ref sig }) => {
(opt_def_id, sig)
}
_ => {
@ -296,7 +293,8 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
bare_fn_ty.repr(tcx))[]);
}
};
let tuple_input_ty = ty::mk_tup(tcx, input_tys.to_vec());
let sig = ty::erase_late_bound_regions(tcx, sig);
let tuple_input_ty = ty::mk_tup(tcx, sig.inputs.to_vec());
let tuple_fn_ty = ty::mk_bare_fn(tcx,
opt_def_id,
tcx.mk_bare_fn(ty::BareFnTy {
@ -305,7 +303,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
sig: ty::Binder(ty::FnSig {
inputs: vec![bare_fn_ty_ref,
tuple_input_ty],
output: output_ty,
output: sig.output,
variadic: false
})}));
debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
@ -326,11 +324,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
llfn,
ast::DUMMY_NODE_ID,
false,
output_ty,
sig.output,
&empty_substs,
None,
&block_arena);
let mut bcx = init_function(&fcx, false, output_ty);
let mut bcx = init_function(&fcx, false, sig.output);
// the first argument (`self`) will be ptr to the the fn pointer
let llfnpointer =
@ -338,14 +336,14 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
// the remaining arguments will be the untupled values
let llargs: Vec<_> =
input_tys.iter()
sig.inputs.iter()
.enumerate()
.map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32))
.collect();
assert!(!fcx.needs_ret_allocas);
let dest = fcx.llretslotptr.get().map(|_|
expr::SaveIn(fcx.get_ret_slot(bcx, output_ty, "ret_slot"))
expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
);
bcx = trans_call_inner(bcx,
@ -355,7 +353,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
ArgVals(llargs[]),
dest).bcx;
finish_fn(&fcx, bcx, output_ty);
finish_fn(&fcx, bcx, sig.output);
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn);
@ -668,7 +666,10 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
let mut bcx = callee.bcx;
let (abi, ret_ty) = match callee_ty.sty {
ty::ty_bare_fn(_, ref f) => (f.abi, f.sig.0.output),
ty::ty_bare_fn(_, ref f) => {
let output = ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output());
(f.abi, output)
}
_ => panic!("expected bare rust fn or closure in trans_call_inner")
};
@ -865,13 +866,18 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
llargs: &mut Vec<ValueRef>,
arg_cleanup_scope: cleanup::ScopeId,
ignore_self: bool)
-> Block<'blk, 'tcx> {
-> Block<'blk, 'tcx>
{
let args =
ty::erase_late_bound_regions(
bcx.tcx(), &ty::ty_fn_args(fn_ty));
// Translate the `self` argument first.
if !ignore_self {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
llargs.push(unpack_result!(bcx, {
trans_arg_datum(bcx,
ty::ty_fn_args(fn_ty)[0],
args[0],
arg_datum,
arg_cleanup_scope,
DontAutorefArg)
@ -926,7 +932,7 @@ fn trans_overloaded_call_args<'blk, 'tcx>(
ignore_self: bool)
-> Block<'blk, 'tcx> {
// Translate the `self` argument first.
let arg_tys = ty::ty_fn_args(fn_ty);
let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(fn_ty));
if !ignore_self {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
llargs.push(unpack_result!(bcx, {
@ -974,7 +980,7 @@ 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 = ty::ty_fn_args(fn_ty);
let arg_tys = ty::erase_late_bound_regions(cx.tcx(), &ty::ty_fn_args(fn_ty));
let variadic = ty::fn_is_variadic(fn_ty);
let mut bcx = cx;

View file

@ -442,7 +442,7 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
bcx.fcx.param_substs,
id,
&[],
ty::ty_fn_ret(fty),
ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fty)),
ty::ty_fn_abi(fty),
ClosureEnv::new(freevars[],
BoxedClosure(cdata_ty, store)));
@ -466,7 +466,7 @@ pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext
// Normalize type so differences in regions and typedefs don't cause
// duplicate declarations
let function_type = ty::normalize_ty(ccx.tcx(), function_type);
let function_type = normalize_ty(ccx.tcx(), function_type);
let params = match function_type.sty {
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
_ => unreachable!()
@ -533,6 +533,8 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect());
let freevar_mode = bcx.tcx().capture_mode(id);
let sig = ty::erase_late_bound_regions(bcx.tcx(), &function_type.sig);
trans_closure(bcx.ccx(),
decl,
body,
@ -540,7 +542,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
bcx.fcx.param_substs,
id,
&[],
function_type.sig.0.output,
sig.output,
function_type.abi,
ClosureEnv::new(freevars[],
UnboxedClosure(freevar_mode)));

View file

@ -58,6 +58,61 @@ use util::nodemap::FnvHashSet;
pub use trans::context::CrateContext;
/// Returns an equivalent type with all the typedefs and self regions removed.
pub fn normalize_ty<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
let u = TypeNormalizer(cx).fold_ty(ty);
debug!("normalize_ty({}) = {}",
ty.repr(cx), u.repr(cx));
return u;
struct TypeNormalizer<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
impl<'a, 'tcx> TypeFolder<'tcx> for TypeNormalizer<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
None => {}
Some(u) => return u
}
let t_norm = ty_fold::super_fold_ty(self, ty);
self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
return t_norm;
}
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
// FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
let u = ty::anonymize_late_bound_regions(self.tcx(), t);
ty_fold::super_fold_binder(self, &u)
}
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
// because late-bound regions affect subtyping, we can't
// erase the bound/free distinction, but we can replace
// all free regions with 'static.
//
// Note that we *CAN* replace early-bound regions -- the
// type system never "sees" those, they get substituted
// away. In trans, they will always be erased to 'static
// whenever a substitution occurs.
match r {
ty::ReLateBound(..) => r,
_ => ty::ReStatic
}
}
fn fold_substs(&mut self,
substs: &subst::Substs<'tcx>)
-> subst::Substs<'tcx> {
subst::Substs { regions: subst::ErasedRegions,
types: substs.types.fold_with(self) }
}
}
}
// Is the type's representation size known at compile time?
pub fn type_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
ty::type_contents(cx, ty).is_sized(cx)

View file

@ -265,7 +265,8 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
pat: &ast::Pat,
head: &ast::Expr,
body: &ast::Block)
-> Block<'blk, 'tcx> {
-> Block<'blk, 'tcx>
{
let _icx = push_ctxt("trans_for");
// bcx
@ -306,7 +307,9 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
.borrow())[method_call]
.ty;
let method_type = monomorphize_type(loopback_bcx_in, method_type);
let method_result_type = ty::ty_fn_ret(method_type).unwrap();
let method_result_type =
ty::assert_no_late_bound_regions( // LB regions are instantiated in invoked methods
loopback_bcx_in.tcx(), &ty::ty_fn_ret(method_type)).unwrap();
let option_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
let option_cleanup_scope_id = cleanup::CustomScope(option_cleanup_scope);

View file

@ -425,10 +425,14 @@ impl<'tcx> TypeMap<'tcx> {
ty::ty_trait(ref trait_data) => {
unique_type_id.push_str("trait ");
let principal =
ty::erase_late_bound_regions(cx.tcx(),
&trait_data.principal);
from_def_id_and_substs(self,
cx,
trait_data.principal_def_id(),
trait_data.principal.0.substs,
principal.def_id,
principal.substs,
&mut unique_type_id);
},
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
@ -440,7 +444,9 @@ impl<'tcx> TypeMap<'tcx> {
unique_type_id.push_str(" fn(");
for &parameter_type in sig.0.inputs.iter() {
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
for &parameter_type in sig.inputs.iter() {
let parameter_type_id =
self.get_unique_type_id_of_type(cx, parameter_type);
let parameter_type_id =
@ -449,12 +455,12 @@ impl<'tcx> TypeMap<'tcx> {
unique_type_id.push(',');
}
if sig.0.variadic {
if sig.variadic {
unique_type_id.push_str("...");
}
unique_type_id.push_str(")->");
match sig.0.output {
match sig.output {
ty::FnConverging(ret_ty) => {
let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
@ -568,7 +574,9 @@ impl<'tcx> TypeMap<'tcx> {
}
};
for &parameter_type in sig.0.inputs.iter() {
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
for &parameter_type in sig.inputs.iter() {
let parameter_type_id =
self.get_unique_type_id_of_type(cx, parameter_type);
let parameter_type_id =
@ -577,13 +585,13 @@ impl<'tcx> TypeMap<'tcx> {
unique_type_id.push(',');
}
if sig.0.variadic {
if sig.variadic {
unique_type_id.push_str("...");
}
unique_type_id.push_str("|->");
match sig.0.output {
match sig.output {
ty::FnConverging(ret_ty) => {
let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
@ -2822,11 +2830,14 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
unique_type_id: UniqueTypeId,
signature: &ty::PolyFnSig<'tcx>,
span: Span)
-> MetadataCreationResult {
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.0.inputs.len() + 1);
-> MetadataCreationResult
{
let signature = ty::erase_late_bound_regions(cx.tcx(), signature);
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
// return type
signature_metadata.push(match signature.0.output {
signature_metadata.push(match signature.output {
ty::FnConverging(ret_ty) => match ret_ty.sty {
ty::ty_tup(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, ret_ty, span)
@ -2835,7 +2846,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
});
// regular arguments
for &argument_type in signature.0.inputs.iter() {
for &argument_type in signature.inputs.iter() {
signature_metadata.push(type_metadata(cx, argument_type, span));
}
@ -3794,8 +3805,9 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
output.push(']');
},
ty::ty_trait(ref trait_data) => {
push_item_name(cx, trait_data.principal_def_id(), false, output);
push_type_params(cx, trait_data.principal.0.substs, output);
let principal = ty::erase_late_bound_regions(cx.tcx(), &trait_data.principal);
push_item_name(cx, principal.def_id, false, output);
push_type_params(cx, principal.substs, output);
},
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == ast::Unsafety::Unsafe {
@ -3810,8 +3822,9 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
output.push_str("fn(");
if sig.0.inputs.len() > 0 {
for &parameter_type in sig.0.inputs.iter() {
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
if sig.inputs.len() > 0 {
for &parameter_type in sig.inputs.iter() {
push_debuginfo_type_name(cx, parameter_type, true, output);
output.push_str(", ");
}
@ -3819,8 +3832,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
output.pop();
}
if sig.0.variadic {
if sig.0.inputs.len() > 0 {
if sig.variadic {
if sig.inputs.len() > 0 {
output.push_str(", ...");
} else {
output.push_str("...");
@ -3829,7 +3842,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
output.push(')');
match sig.0.output {
match sig.output {
ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
ty::FnConverging(result_type) => {
output.push_str(" -> ");

View file

@ -585,14 +585,16 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
.borrow()
.get(&method_call)
.map(|method| method.ty);
let method_ty = monomorphize_type(bcx, method_ty.unwrap());
let base_datum = unpack_datum!(bcx, trans(bcx, &**base));
let mut args = vec![];
start.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
end.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
let result_ty = ty::ty_fn_ret(monomorphize_type(bcx,
method_ty.unwrap())).unwrap();
let result_ty = // LB regions are instantiated in invoked methods
ty::assert_no_late_bound_regions(
bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
let scratch = rvalue_scratch_datum(bcx, result_ty, "trans_slice");
unpack_result!(bcx,
@ -732,12 +734,16 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
.map(|method| method.ty);
let elt_datum = match method_ty {
Some(method_ty) => {
let method_ty = monomorphize_type(bcx, method_ty);
let base_datum = unpack_datum!(bcx, trans(bcx, base));
// Translate index expression.
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)).unwrap();
let ref_ty = // invoked methods have LB regions instantiated:
ty::assert_no_late_bound_regions(
bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
let elt_ty = match ty::deref(ref_ty, true) {
None => {
bcx.tcx().sess.span_bug(index_expr.span,
@ -2181,6 +2187,8 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
.get(&method_call).map(|method| method.ty);
let datum = match method_ty {
Some(method_ty) => {
let method_ty = monomorphize_type(bcx, method_ty);
// Overloaded. Evaluate `trans_overloaded_op`, which will
// invoke the user's deref() method, which basically
// converts from the `Smaht<T>` pointer that we have into
@ -2192,7 +2200,9 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
_ => datum
};
let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)).unwrap();
let ref_ty = // invoked methods have their LB regions instantiated
ty::assert_no_late_bound_regions(
ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,

View file

@ -43,7 +43,7 @@ use util::ppaux::Repr;
struct ForeignTypes<'tcx> {
/// Rust signature of the function
fn_sig: ty::PolyFnSig<'tcx>,
fn_sig: ty::FnSig<'tcx>,
/// Adapter object for handling native ABI rules (trust me, you
/// don't want to know)
@ -180,7 +180,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Make sure the calling convention is right for variadic functions
// (should've been caught if not in typeck)
if tys.fn_sig.0.variadic {
if tys.fn_sig.variadic {
assert!(cc == llvm::CCallConv);
}
@ -218,7 +218,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llretptr: ValueRef,
llargs_rust: &[ValueRef],
passed_arg_tys: Vec<Ty<'tcx>>)
-> Block<'blk, 'tcx> {
-> Block<'blk, 'tcx>
{
let ccx = bcx.ccx();
let tcx = bcx.tcx();
@ -230,9 +231,10 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ccx.tn().val_to_string(llretptr));
let (fn_abi, fn_sig) = match callee_ty.sty {
ty::ty_bare_fn(_, ref fn_ty) => (fn_ty.abi, fn_ty.sig.clone()),
ty::ty_bare_fn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
_ => ccx.sess().bug("trans_native_call called on non-function type")
};
let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig);
let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys[]);
let fn_type = cabi::compute_abi_info(ccx,
llsig.llarg_tys[],
@ -387,7 +389,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty));
if llrust_ret_ty == llforeign_ret_ty {
match fn_sig.0.output {
match fn_sig.output {
ty::FnConverging(result_ty) => {
base::store_ty(bcx, llforeign_retval, llretptr, result_ty)
}
@ -635,7 +637,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
};
// Push Rust return pointer, using null if it will be unused.
let rust_uses_outptr = match tys.fn_sig.0.output {
let rust_uses_outptr = match tys.fn_sig.output {
ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
ty::FnDiverging => false
};
@ -668,7 +670,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
return_ty={}",
ccx.tn().val_to_string(slot),
ccx.tn().type_to_string(llrust_ret_ty),
tys.fn_sig.0.output.repr(tcx));
tys.fn_sig.output.repr(tcx));
llrust_args.push(slot);
return_alloca = Some(slot);
}
@ -683,8 +685,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Build up the arguments to the call to the rust function.
// Careful to adapt for cases where the native convention uses
// a pointer and Rust does not or vice versa.
for i in range(0, tys.fn_sig.0.inputs.len()) {
let rust_ty = tys.fn_sig.0.inputs[i];
for i in range(0, tys.fn_sig.inputs.len()) {
let rust_ty = tys.fn_sig.inputs[i];
let llrust_ty = tys.llsig.llarg_tys[i];
let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
@ -829,10 +831,11 @@ pub fn link_name(i: &ast::ForeignItem) -> InternedString {
/// because foreign functions just plain ignore modes. They also don't pass aggregate values by
/// pointer like we do.
fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_sig: &ty::PolyFnSig<'tcx>, arg_tys: &[Ty<'tcx>])
fn_sig: &ty::FnSig<'tcx>,
arg_tys: &[Ty<'tcx>])
-> LlvmSignature {
let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect();
let (llret_ty, ret_def) = match fn_sig.0.output {
let (llret_ty, ret_def) = match fn_sig.output {
ty::FnConverging(ret_ty) =>
(type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
ty::FnDiverging =>
@ -853,10 +856,11 @@ fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
let fn_sig = match ty.sty {
ty::ty_bare_fn(_, ref fn_ty) => fn_ty.sig.clone(),
ty::ty_bare_fn(_, ref fn_ty) => &fn_ty.sig,
_ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
};
let llsig = foreign_signature(ccx, &fn_sig, fn_sig.0.inputs.as_slice());
let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig);
let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice());
let fn_ty = cabi::compute_abi_info(ccx,
llsig.llarg_tys[],
llsig.llret_ty,
@ -916,7 +920,7 @@ fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> T
llargument_tys.push(llarg_ty);
}
if tys.fn_sig.0.variadic {
if tys.fn_sig.variadic {
Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty)
} else {
Type::func(llargument_tys[], &llreturn_ty)

View file

@ -212,7 +212,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
dtor_did: ast::DefId,
class_did: ast::DefId,
substs: &subst::Substs<'tcx>)
-> Block<'blk, 'tcx> {
-> Block<'blk, 'tcx>
{
let repr = adt::represent_type(bcx.ccx(), t);
// Find and call the actual destructor
@ -228,8 +229,9 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
let self_ty = match fty.sty {
ty::ty_bare_fn(_, ref f) => {
assert!(f.sig.0.inputs.len() == 1);
f.sig.0.inputs[0]
let sig = ty::erase_late_bound_regions(bcx.tcx(), &f.sig);
assert!(sig.inputs.len() == 1);
sig.inputs[0]
}
_ => bcx.sess().bug(format!("Expected function type, found {}",
bcx.ty_to_string(fty))[])

View file

@ -150,14 +150,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
dest: expr::Dest,
substs: subst::Substs<'tcx>,
call_info: NodeInfo)
-> Result<'blk, 'tcx> {
-> Result<'blk, 'tcx>
{
let fcx = bcx.fcx;
let ccx = fcx.ccx;
let tcx = bcx.tcx();
let ret_ty = match callee_ty.sty {
ty::ty_bare_fn(_, ref f) => f.sig.0.output,
ty::ty_bare_fn(_, ref f) => {
ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output())
}
_ => panic!("expected bare_fn in trans_intrinsic_call")
};
let foreign_item = tcx.map.expect_foreign_item(node);

View file

@ -477,13 +477,19 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Load the function from the vtable and cast it to the expected type.
debug!("(translating trait callee) loading method");
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
let llcallee_ty = match callee_ty.sty {
ty::ty_bare_fn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
let fake_sig =
ty::Binder(ty::FnSig {
inputs: f.sig.0.inputs.slice_from(1).to_vec(),
output: f.sig.0.output,
variadic: f.sig.0.variadic,
});
type_of_rust_fn(ccx,
Some(Type::i8p(ccx)),
f.sig.0.inputs.slice_from(1),
f.sig.0.output,
&fake_sig,
f.abi)
}
_ => {
@ -557,7 +563,8 @@ pub fn trans_object_shim<'a, 'tcx>(
// Upcast to the trait in question and extract out the substitutions.
let upcast_trait_ref = traits::upcast(ccx.tcx(), object_trait_ref.clone(), trait_id).unwrap();
let object_substs = upcast_trait_ref.substs().clone().erase_regions();
let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref);
let object_substs = upcast_trait_ref.substs.clone().erase_regions();
debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));
// Lookup the type of this method as deeclared in the trait and apply substitutions.
@ -579,6 +586,8 @@ pub fn trans_object_shim<'a, 'tcx>(
let llfn =
decl_internal_rust_fn(ccx, method_bare_fn_ty, function_name.as_slice());
let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig);
//
let block_arena = TypedArena::new();
let empty_substs = Substs::trans_empty();
@ -586,11 +595,11 @@ pub fn trans_object_shim<'a, 'tcx>(
llfn,
ast::DUMMY_NODE_ID,
false,
fty.sig.0.output,
sig.output,
&empty_substs,
None,
&block_arena);
let mut bcx = init_function(&fcx, false, fty.sig.0.output);
let mut bcx = init_function(&fcx, false, sig.output);
// the first argument (`self`) will be a trait object
let llobject = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
@ -603,18 +612,18 @@ pub fn trans_object_shim<'a, 'tcx>(
match fty.abi {
RustCall => {
// unpack the tuple to extract the input type arguments:
match fty.sig.0.inputs[1].sty {
match sig.inputs[1].sty {
ty::ty_tup(ref tys) => tys.as_slice(),
_ => {
bcx.sess().bug(
format!("rust-call expects a tuple not {}",
fty.sig.0.inputs[1].repr(tcx)).as_slice());
sig.inputs[1].repr(tcx)).as_slice());
}
}
}
_ => {
// skip the self parameter:
fty.sig.0.inputs.slice_from(1)
sig.inputs.slice_from(1)
}
};
@ -631,9 +640,12 @@ pub fn trans_object_shim<'a, 'tcx>(
assert!(!fcx.needs_ret_allocas);
let sig =
ty::erase_late_bound_regions(bcx.tcx(), &fty.sig);
let dest =
fcx.llretslotptr.get().map(
|_| expr::SaveIn(fcx.get_ret_slot(bcx, fty.sig.0.output, "ret_slot")));
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
let method_offset_in_vtable =
traits::get_vtable_index_of_object_method(bcx.tcx(),
@ -653,7 +665,7 @@ pub fn trans_object_shim<'a, 'tcx>(
ArgVals(llargs.as_slice()),
dest).bcx;
finish_fn(&fcx, bcx, fty.sig.0.output);
finish_fn(&fcx, bcx, sig.output);
llfn
}

View file

@ -17,7 +17,7 @@ use trans::adt;
use trans::common::*;
use trans::foreign;
use trans::machine;
use middle::ty::{self, Ty};
use middle::ty::{self, RegionEscape, Ty};
use util::ppaux;
use util::ppaux::Repr;
@ -99,18 +99,21 @@ pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
llenvironment_type: Option<Type>,
inputs: &[Ty<'tcx>],
output: ty::FnOutput<'tcx>,
sig: &ty::Binder<ty::FnSig<'tcx>>,
abi: abi::Abi)
-> Type {
-> Type
{
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
assert!(!sig.variadic); // rust fns are never variadic
let mut atys: Vec<Type> = Vec::new();
// First, munge the inputs, if this has the `rust-call` ABI.
let inputs = untuple_arguments_if_necessary(cx, inputs, abi);
let inputs = untuple_arguments_if_necessary(cx, sig.inputs.as_slice(), abi);
// Arg 0: Output pointer.
// (if the output type is non-immediate)
let lloutputtype = match output {
let lloutputtype = match sig.output {
ty::FnConverging(output) => {
let use_out_pointer = return_uses_outptr(cx, output);
let lloutputtype = arg_type_of(cx, output);
@ -147,11 +150,7 @@ 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.0.inputs.as_slice(),
f.sig.0.output,
f.abi)
type_of_rust_fn(cx, None, &f.sig, f.abi)
} else {
foreign::lltype_for_foreign_fn(cx, fty)
}
@ -279,12 +278,14 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
debug!("type_of {} {}", t.repr(cx.tcx()), t.sty);
assert!(!t.has_escaping_regions());
// Replace any typedef'd types with their equivalent non-typedef
// type. This ensures that all LLVM nominal types that contain
// Rust types are defined as the same LLVM types. If we don't do
// this then, e.g. `Option<{myfield: bool}>` would be a different
// type than `Option<myrec>`.
let t_norm = ty::normalize_ty(cx.tcx(), t);
let t_norm = normalize_ty(cx.tcx(), t);
if t != t_norm {
let llty = type_of(cx, t_norm);

View file

@ -505,9 +505,10 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
let ctor_scheme = ty::lookup_item_type(tcx, enum_def);
let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) {
let fn_ret = ty::assert_no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty));
ty::TypeScheme {
ty: ty::ty_fn_ret(ctor_scheme.ty).unwrap(),
..ctor_scheme
ty: fn_ret.unwrap(),
generics: ctor_scheme.generics,
}
} else {
ctor_scheme

View file

@ -2317,7 +2317,9 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
{
match method {
Some(method) => {
let ref_ty = ty::ty_fn_ret(method.ty);
let ref_ty = // invoked methods have all LB regions instantiated
ty::assert_no_late_bound_regions(
fcx.tcx(), &ty::ty_fn_ret(method.ty));
match method_call {
Some(method_call) => {
fcx.inh.method_map.borrow_mut().insert(method_call,
@ -2448,7 +2450,11 @@ fn try_overloaded_slice_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
let method_ty = method.ty;
make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method));
let result_ty = ty::ty_fn_ret(method_ty);
let result_ty =
// invoked methods have LB regions instantiated
ty::assert_no_late_bound_regions(fcx.tcx(),
&ty::ty_fn_ret(method_ty));
let result_ty = match result_ty {
ty::FnConverging(result_ty) => result_ty,
ty::FnDiverging => {

View file

@ -582,7 +582,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
Some(method) => {
constrain_call(rcx, expr, Some(&**base),
None::<ast::Expr>.iter(), true);
ty::ty_fn_ret(method.ty).unwrap()
let fn_ret = // late-bound regions in overloaded method calls are instantiated
ty::assert_no_late_bound_regions(rcx.tcx(), &ty::ty_fn_ret(method.ty));
fn_ret.unwrap()
}
None => rcx.resolve_node_type(base.id)
};

View file

@ -416,7 +416,13 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
match variant.node.kind {
ast::TupleVariantKind(ref args) if args.len() > 0 => {
let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id);
let arg_tys = ty::ty_fn_args(ctor_ty);
// the regions in the argument types come from the
// enum def'n, and hence will all be early bound
let arg_tys =
ty::assert_no_late_bound_regions(
fcx.tcx(), &ty::ty_fn_args(ctor_ty));
AdtVariant {
fields: args.iter().enumerate().map(|(index, arg)| {
let arg_ty = arg_tys[index];

View file

@ -0,0 +1,35 @@
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// A reduced version of the rustbook ice. The problem this encountered
// had to do with trans ignoring binders.
#![feature(slicing_syntax)]
#![feature(associated_types)]
#![feature(macro_rules)]
use std::iter;
use std::os;
use std::io::File;
#[allow(unused)]
pub fn parse_summary<R: Reader>(_: R, _: &Path) {
let path_from_root = Path::new("");
Path::new(iter::repeat("../")
.take(path_from_root.components().count() - 1)
.collect::<String>());
}
fn main() {
let cwd = os::getcwd().unwrap();
let src = cwd.clone();
let summary = File::open(&src.join("SUMMARY.md"));
let _ = parse_summary(summary, &src);
}