Skip to content

Commit c2dbd62

Browse files
committed
Lower closure binders to hir & properly check them
1 parent f89ef3c commit c2dbd62

File tree

16 files changed

+214
-103
lines changed

16 files changed

+214
-103
lines changed

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
642642
pub fn walk_closure_binder<'a, V: Visitor<'a>>(visitor: &mut V, binder: &'a ClosureBinder) {
643643
match binder {
644644
ClosureBinder::NotPresent => {}
645-
ClosureBinder::For { span: _, generic_params } => {
645+
ClosureBinder::For { generic_params, span: _ } => {
646646
walk_list!(visitor, visit_generic_param, generic_params)
647647
}
648648
}

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
609609

610610
// `static |_task_context| -> <ret_ty> { body }`:
611611
let generator_kind = hir::ExprKind::Closure {
612+
binder: &hir::ClosureBinder::Default,
612613
capture_clause,
613614
bound_generic_params: &[],
614615
fn_decl,
@@ -842,15 +843,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
842843
body: &Expr,
843844
fn_decl_span: Span,
844845
) -> hir::ExprKind<'hir> {
845-
// FIXME(waffle): lower binder
846-
if let &ClosureBinder::For { span, .. } = binder {
847-
self.sess
848-
.struct_span_err(span, "`for<...>` binders for closures are not yet supported")
849-
.help("consider removing `for<...>`")
850-
.emit();
851-
}
846+
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
852847

853-
let (body, generator_option) = self.with_new_scopes(move |this| {
848+
let (body_id, generator_option) = self.with_new_scopes(move |this| {
854849
let prev = this.current_item;
855850
this.current_item = Some(fn_decl_span);
856851
let mut generator_kind = None;
@@ -865,15 +860,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
865860
(body_id, generator_option)
866861
});
867862

868-
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
863+
self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
869864
// Lower outside new scope to preserve `is_in_loop_condition`.
870865
let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
871866

872867
hir::ExprKind::Closure {
868+
binder: binder_clause,
873869
capture_clause,
874870
bound_generic_params,
875871
fn_decl,
876-
body,
872+
body: body_id,
877873
fn_decl_span: this.lower_span(fn_decl_span),
878874
movability: generator_option,
879875
}
@@ -918,6 +914,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
918914
}
919915
}
920916

917+
fn lower_closure_binder<'c>(
918+
&mut self,
919+
binder: &'c ClosureBinder,
920+
) -> (&'hir hir::ClosureBinder, &'c [GenericParam]) {
921+
let (binder, params) = match binder {
922+
ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
923+
&ClosureBinder::For { span, ref generic_params } => {
924+
let span = self.lower_span(span);
925+
(hir::ClosureBinder::For { span }, &**generic_params)
926+
}
927+
};
928+
929+
(self.arena.alloc(binder), params)
930+
}
931+
921932
fn lower_expr_async_closure(
922933
&mut self,
923934
binder: &ClosureBinder,
@@ -928,17 +939,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
928939
body: &Expr,
929940
fn_decl_span: Span,
930941
) -> hir::ExprKind<'hir> {
931-
// FIXME(waffle): lower binder
932942
if let &ClosureBinder::For { span, .. } = binder {
933-
self.sess
934-
.struct_span_err(
935-
span,
936-
"`for<...>` binders for async closures are not yet supported",
937-
)
938-
.help("consider removing `for<...>`")
939-
.emit();
943+
self.tcx.sess.span_err(
944+
span,
945+
"`for<...>` binders on `async` closures are not currently supported",
946+
);
940947
}
941948

949+
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
950+
942951
let outer_decl =
943952
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
944953

@@ -976,13 +985,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
976985
body_id
977986
});
978987

979-
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
988+
self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
980989
// We need to lower the declaration outside the new scope, because we
981990
// have to conserve the state of being inside a loop condition for the
982991
// closure argument types.
983992
let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
984993

985994
hir::ExprKind::Closure {
995+
binder: binder_clause,
986996
capture_clause,
987997
bound_generic_params,
988998
fn_decl,

compiler/rustc_hir/src/hir.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,7 @@ pub enum ExprKind<'hir> {
19311931
/// This may also be a generator literal or an `async block` as indicated by the
19321932
/// `Option<Movability>`.
19331933
Closure {
1934+
binder: &'hir ClosureBinder,
19341935
capture_clause: CaptureBy,
19351936
bound_generic_params: &'hir [GenericParam<'hir>],
19361937
fn_decl: &'hir FnDecl<'hir>,
@@ -2715,6 +2716,17 @@ impl FnRetTy<'_> {
27152716
}
27162717
}
27172718

2719+
/// Represents `for<...>` binder before a closure
2720+
#[derive(Copy, Clone, Debug, HashStable_Generic)]
2721+
pub enum ClosureBinder {
2722+
/// Binder is not specified.
2723+
Default,
2724+
/// Binder is specified.
2725+
///
2726+
/// Span points to the whole `for<...>`.
2727+
For { span: Span },
2728+
}
2729+
27182730
#[derive(Encodable, Debug, HashStable_Generic)]
27192731
pub struct Mod<'hir> {
27202732
pub spans: ModSpans,

compiler/rustc_hir/src/intravisit.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
925925
FnKind::ItemFn(_, generics, ..) => {
926926
visitor.visit_generics(generics);
927927
}
928-
FnKind::Method(..) | FnKind::Closure => {}
928+
FnKind::Closure | FnKind::Method(..) => {}
929929
}
930930
}
931931

@@ -1145,6 +1145,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
11451145
walk_list!(visitor, visit_arm, arms);
11461146
}
11471147
ExprKind::Closure {
1148+
binder: _,
11481149
bound_generic_params,
11491150
ref fn_decl,
11501151
body,
@@ -1153,7 +1154,13 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
11531154
movability: _,
11541155
} => {
11551156
walk_list!(visitor, visit_generic_param, bound_generic_params);
1156-
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
1157+
visitor.visit_fn(
1158+
FnKind::Closure,
1159+
fn_decl,
1160+
body,
1161+
expression.span,
1162+
expression.hir_id,
1163+
)
11571164
}
11581165
ExprKind::Block(ref block, ref opt_label) => {
11591166
walk_list!(visitor, visit_label, opt_label);

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
66
use rustc_ast_pretty::pp::{self, Breaks};
77
use rustc_ast_pretty::pprust::{Comments, PrintState};
88
use rustc_hir as hir;
9+
use rustc_hir::LifetimeParamKind;
910
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
1011
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
1112
use rustc_span::source_map::SourceMap;
@@ -1441,14 +1442,15 @@ impl<'a> State<'a> {
14411442
self.bclose(expr.span);
14421443
}
14431444
hir::ExprKind::Closure {
1445+
binder,
14441446
capture_clause,
14451447
bound_generic_params,
14461448
fn_decl,
14471449
body,
14481450
fn_decl_span: _,
14491451
movability: _,
14501452
} => {
1451-
self.print_formal_generic_params(bound_generic_params);
1453+
self.print_closure_binder(binder, bound_generic_params);
14521454
self.print_capture_clause(capture_clause);
14531455

14541456
self.print_closure_params(fn_decl, body);
@@ -2033,6 +2035,42 @@ impl<'a> State<'a> {
20332035
}
20342036
}
20352037

2038+
pub fn print_closure_binder(
2039+
&mut self,
2040+
binder: &hir::ClosureBinder,
2041+
generic_params: &[GenericParam<'_>],
2042+
) {
2043+
let generic_params = generic_params
2044+
.iter()
2045+
.filter(|p| {
2046+
matches!(
2047+
p,
2048+
GenericParam {
2049+
kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit },
2050+
..
2051+
}
2052+
)
2053+
})
2054+
.collect::<Vec<_>>();
2055+
2056+
match binder {
2057+
hir::ClosureBinder::Default => {}
2058+
// we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions
2059+
hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"),
2060+
hir::ClosureBinder::For { .. } => {
2061+
self.word("for");
2062+
self.word("<");
2063+
2064+
self.commasep(Inconsistent, &generic_params, |s, param| {
2065+
s.print_generic_param(param)
2066+
});
2067+
2068+
self.word(">");
2069+
self.nbsp();
2070+
}
2071+
}
2072+
}
2073+
20362074
pub fn print_bounds<'b>(
20372075
&mut self,
20382076
prefix: &'static str,

compiler/rustc_lint/src/early.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
154154
self.check_id(closure_id);
155155
}
156156
}
157+
157158
run_early_pass!(self, check_fn_post, fk, span, id);
158159
}
159160

compiler/rustc_resolve/src/late.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -844,19 +844,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
844844
this.in_func_body = previous_state;
845845
}
846846
}
847-
FnKind::Closure(declaration, body) => {
848-
// We do not have any explicit generic lifetime parameter.
849-
// FIXME(rfc3216): Change when implementing `for<>` bounds on closures.
847+
FnKind::Closure(binder, declaration, body) => {
848+
this.visit_closure_binder(binder);
849+
850850
this.with_lifetime_rib(
851-
LifetimeRibKind::AnonymousCreateParameter {
852-
binder: fn_id,
853-
report_in_path: false,
851+
match binder {
852+
// We do not have any explicit generic lifetime parameter.
853+
ClosureBinder::NotPresent => {
854+
LifetimeRibKind::AnonymousCreateParameter {
855+
binder: fn_id,
856+
report_in_path: false,
857+
}
858+
}
859+
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
854860
},
855861
// Add each argument to the rib.
856862
|this| this.resolve_params(&declaration.inputs),
857863
);
858864
this.with_lifetime_rib(
859-
LifetimeRibKind::AnonymousPassThrough(fn_id, true),
865+
match binder {
866+
ClosureBinder::NotPresent => {
867+
LifetimeRibKind::AnonymousPassThrough(fn_id, true)
868+
}
869+
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
870+
},
860871
|this| visit::walk_fn_ret_ty(this, &declaration.output),
861872
);
862873

@@ -891,6 +902,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
891902
}
892903
}
893904

905+
fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) {
906+
match b {
907+
ClosureBinder::NotPresent => {}
908+
ClosureBinder::For { generic_params, .. } => {
909+
self.visit_generic_params(
910+
&generic_params,
911+
self.diagnostic_metadata.current_self_item.is_some(),
912+
);
913+
}
914+
}
915+
}
916+
894917
fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
895918
debug!("visit_generic_arg({:?})", arg);
896919
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
@@ -3515,6 +3538,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
35153538
});
35163539
}
35173540
// For closures, ClosureOrAsyncRibKind is added in visit_fn
3541+
ExprKind::Closure(ClosureBinder::For { ref generic_params, span }, ..) => {
3542+
self.with_generic_param_rib(
3543+
&generic_params,
3544+
NormalRibKind,
3545+
LifetimeRibKind::Generics {
3546+
binder: expr.id,
3547+
kind: LifetimeBinderKind::Function,
3548+
span,
3549+
},
3550+
|this| visit::walk_expr(this, expr),
3551+
);
3552+
}
35183553
ExprKind::Closure(..) => visit::walk_expr(self, expr),
35193554
ExprKind::Async(..) => {
35203555
self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));

compiler/rustc_resolve/src/late/lifetimes.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,51 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
571571
}
572572

573573
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
574-
if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind {
574+
if let hir::ExprKind::Closure { binder, bound_generic_params, fn_decl, .. } = e.kind {
575+
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
576+
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
577+
struct V(Option<Span>);
578+
579+
impl<'v> Visitor<'v> for V {
580+
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
581+
match t.kind {
582+
_ if self.0.is_some() => (),
583+
hir::TyKind::Infer => {
584+
self.0 = Some(t.span);
585+
}
586+
_ => intravisit::walk_ty(self, t),
587+
}
588+
}
589+
}
590+
591+
let mut v = V(None);
592+
v.visit_ty(ty);
593+
v.0
594+
}
595+
596+
let infer_in_rt_sp = match fn_decl.output {
597+
hir::FnRetTy::DefaultReturn(sp) => Some(sp),
598+
hir::FnRetTy::Return(ty) => span_of_infer(ty),
599+
};
600+
601+
let infer_spans = fn_decl
602+
.inputs
603+
.into_iter()
604+
.filter_map(span_of_infer)
605+
.chain(infer_in_rt_sp)
606+
.collect::<Vec<_>>();
607+
608+
if !infer_spans.is_empty() {
609+
self.tcx.sess
610+
.struct_span_err(
611+
infer_spans,
612+
"implicit types in closure signatures are forbidden when `for<...>` is present",
613+
)
614+
.span_label(for_sp, "`for<...>` is here")
615+
.emit();
616+
}
617+
}
618+
575619
let next_early_index = self.next_early_index();
576620
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
577621
bound_generic_params
@@ -584,6 +628,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
584628
(pair, r)
585629
})
586630
.unzip();
631+
632+
// FIXME: missing_named_lifetime_spots
633+
587634
self.map.late_bound_vars.insert(e.hir_id, binders);
588635
let scope = Scope::Binder {
589636
hir_id: e.hir_id,

src/test/ui/closures/binder/async-closure-with-binder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
fn main() {
55
for<'a> async || ();
66
//~^ ERROR `for<...>` binders on `async` closures are not currently supported
7+
//~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
78
}

0 commit comments

Comments
 (0)