let_chains: Remove ast_validation logic in favor of lowering with recovery.
This commit is contained in:
parent
10234d286a
commit
2017be4ef6
2 changed files with 49 additions and 67 deletions
|
@ -4344,12 +4344,39 @@ impl<'a> LoweringContext<'a> {
|
||||||
let ohs = P(self.lower_expr(ohs));
|
let ohs = P(self.lower_expr(ohs));
|
||||||
hir::ExprKind::AddrOf(m, ohs)
|
hir::ExprKind::AddrOf(m, ohs)
|
||||||
}
|
}
|
||||||
ExprKind::Let(..) => {
|
ExprKind::Let(ref pats, ref scrutinee) => {
|
||||||
// This should have been caught `ast_validation`!
|
// If we got here, the `let` expression is not allowed.
|
||||||
self.sess.span_err(e.span, "`let` expressions only supported in `if`");
|
self.sess
|
||||||
// ^-- FIXME(53667): Change to `delay_span_bug` when let_chains handled in lowering.
|
.struct_span_err(e.span, "`let` expressions are not supported here")
|
||||||
self.sess.abort_if_errors();
|
.note("only supported directly in conditions of `if`- and `while`-expressions")
|
||||||
hir::ExprKind::Err
|
.note("as well as when nested within `&&` and parenthesis in those conditions")
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
// For better recovery, we emit:
|
||||||
|
// ```
|
||||||
|
// match scrutinee { pats => 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.
|
||||||
|
// 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 expr = self.expr_bool(e.span, true);
|
||||||
|
self.arm(pats, P(expr))
|
||||||
|
};
|
||||||
|
let else_arm = {
|
||||||
|
let pats = hir_vec![self.pat_wild(e.span)];
|
||||||
|
let expr = self.expr_bool(e.span, false);
|
||||||
|
self.arm(pats, P(expr))
|
||||||
|
};
|
||||||
|
hir::ExprKind::Match(
|
||||||
|
P(scrutinee),
|
||||||
|
vec![then_arm, else_arm].into(),
|
||||||
|
hir::MatchSource::Normal,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// FIXME(#53667): handle lowering of && and parens.
|
// FIXME(#53667): handle lowering of && and parens.
|
||||||
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||||
|
@ -5431,10 +5458,15 @@ impl<'a> LoweringContext<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a `true` or `false` literal expression.
|
||||||
|
fn expr_bool(&mut self, span: Span, val: bool) -> hir::Expr {
|
||||||
|
let lit = Spanned { span, node: LitKind::Bool(val) };
|
||||||
|
self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new())
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a `true` or `false` literal pattern.
|
/// Constructs a `true` or `false` literal pattern.
|
||||||
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
|
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
|
||||||
let lit = Spanned { span, node: LitKind::Bool(val) };
|
let expr = self.expr_bool(span, val);
|
||||||
let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new());
|
|
||||||
self.pat(span, hir::PatKind::Lit(P(expr)))
|
self.pat(span, hir::PatKind::Lit(P(expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,6 @@ struct AstValidator<'a> {
|
||||||
/// these booleans.
|
/// these booleans.
|
||||||
warning_period_57979_didnt_record_next_impl_trait: bool,
|
warning_period_57979_didnt_record_next_impl_trait: bool,
|
||||||
warning_period_57979_impl_trait_in_proj: bool,
|
warning_period_57979_impl_trait_in_proj: bool,
|
||||||
|
|
||||||
/// Used to ban `let` expressions in inappropriate places.
|
|
||||||
is_let_allowed: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With the `new` value in `store`,
|
/// With the `new` value in `store`,
|
||||||
|
@ -114,12 +111,6 @@ impl<'a> AstValidator<'a> {
|
||||||
with(self, outer, |this| &mut this.outer_impl_trait, f)
|
with(self, outer, |this| &mut this.outer_impl_trait, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_let_allowed(&mut self, v: bool, f: impl FnOnce(&mut Self, bool)) {
|
|
||||||
let old = mem::replace(&mut self.is_let_allowed, v);
|
|
||||||
f(self, old);
|
|
||||||
self.is_let_allowed = old;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
|
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
|
||||||
match constraint.kind {
|
match constraint.kind {
|
||||||
AssocTyConstraintKind::Equality { ref ty } => {
|
AssocTyConstraintKind::Equality { ref ty } => {
|
||||||
|
@ -335,15 +326,6 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emits an error banning the `let` expression provided.
|
|
||||||
fn ban_let_expr(&self, expr: &'a Expr) {
|
|
||||||
self.err_handler()
|
|
||||||
.struct_span_err(expr.span, "`let` expressions are not supported here")
|
|
||||||
.note("only supported directly in conditions of `if`- and `while`-expressions")
|
|
||||||
.note("as well as when nested within `&&` and parenthesis in those conditions")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_fn_decl(&self, fn_decl: &FnDecl) {
|
fn check_fn_decl(&self, fn_decl: &FnDecl) {
|
||||||
fn_decl
|
fn_decl
|
||||||
.inputs
|
.inputs
|
||||||
|
@ -470,48 +452,17 @@ fn validate_generics_order<'a>(
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for AstValidator<'a> {
|
impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||||
self.with_let_allowed(false, |this, let_allowed| {
|
match &expr.node {
|
||||||
match &expr.node {
|
ExprKind::Closure(_, _, _, fn_decl, _, _) => {
|
||||||
ExprKind::Let(_, _) if !let_allowed => {
|
self.check_fn_decl(fn_decl);
|
||||||
this.ban_let_expr(expr);
|
|
||||||
}
|
|
||||||
// Assuming the context permits, `($expr)` does not impose additional constraints.
|
|
||||||
ExprKind::Paren(_) => {
|
|
||||||
this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
|
|
||||||
return; // We've already walked into `expr`.
|
|
||||||
}
|
|
||||||
// Assuming the context permits,
|
|
||||||
// l && r` allows decendants in `l` and `r` to be `let` expressions.
|
|
||||||
ExprKind::Binary(op, ..) if op.node == BinOpKind::And => {
|
|
||||||
this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
|
|
||||||
return; // We've already walked into `expr`.
|
|
||||||
}
|
|
||||||
// However, we do allow it in the condition of the `if` expression.
|
|
||||||
// We do not allow `let` in `then` and `opt_else` directly.
|
|
||||||
ExprKind::If(cond, then, opt_else) => {
|
|
||||||
this.visit_block(then);
|
|
||||||
walk_list!(this, visit_expr, opt_else);
|
|
||||||
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
|
|
||||||
return; // We've already walked into `expr`.
|
|
||||||
}
|
|
||||||
// The same logic applies to `While`.
|
|
||||||
ExprKind::While(cond, then, opt_label) => {
|
|
||||||
walk_list!(this, visit_label, opt_label);
|
|
||||||
this.visit_block(then);
|
|
||||||
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
|
|
||||||
return; // We've already walked into `expr`.
|
|
||||||
}
|
|
||||||
ExprKind::Closure(_, _, _, fn_decl, _, _) => {
|
|
||||||
this.check_fn_decl(fn_decl);
|
|
||||||
}
|
|
||||||
ExprKind::InlineAsm(..) if !this.session.target.target.options.allow_asm => {
|
|
||||||
span_err!(this.session, expr.span, E0472, "asm! is unsupported on this target");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
|
||||||
|
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
visit::walk_expr(this, expr);
|
visit::walk_expr(self, expr);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||||
|
@ -923,7 +874,6 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
|
||||||
is_assoc_ty_bound_banned: false,
|
is_assoc_ty_bound_banned: false,
|
||||||
warning_period_57979_didnt_record_next_impl_trait: false,
|
warning_period_57979_didnt_record_next_impl_trait: false,
|
||||||
warning_period_57979_impl_trait_in_proj: false,
|
warning_period_57979_impl_trait_in_proj: false,
|
||||||
is_let_allowed: false,
|
|
||||||
};
|
};
|
||||||
visit::walk_crate(&mut validator, krate);
|
visit::walk_crate(&mut validator, krate);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue