Skip to content

Commit da31c14

Browse files
committed
Auto merge of #30242 - arielb1:region-unification, r=nikomatsakis
Fixes #29844 I would prefer to (a) make some performance measurements (b) use the unification table in a few more places before committing further, but this is probably good enough for beta. r? @nikomatsakis
2 parents 89ec45c + 80e191f commit da31c14

File tree

6 files changed

+123
-11
lines changed

6 files changed

+123
-11
lines changed

src/librustc/middle/infer/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12251225
value.fold_with(&mut r)
12261226
}
12271227

1228+
pub fn resolve_type_and_region_vars_if_possible<T>(&self, value: &T) -> T
1229+
where T: TypeFoldable<'tcx>
1230+
{
1231+
let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self);
1232+
value.fold_with(&mut r)
1233+
}
1234+
12281235
/// Resolves all type variables in `t` and then, if any were left
12291236
/// unresolved, substitutes an error type. This is used after the
12301237
/// main checking when doing a second pass before writeback. The

src/librustc/middle/infer/region_inference/mod.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub use self::VarValue::*;
2020
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
2121

2222
use rustc_data_structures::graph::{self, Direction, NodeIndex};
23+
use rustc_data_structures::unify::{self, UnificationTable};
2324
use middle::free_region::FreeRegionMap;
2425
use middle::ty::{self, Ty};
2526
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
@@ -234,15 +235,16 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> {
234235
// bound on a variable and so forth, which can never be rolled
235236
// back.
236237
undo_log: RefCell<Vec<UndoLogEntry>>,
238+
unification_table: RefCell<UnificationTable<ty::RegionVid>>,
237239

238240
// This contains the results of inference. It begins as an empty
239241
// option and only acquires a value after inference is complete.
240242
values: RefCell<Option<Vec<VarValue>>>,
241243
}
242244

243-
#[derive(Debug)]
244245
pub struct RegionSnapshot {
245246
length: usize,
247+
region_snapshot: unify::Snapshot<ty::RegionVid>,
246248
skolemization_count: u32,
247249
}
248250

@@ -260,6 +262,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
260262
skolemization_count: Cell::new(0),
261263
bound_count: Cell::new(0),
262264
undo_log: RefCell::new(Vec::new()),
265+
unification_table: RefCell::new(UnificationTable::new()),
263266
}
264267
}
265268

@@ -273,6 +276,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
273276
self.undo_log.borrow_mut().push(OpenSnapshot);
274277
RegionSnapshot {
275278
length: length,
279+
region_snapshot: self.unification_table.borrow_mut().snapshot(),
276280
skolemization_count: self.skolemization_count.get(),
277281
}
278282
}
@@ -289,6 +293,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
289293
(*undo_log)[snapshot.length] = CommitedSnapshot;
290294
}
291295
self.skolemization_count.set(snapshot.skolemization_count);
296+
self.unification_table.borrow_mut().commit(snapshot.region_snapshot);
292297
}
293298

294299
pub fn rollback_to(&self, snapshot: RegionSnapshot) {
@@ -328,6 +333,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
328333
let c = undo_log.pop().unwrap();
329334
assert!(c == OpenSnapshot);
330335
self.skolemization_count.set(snapshot.skolemization_count);
336+
self.unification_table.borrow_mut()
337+
.rollback_to(snapshot.region_snapshot);
331338
}
332339

333340
pub fn num_vars(&self) -> u32 {
@@ -340,7 +347,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
340347
pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
341348
let id = self.num_vars();
342349
self.var_origins.borrow_mut().push(origin.clone());
343-
let vid = RegionVid { index: id };
350+
let vid = self.unification_table.borrow_mut().new_key(());
351+
assert_eq!(vid.index, id);
344352
if self.in_snapshot() {
345353
self.undo_log.borrow_mut().push(AddVar(vid));
346354
}
@@ -460,6 +468,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
460468
// equating regions.
461469
self.make_subregion(origin.clone(), sub, sup);
462470
self.make_subregion(origin, sup, sub);
471+
472+
if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) {
473+
self.unification_table.borrow_mut().union(sub, sup);
474+
}
463475
}
464476
}
465477

@@ -568,6 +580,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
568580
}
569581
}
570582

583+
pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region {
584+
ty::ReVar(self.unification_table.borrow_mut().find(rid))
585+
}
586+
571587
fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap> {
572588
match t {
573589
Glb => &self.glbs,
@@ -1312,6 +1328,13 @@ impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
13121328
}
13131329
}
13141330

1331+
impl fmt::Debug for RegionSnapshot {
1332+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1333+
write!(f, "RegionSnapshot(length={},skolemization={})",
1334+
self.length, self.skolemization_count)
1335+
}
1336+
}
1337+
13151338
impl<'tcx> fmt::Debug for GenericKind<'tcx> {
13161339
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
13171340
match *self {

src/librustc/middle/infer/resolve.rs

+35
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,41 @@ impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx
4545
}
4646
}
4747

48+
/// The opportunistic type and region resolver is similar to the
49+
/// opportunistic type resolver, but also opportunistly resolves
50+
/// regions. It is useful for canonicalization.
51+
pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx:'a> {
52+
infcx: &'a InferCtxt<'a, 'tcx>,
53+
}
54+
55+
impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> {
56+
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
57+
OpportunisticTypeAndRegionResolver { infcx: infcx }
58+
}
59+
}
60+
61+
impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> {
62+
fn tcx(&self) -> &ty::ctxt<'tcx> {
63+
self.infcx.tcx
64+
}
65+
66+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
67+
if !t.needs_infer() {
68+
t // micro-optimize -- if there is nothing in this type that this fold affects...
69+
} else {
70+
let t0 = self.infcx.shallow_resolve(t);
71+
ty::fold::super_fold_ty(self, t0)
72+
}
73+
}
74+
75+
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
76+
match r {
77+
ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid),
78+
_ => r,
79+
}
80+
}
81+
}
82+
4883
///////////////////////////////////////////////////////////////////////////
4984
// FULL TYPE RESOLUTION
5085

src/librustc/middle/infer/unify_key.rs

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ impl UnifyKey for ty::IntVid {
2323
fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
2424
}
2525

26+
impl UnifyKey for ty::RegionVid {
27+
type Value = ();
28+
fn index(&self) -> u32 { self.index }
29+
fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } }
30+
fn tag(_: Option<ty::RegionVid>) -> &'static str { "RegionVid" }
31+
}
32+
2633
impl<'tcx> ToType<'tcx> for IntVarValue {
2734
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
2835
match *self {

src/librustc_typeck/check/dropck.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use middle::region;
1717
use middle::subst::{self, Subst};
1818
use middle::traits;
1919
use middle::ty::{self, Ty};
20-
use util::nodemap::FnvHashSet;
2120

2221
use syntax::ast;
2322
use syntax::codemap::{self, Span};
@@ -280,7 +279,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>
280279
rcx: rcx,
281280
span: span,
282281
parent_scope: parent_scope,
283-
breadcrumbs: FnvHashSet()
282+
breadcrumbs: Vec::new(),
284283
},
285284
TypeContext::Root,
286285
typ,
@@ -341,7 +340,7 @@ enum TypeContext {
341340
struct DropckContext<'a, 'b: 'a, 'tcx: 'b> {
342341
rcx: &'a mut Rcx<'b, 'tcx>,
343342
/// types that have already been traversed
344-
breadcrumbs: FnvHashSet<Ty<'tcx>>,
343+
breadcrumbs: Vec<Ty<'tcx>>,
345344
/// span for error reporting
346345
span: Span,
347346
/// the scope reachable dtorck types must outlive
@@ -356,6 +355,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
356355
depth: usize) -> Result<(), Error<'tcx>>
357356
{
358357
let tcx = cx.rcx.tcx();
358+
let ty = cx.rcx.infcx().resolve_type_and_region_vars_if_possible(&ty);
359+
359360
// Issue #22443: Watch out for overflow. While we are careful to
360361
// handle regular types properly, non-regular ones cause problems.
361362
let recursion_limit = tcx.sess.recursion_limit.get();
@@ -366,13 +367,19 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
366367
return Err(Error::Overflow(context, ty))
367368
}
368369

369-
if !cx.breadcrumbs.insert(ty) {
370-
debug!("iterate_over_potentially_unsafe_regions_in_type \
371-
{}ty: {} scope: {:?} - cached",
372-
(0..depth).map(|_| ' ').collect::<String>(),
373-
ty, cx.parent_scope);
374-
return Ok(()); // we already visited this type
370+
for breadcrumb in &mut cx.breadcrumbs {
371+
*breadcrumb =
372+
cx.rcx.infcx().resolve_type_and_region_vars_if_possible(breadcrumb);
373+
if *breadcrumb == ty {
374+
debug!("iterate_over_potentially_unsafe_regions_in_type \
375+
{}ty: {} scope: {:?} - cached",
376+
(0..depth).map(|_| ' ').collect::<String>(),
377+
ty, cx.parent_scope);
378+
return Ok(()); // we already visited this type
379+
}
375380
}
381+
cx.breadcrumbs.push(ty);
382+
376383
debug!("iterate_over_potentially_unsafe_regions_in_type \
377384
{}ty: {} scope: {:?}",
378385
(0..depth).map(|_| ' ').collect::<String>(),

src/test/run-pass/issue-29844.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::sync::Arc;
12+
13+
pub struct DescriptorSet<'a> {
14+
pub slots: Vec<AttachInfo<'a, Resources>>
15+
}
16+
17+
pub trait ResourcesTrait<'r>: Sized {
18+
type DescriptorSet: 'r;
19+
}
20+
21+
pub struct Resources;
22+
23+
impl<'a> ResourcesTrait<'a> for Resources {
24+
type DescriptorSet = DescriptorSet<'a>;
25+
}
26+
27+
pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
28+
NextDescriptorSet(Arc<R::DescriptorSet>)
29+
}
30+
31+
fn main() {
32+
let _x = DescriptorSet {slots: Vec::new()};
33+
}

0 commit comments

Comments
 (0)