diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5e2aebfd3187..190b50b10b28 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -425,19 +425,44 @@ impl<'a> LoweringContext<'a> { impl<'tcx, 'interner> Visitor<'tcx> for MiscCollector<'tcx, 'interner> { fn visit_pat(&mut self, p: &'tcx Pat) { - match p.node { + if let PatKind::Paren(..) | PatKind::Rest = p.node { // Doesn't generate a HIR node - PatKind::Paren(..) | PatKind::Rest => {}, - _ => { - if let Some(owner) = self.hir_id_owner { - self.lctx.lower_node_id_with_owner(p.id, owner); - } - } - }; + } else if let Some(owner) = self.hir_id_owner { + self.lctx.lower_node_id_with_owner(p.id, owner); + } visit::walk_pat(self, p) } + // HACK(or_patterns; Centril | dlrobertson): Avoid creating + // HIR nodes for `PatKind::Or` for the top level of a `ast::Arm`. + // This is a temporary hack that should go away once we push down + // `arm.pats: HirVec>` -> `arm.pat: P` to HIR. // Centril + fn visit_arm(&mut self, arm: &'tcx Arm) { + match &arm.pat.node { + PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)), + _ => self.visit_pat(&arm.pat), + } + walk_list!(self, visit_expr, &arm.guard); + self.visit_expr(&arm.body); + walk_list!(self, visit_attribute, &arm.attrs); + } + + // HACK(or_patterns; Centril | dlrobertson): Same as above. // Centril + fn visit_expr(&mut self, e: &'tcx Expr) { + if let ExprKind::Let(pat, scrutinee) = &e.node { + walk_list!(self, visit_attribute, e.attrs.iter()); + match &pat.node { + PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)), + _ => self.visit_pat(&pat), + } + self.visit_expr(scrutinee); + self.visit_expr_post(e); + return; + } + visit::walk_expr(self, e) + } + fn visit_item(&mut self, item: &'tcx Item) { let hir_id = self.lctx.allocate_hir_id_counter(item.id); diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index bd217831faab..0d8986ddec3c 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -68,7 +68,7 @@ impl LoweringContext<'_> { let ohs = P(self.lower_expr(ohs)); hir::ExprKind::AddrOf(m, ohs) } - ExprKind::Let(ref pats, ref scrutinee) => self.lower_expr_let(e.span, pats, scrutinee), + ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee), ExprKind::If(ref cond, ref then, ref else_opt) => { self.lower_expr_if(e.span, cond, then, else_opt.as_deref()) } @@ -227,16 +227,11 @@ impl LoweringContext<'_> { } } - /// Emit an error and lower `ast::ExprKind::Let(pats, scrutinee)` into: + /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into: /// ```rust /// match scrutinee { pats => true, _ => false } /// ``` - fn lower_expr_let( - &mut self, - span: Span, - pats: &[AstP], - scrutinee: &Expr - ) -> hir::ExprKind { + fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind { // If we got here, the `let` expression is not allowed. self.sess .struct_span_err(span, "`let` expressions are not supported here") @@ -246,23 +241,23 @@ impl LoweringContext<'_> { // For better recovery, we emit: // ``` - // match scrutinee { pats => true, _ => false } + // match scrutinee { pat => true, _ => false } // ``` // While this doesn't fully match the user's intent, it has key advantages: // 1. We can avoid using `abort_if_errors`. - // 2. We can typeck both `pats` and `scrutinee`. - // 3. `pats` is allowed to be refutable. + // 2. We can typeck both `pat` and `scrutinee`. + // 3. `pat` is allowed to be refutable. // 4. The return type of the block is `bool` which seems like what the user wanted. let scrutinee = self.lower_expr(scrutinee); let then_arm = { - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); + let pat = self.lower_pat_top_hack(pat); let expr = self.expr_bool(span, true); - self.arm(pats, P(expr)) + self.arm(pat, P(expr)) }; let else_arm = { - let pats = hir_vec![self.pat_wild(span)]; + let pat = self.pat_wild(span); let expr = self.expr_bool(span, false); - self.arm(pats, P(expr)) + self.arm(hir_vec![pat], P(expr)) }; hir::ExprKind::Match( P(scrutinee), @@ -291,13 +286,12 @@ impl LoweringContext<'_> { // Handle then + scrutinee: let then_blk = self.lower_block(then, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); - let (then_pats, scrutinee, desugar) = match cond.node { + let (then_pat, scrutinee, desugar) = match cond.node { // ` => `: - ExprKind::Let(ref pats, ref scrutinee) => { + ExprKind::Let(ref pat, ref scrutinee) => { let scrutinee = self.lower_expr(scrutinee); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; - (pats, scrutinee, desugar) + let pat = self.lower_pat_top_hack(pat); + (pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause }) } // `true => `: _ => { @@ -312,13 +306,11 @@ impl LoweringContext<'_> { // to preserve drop semantics since `if cond { ... }` does not // let temporaries live outside of `cond`. let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); - - let desugar = hir::MatchSource::IfDesugar { contains_else_clause }; - let pats = hir_vec![self.pat_bool(span, true)]; - (pats, cond, desugar) + let pat = self.pat_bool(span, true); + (hir_vec![pat], cond, hir::MatchSource::IfDesugar { contains_else_clause }) } }; - let then_arm = self.arm(then_pats, P(then_expr)); + let then_arm = self.arm(then_pat, P(then_expr)); hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) } @@ -345,8 +337,8 @@ impl LoweringContext<'_> { // Handle then + scrutinee: let then_blk = self.lower_block(body, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); - let (then_pats, scrutinee, desugar, source) = match cond.node { - ExprKind::Let(ref pats, ref scrutinee) => { + let (then_pat, scrutinee, desugar, source) = match cond.node { + ExprKind::Let(ref pat, ref scrutinee) => { // to: // // [opt_ident]: loop { @@ -356,9 +348,8 @@ impl LoweringContext<'_> { // } // } let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee)); - let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); - let desugar = hir::MatchSource::WhileLetDesugar; - (pats, scrutinee, desugar, hir::LoopSource::WhileLet) + let pat = self.lower_pat_top_hack(pat); + (pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet) } _ => { // We desugar: `'label: while $cond $body` into: @@ -383,14 +374,12 @@ impl LoweringContext<'_> { // to preserve drop semantics since `while cond { ... }` does not // let temporaries live outside of `cond`. let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); - - let desugar = hir::MatchSource::WhileDesugar; // `true => `: - let pats = hir_vec![self.pat_bool(span, true)]; - (pats, cond, desugar, hir::LoopSource::While) + let pat = self.pat_bool(span, true); + (hir_vec![pat], cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While) } }; - let then_arm = self.arm(then_pats, P(then_expr)); + let then_arm = self.arm(then_pat, P(then_expr)); // `match { ... }` let match_expr = self.expr_match( @@ -440,7 +429,7 @@ impl LoweringContext<'_> { hir::Arm { hir_id: self.next_id(), attrs: self.lower_attrs(&arm.attrs), - pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), + pats: self.lower_pat_top_hack(&arm.pat), guard: match arm.guard { Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))), _ => None, @@ -450,6 +439,16 @@ impl LoweringContext<'_> { } } + /// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns + /// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready + /// to deal with it. This should by fixed by pushing it down to HIR and then HAIR. + fn lower_pat_top_hack(&mut self, pat: &Pat) -> HirVec> { + match pat.node { + PatKind::Or(ref ps) => ps.iter().map(|x| self.lower_pat(x)).collect(), + _ => hir_vec![self.lower_pat(pat)], + } + } + pub(super) fn make_async_expr( &mut self, capture_clause: CaptureBy, @@ -1255,7 +1254,6 @@ impl LoweringContext<'_> { ThinVec::from(attrs.clone()), )); let ok_pat = self.pat_ok(span, val_pat); - self.arm(hir_vec![ok_pat], val_expr) }; @@ -1486,7 +1484,10 @@ impl LoweringContext<'_> { } } - fn arm(&mut self, pats: hir::HirVec>, expr: P) -> hir::Arm { + /// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns + /// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready + /// to deal with it. This should by fixed by pushing it down to HIR and then HAIR. + fn arm(&mut self, pats: HirVec>, expr: P) -> hir::Arm { hir::Arm { hir_id: self.next_id(), attrs: hir_vec![],