Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit dde825d

Browse files
committedDec 17, 2021
Auto merge of #89841 - cormacrelf:let-else-typed, r=nagisa
Implement let-else type annotations natively Tracking issue: #87335 Fixes #89688, fixes #89807, edit: fixes #89960 as well As explained in #89688 (comment), the previous desugaring moved the let-else scrutinee into a dummy variable, which meant if you wanted to refer to it again in the else block, it had moved. This introduces a new hir type, ~~`hir::LetExpr`~~ `hir::Let`, which takes over all the fields of `hir::ExprKind::Let(...)` and adds an optional type annotation. The `hir::Let` is then treated like a `hir::Local` when type checking a function body, specifically: * `GatherLocalsVisitor` overrides a new `Visitor::visit_let_expr` and does pretty much exactly what it does for `visit_local`, assigning a local type to the `hir::Let` ~~(they could be deduplicated but they are right next to each other, so at least we know they're the same)~~ * It reuses the code in `check_decl_local` to typecheck the `hir::Let`, simply returning 'bool' for the expression type after doing that. * ~~`FnCtxt::check_expr_let` passes this local type in to `demand_scrutinee_type`, and then imitates check_decl_local's pattern checking~~ * ~~`demand_scrutinee_type` (the blindest change for me, please give this extra scrutiny) uses this local type instead of of creating a new one~~ * ~~Just realised the `check_expr_with_needs` was passing NoExpectation further down, need to pass the type there too. And apparently this Expectation API already exists.~~ Some other misc notes: * ~~Is the clippy code supposed to be autoformatted? I tried not to give huge diffs but maybe some rustfmt changes simply haven't hit it yet.~~ * in `rustc_ast_lowering/src/block.rs`, I noticed some existing `self.alias_attrs()` calls in `LoweringContext::lower_stmts` seem to be copying attributes from the lowered locals/etc to the statements. Is that right? I'm new at this, I don't know.
2 parents 7abab1e + fec8a50 commit dde825d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+900
-142
lines changed
 

‎compiler/rustc_ast_lowering/src/block.rs

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
22
use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
33
use rustc_hir as hir;
44
use rustc_session::parse::feature_err;
5-
use rustc_span::symbol::Ident;
65
use rustc_span::{sym, DesugaringKind};
76

87
use smallvec::SmallVec;
@@ -39,8 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
3938
let hir_id = self.lower_node_id(s.id);
4039
match &local.kind {
4140
LocalKind::InitElse(init, els) => {
42-
let (s, e) = self.lower_let_else(hir_id, local, init, els, tail);
43-
stmts.push(s);
41+
let e = self.lower_let_else(hir_id, local, init, els, tail);
4442
expr = Some(e);
4543
// remaining statements are in let-else expression
4644
break;
@@ -125,36 +123,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
125123
init: &Expr,
126124
els: &Block,
127125
tail: &[Stmt],
128-
) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) {
126+
) -> &'hir hir::Expr<'hir> {
129127
let ty = local
130128
.ty
131129
.as_ref()
132130
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
133131
let span = self.lower_span(local.span);
134132
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
135-
let init = Some(self.lower_expr(init));
136-
let val = Ident::with_dummy_span(sym::val);
137-
let (pat, val_id) =
138-
self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated);
133+
let init = self.lower_expr(init);
139134
let local_hir_id = self.lower_node_id(local.id);
140135
self.lower_attrs(local_hir_id, &local.attrs);
141-
// first statement which basically exists for the type annotation
142-
let stmt = {
143-
let local = self.arena.alloc(hir::Local {
136+
let let_expr = {
137+
let lex = self.arena.alloc(hir::Let {
144138
hir_id: local_hir_id,
139+
pat: self.lower_pat(&local.pat),
145140
ty,
146-
pat,
147141
init,
148142
span,
149-
source: hir::LocalSource::Normal,
150143
});
151-
let kind = hir::StmtKind::Local(local);
152-
hir::Stmt { hir_id: stmt_hir_id, kind, span }
153-
};
154-
let let_expr = {
155-
let scrutinee = self.expr_ident(span, val, val_id);
156-
let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span);
157-
self.arena.alloc(self.expr(span, let_kind, AttrVec::new()))
144+
self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new()))
158145
};
159146
let then_expr = {
160147
let (stmts, expr) = self.lower_stmts(tail);
@@ -165,9 +152,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
165152
let block = self.lower_block(els, false);
166153
self.arena.alloc(self.expr_block(block, AttrVec::new()))
167154
};
155+
self.alias_attrs(let_expr.hir_id, local_hir_id);
168156
self.alias_attrs(else_expr.hir_id, local_hir_id);
169157
let if_expr = self.arena.alloc(hir::Expr {
170-
hir_id: self.next_id(),
158+
hir_id: stmt_hir_id,
171159
span,
172160
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
173161
});
@@ -180,6 +168,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
180168
)
181169
.emit();
182170
}
183-
(stmt, if_expr)
171+
if_expr
184172
}
185173
}

‎compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
9191
let ohs = self.lower_expr(ohs);
9292
hir::ExprKind::AddrOf(k, m, ohs)
9393
}
94-
ExprKind::Let(ref pat, ref scrutinee, span) => hir::ExprKind::Let(
95-
self.lower_pat(pat),
96-
self.lower_expr(scrutinee),
97-
self.lower_span(span),
98-
),
94+
ExprKind::Let(ref pat, ref scrutinee, span) => {
95+
hir::ExprKind::Let(self.arena.alloc(hir::Let {
96+
hir_id: self.next_id(),
97+
span: self.lower_span(span),
98+
pat: self.lower_pat(pat),
99+
ty: None,
100+
init: self.lower_expr(scrutinee),
101+
}))
102+
}
99103
ExprKind::If(ref cond, ref then, ref else_opt) => {
100104
self.lower_expr_if(cond, then, else_opt.as_deref())
101105
}

0 commit comments

Comments
 (0)
Please sign in to comment.