Skip to content

Fix ICE that @steveklabnik encountered in rust-book. #20645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
22 changes: 15 additions & 7 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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),
}
Expand All @@ -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() => {

Expand Down
31 changes: 25 additions & 6 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)]
Expand Down
103 changes: 55 additions & 48 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
///
Expand All @@ -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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down Expand Up @@ -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 => {}
}
Expand Down Expand Up @@ -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()
};
Expand All @@ -5159,7 +5191,6 @@ impl<'tcx> VariantInfo<'tcx> {
};
},
ast::StructVariantKind(ref struct_def) => {

let fields: &[StructField] = struct_def.fields[];

assert!(fields.len() > 0);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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>(
Expand All @@ -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`.
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading