Skip to content

Commit 11720a1

Browse files
committed
Expand the "givens" set to cover transitive relations. The givens array
stores relationships like `'c <= '0` (where `'c` is a free region and `'0` is an inference variable) that are derived from closure arguments. These are (rather hackily) ignored for purposes of inference, preventing spurious errors. The current code did not handle transitive cases like `'c <= '0` and `'0 <= '1`. Fixes #24085.
1 parent a691f1e commit 11720a1

File tree

5 files changed

+67
-15
lines changed

5 files changed

+67
-15
lines changed

src/librustc/middle/cfg/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ impl CFG {
6262
}
6363

6464
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
65-
self.graph.depth_traverse(self.entry).any(|node| node.id() == id)
65+
self.graph.depth_traverse(self.entry)
66+
.any(|idx| self.graph.node_data(idx).id() == id)
6667
}
6768
}

src/librustc/middle/graph.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,9 @@ pub struct DepthFirstTraversal<'g, N:'g, E:'g> {
304304
}
305305

306306
impl<'g, N, E> Iterator for DepthFirstTraversal<'g, N, E> {
307-
type Item = &'g N;
307+
type Item = NodeIndex;
308308

309-
fn next(&mut self) -> Option<&'g N> {
309+
fn next(&mut self) -> Option<NodeIndex> {
310310
while let Some(idx) = self.stack.pop() {
311311
if !self.visited.insert(idx.node_id()) {
312312
continue;
@@ -318,7 +318,7 @@ impl<'g, N, E> Iterator for DepthFirstTraversal<'g, N, E> {
318318
true
319319
});
320320

321-
return Some(self.graph.node_data(idx));
321+
return Some(idx);
322322
}
323323

324324
return None;

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

+33-10
Original file line numberDiff line numberDiff line change
@@ -978,13 +978,17 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
978978

979979
// Dorky hack to cause `dump_constraints` to only get called
980980
// if debug mode is enabled:
981-
debug!("----() End constraint listing {:?}---", self.dump_constraints());
981+
debug!("----() End constraint listing (subject={}) {:?}---",
982+
subject, self.dump_constraints(subject));
982983
graphviz::maybe_print_constraints_for(self, subject);
983984

985+
let graph = self.construct_graph();
986+
self.expand_givens(&graph);
984987
self.expansion(&mut var_data);
985988
self.contraction(&mut var_data);
986989
let values =
987990
self.extract_values_and_collect_conflicts(&var_data[..],
991+
&graph,
988992
errors);
989993
self.collect_concrete_region_errors(&values, errors);
990994
values
@@ -1003,13 +1007,38 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
10031007
}).collect()
10041008
}
10051009

1006-
fn dump_constraints(&self) {
1007-
debug!("----() Start constraint listing ()----");
1010+
fn dump_constraints(&self, subject: ast::NodeId) {
1011+
debug!("----() Start constraint listing (subject={}) ()----", subject);
10081012
for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
10091013
debug!("Constraint {} => {}", idx, constraint.repr(self.tcx));
10101014
}
10111015
}
10121016

1017+
fn expand_givens(&self, graph: &RegionGraph) {
1018+
// Givens are a kind of horrible hack to account for
1019+
// constraints like 'c <= '0 that are known to hold due to
1020+
// closure signatures (see the comment above on the `givens`
1021+
// field). They should go away. But until they do, the role
1022+
// of this fn is to account for the transitive nature:
1023+
//
1024+
// Given 'c <= '0
1025+
// and '0 <= '1
1026+
// then 'c <= '1
1027+
1028+
let mut givens = self.givens.borrow_mut();
1029+
let seeds: Vec<_> = givens.iter().cloned().collect();
1030+
for (fr, vid) in seeds {
1031+
let seed_index = NodeIndex(vid.index as usize);
1032+
for succ_index in graph.depth_traverse(seed_index) {
1033+
let succ_index = succ_index.0 as u32;
1034+
if succ_index < self.num_vars() {
1035+
let succ_vid = RegionVid { index: succ_index };
1036+
givens.insert((fr, succ_vid));
1037+
}
1038+
}
1039+
}
1040+
}
1041+
10131042
fn expansion(&self, var_data: &mut [VarData]) {
10141043
self.iterate_until_fixed_point("Expansion", |constraint| {
10151044
debug!("expansion: constraint={} origin={}",
@@ -1241,6 +1270,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
12411270
fn extract_values_and_collect_conflicts(
12421271
&self,
12431272
var_data: &[VarData],
1273+
graph: &RegionGraph,
12441274
errors: &mut Vec<RegionResolutionError<'tcx>>)
12451275
-> Vec<VarValue>
12461276
{
@@ -1259,8 +1289,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
12591289
// overlapping locations.
12601290
let mut dup_vec: Vec<_> = repeat(u32::MAX).take(self.num_vars() as usize).collect();
12611291

1262-
let mut opt_graph = None;
1263-
12641292
for idx in 0..self.num_vars() as usize {
12651293
match var_data[idx].value {
12661294
Value(_) => {
@@ -1296,11 +1324,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
12961324
starts to create problems we'll have to revisit
12971325
this portion of the code and think hard about it. =) */
12981326

1299-
if opt_graph.is_none() {
1300-
opt_graph = Some(self.construct_graph());
1301-
}
1302-
let graph = opt_graph.as_ref().unwrap();
1303-
13041327
let node_vid = RegionVid { index: idx as u32 };
13051328
match var_data[idx].classification {
13061329
Expanding => {

src/librustc_trans/trans/base.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,8 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
11101110
// return slot alloca. This can cause errors related to clean-up due to
11111111
// the clobbering of the existing value in the return slot.
11121112
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
1113-
for n in cfg.graph.depth_traverse(cfg.entry) {
1113+
for index in cfg.graph.depth_traverse(cfg.entry) {
1114+
let n = cfg.graph.node_data(index);
11141115
match tcx.map.find(n.id()) {
11151116
Some(ast_map::NodeExpr(ex)) => {
11161117
if let ast::ExprRet(Some(ref ret_expr)) = ex.node {

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

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2014 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+
// Regression test for #24085. Errors were occuring in region
12+
// inference due to the requirement that `'a:b'`, which was getting
13+
// incorrectly translated in connection with the closure below.
14+
15+
#[derive(Copy,Clone)]
16+
struct Path<'a:'b, 'b> {
17+
x: &'a i32,
18+
tail: Option<&'b Path<'a, 'b>>
19+
}
20+
21+
#[allow(dead_code, unconditional_recursion)]
22+
fn foo<'a,'b,F>(p: Path<'a, 'b>, mut f: F)
23+
where F: for<'c> FnMut(Path<'a, 'c>) {
24+
foo(p, |x| f(x))
25+
}
26+
27+
fn main() { }

0 commit comments

Comments
 (0)