about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2021-01-21 22:09:15 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2021-01-21 22:59:07 +0100
commit3f42abec58ab05d37689f33efdfa6382eb4b1e1a (patch)
tree3bac82b63750b87f086e0a8aa6c92bc4c0cf6b7f
parentc5a96fb7973649807a7943e7395456db158dcab6 (diff)
downloadrust-3f42abec58ab05d37689f33efdfa6382eb4b1e1a.tar.gz
rust-3f42abec58ab05d37689f33efdfa6382eb4b1e1a.zip
Lower closure prototype after its body.
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs31
-rw-r--r--src/test/ui/closures/local-type-mix.rs17
-rw-r--r--src/test/ui/closures/local-type-mix.stderr51
3 files changed, 86 insertions, 13 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 1b9ccbd850b..2470a8791e1 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -770,10 +770,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Expr,
         fn_decl_span: Span,
     ) -> hir::ExprKind<'hir> {
-        // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(decl, None, false, None);
-
-        self.with_new_scopes(move |this| {
+        let (body_id, generator_option) = self.with_new_scopes(move |this| {
             let prev = this.current_item;
             this.current_item = Some(fn_decl_span);
             let mut generator_kind = None;
@@ -785,8 +782,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let generator_option =
                 this.generator_movability_for_fn(&decl, fn_decl_span, generator_kind, movability);
             this.current_item = prev;
-            hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option)
-        })
+            (body_id, generator_option)
+        });
+
+        // Lower outside new scope to preserve `is_in_loop_condition`.
+        let fn_decl = self.lower_fn_decl(decl, None, false, None);
+
+        hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option)
     }
 
     fn generator_movability_for_fn(
@@ -832,12 +834,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> hir::ExprKind<'hir> {
         let outer_decl =
             FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
-        // We need to lower the declaration outside the new scope, because we
-        // have to conserve the state of being inside a loop condition for the
-        // closure argument types.
-        let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
 
-        self.with_new_scopes(move |this| {
+        let body_id = self.with_new_scopes(|this| {
             // FIXME(cramertj): allow `async` non-`move` closures with arguments.
             if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
                 struct_span_err!(
@@ -868,8 +866,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 this.expr(fn_decl_span, async_body, ThinVec::new())
             });
-            hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None)
-        })
+            body_id
+        });
+
+        // We need to lower the declaration outside the new scope, because we
+        // have to conserve the state of being inside a loop condition for the
+        // closure argument types.
+        let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
+
+        hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None)
     }
 
     /// Destructure the LHS of complex assignments.
diff --git a/src/test/ui/closures/local-type-mix.rs b/src/test/ui/closures/local-type-mix.rs
new file mode 100644
index 00000000000..006e6f490f0
--- /dev/null
+++ b/src/test/ui/closures/local-type-mix.rs
@@ -0,0 +1,17 @@
+// Check that using the parameter name in its type does not ICE.
+// edition:2018
+
+#![feature(async_closure)]
+
+fn main() {
+    let _ = |x: x| x; //~ ERROR expected type
+    let _ = |x: bool| -> x { x }; //~ ERROR expected type
+    let _ = async move |x: x| x; //~ ERROR expected type
+    let _ = async move |x: bool| -> x { x }; //~ ERROR expected type
+}
+
+fn foo(x: x) {} //~ ERROR expected type
+fn foo_ret(x: bool) -> x {} //~ ERROR expected type
+
+async fn async_foo(x: x) {} //~ ERROR expected type
+async fn async_foo_ret(x: bool) -> x {} //~ ERROR expected type
diff --git a/src/test/ui/closures/local-type-mix.stderr b/src/test/ui/closures/local-type-mix.stderr
new file mode 100644
index 00000000000..68c320a065d
--- /dev/null
+++ b/src/test/ui/closures/local-type-mix.stderr
@@ -0,0 +1,51 @@
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:7:17
+   |
+LL |     let _ = |x: x| x;
+   |                 ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:8:26
+   |
+LL |     let _ = |x: bool| -> x { x };
+   |                          ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:9:28
+   |
+LL |     let _ = async move |x: x| x;
+   |                            ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:10:37
+   |
+LL |     let _ = async move |x: bool| -> x { x };
+   |                                     ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:13:11
+   |
+LL | fn foo(x: x) {}
+   |           ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:14:24
+   |
+LL | fn foo_ret(x: bool) -> x {}
+   |                        ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:16:23
+   |
+LL | async fn async_foo(x: x) {}
+   |                       ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type-mix.rs:17:36
+   |
+LL | async fn async_foo_ret(x: bool) -> x {}
+   |                                    ^ not a type
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0573`.