diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 37e6cacc8..d98a29218 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -660,6 +660,8 @@ pub fn parse_multispan_value( (arg, error) } SyntaxShape::OneOf(shapes) => { + // handle for `if` command. + let block_then_exp = shapes.as_slice() == [SyntaxShape::Block, SyntaxShape::Expression]; let mut err = None; for shape in shapes.iter() { let (s, option_err) = parse_multispan_value( @@ -671,7 +673,26 @@ pub fn parse_multispan_value( ); match option_err { None => return (s, None), - e => err = err.or(e), + e => { + // `if` is parsing block first and then expression. + // when we're writing something like `else if $a`, parsing as a + // block will result to error(because it's not a block) + // + // If parse as a expression also failed, user is more likely concerned + // about expression failure rather than "expect block failure"". + if block_then_exp { + match &err { + Some(ParseError::Expected(expected, _)) => { + if expected.starts_with("block") { + err = e + } + } + _ => err = err.or(e), + } + } else { + err = err.or(e) + } + } } } let span = spans[*spans_idx]; diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index b2c125b47..9297302db 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -1972,4 +1972,23 @@ mod input_types { assert!(matches!(err, ParseError::VariableNotFound(_))); } + + #[test] + fn else_if_errors_correctly() { + let mut engine_state = EngineState::new(); + add_declarations(&mut engine_state); + + let mut working_set = StateWorkingSet::new(&engine_state); + let (_, err) = parse( + &mut working_set, + None, + b"if false { 'a' } else $foo { 'b' }", + true, + &[], + ); + + let err = err.unwrap(); + + assert!(matches!(err, ParseError::VariableNotFound(_))); + } }