Skip to content

Commit 2486d93

Browse files
committed
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.
1 parent 8efd990 commit 2486d93

23 files changed

+399
-183
lines changed

src/librustc/middle/cfg/construct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
514514

515515
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
516516
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
517-
if return_ty == ty::FnDiverging {
517+
if return_ty.diverges() {
518518
self.add_node(ast::DUMMY_NODE_ID, &[])
519519
} else {
520520
ret

src/librustc/middle/expr_use_visitor.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
864864
None => {}
865865
Some(method_ty) => {
866866
let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
867-
let self_ty = ty::ty_fn_args(method_ty)[0];
867+
868+
// the method call infrastructure should have
869+
// replaced all late-bound regions with variables:
870+
let self_ty = ty::ty_fn_sig(method_ty).input(0);
871+
let self_ty = ty::assert_no_late_bound_regions(self.tcx(), &self_ty);
872+
868873
let (m, r) = match self_ty.sty {
869874
ty::ty_rptr(r, ref m) => (m.mutbl, r),
870875
_ => self.tcx().sess.span_bug(expr.span,

src/librustc/middle/liveness.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ use self::VarKind::*;
112112
use middle::def::*;
113113
use middle::mem_categorization::Typer;
114114
use middle::pat_util;
115+
use middle::region::CodeExtent;
115116
use middle::ty;
116117
use middle::ty::UnboxedClosureTyper;
117118
use lint;
@@ -1149,8 +1150,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11491150

11501151
ast::ExprCall(ref f, ref args) => {
11511152
let diverges = !self.ir.tcx.is_method_call(expr.id) && {
1152-
let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f));
1153-
t_ret == ty::FnDiverging
1153+
ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f)).diverges()
11541154
};
11551155
let succ = if diverges {
11561156
self.s.exit_ln
@@ -1164,7 +1164,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11641164
ast::ExprMethodCall(_, _, ref args) => {
11651165
let method_call = ty::MethodCall::expr(expr.id);
11661166
let method_ty = self.ir.tcx.method_map.borrow().get(&method_call).unwrap().ty;
1167-
let diverges = ty::ty_fn_ret(method_ty) == ty::FnDiverging;
1167+
let diverges = ty::ty_fn_ret(method_ty).diverges();
11681168
let succ = if diverges {
11691169
self.s.exit_ln
11701170
} else {
@@ -1514,11 +1514,11 @@ fn check_fn(_v: &Liveness,
15141514
}
15151515

15161516
impl<'a, 'tcx> Liveness<'a, 'tcx> {
1517-
fn fn_ret(&self, id: NodeId) -> ty::FnOutput<'tcx> {
1517+
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
15181518
let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
15191519
match fn_ty.sty {
15201520
ty::ty_unboxed_closure(closure_def_id, _, substs) =>
1521-
self.ir.tcx.unboxed_closure_type(closure_def_id, substs).sig.0.output,
1521+
self.ir.tcx.unboxed_closure_type(closure_def_id, substs).sig.output(),
15221522
_ =>
15231523
ty::ty_fn_ret(fn_ty),
15241524
}
@@ -1529,8 +1529,16 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15291529
sp: Span,
15301530
_fk: FnKind,
15311531
entry_ln: LiveNode,
1532-
body: &ast::Block) {
1533-
match self.fn_ret(id) {
1532+
body: &ast::Block)
1533+
{
1534+
// within the fn body, late-bound regions are liberated:
1535+
let fn_ret =
1536+
ty::liberate_late_bound_regions(
1537+
self.ir.tcx,
1538+
CodeExtent::from_node_id(body.id),
1539+
&self.fn_ret(id));
1540+
1541+
match fn_ret {
15341542
ty::FnConverging(t_ret)
15351543
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => {
15361544

src/librustc/middle/mem_categorization.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
492492
let method_call = ty::MethodCall::expr(expr.id());
493493
match self.typer.node_method_ty(method_call) {
494494
Some(method_ty) => {
495-
// If this is an index implemented by a method call, then it will
496-
// include an implicit deref of the result.
497-
let ret_ty = ty::ty_fn_ret(method_ty).unwrap();
495+
// If this is an index implemented by a
496+
// method call, then it will include an
497+
// implicit deref of the result.
498+
let ret_ty = self.overloaded_method_return_ty(method_ty);
498499
self.cat_deref(expr,
499500
self.cat_rvalue_node(expr.id(),
500501
expr.span(),
@@ -865,7 +866,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
865866

866867
let base_cmt = match method_ty {
867868
Some(method_ty) => {
868-
let ref_ty = ty::ty_fn_ret(method_ty).unwrap();
869+
let ref_ty =
870+
ty::assert_no_late_bound_regions(
871+
self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
869872
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
870873
}
871874
None => base_cmt
@@ -945,9 +948,12 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
945948

946949
let element_ty = match method_ty {
947950
Some(method_ty) => {
948-
let ref_ty = ty::ty_fn_ret(method_ty).unwrap();
951+
let ref_ty = self.overloaded_method_return_ty(method_ty);
949952
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
950-
ty::ty_fn_args(method_ty)[0]
953+
954+
// FIXME(#20649) -- why are we using the `self_ty` as the element type...?
955+
let self_ty = ty::ty_fn_sig(method_ty).input(0);
956+
ty::assert_no_late_bound_regions(self.tcx(), &self_ty)
951957
}
952958
None => {
953959
match ty::array_element_ty(self.tcx(), base_cmt.ty) {
@@ -1269,6 +1275,19 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
12691275

12701276
Ok(())
12711277
}
1278+
1279+
fn overloaded_method_return_ty(&self,
1280+
method_ty: Ty<'tcx>)
1281+
-> Ty<'tcx>
1282+
{
1283+
// When we process an overloaded `*` or `[]` etc, we often
1284+
// need to extract the return type of the method. These method
1285+
// types are generated by method resolution and always have
1286+
// all late-bound regions fully instantiated, so we just want
1287+
// to skip past the binder.
1288+
ty::assert_no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty))
1289+
.unwrap() // overloaded ops do not diverge, either
1290+
}
12721291
}
12731292

12741293
#[derive(Copy)]

src/librustc/middle/ty.rs

+55-48
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,10 @@ pub enum FnOutput<'tcx> {
10541054
}
10551055

10561056
impl<'tcx> FnOutput<'tcx> {
1057+
pub fn diverges(&self) -> bool {
1058+
*self == FnDiverging
1059+
}
1060+
10571061
pub fn unwrap(self) -> Ty<'tcx> {
10581062
match self {
10591063
ty::FnConverging(t) => t,
@@ -1062,6 +1066,14 @@ impl<'tcx> FnOutput<'tcx> {
10621066
}
10631067
}
10641068

1069+
pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
1070+
1071+
impl<'tcx> PolyFnOutput<'tcx> {
1072+
pub fn diverges(&self) -> bool {
1073+
self.0.diverges()
1074+
}
1075+
}
1076+
10651077
/// Signature of a function type, which I have arbitrarily
10661078
/// decided to use to refer to the input/output types.
10671079
///
@@ -1077,6 +1089,21 @@ pub struct FnSig<'tcx> {
10771089

10781090
pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
10791091

1092+
impl<'tcx> PolyFnSig<'tcx> {
1093+
pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
1094+
ty::Binder(self.0.inputs.clone())
1095+
}
1096+
pub fn input(&self, index: uint) -> ty::Binder<Ty<'tcx>> {
1097+
ty::Binder(self.0.inputs[index])
1098+
}
1099+
pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
1100+
ty::Binder(self.0.output.clone())
1101+
}
1102+
pub fn variadic(&self) -> bool {
1103+
self.0.variadic
1104+
}
1105+
}
1106+
10801107
#[derive(Clone, Copy, PartialEq, Eq, Hash, Show)]
10811108
pub struct ParamTy {
10821109
pub space: subst::ParamSpace,
@@ -4145,8 +4172,8 @@ pub fn ty_fn_abi(fty: Ty) -> abi::Abi {
41454172
}
41464173

41474174
// Type accessors for substructures of types
4148-
pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> &'tcx [Ty<'tcx>] {
4149-
ty_fn_sig(fty).0.inputs.as_slice()
4175+
pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> ty::Binder<Vec<Ty<'tcx>>> {
4176+
ty_fn_sig(fty).inputs()
41504177
}
41514178

41524179
pub fn ty_closure_store(fty: Ty) -> TraitStore {
@@ -4162,9 +4189,9 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore {
41624189
}
41634190
}
41644191

4165-
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> {
4192+
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> Binder<FnOutput<'tcx>> {
41664193
match fty.sty {
4167-
ty_bare_fn(_, ref f) => f.sig.0.output,
4194+
ty_bare_fn(_, ref f) => f.sig.output(),
41684195
ref s => {
41694196
panic!("ty_fn_ret() called on non-fn type: {}", s)
41704197
}
@@ -4319,9 +4346,12 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
43194346
let method_call = MethodCall::autoderef(expr_id, i);
43204347
match method_type(method_call) {
43214348
Some(method_ty) => {
4322-
if let ty::FnConverging(result_type) = ty_fn_ret(method_ty) {
4323-
adjusted_ty = result_type;
4324-
}
4349+
// overloaded deref operators have all late-bound
4350+
// regions fully instantiated and coverge
4351+
let fn_ret =
4352+
ty::assert_no_late_bound_regions(cx,
4353+
&ty_fn_ret(method_ty));
4354+
adjusted_ty = fn_ret.unwrap();
43254355
}
43264356
None => {}
43274357
}
@@ -5143,7 +5173,9 @@ impl<'tcx> VariantInfo<'tcx> {
51435173
match ast_variant.node.kind {
51445174
ast::TupleVariantKind(ref args) => {
51455175
let arg_tys = if args.len() > 0 {
5146-
ty_fn_args(ctor_ty).iter().map(|a| *a).collect()
5176+
// the regions in the argument types come from the
5177+
// enum def'n, and hence will all be early bound
5178+
ty::assert_no_late_bound_regions(cx, &ty_fn_args(ctor_ty))
51475179
} else {
51485180
Vec::new()
51495181
};
@@ -5159,7 +5191,6 @@ impl<'tcx> VariantInfo<'tcx> {
51595191
};
51605192
},
51615193
ast::StructVariantKind(ref struct_def) => {
5162-
51635194
let fields: &[StructField] = struct_def.fields[];
51645195

51655196
assert!(fields.len() > 0);
@@ -5791,40 +5822,6 @@ pub fn is_binopable<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, op: ast::BinOp) -> bool
57915822
return tbl[tycat(cx, ty) as uint ][opcat(op) as uint];
57925823
}
57935824

5794-
/// Returns an equivalent type with all the typedefs and self regions removed.
5795-
pub fn normalize_ty<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
5796-
let u = TypeNormalizer(cx).fold_ty(ty);
5797-
return u;
5798-
5799-
struct TypeNormalizer<'a, 'tcx: 'a>(&'a ctxt<'tcx>);
5800-
5801-
impl<'a, 'tcx> TypeFolder<'tcx> for TypeNormalizer<'a, 'tcx> {
5802-
fn tcx(&self) -> &ctxt<'tcx> { let TypeNormalizer(c) = *self; c }
5803-
5804-
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
5805-
match self.tcx().normalized_cache.borrow().get(&ty).cloned() {
5806-
None => {}
5807-
Some(u) => return u
5808-
}
5809-
5810-
let t_norm = ty_fold::super_fold_ty(self, ty);
5811-
self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
5812-
return t_norm;
5813-
}
5814-
5815-
fn fold_region(&mut self, _: ty::Region) -> ty::Region {
5816-
ty::ReStatic
5817-
}
5818-
5819-
fn fold_substs(&mut self,
5820-
substs: &subst::Substs<'tcx>)
5821-
-> subst::Substs<'tcx> {
5822-
subst::Substs { regions: subst::ErasedRegions,
5823-
types: substs.types.fold_with(self) }
5824-
}
5825-
}
5826-
}
5827-
58285825
// Returns the repeat count for a repeating vector expression.
58295826
pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
58305827
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) -
62046201
mt.mutbl.hash(state);
62056202
};
62066203
let fn_sig = |&: state: &mut sip::SipState, sig: &Binder<FnSig<'tcx>>| {
6207-
let sig = anonymize_late_bound_regions(tcx, sig);
6204+
let sig = anonymize_late_bound_regions(tcx, sig).0;
62086205
for a in sig.inputs.iter() { helper(tcx, *a, svh, state); }
62096206
if let ty::FnConverging(output) = sig.output {
62106207
helper(tcx, output, svh, state);
@@ -6265,7 +6262,7 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
62656262
did(state, data.principal_def_id());
62666263
hash!(data.bounds);
62676264

6268-
let principal = anonymize_late_bound_regions(tcx, &data.principal);
6265+
let principal = anonymize_late_bound_regions(tcx, &data.principal).0;
62696266
for subty in principal.substs.types.iter() {
62706267
helper(tcx, *subty, svh, state);
62716268
}
@@ -6696,6 +6693,16 @@ pub fn binds_late_bound_regions<'tcx, T>(
66966693
count_late_bound_regions(tcx, value) > 0
66976694
}
66986695

6696+
pub fn assert_no_late_bound_regions<'tcx, T>(
6697+
tcx: &ty::ctxt<'tcx>,
6698+
value: &Binder<T>)
6699+
-> T
6700+
where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
6701+
{
6702+
assert!(!binds_late_bound_regions(tcx, value));
6703+
value.0.clone()
6704+
}
6705+
66996706
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
67006707
/// method lookup and a few other places where precise region relationships are not required.
67016708
pub fn erase_late_bound_regions<'tcx, T>(
@@ -6718,14 +6725,14 @@ pub fn erase_late_bound_regions<'tcx, T>(
67186725
pub fn anonymize_late_bound_regions<'tcx, T>(
67196726
tcx: &ctxt<'tcx>,
67206727
sig: &Binder<T>)
6721-
-> T
6728+
-> Binder<T>
67226729
where T : TypeFoldable<'tcx> + Repr<'tcx>,
67236730
{
67246731
let mut counter = 0;
6725-
replace_late_bound_regions(tcx, sig, |_, db| {
6732+
ty::Binder(replace_late_bound_regions(tcx, sig, |_, db| {
67266733
counter += 1;
67276734
ReLateBound(db, BrAnon(counter))
6728-
}).0
6735+
}).0)
67296736
}
67306737

67316738
/// Replaces the late-bound-regions in `value` that are bound by `value`.

src/librustc/middle/ty_fold.rs

+3
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
868868
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
869869

870870
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
871+
// because whether or not a region is bound affects subtyping,
872+
// we can't erase the bound/free distinction, but we can
873+
// replace all free regions with 'static
871874
match r {
872875
ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
873876
_ => ty::ReStatic

0 commit comments

Comments
 (0)