Skip to content

Commit 20f5e3f

Browse files
committed
Exhaustively handle expressions in patterns
1 parent 637ded1 commit 20f5e3f

File tree

36 files changed

+412
-193
lines changed

36 files changed

+412
-193
lines changed

Diff for: compiler/rustc_ast_lowering/src/expr.rs

+28-23
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
103103

104104
let kind = match &e.kind {
105105
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
106-
ExprKind::ConstBlock(c) => {
107-
let c = self.with_new_scopes(c.value.span, |this| {
108-
let def_id = this.local_def_id(c.id);
109-
hir::ConstBlock {
110-
def_id,
111-
hir_id: this.lower_node_id(c.id),
112-
body: this.lower_const_body(c.value.span, Some(&c.value)),
113-
}
114-
});
115-
hir::ExprKind::ConstBlock(c)
116-
}
106+
ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
117107
ExprKind::Repeat(expr, count) => {
118108
let expr = self.lower_expr(expr);
119109
let count = self.lower_array_length_to_const_arg(count);
@@ -154,18 +144,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
154144
let ohs = self.lower_expr(ohs);
155145
hir::ExprKind::Unary(op, ohs)
156146
}
157-
ExprKind::Lit(token_lit) => {
158-
let lit_kind = match LitKind::from_token_lit(*token_lit) {
159-
Ok(lit_kind) => lit_kind,
160-
Err(err) => {
161-
let guar =
162-
report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span);
163-
LitKind::Err(guar)
164-
}
165-
};
166-
let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
167-
hir::ExprKind::Lit(lit)
168-
}
147+
ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
169148
ExprKind::IncludedBytes(bytes) => {
170149
let lit = self.arena.alloc(respan(
171150
self.lower_span(e.span),
@@ -396,6 +375,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
396375
})
397376
}
398377

378+
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
379+
self.with_new_scopes(c.value.span, |this| {
380+
let def_id = this.local_def_id(c.id);
381+
hir::ConstBlock {
382+
def_id,
383+
hir_id: this.lower_node_id(c.id),
384+
body: this.lower_const_body(c.value.span, Some(&c.value)),
385+
}
386+
})
387+
}
388+
389+
pub(crate) fn lower_lit(
390+
&mut self,
391+
token_lit: &token::Lit,
392+
span: Span,
393+
) -> &'hir Spanned<LitKind> {
394+
let lit_kind = match LitKind::from_token_lit(*token_lit) {
395+
Ok(lit_kind) => lit_kind,
396+
Err(err) => {
397+
let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);
398+
LitKind::Err(guar)
399+
}
400+
};
401+
self.arena.alloc(respan(self.lower_span(span), lit_kind))
402+
}
403+
399404
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
400405
match u {
401406
UnOp::Deref => hir::UnOp::Deref,

Diff for: compiler/rustc_ast_lowering/src/index.rs

+8
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
209209
});
210210
}
211211

212+
fn visit_pat_lit(&mut self, lit: &'hir PatLit<'hir>) {
213+
self.insert(lit.span, lit.hir_id, Node::PatLit(lit));
214+
215+
self.with_parent(lit.hir_id, |this| {
216+
intravisit::walk_pat_lit(this, lit);
217+
});
218+
}
219+
212220
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
213221
self.insert(field.span, field.hir_id, Node::PatField(field));
214222
self.with_parent(field.hir_id, |this| {

Diff for: compiler/rustc_ast_lowering/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#![doc(rust_logo)]
3636
#![feature(assert_matches)]
3737
#![feature(box_patterns)]
38+
#![feature(if_let_guard)]
3839
#![feature(let_chains)]
3940
#![feature(rustdoc_internals)]
4041
#![warn(unreachable_pub)]

Diff for: compiler/rustc_ast_lowering/src/pat.rs

+38-13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use std::sync::Arc;
2+
13
use rustc_ast::ptr::P;
24
use rustc_ast::*;
35
use rustc_data_structures::stack::ensure_sufficient_stack;
46
use rustc_hir as hir;
57
use rustc_hir::def::Res;
8+
use rustc_middle::span_bug;
69
use rustc_span::Span;
7-
use rustc_span::source_map::Spanned;
10+
use rustc_span::source_map::{Spanned, respan};
811
use rustc_span::symbol::Ident;
912

1013
use super::errors::{
@@ -360,24 +363,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
360363
// }
361364
// m!(S);
362365
// ```
363-
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
364-
match &expr.kind {
365-
ExprKind::Lit(..)
366-
| ExprKind::ConstBlock(..)
367-
| ExprKind::IncludedBytes(..)
368-
| ExprKind::Err(_)
369-
| ExprKind::Dummy => {}
370-
ExprKind::Path(..) if allow_paths => {}
371-
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
366+
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::PatLit<'hir> {
367+
let err = |guar| hir::PatLitKind::Lit {
368+
lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
369+
negated: false,
370+
};
371+
let kind = match &expr.kind {
372+
ExprKind::Lit(lit) => {
373+
hir::PatLitKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
374+
}
375+
ExprKind::ConstBlock(c) => hir::PatLitKind::ConstBlock(self.lower_const_block(c)),
376+
ExprKind::IncludedBytes(bytes) => hir::PatLitKind::Lit {
377+
lit: self.arena.alloc(respan(
378+
self.lower_span(expr.span),
379+
LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
380+
)),
381+
negated: false,
382+
},
383+
ExprKind::Err(guar) => err(*guar),
384+
ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
385+
ExprKind::Path(qself, path) if allow_paths => hir::PatLitKind::Path(self.lower_qpath(
386+
expr.id,
387+
qself,
388+
path,
389+
ParamMode::Optional,
390+
AllowReturnTypeNotation::No,
391+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
392+
None,
393+
)),
394+
ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
395+
hir::PatLitKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
396+
}
372397
_ => {
373398
let pattern_from_macro = expr.is_approximately_pattern();
374399
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
375400
span: expr.span,
376401
pattern_from_macro_note: pattern_from_macro,
377402
});
378-
return self.arena.alloc(self.expr_err(expr.span, guar));
403+
err(guar)
379404
}
380-
}
381-
self.lower_expr(expr)
405+
};
406+
self.arena.alloc(hir::PatLit { hir_id: self.lower_node_id(expr.id), span: expr.span, kind })
382407
}
383408
}

Diff for: compiler/rustc_hir/src/hir.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,26 @@ impl fmt::Debug for DotDotPos {
12701270
}
12711271
}
12721272

1273+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
1274+
pub struct PatLit<'hir> {
1275+
pub hir_id: HirId,
1276+
pub span: Span,
1277+
pub kind: PatLitKind<'hir>,
1278+
}
1279+
1280+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
1281+
pub enum PatLitKind<'hir> {
1282+
Lit {
1283+
lit: &'hir Lit,
1284+
// FIXME: move this into `Lit` and handle negated literal expressions
1285+
// once instead of matching on unop neg expressions everywhere.
1286+
negated: bool,
1287+
},
1288+
ConstBlock(ConstBlock),
1289+
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
1290+
Path(QPath<'hir>),
1291+
}
1292+
12731293
#[derive(Debug, Clone, Copy, HashStable_Generic)]
12741294
pub enum PatKind<'hir> {
12751295
/// Represents a wildcard pattern (i.e., `_`).
@@ -1315,10 +1335,10 @@ pub enum PatKind<'hir> {
13151335
Ref(&'hir Pat<'hir>, Mutability),
13161336

13171337
/// A literal.
1318-
Lit(&'hir Expr<'hir>),
1338+
Lit(&'hir PatLit<'hir>),
13191339

13201340
/// A range pattern (e.g., `1..=2` or `1..2`).
1321-
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd),
1341+
Range(Option<&'hir PatLit<'hir>>, Option<&'hir PatLit<'hir>>, RangeEnd),
13221342

13231343
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
13241344
///
@@ -3833,6 +3853,10 @@ pub enum Node<'hir> {
38333853
OpaqueTy(&'hir OpaqueTy<'hir>),
38343854
Pat(&'hir Pat<'hir>),
38353855
PatField(&'hir PatField<'hir>),
3856+
/// Needed as its own node with its own HirId for tracking
3857+
/// the unadjusted type of literals within patterns
3858+
/// (e.g. byte str literals not being of slice type).
3859+
PatLit(&'hir PatLit<'hir>),
38363860
Arm(&'hir Arm<'hir>),
38373861
Block(&'hir Block<'hir>),
38383862
LetStmt(&'hir LetStmt<'hir>),
@@ -3889,6 +3913,7 @@ impl<'hir> Node<'hir> {
38893913
| Node::Block(..)
38903914
| Node::Ctor(..)
38913915
| Node::Pat(..)
3916+
| Node::PatLit(..)
38923917
| Node::Arm(..)
38933918
| Node::LetStmt(..)
38943919
| Node::Crate(..)

Diff for: compiler/rustc_hir/src/intravisit.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ pub trait Visitor<'v>: Sized {
343343
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
344344
walk_pat_field(self, f)
345345
}
346+
fn visit_pat_lit(&mut self, lit: &'v PatLit<'v>) -> Self::Result {
347+
walk_pat_lit(self, lit)
348+
}
346349
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
347350
walk_anon_const(self, c)
348351
}
@@ -686,10 +689,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
686689
try_visit!(visitor.visit_ident(ident));
687690
visit_opt!(visitor, visit_pat, optional_subpattern);
688691
}
689-
PatKind::Lit(ref expression) => try_visit!(visitor.visit_expr(expression)),
692+
PatKind::Lit(lit) => try_visit!(visitor.visit_pat_lit(lit)),
690693
PatKind::Range(ref lower_bound, ref upper_bound, _) => {
691-
visit_opt!(visitor, visit_expr, lower_bound);
692-
visit_opt!(visitor, visit_expr, upper_bound);
694+
visit_opt!(visitor, visit_pat_lit, lower_bound);
695+
visit_opt!(visitor, visit_pat_lit, upper_bound);
693696
}
694697
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
695698
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
@@ -707,6 +710,15 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
707710
visitor.visit_pat(field.pat)
708711
}
709712

713+
pub fn walk_pat_lit<'v, V: Visitor<'v>>(visitor: &mut V, lit: &'v PatLit<'v>) -> V::Result {
714+
try_visit!(visitor.visit_id(lit.hir_id));
715+
match &lit.kind {
716+
PatLitKind::Lit { .. } => V::Result::output(),
717+
PatLitKind::ConstBlock(c) => visitor.visit_inline_const(c),
718+
PatLitKind::Path(qpath) => visitor.visit_qpath(qpath, lit.hir_id, lit.span),
719+
}
720+
}
721+
710722
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
711723
try_visit!(visitor.visit_id(constant.hir_id));
712724
visitor.visit_nested_body(constant.body)

Diff for: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+20-22
Original file line numberDiff line numberDiff line change
@@ -2430,17 +2430,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24302430
Ty::new_error(tcx, err)
24312431
}
24322432
hir::PatKind::Range(start, end, include_end) => {
2433-
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
2434-
let (expr, neg) = match expr.kind {
2435-
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
2436-
(negated, Some((expr.hir_id, expr.span)))
2437-
}
2438-
_ => (expr, None),
2439-
};
2440-
let (c, c_ty) = match &expr.kind {
2441-
hir::ExprKind::Lit(lit) => {
2433+
let expr_to_const = |expr: &'tcx hir::PatLit<'tcx>| -> ty::Const<'tcx> {
2434+
let (c, c_ty) = match expr.kind {
2435+
hir::PatLitKind::Lit { lit, negated } => {
24422436
let lit_input =
2443-
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
2437+
LitToConstInput { lit: &lit.node, ty, neg: negated };
24442438
let ct = match tcx.lit_to_const(lit_input) {
24452439
Ok(c) => c,
24462440
Err(LitToConstError::Reported(err)) => {
@@ -2451,23 +2445,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24512445
(ct, ty)
24522446
}
24532447

2454-
hir::ExprKind::Path(hir::QPath::Resolved(
2448+
hir::PatLitKind::Path(hir::QPath::Resolved(
24552449
_,
24562450
path @ &hir::Path {
24572451
res: Res::Def(DefKind::ConstParam, def_id),
24582452
..
24592453
},
24602454
)) => {
2461-
let _ = self.prohibit_generic_args(
2455+
match self.prohibit_generic_args(
24622456
path.segments.iter(),
24632457
GenericsArgsErrExtend::Param(def_id),
2464-
);
2465-
let ty = tcx
2466-
.type_of(def_id)
2467-
.no_bound_vars()
2468-
.expect("const parameter types cannot be generic");
2469-
let ct = self.lower_const_param(def_id, expr.hir_id);
2470-
(ct, ty)
2458+
) {
2459+
Ok(()) => {
2460+
let ty = tcx
2461+
.type_of(def_id)
2462+
.no_bound_vars()
2463+
.expect("const parameter types cannot be generic");
2464+
let ct = self.lower_const_param(def_id, expr.hir_id);
2465+
(ct, ty)
2466+
}
2467+
Err(guar) => (
2468+
ty::Const::new_error(tcx, guar),
2469+
Ty::new_error(tcx, guar),
2470+
),
2471+
}
24712472
}
24722473

24732474
_ => {
@@ -2478,9 +2479,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24782479
}
24792480
};
24802481
self.record_ty(expr.hir_id, c_ty, expr.span);
2481-
if let Some((id, span)) = neg {
2482-
self.record_ty(id, c_ty, span);
2483-
}
24842482
c
24852483
};
24862484

Diff for: compiler/rustc_hir_pretty/src/lib.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ impl<'a> State<'a> {
9898
Node::OpaqueTy(o) => self.print_opaque_ty(o),
9999
Node::Pat(a) => self.print_pat(a),
100100
Node::PatField(a) => self.print_patfield(a),
101+
Node::PatLit(a) => self.print_pat_lit(a),
101102
Node::Arm(a) => self.print_arm(a),
102103
Node::Infer(_) => self.word("_"),
103104
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
@@ -1715,6 +1716,19 @@ impl<'a> State<'a> {
17151716
}
17161717
}
17171718

1719+
fn print_pat_lit(&mut self, lit: &hir::PatLit<'_>) {
1720+
match &lit.kind {
1721+
hir::PatLitKind::Lit { lit, negated } => {
1722+
if *negated {
1723+
self.word("-");
1724+
}
1725+
self.print_literal(lit);
1726+
}
1727+
hir::PatLitKind::ConstBlock(c) => self.print_inline_const(c),
1728+
hir::PatLitKind::Path(qpath) => self.print_qpath(qpath, true),
1729+
}
1730+
}
1731+
17181732
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
17191733
self.maybe_print_comment(pat.span.lo());
17201734
self.ann.pre(self, AnnNode::Pat(pat));
@@ -1832,17 +1846,17 @@ impl<'a> State<'a> {
18321846
self.pclose();
18331847
}
18341848
}
1835-
PatKind::Lit(e) => self.print_expr(e),
1849+
PatKind::Lit(e) => self.print_pat_lit(e),
18361850
PatKind::Range(begin, end, end_kind) => {
18371851
if let Some(expr) = begin {
1838-
self.print_expr(expr);
1852+
self.print_pat_lit(expr);
18391853
}
18401854
match end_kind {
18411855
RangeEnd::Included => self.word("..."),
18421856
RangeEnd::Excluded => self.word(".."),
18431857
}
18441858
if let Some(expr) = end {
1845-
self.print_expr(expr);
1859+
self.print_pat_lit(expr);
18461860
}
18471861
}
18481862
PatKind::Slice(before, slice, after) => {

0 commit comments

Comments
 (0)