diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b39ddfe95c83ab0c7c74629bbf6cad28d78b0038..d677328e415a8a0085bd58b8dcbb2f7794711e1f 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1225,6 +1225,13 @@ pub fn resolve_type_vars_if_possible(&self, value: &T) -> T value.fold_with(&mut r) } + pub fn resolve_type_and_region_vars_if_possible(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self); + value.fold_with(&mut r) + } + /// Resolves all type variables in `t` and then, if any were left /// unresolved, substitutes an error type. This is used after the /// main checking when doing a second pass before writeback. The diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index f6068f1b6449852d94227bfb22af402330deb901..30cf6344e2332dd6a1fb65990232897eb18f5f2d 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -20,6 +20,7 @@ use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use rustc_data_structures::graph::{self, Direction, NodeIndex}; +use rustc_data_structures::unify::{self, UnificationTable}; use middle::free_region::FreeRegionMap; use middle::ty::{self, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; @@ -234,15 +235,16 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> { // bound on a variable and so forth, which can never be rolled // back. undo_log: RefCell>, + unification_table: RefCell>, // This contains the results of inference. It begins as an empty // option and only acquires a value after inference is complete. values: RefCell>>, } -#[derive(Debug)] pub struct RegionSnapshot { length: usize, + region_snapshot: unify::Snapshot, skolemization_count: u32, } @@ -260,6 +262,7 @@ pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { skolemization_count: Cell::new(0), bound_count: Cell::new(0), undo_log: RefCell::new(Vec::new()), + unification_table: RefCell::new(UnificationTable::new()), } } @@ -273,6 +276,7 @@ pub fn start_snapshot(&self) -> RegionSnapshot { self.undo_log.borrow_mut().push(OpenSnapshot); RegionSnapshot { length: length, + region_snapshot: self.unification_table.borrow_mut().snapshot(), skolemization_count: self.skolemization_count.get(), } } @@ -289,6 +293,7 @@ pub fn commit(&self, snapshot: RegionSnapshot) { (*undo_log)[snapshot.length] = CommitedSnapshot; } self.skolemization_count.set(snapshot.skolemization_count); + self.unification_table.borrow_mut().commit(snapshot.region_snapshot); } pub fn rollback_to(&self, snapshot: RegionSnapshot) { @@ -328,6 +333,8 @@ pub fn rollback_to(&self, snapshot: RegionSnapshot) { let c = undo_log.pop().unwrap(); assert!(c == OpenSnapshot); self.skolemization_count.set(snapshot.skolemization_count); + self.unification_table.borrow_mut() + .rollback_to(snapshot.region_snapshot); } pub fn num_vars(&self) -> u32 { @@ -340,7 +347,8 @@ pub fn num_vars(&self) -> u32 { pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { let id = self.num_vars(); self.var_origins.borrow_mut().push(origin.clone()); - let vid = RegionVid { index: id }; + let vid = self.unification_table.borrow_mut().new_key(()); + assert_eq!(vid.index, id); if self.in_snapshot() { self.undo_log.borrow_mut().push(AddVar(vid)); } @@ -460,6 +468,10 @@ pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Reg // equating regions. self.make_subregion(origin.clone(), sub, sup); self.make_subregion(origin, sup, sub); + + if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) { + self.unification_table.borrow_mut().union(sub, sup); + } } } @@ -568,6 +580,10 @@ pub fn resolve_var(&self, rid: RegionVid) -> ty::Region { } } + pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region { + ty::ReVar(self.unification_table.borrow_mut().find(rid)) + } + fn combine_map(&self, t: CombineMapType) -> &RefCell { match t { Glb => &self.glbs, @@ -1312,6 +1328,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +impl fmt::Debug for RegionSnapshot { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegionSnapshot(length={},skolemization={})", + self.length, self.skolemization_count) + } +} + impl<'tcx> fmt::Debug for GenericKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index 4bcceade775999c1d90d024890a7bfb4421e044f..5190c658194f723da547c83803acce5ecde8e221 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -45,6 +45,41 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { } } +/// The opportunistic type and region resolver is similar to the +/// opportunistic type resolver, but also opportunistly resolves +/// regions. It is useful for canonicalization. +pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + OpportunisticTypeAndRegionResolver { infcx: infcx } + } +} + +impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.needs_infer() { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + ty::fold::super_fold_ty(self, t0) + } + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid), + _ => r, + } + } +} + /////////////////////////////////////////////////////////////////////////// // FULL TYPE RESOLUTION diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs index 41aa191ac24d210f23a3e36dd7cf84293ad6fe5c..85d7d67a0e3ca0bd480dc11599a07ac0a3ac87b4 100644 --- a/src/librustc/middle/infer/unify_key.rs +++ b/src/librustc/middle/infer/unify_key.rs @@ -23,6 +23,13 @@ fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } fn tag(_: Option) -> &'static str { "IntVid" } } +impl UnifyKey for ty::RegionVid { + type Value = (); + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } } + fn tag(_: Option) -> &'static str { "RegionVid" } +} + impl<'tcx> ToType<'tcx> for IntVarValue { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { match *self { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index d68959b99be0fee092346608b85510357499050e..0fbe83674931c2bbf89be4ba3107840afcb4b1b9 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -17,7 +17,6 @@ use middle::subst::{self, Subst}; use middle::traits; use middle::ty::{self, Ty}; -use util::nodemap::FnvHashSet; use syntax::ast; use syntax::codemap::{self, Span}; @@ -280,7 +279,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> rcx: rcx, span: span, parent_scope: parent_scope, - breadcrumbs: FnvHashSet() + breadcrumbs: Vec::new(), }, TypeContext::Root, typ, @@ -341,7 +340,7 @@ enum TypeContext { struct DropckContext<'a, 'b: 'a, 'tcx: 'b> { rcx: &'a mut Rcx<'b, 'tcx>, /// types that have already been traversed - breadcrumbs: FnvHashSet>, + breadcrumbs: Vec>, /// span for error reporting span: Span, /// the scope reachable dtorck types must outlive @@ -356,6 +355,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( depth: usize) -> Result<(), Error<'tcx>> { let tcx = cx.rcx.tcx(); + let ty = cx.rcx.infcx().resolve_type_and_region_vars_if_possible(&ty); + // Issue #22443: Watch out for overflow. While we are careful to // handle regular types properly, non-regular ones cause problems. let recursion_limit = tcx.sess.recursion_limit.get(); @@ -366,13 +367,19 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( return Err(Error::Overflow(context, ty)) } - if !cx.breadcrumbs.insert(ty) { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - cached", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - return Ok(()); // we already visited this type + for breadcrumb in &mut cx.breadcrumbs { + *breadcrumb = + cx.rcx.infcx().resolve_type_and_region_vars_if_possible(breadcrumb); + if *breadcrumb == ty { + debug!("iterate_over_potentially_unsafe_regions_in_type \ + {}ty: {} scope: {:?} - cached", + (0..depth).map(|_| ' ').collect::(), + ty, cx.parent_scope); + return Ok(()); // we already visited this type + } } + cx.breadcrumbs.push(ty); + debug!("iterate_over_potentially_unsafe_regions_in_type \ {}ty: {} scope: {:?}", (0..depth).map(|_| ' ').collect::(), diff --git a/src/test/run-pass/issue-29844.rs b/src/test/run-pass/issue-29844.rs new file mode 100644 index 0000000000000000000000000000000000000000..51df4d60f0459359bce4ebdd67092342060a8bf6 --- /dev/null +++ b/src/test/run-pass/issue-29844.rs @@ -0,0 +1,33 @@ +// 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. + +use std::sync::Arc; + +pub struct DescriptorSet<'a> { + pub slots: Vec> +} + +pub trait ResourcesTrait<'r>: Sized { + type DescriptorSet: 'r; +} + +pub struct Resources; + +impl<'a> ResourcesTrait<'a> for Resources { + type DescriptorSet = DescriptorSet<'a>; +} + +pub enum AttachInfo<'a, R: ResourcesTrait<'a>> { + NextDescriptorSet(Arc) +} + +fn main() { + let _x = DescriptorSet {slots: Vec::new()}; +}