@@ -120,12 +120,21 @@ impl<'a> AstValidator<'a> {
120
120
let err = "`let` expressions are not supported here" ;
121
121
let mut diag = sess. struct_span_err ( expr. span , err) ;
122
122
diag. note ( "only supported directly in conditions of `if` and `while` expressions" ) ;
123
- diag. note ( "as well as when nested within `&&` and parentheses in those conditions" ) ;
124
- if let ForbiddenLetReason :: ForbiddenWithOr ( span) = forbidden_let_reason {
125
- diag. span_note (
126
- span,
127
- "`||` operators are not currently supported in let chain expressions" ,
128
- ) ;
123
+ match forbidden_let_reason {
124
+ ForbiddenLetReason :: GenericForbidden => { }
125
+ ForbiddenLetReason :: NotSupportedOr ( span) => {
126
+ diag. span_note (
127
+ span,
128
+ "`||` operators are not supported in let chain expressions" ,
129
+ ) ;
130
+ }
131
+ ForbiddenLetReason :: NotSupportedParentheses ( span) => {
132
+ diag. span_note (
133
+ span,
134
+ "`let`s wrapped in parentheses are not supported in a context with let \
135
+ chains",
136
+ ) ;
137
+ }
129
138
}
130
139
diag. emit ( ) ;
131
140
} else {
@@ -1009,9 +1018,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1009
1018
self . with_let_management ( Some ( ForbiddenLetReason :: GenericForbidden ) , |this, forbidden_let_reason| {
1010
1019
match & expr. kind {
1011
1020
ExprKind :: Binary ( Spanned { node : BinOpKind :: Or , span } , lhs, rhs) => {
1012
- let forbidden_let_reason = Some ( ForbiddenLetReason :: ForbiddenWithOr ( * span) ) ;
1013
- this. with_let_management ( forbidden_let_reason , |this, _| this. visit_expr ( lhs) ) ;
1014
- this. with_let_management ( forbidden_let_reason , |this, _| this. visit_expr ( rhs) ) ;
1021
+ let local_reason = Some ( ForbiddenLetReason :: NotSupportedOr ( * span) ) ;
1022
+ this. with_let_management ( local_reason , |this, _| this. visit_expr ( lhs) ) ;
1023
+ this. with_let_management ( local_reason , |this, _| this. visit_expr ( rhs) ) ;
1015
1024
}
1016
1025
ExprKind :: If ( cond, then, opt_else) => {
1017
1026
this. visit_block ( then) ;
@@ -1036,7 +1045,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1036
1045
}
1037
1046
}
1038
1047
}
1039
- ExprKind :: Paren ( _) | ExprKind :: Binary ( Spanned { node : BinOpKind :: And , .. } , ..) => {
1048
+ ExprKind :: Paren ( local_expr) => {
1049
+ fn has_let_expr ( expr : & Expr ) -> bool {
1050
+ match expr. kind {
1051
+ ExprKind :: Binary ( _, ref lhs, ref rhs) => has_let_expr ( lhs) || has_let_expr ( rhs) ,
1052
+ ExprKind :: Let ( ..) => true ,
1053
+ _ => false ,
1054
+ }
1055
+ }
1056
+ let local_reason = if has_let_expr ( local_expr) {
1057
+ Some ( ForbiddenLetReason :: NotSupportedParentheses ( local_expr. span ) )
1058
+ }
1059
+ else {
1060
+ forbidden_let_reason
1061
+ } ;
1062
+ this. with_let_management ( local_reason, |this, _| this. visit_expr ( local_expr) ) ;
1063
+ }
1064
+ ExprKind :: Binary ( Spanned { node : BinOpKind :: And , .. } , ..) => {
1040
1065
this. with_let_management ( forbidden_let_reason, |this, _| visit:: walk_expr ( this, expr) ) ;
1041
1066
return ;
1042
1067
}
@@ -1810,8 +1835,13 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
1810
1835
/// Used to forbid `let` expressions in certain syntactic locations.
1811
1836
#[ derive( Clone , Copy ) ]
1812
1837
enum ForbiddenLetReason {
1813
- /// A let chain with the `||` operator
1814
- ForbiddenWithOr ( Span ) ,
1815
1838
/// `let` is not valid and the source environment is not important
1816
1839
GenericForbidden ,
1840
+ /// A let chain with the `||` operator
1841
+ NotSupportedOr ( Span ) ,
1842
+ /// A let chain with invalid parentheses
1843
+ ///
1844
+ /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
1845
+ /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
1846
+ NotSupportedParentheses ( Span ) ,
1817
1847
}
0 commit comments