Skip to content

Commit 0ada1a5

Browse files
committed
Point the bare '<>' ExpectedExpression diagnostic at its start
ruff's parser reports the error at the unexpected '>' (one past '<>'s start); CPython's tokenizer treats '<>' as a single obsolete token and points at its start instead. Detect the '<' immediately preceding the ExpectedExpression location and shift the reported range back over it, ahead of the generic ExpectedExpression -> 'invalid syntax' collapse.
1 parent bfc688e commit 0ada1a5

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

crates/compiler/src/lib.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,16 @@ fn cpython_parse_diagnostic_override(
362362
));
363363
}
364364

365+
// `2 <> 3` outside Barry mode: ruff lexes `<` then an unexpected `>` and
366+
// reports `ExpectedExpression` starting at the `>`. CPython's tokenizer
367+
// treats `<>` as a single obsolete token and points at its start (the
368+
// `<`) instead, so shift the reported location back over it.
369+
source_error!(barry_flufl_obsolete_operator_error(error, source_text));
370+
365371
// CPython's PEG parser collapses a bare "expected an expression" failure
366-
// into the generic "invalid syntax" message (e.g. `2 <> 3` outside Barry
367-
// mode). rustpython-vm's `vm_new.rs` does this same collapse for its own
368-
// callers; rustpython-compiler has no vm dependency, so mirror it here.
372+
// into the generic "invalid syntax" message. rustpython-vm's `vm_new.rs`
373+
// does this same collapse for its own callers; rustpython-compiler has no
374+
// vm dependency, so mirror it here.
369375
if matches!(&error.error, parser::ParseErrorType::ExpectedExpression) {
370376
let (loc, end_loc) = adjusted_error_locations(source_file, error.location);
371377
return Some(NormalizedParseDiagnostic::new(
@@ -378,6 +384,20 @@ fn cpython_parse_diagnostic_override(
378384
None
379385
}
380386

387+
fn barry_flufl_obsolete_operator_error(
388+
error: &parser::ParseError,
389+
source: &str,
390+
) -> Option<(String, usize, usize)> {
391+
if !matches!(&error.error, parser::ParseErrorType::ExpectedExpression) {
392+
return None;
393+
}
394+
let start = error.location.start().to_usize();
395+
if start == 0 || source.as_bytes().get(start - 1) != Some(&b'<') {
396+
return None;
397+
}
398+
Some(("invalid syntax".to_string(), start - 1, start + 1))
399+
}
400+
381401
fn eof_parse_diagnostic(
382402
error: &parser::ParseError,
383403
source_file: &SourceFile,

0 commit comments

Comments
 (0)