Skip to content
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

Fix region erasure issue #20582 #20707

Merged
merged 5 commits into from
Jan 8, 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/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
* when higher-ranked things are involved. See `doc.rs` for more details.
*/

let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br, _| {
let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br| {
infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
});

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,7 +1056,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ty::replace_late_bound_regions(
self.tcx,
value,
|br, _| self.next_region_var(LateBoundRegion(span, br, lbrct)))
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
}

/// See `verify_generic_bound` method in `region_inference`
Expand Down
27 changes: 19 additions & 8 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6672,7 +6672,7 @@ pub fn liberate_late_bound_regions<'tcx, T>(
{
replace_late_bound_regions(
tcx, value,
|br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0
|br| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0
}

pub fn count_late_bound_regions<'tcx, T>(
Expand All @@ -6681,7 +6681,7 @@ pub fn count_late_bound_regions<'tcx, T>(
-> uint
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
let (_, skol_map) = replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic);
let (_, skol_map) = replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
skol_map.len()
}

Expand Down Expand Up @@ -6712,7 +6712,7 @@ pub fn erase_late_bound_regions<'tcx, T>(
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0
replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
}

/// Rewrite any late-bound regions so that they are anonymous. Region numbers are
Expand All @@ -6730,9 +6730,9 @@ pub fn anonymize_late_bound_regions<'tcx, T>(
where T : TypeFoldable<'tcx> + Repr<'tcx>,
{
let mut counter = 0;
ty::Binder(replace_late_bound_regions(tcx, sig, |_, db| {
ty::Binder(replace_late_bound_regions(tcx, sig, |_| {
counter += 1;
ReLateBound(db, BrAnon(counter))
ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter))
}).0)
}

Expand All @@ -6743,7 +6743,7 @@ pub fn replace_late_bound_regions<'tcx, T, F>(
mut mapf: F)
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
where T : TypeFoldable<'tcx> + Repr<'tcx>,
F : FnMut(BoundRegion, DebruijnIndex) -> ty::Region,
F : FnMut(BoundRegion) -> ty::Region,
{
debug!("replace_late_bound_regions({})", binder.repr(tcx));

Expand All @@ -6755,8 +6755,19 @@ pub fn replace_late_bound_regions<'tcx, T, F>(
debug!("region={}", region.repr(tcx));
match region {
ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
* map.entry(br).get().unwrap_or_else(
|vacant_entry| vacant_entry.insert(mapf(br, debruijn)))
let region =
* map.entry(br).get().unwrap_or_else(
|vacant_entry| vacant_entry.insert(mapf(br)));

if let ty::ReLateBound(debruijn1, br) = region {
// If the callback returns a late-bound region,
// that region should always use depth 1. Then we
// adjust it to the correct depth.
assert_eq!(debruijn1.depth, 1);
ty::ReLateBound(debruijn, br)
} else {
region
}
}
_ => {
region
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
///////////////////////////////////////////////////////////////////////////
// Region eraser
//
// Replaces all free regions with 'static. Useful in trans.
// Replaces all free regions with 'static. Useful in contexts, such as
// method probing, where precise region relationships are not
// important. Note that in trans you should use
// `common::erase_regions` instead.

pub struct RegionEraser<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,8 +1182,8 @@ impl<'tcx, T> UserString<'tcx> for ty::Binder<T>
// the output. We'll probably want to tweak this over time to
// decide just how much information to give.
let mut names = Vec::new();
let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| {
ty::ReLateBound(debruijn, match br {
let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br| {
ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
ty::BrNamed(_, name) => {
names.push(token::get_name(name));
br
Expand Down
13 changes: 11 additions & 2 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,15 @@ pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId)

pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
debug!("decl_rust_fn(fn_ty={}, name={:?})",
fn_ty.repr(ccx.tcx()),
name);

let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty);

debug!("decl_rust_fn: fn_ty={} (after normalized associated types)",
fn_ty.repr(ccx.tcx()));

let function_type; // placeholder so that the memory ownership works out ok

let (sig, abi, env) = match fn_ty.sty {
Expand All @@ -305,10 +312,12 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let sig = ty::erase_late_bound_regions(ccx.tcx(), sig);
let sig = ty::Binder(sig);

debug!("decl_rust_fn: sig={} (after erasing regions)",
sig.repr(ccx.tcx()));

let llfty = type_of_rust_fn(ccx, env, &sig, abi);

debug!("decl_rust_fn(sig={}, type={})",
sig.repr(ccx.tcx()),
debug!("decl_rust_fn: llfty={}",
ccx.tn().type_to_string(llfty));

let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output /* (1) */);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = normalize_ty(tcx, bare_fn_ty);
let bare_fn_ty = erase_regions(tcx, &bare_fn_ty);
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
Some(&llval) => { return llval; }
None => { }
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = normalize_ty(ccx.tcx(), function_type);
let function_type = erase_regions(ccx.tcx(), &function_type);
let params = match function_type.sty {
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
_ => unreachable!()
Expand Down
24 changes: 14 additions & 10 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,21 @@ 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;
/// Returns an equivalent value with all free regions removed (note
/// that late-bound regions remain, because they are important for
/// subtyping, but they are anonymized and normalized as well). This
/// is a stronger, caching version of `ty_fold::erase_regions`.
pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
let value1 = value.fold_with(&mut RegionEraser(cx));
debug!("erase_regions({}) = {}",
value.repr(cx), value1.repr(cx));
return value1;

struct TypeNormalizer<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);

impl<'a, 'tcx> TypeFolder<'tcx> for TypeNormalizer<'a, 'tcx> {
impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.0 }

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
Expand All @@ -84,7 +89,6 @@ pub fn normalize_ty<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
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)
}
Expand Down Expand Up @@ -988,7 +992,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let tcx = ccx.tcx();

// Remove any references to regions; this helps improve caching.
let trait_ref = ty_fold::erase_regions(tcx, trait_ref);
let trait_ref = erase_regions(tcx, &trait_ref);

// First check the cache.
match ccx.trait_cache().borrow().get(&trait_ref) {
Expand Down
6 changes: 4 additions & 2 deletions src/librustc_trans/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,10 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
{
debug!("normalize_associated_type(t={})", value.repr(tcx));

let value = erase_regions(tcx, value);

if !value.has_projection_types() {
return value.clone();
return value;
}

// FIXME(#20304) -- cache
Expand All @@ -326,7 +328,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, value);
traits::normalize(&mut selcx, cause, &value);

debug!("normalize_associated_type: result={} obligations={}",
result.repr(tcx),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
// 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 = normalize_ty(cx.tcx(), t);
let t_norm = erase_regions(cx.tcx(), &t);

if t != t_norm {
let llty = type_of(cx, t_norm);
Expand Down
27 changes: 27 additions & 0 deletions src/test/run-pass/associated-types-region-erasure-issue-20582.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 <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.

// Regression test for #20582. This test caused an ICE related to
// inconsistent region erasure in trans.

struct Foo<'a> {
buf: &'a[u8]
}

impl<'a> Iterator for Foo<'a> {
type Item = &'a[u8];

fn next(&mut self) -> Option<<Self as Iterator>::Item> {
Some(self.buf)
}
}

fn main() {
}