Skip to content

Commit 0431134

Browse files
committed
Remove the explicit closure kind syntax from the parser and AST;
upgrade the inference based on expected type so that it is able to infer the fn kind in isolation even if the full signature is not available (and we could perhaps do better still in some cases, such as extracting just the types of the arguments but not the return value).
1 parent 47f1865 commit 0431134

File tree

23 files changed

+155
-136
lines changed

23 files changed

+155
-136
lines changed

src/librustc/middle/check_loop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
4545
ast::ExprLoop(ref b, _) => {
4646
self.with_context(Loop, |v| v.visit_block(&**b));
4747
}
48-
ast::ExprClosure(_, _, _, ref b) => {
48+
ast::ExprClosure(_, _, ref b) => {
4949
self.with_context(Closure, |v| v.visit_block(&**b));
5050
}
5151
ast::ExprBreak(_) => self.require_loop("break", e.span),

src/librustc/middle/liveness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
959959
self.propagate_through_expr(&**e, succ)
960960
}
961961

962-
ast::ExprClosure(_, _, _, ref blk) => {
962+
ast::ExprClosure(_, _, ref blk) => {
963963
debug!("{} is an ExprClosure",
964964
expr_to_string(expr));
965965

src/librustc/middle/mem_categorization.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
739739
};
740740

741741
match fn_expr.node {
742-
ast::ExprClosure(_, _, _, ref body) => body.id,
742+
ast::ExprClosure(_, _, ref body) => body.id,
743743
_ => unreachable!()
744744
}
745745
};

src/librustc_borrowck/borrowck/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
324324
tcx: &ty::ctxt) -> ast::NodeId {
325325
match tcx.map.get(closure_id) {
326326
ast_map::NodeExpr(expr) => match expr.node {
327-
ast::ExprClosure(_, _, _, ref block) => {
327+
ast::ExprClosure(_, _, ref block) => {
328328
block.id
329329
}
330330
_ => {

src/librustc_resolve/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4521,7 +4521,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
45214521
visit::walk_expr(self, expr);
45224522
}
45234523

4524-
ExprClosure(_, _, ref fn_decl, ref block) => {
4524+
ExprClosure(_, ref fn_decl, ref block) => {
45254525
self.resolve_function(ClosureRibKind(expr.id),
45264526
Some(&**fn_decl), NoTypeParameters,
45274527
&**block);

src/librustc_trans/save/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
13941394
type, found {:?}", ty)[]),
13951395
}
13961396
},
1397-
ast::ExprClosure(_, _, ref decl, ref body) => {
1397+
ast::ExprClosure(_, ref decl, ref body) => {
13981398
if generated_code(body.span) {
13991399
return
14001400
}

src/librustc_trans/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
13401340
}
13411341
Some(ast_map::NodeExpr(e)) => {
13421342
match e.node {
1343-
ast::ExprClosure(_, _, _, ref blk) => {
1343+
ast::ExprClosure(_, _, ref blk) => {
13441344
blk
13451345
}
13461346
_ => tcx.sess.bug("unexpected expr variant in has_nested_returns")

src/librustc_trans/trans/debuginfo.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
12831283
}
12841284
ast_map::NodeExpr(ref expr) => {
12851285
match expr.node {
1286-
ast::ExprClosure(_, _, ref fn_decl, ref top_level_block) => {
1286+
ast::ExprClosure(_, ref fn_decl, ref top_level_block) => {
12871287
let name = format!("fn{}", token::gensym("fn"));
12881288
let name = token::str_to_ident(&name[]);
12891289
(name, &**fn_decl,
@@ -3595,7 +3595,7 @@ fn create_scope_map(cx: &CrateContext,
35953595
})
35963596
}
35973597

3598-
ast::ExprClosure(_, _, ref decl, ref block) => {
3598+
ast::ExprClosure(_, ref decl, ref block) => {
35993599
with_new_scope(cx,
36003600
block.span,
36013601
scope_stack,

src/librustc_trans/trans/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10941094
ast::ExprVec(..) | ast::ExprRepeat(..) => {
10951095
tvec::trans_fixed_vstore(bcx, expr, dest)
10961096
}
1097-
ast::ExprClosure(_, _, ref decl, ref body) => {
1097+
ast::ExprClosure(_, ref decl, ref body) => {
10981098
closure::trans_closure_expr(bcx, &**decl, &**body, expr.id, dest)
10991099
}
11001100
ast::ExprCall(ref f, ref args) => {

src/librustc_typeck/check/closure.rs

Lines changed: 90 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,21 @@ use util::ppaux::Repr;
2525
pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
2626
expr: &ast::Expr,
2727
_capture: ast::CaptureClause,
28-
opt_kind: Option<ast::ClosureKind>,
2928
decl: &'tcx ast::FnDecl,
3029
body: &'tcx ast::Block,
3130
expected: Expectation<'tcx>) {
3231
debug!("check_expr_closure(expr={},expected={})",
3332
expr.repr(fcx.tcx()),
3433
expected.repr(fcx.tcx()));
3534

36-
let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
37-
deduce_expectations_from_expected_type(fcx, ty)
38-
});
39-
40-
match opt_kind {
41-
None => {
42-
// If users didn't specify what sort of closure they want,
43-
// examine the expected type. For now, if we see explicit
44-
// evidence than an unboxed closure is desired, we'll use
45-
// that. Otherwise, we leave it unspecified, to be filled
46-
// in by upvar inference.
47-
match expected_sig_and_kind {
48-
None => { // don't have information about the kind, request explicit annotation
49-
check_closure(fcx, expr, None, decl, body, None);
50-
},
51-
Some((sig, kind)) => {
52-
check_closure(fcx, expr, Some(kind), decl, body, Some(sig));
53-
}
54-
}
55-
}
56-
57-
Some(kind) => {
58-
let kind = match kind {
59-
ast::FnClosureKind => ty::FnClosureKind,
60-
ast::FnMutClosureKind => ty::FnMutClosureKind,
61-
ast::FnOnceClosureKind => ty::FnOnceClosureKind,
62-
};
63-
64-
let expected_sig = expected_sig_and_kind.map(|t| t.0);
65-
check_closure(fcx, expr, Some(kind), decl, body, expected_sig);
66-
}
67-
}
35+
// It's always helpful for inference if we know the kind of
36+
// closure sooner rather than later, so first examine the expected
37+
// type, and see if can glean a closure kind from there.
38+
let (expected_sig,expected_kind) = match expected.to_option(fcx) {
39+
Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
40+
None => (None, None)
41+
};
42+
check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
6843
}
6944

7045
fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
@@ -133,55 +108,92 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
133108
fn deduce_expectations_from_expected_type<'a,'tcx>(
134109
fcx: &FnCtxt<'a,'tcx>,
135110
expected_ty: Ty<'tcx>)
136-
-> Option<(ty::FnSig<'tcx>,ty::ClosureKind)>
111+
-> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
137112
{
113+
debug!("deduce_expectations_from_expected_type(expected_ty={})",
114+
expected_ty.repr(fcx.tcx()));
115+
138116
match expected_ty.sty {
139117
ty::ty_trait(ref object_type) => {
140118
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
141119
fcx.tcx().types.err);
142-
proj_bounds.iter()
143-
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
144-
.next()
120+
let expectations =
121+
proj_bounds.iter()
122+
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
123+
.next();
124+
125+
match expectations {
126+
Some((sig, kind)) => (Some(sig), Some(kind)),
127+
None => (None, None)
128+
}
145129
}
146130
ty::ty_infer(ty::TyVar(vid)) => {
147131
deduce_expectations_from_obligations(fcx, vid)
148132
}
149133
_ => {
150-
None
134+
(None, None)
151135
}
152136
}
153137
}
154138

155139
fn deduce_expectations_from_obligations<'a,'tcx>(
156140
fcx: &FnCtxt<'a,'tcx>,
157141
expected_vid: ty::TyVid)
158-
-> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
142+
-> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
159143
{
160144
let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
161145
// Here `expected_ty` is known to be a type inference variable.
162146

163-
fulfillment_cx.pending_obligations()
164-
.iter()
165-
.filter_map(|obligation| {
166-
match obligation.predicate {
167-
ty::Predicate::Projection(ref proj_predicate) => {
168-
let trait_ref = proj_predicate.to_poly_trait_ref();
169-
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
170-
match self_ty.sty {
171-
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => {
172-
deduce_expectations_from_projection(fcx, proj_predicate)
173-
}
174-
_ => {
175-
None
176-
}
177-
}
178-
}
179-
_ => {
180-
None
181-
}
182-
}
183-
})
184-
.next()
147+
let expected_sig_and_kind =
148+
fulfillment_cx
149+
.pending_obligations()
150+
.iter()
151+
.filter_map(|obligation| {
152+
debug!("deduce_expectations_from_obligations: obligation.predicate={}",
153+
obligation.predicate.repr(fcx.tcx()));
154+
155+
match obligation.predicate {
156+
// Given a Projection predicate, we can potentially infer
157+
// the complete signature.
158+
ty::Predicate::Projection(ref proj_predicate) => {
159+
let trait_ref = proj_predicate.to_poly_trait_ref();
160+
self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
161+
.and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
162+
}
163+
_ => {
164+
None
165+
}
166+
}
167+
})
168+
.next();
169+
170+
match expected_sig_and_kind {
171+
Some((sig, kind)) => { return (Some(sig), Some(kind)); }
172+
None => { }
173+
}
174+
175+
// Even if we can't infer the full signature, we may be able to
176+
// infer the kind. This can occur if there is a trait-reference
177+
// like `F : Fn<A>`.
178+
let expected_kind =
179+
fulfillment_cx
180+
.pending_obligations()
181+
.iter()
182+
.filter_map(|obligation| {
183+
let opt_trait_ref = match obligation.predicate {
184+
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
185+
ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
186+
ty::Predicate::Equate(..) => None,
187+
ty::Predicate::RegionOutlives(..) => None,
188+
ty::Predicate::TypeOutlives(..) => None,
189+
};
190+
opt_trait_ref
191+
.and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
192+
.and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
193+
})
194+
.next();
195+
196+
(None, expected_kind)
185197
}
186198

187199
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
@@ -229,3 +241,20 @@ fn deduce_expectations_from_projection<'a,'tcx>(
229241
return Some((fn_sig, kind));
230242
}
231243

244+
fn self_type_matches_expected_vid<'a,'tcx>(
245+
fcx: &FnCtxt<'a,'tcx>,
246+
trait_ref: ty::PolyTraitRef<'tcx>,
247+
expected_vid: ty::TyVid)
248+
-> Option<ty::PolyTraitRef<'tcx>>
249+
{
250+
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
251+
debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
252+
trait_ref.repr(fcx.tcx()),
253+
self_ty.repr(fcx.tcx()));
254+
match self_ty.sty {
255+
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
256+
_ => None,
257+
}
258+
}
259+
260+

0 commit comments

Comments
 (0)