diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 5d3e2dc9c93e3149c175f5040dd09d8219fb2467..0df84323ae53f4d64aa07df1acce62989a1aa1df 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -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) }); diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 57893ec97a2186fd673adc2e8526440005a41574..ab1c41f69683eb074ecb8dd5a9eaa857bdebd84a 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1048,7 +1048,7 @@ pub fn replace_late_bound_regions_with_fresh_var( 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` diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 33efc1fa10b6c4016524de4d3cafe301fb7963cb..64f0bcb1c88db280d4bc73b44f0fcc260bba4fa2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -6686,7 +6686,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>( @@ -6695,7 +6695,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() } @@ -6726,7 +6726,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 @@ -6744,9 +6744,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) } @@ -6757,7 +6757,7 @@ pub fn replace_late_bound_regions<'tcx, T, F>( mut mapf: F) -> (T, FnvHashMap) 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)); @@ -6769,8 +6769,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 diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index dedd69deabb0b27a864fb6e9ff341e3325980e56..b81a4ed2f58ff79f76a0f197111056e75346a64d 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -862,7 +862,10 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region { /////////////////////////////////////////////////////////////////////////// // 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>, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index b510fedc5f95245307efb57253c21a40d407909d..559ec533baa9eca1ed0a67d7bbca462541c5ad9f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1183,8 +1183,8 @@ fn user_string(&self, tcx: &ctxt<'tcx>) -> String { // 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 diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 78fe7861854dd351cfc548da43c849c9b708c638..74071a1de4c3d080c797133c0db7a5d1577a1342 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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 { @@ -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) */); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 274c3e0a50ae3405ac1169c4b7b379e573949ae5..6196f9e5eab65eff401594f9cfad0699ecfd9378 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -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 => { } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 76f82c14e0a8a5b6f8dacd5daf5ffeed2c1873e6..8989dfd493236a80c186f4dcb5105b1d0819b7a8 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -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!() diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 1a74137c10df6c528858d2389dfedb52904116bc..ab5b563b99c7259ada392acf0ac6b1e427515d45 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -58,16 +58,21 @@ 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> { @@ -84,7 +89,6 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder 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) } @@ -989,7 +993,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) { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 435f94f35fa8aaab9c708bee94446fb08e18badf..93076260349abd5c81aee5d5801823a800ec4a2d 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -313,8 +313,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 @@ -324,7 +326,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), diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index c908441e3662b686f8f2891495afa79431e5adc6..034a1ee8be5925ef2903803cb4de9def9da020ec 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -285,7 +285,7 @@ fn type_of_unsize_info<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty // 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`. - 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); diff --git a/src/test/run-pass/associated-types-region-erasure-issue-20582.rs b/src/test/run-pass/associated-types-region-erasure-issue-20582.rs new file mode 100644 index 0000000000000000000000000000000000000000..03ab8f7e43136910ef3a75cb2672a875af6da184 --- /dev/null +++ b/src/test/run-pass/associated-types-region-erasure-issue-20582.rs @@ -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 or the MIT license +// , 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<::Item> { + Some(self.buf) + } +} + +fn main() { +}