Skip to content

Commit 2ec305d

Browse files
committed
Move checks for closure bounds out of kind.rs
1 parent 034f69e commit 2ec305d

File tree

10 files changed

+74
-171
lines changed

10 files changed

+74
-171
lines changed

src/librustc/diagnostics.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,7 @@ register_diagnostics!(
146146
E0139,
147147
E0140,
148148
E0141,
149-
E0143,
150149
E0144,
151-
E0145,
152-
E0146,
153150
E0152,
154151
E0153,
155152
E0154,

src/librustc/middle/kind.rs

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ pub struct Context<'a,'tcx:'a> {
3030
}
3131

3232
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
33-
fn visit_fn(&mut self, fk: visit::FnKind, fd: &'v FnDecl,
34-
b: &'v Block, s: Span, n: NodeId) {
35-
check_fn(self, fk, fd, b, s, n);
36-
}
37-
3833
fn visit_ty(&mut self, t: &Ty) {
3934
check_ty(self, t);
4035
}
@@ -48,110 +43,6 @@ pub fn check_crate(tcx: &ty::ctxt) {
4843
tcx.sess.abort_if_errors();
4944
}
5045

51-
// Yields the appropriate function to check the kind of closed over
52-
// variables. `id` is the NodeId for some expression that creates the
53-
// closure.
54-
fn with_appropriate_checker(cx: &Context,
55-
id: NodeId,
56-
fn_span: Span,
57-
b: |checker: |&Context, &ty::Freevar||) {
58-
fn check_for_uniq(cx: &Context,
59-
fn_span: Span,
60-
fv: &ty::Freevar,
61-
bounds: ty::BuiltinBounds) {
62-
// all captured data must be owned, regardless of whether it is
63-
// moved in or copied in.
64-
let id = fv.def.def_id().node;
65-
let var_t = ty::node_id_to_type(cx.tcx, id);
66-
67-
check_freevar_bounds(cx, fn_span, fv.span, var_t, bounds, None);
68-
}
69-
70-
fn check_for_block(cx: &Context,
71-
fn_span: Span,
72-
fn_id: NodeId,
73-
fv: &ty::Freevar,
74-
bounds: ty::BuiltinBounds) {
75-
let id = fv.def.def_id().node;
76-
let var_t = ty::node_id_to_type(cx.tcx, id);
77-
let upvar_id = ty::UpvarId { var_id: id, closure_expr_id: fn_id };
78-
let upvar_borrow = cx.tcx.upvar_borrow(upvar_id);
79-
let implicit_borrowed_type =
80-
ty::mk_rptr(cx.tcx,
81-
upvar_borrow.region,
82-
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
83-
ty: var_t });
84-
check_freevar_bounds(cx, fn_span, fv.span, implicit_borrowed_type,
85-
bounds, Some(var_t));
86-
}
87-
88-
fn check_for_bare(cx: &Context, fv: &ty::Freevar) {
89-
span_err!(cx.tcx.sess, fv.span, E0143,
90-
"can't capture dynamic environment in a fn item; \
91-
use the || {} closure form instead", "{ ... }");
92-
} // same check is done in resolve.rs, but shouldn't be done
93-
94-
let fty = ty::node_id_to_type(cx.tcx, id);
95-
match ty::get(fty).sty {
96-
ty::ty_closure(box ty::ClosureTy {
97-
store: ty::UniqTraitStore,
98-
bounds: bounds,
99-
..
100-
}) => {
101-
b(|cx, fv| check_for_uniq(cx, fn_span, fv,
102-
bounds.builtin_bounds))
103-
}
104-
105-
ty::ty_closure(box ty::ClosureTy {
106-
store: ty::RegionTraitStore(..), bounds, ..
107-
}) => {
108-
b(|cx, fv| check_for_block(cx, fn_span, id, fv,
109-
bounds.builtin_bounds))
110-
}
111-
112-
ty::ty_bare_fn(_) => {
113-
b(check_for_bare)
114-
}
115-
116-
ty::ty_unboxed_closure(..) => {}
117-
118-
ref s => {
119-
cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
120-
{:?}",
121-
s).as_slice());
122-
}
123-
}
124-
}
125-
126-
// Check that the free variables used in a shared/sendable closure conform
127-
// to the copy/move kind bounds. Then recursively check the function body.
128-
fn check_fn(
129-
cx: &mut Context,
130-
fk: visit::FnKind,
131-
decl: &FnDecl,
132-
body: &Block,
133-
sp: Span,
134-
fn_id: NodeId) {
135-
136-
// <Check kinds on free variables:
137-
with_appropriate_checker(cx, fn_id, sp, |chk| {
138-
ty::with_freevars(cx.tcx, fn_id, |freevars| {
139-
for fv in freevars.iter() {
140-
chk(cx, fv);
141-
}
142-
});
143-
});
144-
145-
match fk {
146-
visit::FkFnBlock(..) => {
147-
visit::walk_fn(cx, fk, decl, body, sp)
148-
}
149-
visit::FkItemFn(..) | visit::FkMethod(..) => {
150-
visit::walk_fn(cx, fk, decl, body, sp);
151-
}
152-
}
153-
}
154-
15546
fn check_ty(cx: &mut Context, aty: &Ty) {
15647
match aty.node {
15748
TyPath(_, _, id) => {
@@ -208,29 +99,3 @@ pub fn check_typaram_bounds(cx: &Context,
20899
});
209100
}
210101

211-
pub fn check_freevar_bounds(cx: &Context, fn_span: Span, sp: Span, ty: ty::t,
212-
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
213-
{
214-
check_builtin_bounds(cx, ty, bounds, |missing| {
215-
// Will be Some if the freevar is implicitly borrowed (stack closure).
216-
// Emit a less mysterious error message in this case.
217-
match referenced_ty {
218-
Some(rty) => {
219-
span_err!(cx.tcx.sess, sp, E0145,
220-
"cannot implicitly borrow variable of type `{}` in a \
221-
bounded stack closure (implicit reference does not fulfill `{}`)",
222-
ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx));
223-
}
224-
None => {
225-
span_err!(cx.tcx.sess, sp, E0146,
226-
"cannot capture variable of type `{}`, which does \
227-
not fulfill `{}`, in a bounded closure",
228-
ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
229-
}
230-
}
231-
span_note!(cx.tcx.sess, fn_span,
232-
"this closure's environment must satisfy `{}`",
233-
bounds.user_string(cx.tcx));
234-
});
235-
}
236-

src/librustc/middle/traits/coherence.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
/*! See `doc.rs` for high-level documentation */
1212

13-
use super::DUMMY_CAUSE;
1413
use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch};
1514
use super::{evaluate_impl};
15+
use super::ObligationCause;
1616
use super::util;
1717

1818
use middle::subst;
@@ -39,7 +39,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
3939
// Determine whether `impl2` can provide an implementation for those
4040
// same types.
4141
let param_env = ty::empty_parameter_environment();
42-
match evaluate_impl(infcx, &param_env, infcx.tcx, DUMMY_CAUSE,
42+
match evaluate_impl(infcx, &param_env, infcx.tcx, ObligationCause::dummy(),
4343
impl2_def_id, impl1_self_ty) {
4444
EvaluatedToMatch | EvaluatedToAmbiguity => true,
4545
EvaluatedToUnmatch => false,

src/librustc/middle/traits/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ pub enum ObligationCauseCode {
7777
StructInitializerSized, // S { ... } must be Sized
7878
VariableType(ast::NodeId), // Type of each variable must be Sized
7979
RepeatVec, // [T,..n] --> T must be Copy
80-
}
8180

82-
pub static DUMMY_CAUSE: ObligationCause =
83-
ObligationCause { span: DUMMY_SP,
84-
code: MiscObligation };
81+
// Captures of variable the given id by a closure (span is the
82+
// span of the closure)
83+
ClosureCapture(ast::NodeId, Span)
84+
}
8585

8686
pub type Obligations = subst::VecPerParamSpace<Obligation>;
8787

@@ -358,6 +358,10 @@ impl ObligationCause {
358358
pub fn misc(span: Span) -> ObligationCause {
359359
ObligationCause { span: span, code: MiscObligation }
360360
}
361+
362+
pub fn dummy() -> ObligationCause {
363+
ObligationCause { span: DUMMY_SP, code: MiscObligation }
364+
}
361365
}
362366

363367
impl<N> Vtable<N> {

src/librustc/middle/typeck/check/regionck.rs

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,13 @@ and report an error, and it just seems like more mess in the end.)
120120

121121
use middle::def;
122122
use middle::mem_categorization as mc;
123+
use middle::traits;
123124
use middle::ty::{ReScope};
124125
use middle::ty;
125126
use middle::typeck::astconv::AstConv;
126127
use middle::typeck::check::FnCtxt;
127128
use middle::typeck::check::regionmanip;
129+
use middle::typeck::check::vtable2;
128130
use middle::typeck::infer::resolve_and_force_all_but_regions;
129131
use middle::typeck::infer::resolve_type;
130132
use middle::typeck::infer;
@@ -165,6 +167,11 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
165167
// regionck assumes typeck succeeded
166168
rcx.visit_fn_body(id, blk);
167169
}
170+
171+
// Region checking a fn can introduce new trait obligations,
172+
// particularly around closure bounds.
173+
vtable2::select_all_fcx_obligations_or_error(fcx);
174+
168175
fcx.infcx().resolve_regions_and_report_errors();
169176
}
170177

@@ -848,16 +855,6 @@ fn check_expr_fn_block(rcx: &mut Rcx,
848855
}
849856
});
850857
}
851-
ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore,
852-
bounds: ref bounds,
853-
..}) => {
854-
// For proc, ensure that the *types* of the variables
855-
// outlive region bound, since they are captured by value.
856-
ty::with_freevars(tcx, expr.id, |freevars| {
857-
ensure_free_variable_types_outlive_closure_bound(
858-
rcx, bounds.region_bound, expr, freevars);
859-
});
860-
}
861858
ty::ty_unboxed_closure(_, region) => {
862859
ty::with_freevars(tcx, expr.id, |freevars| {
863860
// No free variables means that there is no environment and
@@ -868,8 +865,9 @@ fn check_expr_fn_block(rcx: &mut Rcx,
868865
// NDM -- this seems wrong, discuss with pcwalton, should
869866
// be straightforward enough.
870867
if !freevars.is_empty() {
868+
let bounds = ty::region_existential_bound(region);
871869
ensure_free_variable_types_outlive_closure_bound(
872-
rcx, region, expr, freevars);
870+
rcx, bounds, expr, freevars);
873871
}
874872
})
875873
}
@@ -881,20 +879,26 @@ fn check_expr_fn_block(rcx: &mut Rcx,
881879
rcx.set_repeating_scope(repeating_scope);
882880

883881
match ty::get(function_type).sty {
884-
ty::ty_closure(box ty::ClosureTy {
885-
store: ty::RegionTraitStore(..),
886-
..
887-
}) => {
882+
ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. }) => {
888883
ty::with_freevars(tcx, expr.id, |freevars| {
889884
propagate_upupvar_borrow_kind(rcx, expr, freevars);
890885
})
891886
}
892-
_ => ()
887+
_ => {}
888+
}
889+
890+
match ty::get(function_type).sty {
891+
ty::ty_closure(box ty::ClosureTy {bounds, ..}) => {
892+
ty::with_freevars(tcx, expr.id, |freevars| {
893+
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
894+
})
895+
}
896+
_ => {}
893897
}
894898

895899
fn ensure_free_variable_types_outlive_closure_bound(
896900
rcx: &mut Rcx,
897-
region_bound: ty::Region,
901+
bounds: ty::ExistentialBounds,
898902
expr: &ast::Expr,
899903
freevars: &[ty::Freevar])
900904
{
@@ -908,7 +912,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
908912
let tcx = rcx.fcx.ccx.tcx;
909913

910914
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
911-
region_bound.repr(tcx), expr.repr(tcx));
915+
bounds.region_bound.repr(tcx), expr.repr(tcx));
912916

913917
for freevar in freevars.iter() {
914918
let var_node_id = {
@@ -917,11 +921,35 @@ fn check_expr_fn_block(rcx: &mut Rcx,
917921
def_id.node
918922
};
919923

920-
let var_ty = rcx.resolve_node_type(var_node_id);
924+
// Compute the type of the field in the environment that
925+
// represents `var_node_id`. For a by-value closure, this
926+
// will be the same as the type of the variable. For a
927+
// by-reference closure, this will be `&T` where `T` is
928+
// the type of the variable.
929+
let raw_var_ty = rcx.resolve_node_type(var_node_id);
930+
let upvar_id = ty::UpvarId { var_id: var_node_id,
931+
closure_expr_id: expr.id };
932+
let var_ty = match rcx.fcx.inh.upvar_borrow_map.borrow().find(&upvar_id) {
933+
Some(upvar_borrow) => {
934+
ty::mk_rptr(rcx.tcx(),
935+
upvar_borrow.region,
936+
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
937+
ty: raw_var_ty })
938+
}
939+
None => raw_var_ty
940+
};
921941

942+
// Check that the type meets the criteria of the existential bounds:
943+
for builtin_bound in bounds.builtin_bounds.iter() {
944+
let code = traits::ClosureCapture(var_node_id, expr.span);
945+
let cause = traits::ObligationCause::new(freevar.span, code);
946+
let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause,
947+
var_ty, builtin_bound);
948+
rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(), obligation);
949+
}
922950
type_must_outlive(
923951
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
924-
var_ty, region_bound);
952+
var_ty, bounds.region_bound);
925953
}
926954
}
927955

src/librustc/middle/typeck/check/vtable2.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,5 +398,13 @@ fn note_obligation_cause(fcx: &FnCtxt,
398398
"use \"#[unsafe_destructor]\" on the implementation \
399399
to force the compiler to allow this");
400400
}
401+
traits::ClosureCapture(var_id, closure_span) => {
402+
let name = ty::local_var_name_str(tcx, var_id);
403+
span_note!(tcx.sess, closure_span,
404+
"the closure that captures `{}` requires that all captured variables \"
405+
implement the trait `{}`",
406+
name,
407+
trait_name);
408+
}
401409
}
402410
}

src/librustc/middle/typeck/infer/error_reporting.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,7 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> {
15601560
"...so that it can be closed over into an object");
15611561
}
15621562
infer::RelateProcBound(span, var_node_id, _ty) => {
1563-
self.tcx.sess.span_err(
1563+
self.tcx.sess.span_note(
15641564
span,
15651565
format!(
15661566
"...so that the variable `{}` can be captured \

src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ fn bar(blk: ||:'static) {
1212
}
1313

1414
fn foo(x: &()) {
15-
bar(|| {
16-
let _ = x; //~ ERROR captured variable `x` does not outlive
15+
bar(|| { //~ ERROR cannot infer an appropriate lifetime
16+
let _ = x;
17+
//~^ ERROR captured variable `x` does not outlive
1718
})
1819
}
1920

src/test/compile-fail/kindck-nonsendable-1.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ fn foo(_x: Gc<uint>) {}
1515

1616
fn main() {
1717
let x = box(GC) 3u;
18-
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
19-
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
20-
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
18+
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
19+
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
20+
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
2121
let _: proc() = proc() foo(x);
2222
}

0 commit comments

Comments
 (0)