Skip to content

Commit 29c8653

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 2f56839 commit 29c8653

File tree

5 files changed

+68
-16
lines changed

5 files changed

+68
-16
lines changed

src/librustc/middle/cfg/mod.rs

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

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

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

+34-11
Original file line numberDiff line numberDiff line change
@@ -984,14 +984,18 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
984984

985985
// Dorky hack to cause `dump_constraints` to only get called
986986
// if debug mode is enabled:
987-
debug!("----() End constraint listing {:?}---", self.dump_constraints());
987+
debug!("----() End constraint listing (subject={}) {:?}---",
988+
subject, self.dump_constraints(subject));
988989
graphviz::maybe_print_constraints_for(self, subject);
989990

991+
let graph = self.construct_graph();
992+
self.expand_givens(&graph);
990993
self.expansion(free_regions, &mut var_data);
991994
self.contraction(free_regions, &mut var_data);
992995
let values =
993996
self.extract_values_and_collect_conflicts(free_regions,
994-
&var_data[..],
997+
&var_data,
998+
&graph,
995999
errors);
9961000
self.collect_concrete_region_errors(free_regions, &values, errors);
9971001
values
@@ -1010,13 +1014,38 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
10101014
}).collect()
10111015
}
10121016

1013-
fn dump_constraints(&self) {
1014-
debug!("----() Start constraint listing ()----");
1017+
fn dump_constraints(&self, subject: ast::NodeId) {
1018+
debug!("----() Start constraint listing (subject={}) ()----", subject);
10151019
for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
10161020
debug!("Constraint {} => {}", idx, constraint.repr(self.tcx));
10171021
}
10181022
}
10191023

1024+
fn expand_givens(&self, graph: &RegionGraph) {
1025+
// Givens are a kind of horrible hack to account for
1026+
// constraints like 'c <= '0 that are known to hold due to
1027+
// closure signatures (see the comment above on the `givens`
1028+
// field). They should go away. But until they do, the role
1029+
// of this fn is to account for the transitive nature:
1030+
//
1031+
// Given 'c <= '0
1032+
// and '0 <= '1
1033+
// then 'c <= '1
1034+
1035+
let mut givens = self.givens.borrow_mut();
1036+
let seeds: Vec<_> = givens.iter().cloned().collect();
1037+
for (fr, vid) in seeds {
1038+
let seed_index = NodeIndex(vid.index as usize);
1039+
for succ_index in graph.depth_traverse(seed_index) {
1040+
let succ_index = succ_index.0 as u32;
1041+
if succ_index < self.num_vars() {
1042+
let succ_vid = RegionVid { index: succ_index };
1043+
givens.insert((fr, succ_vid));
1044+
}
1045+
}
1046+
}
1047+
}
1048+
10201049
fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
10211050
self.iterate_until_fixed_point("Expansion", |constraint| {
10221051
debug!("expansion: constraint={} origin={}",
@@ -1258,6 +1287,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
12581287
&self,
12591288
free_regions: &FreeRegionMap,
12601289
var_data: &[VarData],
1290+
graph: &RegionGraph,
12611291
errors: &mut Vec<RegionResolutionError<'tcx>>)
12621292
-> Vec<VarValue>
12631293
{
@@ -1276,8 +1306,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
12761306
// overlapping locations.
12771307
let mut dup_vec: Vec<_> = repeat(u32::MAX).take(self.num_vars() as usize).collect();
12781308

1279-
let mut opt_graph = None;
1280-
12811309
for idx in 0..self.num_vars() as usize {
12821310
match var_data[idx].value {
12831311
Value(_) => {
@@ -1313,11 +1341,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
13131341
starts to create problems we'll have to revisit
13141342
this portion of the code and think hard about it. =) */
13151343

1316-
if opt_graph.is_none() {
1317-
opt_graph = Some(self.construct_graph());
1318-
}
1319-
let graph = opt_graph.as_ref().unwrap();
1320-
13211344
let node_vid = RegionVid { index: idx as u32 };
13221345
match var_data[idx].classification {
13231346
Expanding => {

src/librustc_data_structures/graph/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,9 @@ pub struct DepthFirstTraversal<'g, N:'g, E:'g> {
358358
}
359359

360360
impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> {
361-
type Item = &'g N;
361+
type Item = NodeIndex;
362362

363-
fn next(&mut self) -> Option<&'g N> {
363+
fn next(&mut self) -> Option<NodeIndex> {
364364
while let Some(idx) = self.stack.pop() {
365365
if !self.visited.insert(idx.node_id()) {
366366
continue;
@@ -372,7 +372,7 @@ impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> {
372372
}
373373
}
374374

375-
return Some(self.graph.node_data(idx));
375+
return Some(idx);
376376
}
377377

378378
return None;

src/librustc_trans/trans/base.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,8 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
11421142
// return slot alloca. This can cause errors related to clean-up due to
11431143
// the clobbering of the existing value in the return slot.
11441144
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
1145-
for n in cfg.graph.depth_traverse(cfg.entry) {
1145+
for index in cfg.graph.depth_traverse(cfg.entry) {
1146+
let n = cfg.graph.node_data(index);
11461147
match tcx.map.find(n.id()) {
11471148
Some(ast_map::NodeExpr(ex)) => {
11481149
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)