Skip to content

Commit af1eea3

Browse files
committed
Auto merge of rust-lang#89841 - cormacrelf:let-else-typed, r=nagisa
Implement let-else type annotations natively Tracking issue: rust-lang#87335 Fixes rust-lang#89688, fixes rust-lang#89807, edit: fixes rust-lang#89960 as well As explained in rust-lang#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 ece0946 + 17c1ff9 commit af1eea3

File tree

10 files changed

+56
-31
lines changed

10 files changed

+56
-31
lines changed

clippy_lints/src/equatable_if_let.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,20 @@ fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx
6767
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
6868
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
6969
if_chain! {
70-
if let ExprKind::Let(pat, exp, _) = expr.kind;
71-
if unary_pattern(pat);
72-
let exp_ty = cx.typeck_results().expr_ty(exp);
73-
let pat_ty = cx.typeck_results().pat_ty(pat);
70+
if let ExprKind::Let(let_expr) = expr.kind;
71+
if unary_pattern(let_expr.pat);
72+
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
73+
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
7474
if is_structural_partial_eq(cx, exp_ty, pat_ty);
7575
then {
7676

7777
let mut applicability = Applicability::MachineApplicable;
78-
let pat_str = match pat.kind {
78+
let pat_str = match let_expr.pat.kind {
7979
PatKind::Struct(..) => format!(
8080
"({})",
81-
snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0,
81+
snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
8282
),
83-
_ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
83+
_ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
8484
};
8585
span_lint_and_sugg(
8686
cx,
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
9090
"try",
9191
format!(
9292
"{} == {}",
93-
snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0,
93+
snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
9494
pat_str,
9595
),
9696
applicability,

clippy_lints/src/loops/never_loop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
115115
| ExprKind::Unary(_, e)
116116
| ExprKind::Cast(e, _)
117117
| ExprKind::Type(e, _)
118-
| ExprKind::Let(_, e, _)
119118
| ExprKind::Field(e, _)
120119
| ExprKind::AddrOf(_, _, e)
121120
| ExprKind::Struct(_, _, Some(e))
122121
| ExprKind::Repeat(e, _)
123122
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
123+
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
124124
ExprKind::Array(es) | ExprKind::MethodCall(_, _, es, _) | ExprKind::Tup(es) => {
125125
never_loop_expr_all(&mut es.iter(), main_loop_id)
126126
},

clippy_lints/src/manual_assert.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl LateLintPass<'_> for ManualAssert {
5050
..
5151
} = &expr;
5252
if is_expn_of(stmt.span, "panic").is_some();
53-
if !matches!(cond.kind, ExprKind::Let(_, _, _));
53+
if !matches!(cond.kind, ExprKind::Let(_));
5454
if let StmtKind::Semi(semi) = stmt.kind;
5555
if !cx.tcx.sess.source_map().is_multiline(cond.span);
5656

clippy_lints/src/pattern_type_mismatch.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
22
use rustc_hir::{
3-
intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
3+
intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
44
};
55
use rustc_lint::{LateContext, LateLintPass, LintContext};
66
use rustc_middle::lint::in_external_macro;
@@ -104,8 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
104104
}
105105
}
106106
}
107-
if let ExprKind::Let(let_pat, ..) = expr.kind {
108-
apply_lint(cx, let_pat, DerefPossible::Possible);
107+
if let ExprKind::Let(Let { pat, .. }) = expr.kind {
108+
apply_lint(cx, pat, DerefPossible::Possible);
109109
}
110110
}
111111

clippy_lints/src/utils/author.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,18 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
373373
}
374374

375375
match expr.value.kind {
376-
ExprKind::Let(pat, expr, _) => {
377-
bind!(self, pat, expr);
378-
kind!("Let({pat}, {expr}, _)");
379-
self.pat(pat);
380-
self.expr(expr);
376+
ExprKind::Let(let_expr) => {
377+
bind!(self, let_expr);
378+
kind!("Let({let_expr})");
379+
self.pat(field!(let_expr.pat));
380+
// Does what ExprKind::Cast does, only adds a clause for the type
381+
// if it's a path
382+
if let Some(TyKind::Path(ref qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
383+
bind!(self, qpath);
384+
out!("if let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind;");
385+
self.qpath(qpath);
386+
}
387+
self.expr(field!(let_expr.init));
381388
},
382389
ExprKind::Box(inner) => {
383390
bind!(self, inner);

clippy_lints/src/utils/inspector.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,12 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
142142
print_expr(cx, arg, indent + 1);
143143
}
144144
},
145-
hir::ExprKind::Let(pat, expr, _) => {
145+
hir::ExprKind::Let(hir::Let { pat, init, ty, .. }) => {
146146
print_pat(cx, pat, indent + 1);
147-
print_expr(cx, expr, indent + 1);
147+
if let Some(ty) = ty {
148+
println!("{} type annotation: {:?}", ind, ty);
149+
}
150+
print_expr(cx, init, indent + 1);
148151
},
149152
hir::ExprKind::MethodCall(path, _, args, _) => {
150153
println!("{}MethodCall", ind);

clippy_utils/src/higher.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,12 @@ impl<'hir> IfLet<'hir> {
101101
pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
102102
if let ExprKind::If(
103103
Expr {
104-
kind: ExprKind::Let(let_pat, let_expr, _),
104+
kind:
105+
ExprKind::Let(hir::Let {
106+
pat: let_pat,
107+
init: let_expr,
108+
..
109+
}),
105110
..
106111
},
107112
if_then,
@@ -368,7 +373,12 @@ impl<'hir> WhileLet<'hir> {
368373
kind:
369374
ExprKind::If(
370375
Expr {
371-
kind: ExprKind::Let(let_pat, let_expr, _),
376+
kind:
377+
ExprKind::Let(hir::Let {
378+
pat: let_pat,
379+
init: let_expr,
380+
..
381+
}),
372382
..
373383
},
374384
if_then,

clippy_utils/src/hir_utils.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_hir::def::Res;
77
use rustc_hir::HirIdMap;
88
use rustc_hir::{
99
BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
10-
InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
10+
InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
1111
StmtKind, Ty, TyKind, TypeBinding,
1212
};
1313
use rustc_lexer::{tokenize, TokenKind};
@@ -234,7 +234,9 @@ impl HirEqInterExpr<'_, '_, '_> {
234234
(&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
235235
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
236236
},
237-
(&ExprKind::Let(lp, le, _), &ExprKind::Let(rp, re, _)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
237+
(&ExprKind::Let(l), &ExprKind::Let(r)) => {
238+
self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
239+
},
238240
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
239241
(&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
240242
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
@@ -668,8 +670,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
668670
}
669671
}
670672
},
671-
ExprKind::Let(pat, expr, _) => {
672-
self.hash_expr(expr);
673+
ExprKind::Let(Let { pat, init, ty, .. }) => {
674+
self.hash_expr(init);
675+
if let Some(ty) = ty {
676+
self.hash_ty(ty);
677+
}
673678
self.hash_pat(pat);
674679
},
675680
ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},

clippy_utils/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -870,8 +870,8 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind
870870
capture_expr_ty = e;
871871
}
872872
},
873-
ExprKind::Let(pat, ..) => {
874-
let mutability = match pat_capture_kind(cx, pat) {
873+
ExprKind::Let(let_expr) => {
874+
let mutability = match pat_capture_kind(cx, let_expr.pat) {
875875
CaptureKind::Value => Mutability::Not,
876876
CaptureKind::Ref(m) => m,
877877
};

tests/ui/author/if.stdout

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ if_chain! {
3232
}
3333
if_chain! {
3434
if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind;
35-
if let ExprKind::Let(pat, expr1, _) = cond.kind;
36-
if let PatKind::Lit(lit_expr) = pat.kind;
35+
if let ExprKind::Let(let_expr) = cond.kind;
36+
if let PatKind::Lit(lit_expr) = let_expr.pat.kind;
3737
if let ExprKind::Lit(ref lit) = lit_expr.kind;
3838
if let LitKind::Bool(true) = lit.node;
39-
if let ExprKind::Path(ref qpath) = expr1.kind;
39+
if let ExprKind::Path(ref qpath) = let_expr.init.kind;
4040
if match_qpath(qpath, &["a"]);
4141
if let ExprKind::Block(block, None) = then.kind;
4242
if block.stmts.is_empty();

0 commit comments

Comments
 (0)