Skip to content

Commit fc8f9a4

Browse files
Do not gather local all together at the beginning of typeck
1 parent 0e517d3 commit fc8f9a4

24 files changed

+281
-277
lines changed

compiler/rustc_hir_typeck/src/_match.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{
1111
use tracing::{debug, instrument};
1212

1313
use crate::coercion::{AsCoercionSite, CoerceMany};
14-
use crate::{Diverges, Expectation, FnCtxt, Needs};
14+
use crate::{Diverges, Expectation, FnCtxt, GatherLocalsVisitor, Needs};
1515

1616
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1717
#[instrument(skip(self), level = "debug", ret)]
@@ -43,6 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4343
// #55810: Type check patterns first so we get types for all bindings.
4444
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
4545
for arm in arms {
46+
GatherLocalsVisitor::gather_from_arm(self, arm);
47+
4648
self.check_pat_top(arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None);
4749
}
4850

compiler/rustc_hir_typeck/src/check.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::cell::RefCell;
33
use rustc_abi::ExternAbi;
44
use rustc_hir as hir;
55
use rustc_hir::def::DefKind;
6-
use rustc_hir::intravisit::Visitor;
76
use rustc_hir::lang_items::LangItem;
87
use rustc_hir_analysis::check::check_function_signature;
98
use rustc_infer::infer::RegionVariableOrigin;
@@ -50,7 +49,9 @@ pub(super) fn check_fn<'a, 'tcx>(
5049

5150
let span = body.value.span;
5251

53-
GatherLocalsVisitor::new(fcx).visit_body(body);
52+
for param in body.params {
53+
GatherLocalsVisitor::gather_from_param(fcx, param);
54+
}
5455

5556
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
5657
// (as it's created inside the body itself, not passed in from outside).

compiler/rustc_hir_typeck/src/expr.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use rustc_errors::{
1616
};
1717
use rustc_hir::def::{CtorKind, DefKind, Res};
1818
use rustc_hir::def_id::DefId;
19-
use rustc_hir::intravisit::Visitor;
2019
use rustc_hir::lang_items::LangItem;
2120
use rustc_hir::{ExprKind, HirId, QPath};
2221
use rustc_hir_analysis::NoVariantNamed;
@@ -50,8 +49,8 @@ use crate::errors::{
5049
YieldExprOutsideOfCoroutine,
5150
};
5251
use crate::{
53-
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, TupleArgumentsFlag, cast,
54-
fatally_break_rust, report_unexpected_variant_res, type_error_struct,
52+
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs,
53+
TupleArgumentsFlag, cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct,
5554
};
5655

5756
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -1521,8 +1520,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15211520
// for let statements, this is done in check_stmt
15221521
let init = let_expr.init;
15231522
self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
1523+
1524+
GatherLocalsVisitor::gather_from_let_expr(self, let_expr, hir_id);
1525+
15241526
// otherwise check exactly as a let statement
15251527
self.check_decl((let_expr, hir_id).into());
1528+
15261529
// but return a bool, for this is a boolean expression
15271530
if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered {
15281531
self.set_tainted_by_errors(error_guaranteed);
@@ -1827,7 +1830,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18271830
// Create a new function context.
18281831
let def_id = block.def_id;
18291832
let fcx = FnCtxt::new(self, self.param_env, def_id);
1830-
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
18311833

18321834
let ty = fcx.check_expr_with_expectation(body.value, expected);
18331835
fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::SizedConstOrStatic);

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ use crate::method::probe::IsSuggestion;
3737
use crate::method::probe::Mode::MethodCall;
3838
use crate::method::probe::ProbeScope::TraitsInScope;
3939
use crate::{
40-
BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors,
41-
struct_span_code_err,
40+
BreakableCtxt, Diverges, Expectation, FnCtxt, GatherLocalsVisitor, LoweredTy, Needs,
41+
TupleArgumentsFlag, errors, struct_span_code_err,
4242
};
4343

4444
rustc_index::newtype_index! {
@@ -1765,6 +1765,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17651765

17661766
/// Type check a `let` statement.
17671767
fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
1768+
GatherLocalsVisitor::gather_from_local(self, local);
1769+
17681770
let ty = self.check_decl(local.into());
17691771
self.write_ty(local.hir_id, ty);
17701772
if local.pat.is_never_pattern() {

compiler/rustc_hir_typeck/src/gather_locals.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,46 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
6464
}
6565

6666
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
67-
pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>) -> Self {
68-
Self { fcx, outermost_fn_param_pat: None }
67+
pub(crate) fn gather_from_local(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::LetStmt<'tcx>) {
68+
let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None };
69+
visitor.declare(local.into());
70+
visitor.visit_pat(local.pat);
71+
}
72+
73+
pub(crate) fn gather_from_let_expr(
74+
fcx: &'a FnCtxt<'a, 'tcx>,
75+
let_expr: &'tcx hir::LetExpr<'tcx>,
76+
expr_hir_id: hir::HirId,
77+
) {
78+
let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None };
79+
visitor.declare((let_expr, expr_hir_id).into());
80+
visitor.visit_pat(let_expr.pat);
81+
}
82+
83+
pub(crate) fn gather_from_param(fcx: &'a FnCtxt<'a, 'tcx>, param: &'tcx hir::Param<'tcx>) {
84+
let mut visitor = GatherLocalsVisitor {
85+
fcx,
86+
outermost_fn_param_pat: Some((param.ty_span, param.hir_id)),
87+
};
88+
visitor.visit_pat(param.pat);
89+
}
90+
91+
pub(crate) fn gather_from_arm(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::Arm<'tcx>) {
92+
let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None };
93+
visitor.visit_pat(local.pat);
6994
}
7095

7196
fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
7297
match ty_opt {
7398
None => {
7499
// Infer the variable's type.
75100
let var_ty = self.fcx.next_ty_var(span);
76-
self.fcx.locals.borrow_mut().insert(nid, var_ty);
101+
assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None);
77102
var_ty
78103
}
79104
Some(typ) => {
80105
// Take type that the user specified.
81-
self.fcx.locals.borrow_mut().insert(nid, typ);
106+
assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None);
82107
typ
83108
}
84109
}
@@ -133,13 +158,6 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
133158
intravisit::walk_expr(self, expr)
134159
}
135160

136-
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
137-
let old_outermost_fn_param_pat =
138-
self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id));
139-
intravisit::walk_param(self, param);
140-
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
141-
}
142-
143161
// Add pattern bindings.
144162
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
145163
if let PatKind::Binding(_, _, ident, _) = p.kind {

compiler/rustc_hir_typeck/src/lib.rs

-4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ use rustc_errors::codes::*;
4646
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
4747
use rustc_hir as hir;
4848
use rustc_hir::def::{DefKind, Res};
49-
use rustc_hir::intravisit::Visitor;
5049
use rustc_hir::{HirId, HirIdMap, Node};
5150
use rustc_hir_analysis::check::check_abi;
5251
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@@ -191,9 +190,6 @@ fn typeck_with_inspect<'tcx>(
191190
let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
192191
fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);
193192

194-
// Gather locals in statics (because of block expressions).
195-
GatherLocalsVisitor::new(&fcx).visit_body(body);
196-
197193
fcx.check_expr_coercible_to_type(body.value, expected_type, None);
198194

199195
fcx.write_ty(id, expected_type);

tests/ui/async-await/async-closures/def-path.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ LL | let x = async || {};
55
| -- the expected `async` closure body
66
LL |
77
LL | let () = x();
8-
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}`
8+
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}`
99
| |
1010
| expected `async` closure body, found `()`
1111
|
12-
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}`
12+
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}`
1313
found unit type `()`
1414

1515
error: aborting due to 1 previous error

tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | let c1 : () = c;
99
| expected due to this
1010
|
1111
= note: expected unit type `()`
12-
found closure `{mod1::f<T>::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}`
12+
found closure `{mod1::f<T>::{closure#0} closure_kind_ty=?7t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?6t}`
1313
help: use parentheses to call this closure
1414
|
1515
LL | let c1 : () = c();

tests/ui/closures/print/closure-print-generic-verbose-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | let c1 : () = c;
99
| expected due to this
1010
|
1111
= note: expected unit type `()`
12-
found closure `{f<T>::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}`
12+
found closure `{f<T>::{closure#0} closure_kind_ty=?7t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?6t}`
1313
help: use parentheses to call this closure
1414
|
1515
LL | let c1 : () = c();

tests/ui/const-generics/const-arg-in-const-arg.min.stderr

+35-35
Original file line numberDiff line numberDiff line change
@@ -240,41 +240,6 @@ note: the late bound lifetime parameter is introduced here
240240
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
241241
| ^^
242242

243-
error[E0747]: unresolved item provided when a constant was expected
244-
--> $DIR/const-arg-in-const-arg.rs:36:24
245-
|
246-
LL | let _: Foo<{ bar::<N>() }>;
247-
| ^
248-
|
249-
help: if this generic argument was intended as a const parameter, surround it with braces
250-
|
251-
LL | let _: Foo<{ bar::<{ N }>() }>;
252-
| + +
253-
254-
error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
255-
--> $DIR/const-arg-in-const-arg.rs:38:24
256-
|
257-
LL | let _: Foo<{ faz::<'a>(&()) }>;
258-
| ^^
259-
|
260-
note: the late bound lifetime parameter is introduced here
261-
--> $DIR/const-arg-in-const-arg.rs:10:14
262-
|
263-
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
264-
| ^^
265-
266-
error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
267-
--> $DIR/const-arg-in-const-arg.rs:41:24
268-
|
269-
LL | let _: Foo<{ faz::<'b>(&()) }>;
270-
| ^^
271-
|
272-
note: the late bound lifetime parameter is introduced here
273-
--> $DIR/const-arg-in-const-arg.rs:10:14
274-
|
275-
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
276-
| ^^
277-
278243
error: constant expression depends on a generic parameter
279244
--> $DIR/const-arg-in-const-arg.rs:25:17
280245
|
@@ -326,6 +291,41 @@ note: the late bound lifetime parameter is introduced here
326291
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
327292
| ^^
328293

294+
error[E0747]: unresolved item provided when a constant was expected
295+
--> $DIR/const-arg-in-const-arg.rs:36:24
296+
|
297+
LL | let _: Foo<{ bar::<N>() }>;
298+
| ^
299+
|
300+
help: if this generic argument was intended as a const parameter, surround it with braces
301+
|
302+
LL | let _: Foo<{ bar::<{ N }>() }>;
303+
| + +
304+
305+
error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
306+
--> $DIR/const-arg-in-const-arg.rs:38:24
307+
|
308+
LL | let _: Foo<{ faz::<'a>(&()) }>;
309+
| ^^
310+
|
311+
note: the late bound lifetime parameter is introduced here
312+
--> $DIR/const-arg-in-const-arg.rs:10:14
313+
|
314+
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
315+
| ^^
316+
317+
error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
318+
--> $DIR/const-arg-in-const-arg.rs:41:24
319+
|
320+
LL | let _: Foo<{ faz::<'b>(&()) }>;
321+
| ^^
322+
|
323+
note: the late bound lifetime parameter is introduced here
324+
--> $DIR/const-arg-in-const-arg.rs:10:14
325+
|
326+
LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
327+
| ^^
328+
329329
error[E0747]: unresolved item provided when a constant was expected
330330
--> $DIR/const-arg-in-const-arg.rs:45:27
331331
|

tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
1-
error: overly complex generic constant
2-
--> $DIR/dependence_lint.rs:21:17
3-
|
4-
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
6-
|
7-
= help: consider moving this anonymous constant into a `const` function
8-
91
error: unconstrained generic constant
10-
--> $DIR/dependence_lint.rs:14:12
2+
--> $DIR/dependence_lint.rs:10:9
113
|
12-
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
5+
| ^^^^^^^^^^^^^^^^^^^
146
|
157
help: try adding a `where` bound
168
|
179
LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
1810
| ++++++++++++++++++++++++++++++++
1911

12+
error: overly complex generic constant
13+
--> $DIR/dependence_lint.rs:17:9
14+
|
15+
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
17+
|
18+
= help: consider moving this anonymous constant into a `const` function
19+
2020
error: unconstrained generic constant
21-
--> $DIR/dependence_lint.rs:10:9
21+
--> $DIR/dependence_lint.rs:14:12
2222
|
23-
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
24-
| ^^^^^^^^^^^^^^^^^^^
23+
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
2525
|
2626
help: try adding a `where` bound
2727
|
2828
LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
2929
| ++++++++++++++++++++++++++++++++
3030

3131
error: overly complex generic constant
32-
--> $DIR/dependence_lint.rs:17:9
32+
--> $DIR/dependence_lint.rs:21:17
3333
|
34-
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
35-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
34+
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
3636
|
3737
= help: consider moving this anonymous constant into a `const` function
3838

0 commit comments

Comments
 (0)