Skip to content

Commit 3b05f6e

Browse files
committed
unify typeck of hir::Local and hir::Let
1 parent c46d910 commit 3b05f6e

File tree

3 files changed

+66
-67
lines changed

3 files changed

+66
-67
lines changed

compiler/rustc_typeck/src/check/expr.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -997,27 +997,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
997997
}
998998

999999
fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
1000-
// overall similar operation to check_decl_local
1000+
// for let statements, this is done in check_stmt
10011001
let init = let_expr.init;
1002-
1003-
let ty = self.local_ty(let_expr.span, let_expr.hir_id).decl_ty;
1004-
self.write_ty(let_expr.hir_id, ty);
1005-
1006-
// main difference: we check if the expression is unreachable
10071002
self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
1008-
1009-
let init_ty = self.check_decl_initializer(let_expr.hir_id, let_expr.pat, &init);
1010-
self.overwrite_local_ty_if_err(let_expr.hir_id, let_expr.pat, ty, init_ty);
1011-
1012-
// Does the expected pattern type originate from an expression and what is the span?
1013-
let (origin_expr, ty_span) = match let_expr.ty {
1014-
Some(explicit) => (false, Some(explicit.span)), // Bias towards the explicit user type.
1015-
_ => (true, Some(init.span)), // No explicit type; so use the scrutinee.
1016-
};
1017-
1018-
self.check_pat_top(let_expr.pat, init_ty, ty_span, origin_expr);
1019-
let pat_ty = self.node_ty(let_expr.pat.hir_id);
1020-
self.overwrite_local_ty_if_err(let_expr.hir_id, let_expr.pat, ty, pat_ty);
1003+
// otherwise check exactly as a let statement
1004+
self.check_decl(let_expr.into());
1005+
// but return a bool, for this is a boolean expression
10211006
self.tcx.types.bool
10221007
}
10231008

compiler/rustc_typeck/src/check/fn_ctxt/checks.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::astconv::AstConv;
22
use crate::check::coercion::CoerceMany;
3+
use crate::check::gather_locals::Declaration;
34
use crate::check::method::MethodCallee;
45
use crate::check::Expectation::*;
56
use crate::check::TupleArgumentsFlag::*;
@@ -585,29 +586,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
585586
}
586587
}
587588

588-
/// Type check a `let` statement.
589-
pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
589+
pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
590590
// Determine and write the type which we'll check the pattern against.
591-
let ty = self.local_ty(local.span, local.hir_id).decl_ty;
592-
self.write_ty(local.hir_id, ty);
591+
let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty;
592+
self.write_ty(decl.hir_id, decl_ty);
593593

594594
// Type check the initializer.
595-
if let Some(ref init) = local.init {
596-
let init_ty = self.check_decl_initializer(local.hir_id, local.pat, &init);
597-
self.overwrite_local_ty_if_err(local.hir_id, local.pat, ty, init_ty);
595+
if let Some(ref init) = decl.init {
596+
let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init);
597+
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty);
598598
}
599599

600600
// Does the expected pattern type originate from an expression and what is the span?
601-
let (origin_expr, ty_span) = match (local.ty, local.init) {
601+
let (origin_expr, ty_span) = match (decl.ty, decl.init) {
602602
(Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
603603
(_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
604604
_ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
605605
};
606606

607607
// Type check the pattern. Override if necessary to avoid knock-on errors.
608-
self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
609-
let pat_ty = self.node_ty(local.pat.hir_id);
610-
self.overwrite_local_ty_if_err(local.hir_id, local.pat, ty, pat_ty);
608+
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
609+
let pat_ty = self.node_ty(decl.pat.hir_id);
610+
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
611+
}
612+
613+
/// Type check a `let` statement.
614+
pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
615+
self.check_decl(local.into());
611616
}
612617

613618
pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) {

compiler/rustc_typeck/src/check/gather_locals.rs

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,31 @@ use rustc_middle::ty::Ty;
77
use rustc_span::Span;
88
use rustc_trait_selection::traits;
99

10+
/// A declaration is an abstraction of [hir::Local] and [hir::Let].
11+
///
12+
/// It must have a hir_id, as this is how we connect gather_locals to the check functions.
13+
pub(super) struct Declaration<'a> {
14+
pub hir_id: hir::HirId,
15+
pub pat: &'a hir::Pat<'a>,
16+
pub ty: Option<&'a hir::Ty<'a>>,
17+
pub span: Span,
18+
pub init: Option<&'a hir::Expr<'a>>,
19+
}
20+
21+
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
22+
fn from(local: &'a hir::Local<'a>) -> Self {
23+
let hir::Local { hir_id, pat, ty, span, init, .. } = *local;
24+
Declaration { hir_id, pat, ty, span, init }
25+
}
26+
}
27+
28+
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
29+
fn from(let_expr: &'a hir::Let<'a>) -> Self {
30+
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
31+
Declaration { hir_id, pat, ty, span, init: Some(init) }
32+
}
33+
}
34+
1035
pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
1136
fcx: &'a FnCtxt<'a, 'tcx>,
1237
// parameters are special cases of patterns, but we want to handle them as
@@ -41,18 +66,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
4166
}
4267
}
4368
}
44-
}
45-
46-
impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
47-
type Map = intravisit::ErasedMap<'tcx>;
4869

49-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
50-
NestedVisitorMap::None
51-
}
52-
53-
// Add explicitly-declared locals.
54-
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
55-
let local_ty = match local.ty {
70+
/// Allocates a [LocalTy] for a declaration, which may have a type annotation. If it does have
71+
/// a type annotation, then the LocalTy stored will be the resolved type. This may be found
72+
/// again during type checking by querying [FnCtxt::local_ty] for the same hir_id.
73+
fn declare(&mut self, decl: Declaration<'tcx>) {
74+
let local_ty = match decl.ty {
5675
Some(ref ty) => {
5776
let o_ty = self.fcx.to_ty(&ty);
5877

@@ -68,41 +87,31 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
6887
}
6988
None => None,
7089
};
71-
self.assign(local.span, local.hir_id, local_ty);
90+
self.assign(decl.span, decl.hir_id, local_ty);
7291

7392
debug!(
7493
"local variable {:?} is assigned type {}",
75-
local.pat,
76-
self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
94+
decl.pat,
95+
self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
7796
);
78-
intravisit::walk_local(self, local);
7997
}
98+
}
8099

81-
fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {
82-
let local_ty = match let_expr.ty {
83-
Some(ref ty) => {
84-
let o_ty = self.fcx.to_ty(&ty);
100+
impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
101+
type Map = intravisit::ErasedMap<'tcx>;
85102

86-
let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty));
87-
debug!("visit_let_expr: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
88-
self.fcx
89-
.typeck_results
90-
.borrow_mut()
91-
.user_provided_types_mut()
92-
.insert(ty.hir_id, c_ty);
103+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
104+
NestedVisitorMap::None
105+
}
93106

94-
Some(LocalTy { decl_ty: o_ty, revealed_ty: o_ty })
95-
}
96-
None => None,
97-
};
98-
self.assign(let_expr.span, let_expr.hir_id, local_ty);
107+
// Add explicitly-declared locals.
108+
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
109+
self.declare(local.into());
110+
intravisit::walk_local(self, local);
111+
}
99112

100-
debug!(
101-
"local variable {:?} is assigned type {}",
102-
let_expr.pat,
103-
self.fcx
104-
.ty_to_string(&*self.fcx.locals.borrow().get(&let_expr.hir_id).unwrap().decl_ty)
105-
);
113+
fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {
114+
self.declare(let_expr.into());
106115
intravisit::walk_let_expr(self, let_expr);
107116
}
108117

0 commit comments

Comments
 (0)