Skip to content

Commit f0d4d74

Browse files
authored
Merge pull request rust-lang#35527 from alexcrichton/beta-next
Backport rust-lang#34986 to beta
2 parents 44643b7 + ff6f473 commit f0d4d74

File tree

4 files changed

+123
-53
lines changed

4 files changed

+123
-53
lines changed

src/librustc/middle/expr_use_visitor.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,19 @@ enum PassArgs {
271271

272272
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
273273
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
274-
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self
274+
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
275+
-> Self
276+
{
277+
ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default())
278+
}
279+
280+
pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
281+
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
282+
options: mc::MemCategorizationOptions)
283+
-> Self
275284
{
276285
ExprUseVisitor {
277-
mc: mc::MemCategorizationContext::new(infcx),
286+
mc: mc::MemCategorizationContext::with_options(infcx, options),
278287
delegate: delegate
279288
}
280289
}

src/librustc/middle/mem_categorization.rs

+36-5
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,18 @@ impl ast_node for hir::Pat {
259259
#[derive(Copy, Clone)]
260260
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
261261
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
262+
options: MemCategorizationOptions,
263+
}
264+
265+
#[derive(Copy, Clone, Default)]
266+
pub struct MemCategorizationOptions {
267+
// If true, then when analyzing a closure upvar, if the closure
268+
// has a missing kind, we treat it like a Fn closure. When false,
269+
// we ICE if the closure has a missing kind. Should be false
270+
// except during closure kind inference. It is used by the
271+
// mem-categorization code to be able to have stricter assertions
272+
// (which are always true except during upvar inference).
273+
pub during_closure_kind_inference: bool,
262274
}
263275

264276
pub type McResult<T> = Result<T, ()>;
@@ -362,7 +374,16 @@ impl MutabilityCategory {
362374
impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
363375
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
364376
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
365-
MemCategorizationContext { infcx: infcx }
377+
MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default())
378+
}
379+
380+
pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
381+
options: MemCategorizationOptions)
382+
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
383+
MemCategorizationContext {
384+
infcx: infcx,
385+
options: options,
386+
}
366387
}
367388

368389
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@@ -584,10 +605,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
584605
self.cat_upvar(id, span, var_id, fn_node_id, kind)
585606
}
586607
None => {
587-
span_bug!(
588-
span,
589-
"No closure kind for {:?}",
590-
closure_id);
608+
if !self.options.during_closure_kind_inference {
609+
span_bug!(
610+
span,
611+
"No closure kind for {:?}",
612+
closure_id);
613+
}
614+
615+
// during closure kind inference, we
616+
// don't know the closure kind yet, but
617+
// it's ok because we detect that we are
618+
// accessing an upvar and handle that
619+
// case specially anyhow. Use Fn
620+
// arbitrarily.
621+
self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
591622
}
592623
}
593624
}

src/librustc_typeck/check/upvar.rs

+44-46
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ use middle::mem_categorization as mc;
4747
use middle::mem_categorization::Categorization;
4848
use rustc::ty::{self, Ty};
4949
use rustc::infer::UpvarRegion;
50-
use std::collections::HashSet;
5150
use syntax::ast;
5251
use syntax_pos::Span;
5352
use rustc::hir;
5453
use rustc::hir::intravisit::{self, Visitor};
54+
use rustc::util::nodemap::NodeMap;
5555

5656
///////////////////////////////////////////////////////////////////////////
5757
// PUBLIC ENTRY POINTS
@@ -60,9 +60,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
6060
pub fn closure_analyze_fn(&self, body: &hir::Block) {
6161
let mut seed = SeedBorrowKind::new(self);
6262
seed.visit_block(body);
63-
let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
6463

65-
let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
64+
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
6665
adjust.visit_block(body);
6766

6867
// it's our job to process these.
@@ -72,9 +71,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
7271
pub fn closure_analyze_const(&self, body: &hir::Expr) {
7372
let mut seed = SeedBorrowKind::new(self);
7473
seed.visit_expr(body);
75-
let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
7674

77-
let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds);
75+
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
7876
adjust.visit_expr(body);
7977

8078
// it's our job to process these.
@@ -87,7 +85,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
8785

8886
struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
8987
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
90-
closures_with_inferred_kinds: HashSet<ast::NodeId>,
88+
temp_closure_kinds: NodeMap<ty::ClosureKind>,
9189
}
9290

9391
impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> {
@@ -106,7 +104,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> {
106104

107105
impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
108106
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> {
109-
SeedBorrowKind { fcx: fcx, closures_with_inferred_kinds: HashSet::new() }
107+
SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() }
110108
}
111109

112110
fn check_closure(&mut self,
@@ -116,11 +114,8 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
116114
{
117115
let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
118116
if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
119-
self.closures_with_inferred_kinds.insert(expr.id);
120-
self.fcx.tables.borrow_mut().closure_kinds
121-
.insert(closure_def_id, ty::ClosureKind::Fn);
122-
debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
123-
closure_def_id);
117+
self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn);
118+
debug!("check_closure: adding closure {:?} as Fn", expr.id);
124119
}
125120

126121
self.fcx.tcx.with_freevars(expr.id, |freevars| {
@@ -154,14 +149,14 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
154149

155150
struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
156151
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
157-
closures_with_inferred_kinds: &'a HashSet<ast::NodeId>,
152+
temp_closure_kinds: NodeMap<ty::ClosureKind>,
158153
}
159154

160155
impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
161156
fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
162-
closures_with_inferred_kinds: &'a HashSet<ast::NodeId>)
157+
temp_closure_kinds: NodeMap<ty::ClosureKind>)
163158
-> AdjustBorrowKind<'a, 'gcx, 'tcx> {
164-
AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds }
159+
AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds }
165160
}
166161

167162
fn analyze_closure(&mut self,
@@ -176,7 +171,12 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
176171
debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id);
177172

178173
{
179-
let mut euv = euv::ExprUseVisitor::new(self, self.fcx);
174+
let mut euv =
175+
euv::ExprUseVisitor::with_options(self,
176+
self.fcx,
177+
mc::MemCategorizationOptions {
178+
during_closure_kind_inference: true
179+
});
180180
euv.walk_fn(decl, body);
181181
}
182182

@@ -211,10 +211,14 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
211211
self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
212212
}
213213

214-
// Now we must process and remove any deferred resolutions,
215-
// since we have a concrete closure kind.
214+
// If we are also inferred the closure kind here, update the
215+
// main table and process any deferred resolutions.
216216
let closure_def_id = self.fcx.tcx.map.local_def_id(id);
217-
if self.closures_with_inferred_kinds.contains(&id) {
217+
if let Some(&kind) = self.temp_closure_kinds.get(&id) {
218+
self.fcx.tables.borrow_mut().closure_kinds
219+
.insert(closure_def_id, kind);
220+
debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
221+
218222
let mut deferred_call_resolutions =
219223
self.fcx.remove_deferred_call_resolutions(closure_def_id);
220224
for deferred_call_resolution in &mut deferred_call_resolutions {
@@ -259,7 +263,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
259263
})
260264
}
261265

262-
fn adjust_upvar_borrow_kind_for_consume(&self,
266+
fn adjust_upvar_borrow_kind_for_consume(&mut self,
263267
cmt: mc::cmt<'tcx>,
264268
mode: euv::ConsumeMode)
265269
{
@@ -350,7 +354,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
350354
}
351355
}
352356

353-
fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
357+
fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) {
354358
debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})",
355359
cmt);
356360

@@ -381,7 +385,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
381385
}
382386
}
383387

384-
fn try_adjust_upvar_deref(&self,
388+
fn try_adjust_upvar_deref(&mut self,
385389
note: &mc::Note,
386390
borrow_kind: ty::BorrowKind)
387391
-> bool
@@ -430,7 +434,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
430434
/// moving from left to right as needed (but never right to left).
431435
/// Here the argument `mutbl` is the borrow_kind that is required by
432436
/// some particular use.
433-
fn adjust_upvar_borrow_kind(&self,
437+
fn adjust_upvar_borrow_kind(&mut self,
434438
upvar_id: ty::UpvarId,
435439
upvar_capture: &mut ty::UpvarCapture,
436440
kind: ty::BorrowKind) {
@@ -460,36 +464,30 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
460464
}
461465
}
462466

463-
fn adjust_closure_kind(&self,
467+
fn adjust_closure_kind(&mut self,
464468
closure_id: ast::NodeId,
465469
new_kind: ty::ClosureKind) {
466470
debug!("adjust_closure_kind(closure_id={}, new_kind={:?})",
467471
closure_id, new_kind);
468472

469-
if !self.closures_with_inferred_kinds.contains(&closure_id) {
470-
return;
471-
}
472-
473-
let closure_def_id = self.fcx.tcx.map.local_def_id(closure_id);
474-
let closure_kinds = &mut self.fcx.tables.borrow_mut().closure_kinds;
475-
let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
473+
if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) {
474+
debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
475+
closure_id, existing_kind, new_kind);
476476

477-
debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}",
478-
closure_id, existing_kind, new_kind);
479-
480-
match (existing_kind, new_kind) {
481-
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
482-
(ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
483-
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
484-
(ty::ClosureKind::FnOnce, _) => {
485-
// no change needed
486-
}
477+
match (existing_kind, new_kind) {
478+
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
479+
(ty::ClosureKind::FnMut, ty::ClosureKind::Fn) |
480+
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
481+
(ty::ClosureKind::FnOnce, _) => {
482+
// no change needed
483+
}
487484

488-
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
489-
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
490-
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
491-
// new kind is stronger than the old kind
492-
closure_kinds.insert(closure_def_id, new_kind);
485+
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) |
486+
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
487+
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
488+
// new kind is stronger than the old kind
489+
self.temp_closure_kinds.insert(closure_id, new_kind);
490+
}
493491
}
494492
}
495493
}

src/test/compile-fail/issue-34349.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2016 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+
// This is a regression test for a problem encountered around upvar
12+
// inference and trait caching: in particular, we were entering a
13+
// temporary closure kind during inference, and then caching results
14+
// based on that temporary kind, which led to no error being reported
15+
// in this particular test.
16+
17+
fn main() {
18+
let inc = || {};
19+
inc();
20+
21+
fn apply<F>(f: F) where F: Fn() {
22+
f()
23+
}
24+
25+
let mut farewell = "goodbye".to_owned();
26+
let diary = || { //~ ERROR E0525
27+
farewell.push_str("!!!");
28+
println!("Then I screamed {}.", farewell);
29+
};
30+
31+
apply(diary);
32+
}

0 commit comments

Comments
 (0)