refactor(parser): improve expression parsing (#3352)

This commit is contained in:
Boshen 2024-05-19 21:28:16 +08:00 committed by GitHub
parent e818fba21c
commit 89a1f97320
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 192 additions and 129 deletions

View file

@ -1770,6 +1770,20 @@ impl<'a> AstBuilder<'a> {
}))
}
#[inline]
pub fn ts_instantiation_expression(
&self,
span: Span,
expression: Expression<'a>,
type_parameters: Box<'a, TSTypeParameterInstantiation<'a>>,
) -> Expression<'a> {
Expression::TSInstantiationExpression(self.alloc(TSInstantiationExpression {
span,
expression,
type_parameters,
}))
}
#[inline]
pub fn ts_non_null_expression(&self, span: Span, expression: Expression<'a>) -> Expression<'a> {
Expression::TSNonNullExpression(self.alloc(TSNonNullExpression { span, expression }))

View file

@ -2,8 +2,9 @@ use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_diagnostics::Result;
use oxc_span::{GetSpan, Span};
use oxc_syntax::precedence::Precedence;
use crate::{diagnostics, lexer::Kind, AstBuilder, ParserImpl};
use crate::{diagnostics, lexer::Kind, ParserImpl};
use super::Tristate;
@ -34,8 +35,9 @@ impl<'a> ParserImpl<'a> {
{
let span = self.start_span();
self.bump_any(); // bump `async`
let expr = self.parse_binary_expression_or_higher(Precedence::lowest())?;
return self
.parse_simple_arrow_function_expression(span, /* is_async */ true)
.parse_simple_arrow_function_expression(span, expr, /* async */ true)
.map(Some);
}
Ok(None)
@ -186,7 +188,7 @@ impl<'a> ParserImpl<'a> {
}
// Check for un-parenthesized AsyncArrowFunction
if first.is_binding_identifier() {
// Arrow before newline is checkedin `parse_simple_arrow_function_expression`
// Arrow before newline is checked in `parse_simple_arrow_function_expression`
if self.nth_at(2, Kind::Arrow) {
return Tristate::True;
}
@ -198,24 +200,24 @@ impl<'a> ParserImpl<'a> {
pub(crate) fn parse_simple_arrow_function_expression(
&mut self,
span: Span,
ident: Expression<'a>,
r#async: bool,
) -> Result<Expression<'a>> {
let has_await = self.ctx.has_await();
self.ctx = self.ctx.union_await_if(r#async);
let params = {
let params_span = self.start_span();
let param = self.parse_binding_identifier()?;
let ident = self.ast.binding_pattern_identifier(param);
let params_span = self.end_span(params_span);
let formal_parameter = self.ast.formal_parameter(
params_span,
self.ast.binding_pattern(ident, None, false),
None,
false,
false,
AstBuilder::new_vec(&self.ast),
);
let ident = match ident {
Expression::Identifier(ident) => {
let name = ident.name.clone();
BindingIdentifier::new(ident.span, name)
}
_ => unreachable!(),
};
let params_span = self.end_span(ident.span);
let ident = self.ast.binding_pattern_identifier(ident);
let pattern = self.ast.binding_pattern(ident, None, false);
let formal_parameter = self.ast.plain_formal_parameter(params_span, pattern);
self.ast.formal_parameters(
params_span,
FormalParameterKind::ArrowFormalParameters,

View file

@ -122,7 +122,7 @@ impl<'a> ParserImpl<'a> {
let mut extends = self.ast.new_vec();
let span = self.start_span();
let mut first_extends = self.parse_lhs_expression()?;
let mut first_extends = self.parse_lhs_expression_or_higher()?;
let first_type_argument;
if let Expression::TSInstantiationExpression(expr) = first_extends {
let expr = expr.unbox();
@ -135,7 +135,7 @@ impl<'a> ParserImpl<'a> {
while self.eat(Kind::Comma) {
let span = self.start_span();
let mut extend = self.parse_lhs_expression()?;
let mut extend = self.parse_lhs_expression_or_higher()?;
let type_argument;
if let Expression::TSInstantiationExpression(expr) = extend {
let expr = expr.unbox();

View file

@ -115,11 +115,11 @@ impl<'a> ParserImpl<'a> {
pub(crate) fn check_identifier(&mut self, span: Span, name: &Atom) {
// It is a Syntax Error if this production has an [Await] parameter.
if self.ctx.has_await() && *name == "await" {
if self.ctx.has_await() && name.as_str() == "await" {
self.error(diagnostics::identifier_async("await", span));
}
// It is a Syntax Error if this production has a [Yield] parameter.
if self.ctx.has_yield() && *name == "yield" {
if self.ctx.has_yield() && name.as_str() == "yield" {
self.error(diagnostics::identifier_generator("yield", span));
}
}
@ -498,11 +498,11 @@ impl<'a> ParserImpl<'a> {
}
/// Section 13.3 Left-Hand-Side Expression
pub(crate) fn parse_lhs_expression(&mut self) -> Result<Expression<'a>> {
pub(crate) fn parse_lhs_expression_or_higher(&mut self) -> Result<Expression<'a>> {
let span = self.start_span();
let mut in_optional_chain = false;
let lhs = self.parse_member_expression_base(&mut in_optional_chain)?;
let lhs = self.parse_call_expression(span, lhs, &mut in_optional_chain)?;
let lhs = self.parse_member_expression_or_higher(&mut in_optional_chain)?;
let lhs = self.parse_call_expression_rest(span, lhs, &mut in_optional_chain)?;
if in_optional_chain {
let span = self.end_span(span);
Ok(self.map_to_chain_expression(span, lhs))
@ -525,13 +525,13 @@ impl<'a> ParserImpl<'a> {
}
/// Section 13.3 Member Expression
fn parse_member_expression_base(
fn parse_member_expression_or_higher(
&mut self,
in_optional_chain: &mut bool,
) -> Result<Expression<'a>> {
let span = self.start_span();
self.parse_primary_expression()
.and_then(|lhs| self.parse_member_expression_rhs(span, lhs, in_optional_chain))
.and_then(|lhs| self.parse_member_expression_rest(span, lhs, in_optional_chain))
}
/// Section 13.3 Super Call
@ -554,7 +554,7 @@ impl<'a> ParserImpl<'a> {
}
/// parse rhs of a member expression, starting from lhs
fn parse_member_expression_rhs(
fn parse_member_expression_rest(
&mut self,
lhs_span: Span,
lhs: Expression<'a>,
@ -600,15 +600,15 @@ impl<'a> ParserImpl<'a> {
};
self.parse_tagged_template(lhs_span, expr, *in_optional_chain, type_parameters)?
}
Kind::LAngle | Kind::ShiftLeft if self.ts_enabled() => {
if let Some(arguments) = self.parse_ts_type_arguments_in_expression() {
lhs = Expression::TSInstantiationExpression(self.ast.alloc(
TSInstantiationExpression {
span: self.end_span(lhs_span),
expression: lhs,
type_parameters: arguments,
},
));
Kind::LAngle | Kind::ShiftLeft => {
if let Ok(Some(arguments)) =
self.try_parse(Self::parse_ts_type_arguments_in_expression)
{
lhs = self.ast.ts_instantiation_expression(
self.end_span(lhs_span),
lhs,
arguments,
);
continue;
}
break;
@ -667,7 +667,7 @@ impl<'a> ParserImpl<'a> {
let rhs_span = self.start_span();
let mut optional = false;
let mut callee = self.parse_member_expression_base(&mut optional)?;
let mut callee = self.parse_member_expression_or_higher(&mut optional)?;
let mut type_parameter = None;
if let Expression::TSInstantiationExpression(instantiation_expr) = callee {
@ -699,7 +699,7 @@ impl<'a> ParserImpl<'a> {
}
/// Section 13.3 Call Expression
fn parse_call_expression(
fn parse_call_expression_rest(
&mut self,
lhs_span: Span,
lhs: Expression<'a>,
@ -708,12 +708,15 @@ impl<'a> ParserImpl<'a> {
let mut lhs = lhs;
loop {
let mut type_arguments = None;
lhs = self.parse_member_expression_rhs(lhs_span, lhs, in_optional_chain)?;
lhs = self.parse_member_expression_rest(lhs_span, lhs, in_optional_chain)?;
let optional_call = self.eat(Kind::QuestionDot);
*in_optional_chain = if optional_call { true } else { *in_optional_chain };
if optional_call {
type_arguments = self.parse_ts_type_arguments_in_expression();
if let Ok(Some(args)) = self.try_parse(Self::parse_ts_type_arguments_in_expression)
{
type_arguments = Some(args);
}
if self.cur_kind().is_template_start_of_tagged_template() {
lhs =
self.parse_tagged_template(lhs_span, lhs, optional_call, type_arguments)?;
@ -758,9 +761,31 @@ impl<'a> ParserImpl<'a> {
}
/// Section 13.4 Update Expression
fn parse_update_expression(&mut self) -> Result<Expression<'a>> {
fn parse_update_expression(&mut self, lhs_span: Span) -> Result<Expression<'a>> {
let kind = self.cur_kind();
// ++ -- prefix update expressions
if kind.is_update_operator() {
let operator = map_update_operator(kind);
self.bump_any();
let argument = self.parse_unary_expression_or_higher(lhs_span)?;
let argument = SimpleAssignmentTarget::cover(argument, self)?;
return Ok(self.ast.update_expression(
self.end_span(lhs_span),
operator,
true,
argument,
));
}
if self.source_type.is_jsx()
&& kind == Kind::LAngle
&& self.peek_kind().is_identifier_name()
{
return self.parse_jsx_expression();
}
let span = self.start_span();
let lhs = self.parse_lhs_expression()?;
let lhs = self.parse_lhs_expression_or_higher()?;
// ++ -- postfix update expressions
if self.cur_kind().is_update_operator() && !self.cur_token().is_on_new_line {
let operator = map_update_operator(self.cur_kind());
@ -772,50 +797,46 @@ impl<'a> ParserImpl<'a> {
}
/// Section 13.5 Unary Expression
pub(crate) fn parse_unary_expression_base(&mut self, lhs_span: Span) -> Result<Expression<'a>> {
// [+Await] AwaitExpression
if self.is_await_expression() {
return self.parse_await_expression(lhs_span);
}
if (self.at(Kind::LAngle) || self.at(Kind::ShiftLeft))
&& !self.source_type.is_jsx()
&& self.ts_enabled()
{
return self.parse_ts_type_assertion();
}
pub(crate) fn parse_unary_expression_or_higher(
&mut self,
lhs_span: Span,
) -> Result<Expression<'a>> {
// ++ -- prefix update expressions
if self.cur_kind().is_update_operator() {
let operator = map_update_operator(self.cur_kind());
self.bump_any();
let argument = self.parse_unary_expression_base(lhs_span)?;
let argument = SimpleAssignmentTarget::cover(argument, self)?;
return Ok(self.ast.update_expression(
self.end_span(lhs_span),
operator,
true,
argument,
));
if self.is_update_expression() {
return self.parse_update_expression(lhs_span);
}
self.parse_simple_unary_expression(lhs_span)
}
// delete void typeof + - ~ ! prefix unary expressions
if self.cur_kind().is_unary_operator() {
return self.parse_unary_expression();
pub(crate) fn parse_simple_unary_expression(
&mut self,
lhs_span: Span,
) -> Result<Expression<'a>> {
match self.cur_kind() {
kind if kind.is_unary_operator() => self.parse_unary_expression(),
Kind::LAngle => {
if self.source_type.is_jsx() {
return self.parse_jsx_expression();
}
if self.ts_enabled() {
return self.parse_ts_type_assertion();
}
Err(self.unexpected())
}
Kind::Await if self.is_await_expression() => self.parse_await_expression(lhs_span),
_ => self.parse_update_expression(lhs_span),
}
self.parse_update_expression()
}
fn parse_unary_expression(&mut self) -> Result<Expression<'a>> {
let span = self.start_span();
let operator = map_unary_operator(self.cur_kind());
self.bump_any();
let argument = self.parse_unary_expression_base(span)?;
let argument = self.parse_simple_unary_expression(span)?;
Ok(self.ast.unary_expression(self.end_span(span), operator, argument))
}
fn parse_binary_or_logical_expression_base(
pub(crate) fn parse_binary_expression_or_higher(
&mut self,
lhs_precedence: Precedence,
) -> Result<Expression<'a>> {
@ -824,7 +845,7 @@ impl<'a> ParserImpl<'a> {
let lhs = if self.ctx.has_in() && self.at(Kind::PrivateIdentifier) {
let left = self.parse_private_identifier();
self.expect(Kind::In)?;
let right = self.parse_unary_expression_base(lhs_span)?;
let right = self.parse_unary_expression_or_higher(lhs_span)?;
Expression::PrivateInExpression(self.ast.alloc(PrivateInExpression {
span: self.end_span(lhs_span),
left,
@ -832,14 +853,14 @@ impl<'a> ParserImpl<'a> {
right,
}))
} else {
self.parse_unary_expression_base(lhs_span)?
self.parse_unary_expression_or_higher(lhs_span)?
};
self.parse_binary_or_logical_expression_recursive(lhs_span, lhs, lhs_precedence)
self.parse_binary_expression_rest(lhs_span, lhs, lhs_precedence)
}
/// Section 13.6 - 13.13 Binary Expression
fn parse_binary_or_logical_expression_recursive(
fn parse_binary_expression_rest(
&mut self,
lhs_span: Span,
lhs: Expression<'a>,
@ -888,7 +909,7 @@ impl<'a> ParserImpl<'a> {
}
self.bump_any(); // bump operator
let rhs = self.parse_binary_or_logical_expression_base(left_precedence)?;
let rhs = self.parse_binary_expression_or_higher(left_precedence)?;
lhs = if kind.is_logical_operator() {
self.ast.logical_expression(
@ -916,9 +937,11 @@ impl<'a> ParserImpl<'a> {
/// `ConditionalExpression`[In, Yield, Await] :
/// `ShortCircuitExpression`[?In, ?Yield, ?Await]
/// `ShortCircuitExpression`[?In, ?Yield, ?Await] ? `AssignmentExpression`[+In, ?Yield, ?Await] : `AssignmentExpression`[?In, ?Yield, ?Await]
fn parse_conditional_expression(&mut self) -> Result<Expression<'a>> {
let span = self.start_span();
let lhs = self.parse_binary_or_logical_expression_base(Precedence::lowest())?;
fn parse_conditional_expression_rest(
&mut self,
lhs_span: Span,
lhs: Expression<'a>,
) -> Result<Expression<'a>> {
if !self.eat(Kind::Question) {
return Ok(lhs);
}
@ -929,7 +952,7 @@ impl<'a> ParserImpl<'a> {
)?;
self.expect(Kind::Colon)?;
let alternate = self.parse_assignment_expression_or_higher()?;
Ok(self.ast.conditional_expression(self.end_span(span), lhs, consequent, alternate))
Ok(self.ast.conditional_expression(self.end_span(lhs_span), lhs, consequent, alternate))
}
/// `AssignmentExpression`[In, Yield, Await] :
@ -946,13 +969,21 @@ impl<'a> ParserImpl<'a> {
if let Some(arrow_expr) = self.try_parse_async_simple_arrow_function_expression()? {
return Ok(arrow_expr);
}
let span = self.start_span();
let lhs = self.parse_binary_expression_or_higher(Precedence::lowest())?;
let kind = self.cur_kind();
// `x => {}`
if self.cur_kind().is_binding_identifier() && self.peek_at(Kind::Arrow) {
return self.parse_simple_arrow_function_expression(span, /* r#async */ false);
if lhs.is_identifier_reference() && kind == Kind::Arrow {
return self.parse_simple_arrow_function_expression(span, lhs, /* async */ false);
}
let lhs = self.parse_conditional_expression()?;
self.parse_assignment_expression_recursive(span, lhs)
if kind.is_assignment_operator() {
return self.parse_assignment_expression_recursive(span, lhs);
}
self.parse_conditional_expression_rest(span, lhs)
}
fn parse_assignment_expression_recursive(
@ -960,12 +991,7 @@ impl<'a> ParserImpl<'a> {
span: Span,
lhs: Expression<'a>,
) -> Result<Expression<'a>> {
if !self.cur_kind().is_assignment_operator() {
return Ok(lhs);
}
let operator = map_assignment_operator(self.cur_kind());
// 13.15.5 Destructuring Assignment
// LeftHandSideExpression = AssignmentExpression
// is converted to
@ -973,9 +999,7 @@ impl<'a> ParserImpl<'a> {
// ObjectAssignmentPattern
// ArrayAssignmentPattern
let left = AssignmentTarget::cover(lhs, self)?;
self.bump_any();
let right = self.parse_assignment_expression_or_higher()?;
Ok(self.ast.assignment_expression(self.end_span(span), operator, left, right))
}
@ -1004,7 +1028,7 @@ impl<'a> ParserImpl<'a> {
self.error(diagnostics::await_expression(Span::new(span.start, span.start + 5)));
}
let argument = self.context(Context::Await, Context::empty(), |p| {
p.parse_unary_expression_base(lhs_span)
p.parse_simple_unary_expression(lhs_span)
})?;
Ok(self.ast.await_expression(self.end_span(span), argument))
}
@ -1016,18 +1040,38 @@ impl<'a> ParserImpl<'a> {
pub(crate) fn parse_decorator(&mut self) -> Result<Decorator<'a>> {
let span = self.start_span();
self.bump_any(); // bump @
let expr =
self.context(Context::Decorator, Context::empty(), Self::parse_lhs_expression)?;
let expr = self.context(
Context::Decorator,
Context::empty(),
Self::parse_lhs_expression_or_higher,
)?;
Ok(self.ast.decorator(self.end_span(span), expr))
}
fn is_update_expression(&self) -> bool {
match self.cur_kind() {
kind if kind.is_unary_operator() => false,
Kind::Await => false,
Kind::LAngle => {
if !self.source_type.is_jsx() {
return false;
}
true
}
_ => true,
}
}
fn is_await_expression(&mut self) -> bool {
if self.at(Kind::Await) {
let peek_token = self.peek_token();
// Allow arrow expression `await => {}`
if peek_token.kind == Kind::Arrow {
return false;
}
if self.ctx.has_await() {
return true;
}
let peek_token = self.peek_token();
// The following expressions are ambiguous
// await + 0, await - 0, await ( 0 ), await [ 0 ], await / 0 /u, await ``, await of []
if matches!(
@ -1037,7 +1081,7 @@ impl<'a> ParserImpl<'a> {
return false;
}
return peek_token.kind.is_after_await_or_yield() && !peek_token.is_on_new_line;
return !peek_token.is_on_new_line && peek_token.kind.is_after_await_or_yield();
}
false
}
@ -1045,13 +1089,14 @@ impl<'a> ParserImpl<'a> {
fn is_yield_expression(&mut self) -> bool {
if self.at(Kind::Yield) {
let peek_token = self.peek_token();
// Allow arrow expression `yield => {}`
if peek_token.kind == Kind::Arrow {
return false;
}
if self.ctx.has_yield() {
return true;
}
return peek_token.kind.is_after_await_or_yield() && !peek_token.is_on_new_line;
return !peek_token.is_on_new_line && peek_token.kind.is_after_await_or_yield();
}
false
}

View file

@ -359,7 +359,7 @@ impl<'a> ParserImpl<'a> {
let type_annotation = self.parse_ts_type()?;
self.expect(Kind::RAngle)?;
let lhs_span = self.start_span();
let expression = self.parse_unary_expression_base(lhs_span)?;
let expression = self.parse_simple_unary_expression(lhs_span)?;
Ok(self.ast.ts_type_assertion(self.end_span(span), type_annotation, expression))
}

View file

@ -532,25 +532,26 @@ impl<'a> ParserImpl<'a> {
pub(crate) fn parse_ts_type_arguments_in_expression(
&mut self,
) -> Option<Box<'a, TSTypeParameterInstantiation<'a>>> {
if !matches!(self.cur_kind(), Kind::LAngle | Kind::ShiftLeft) {
return None;
) -> Result<Option<Box<'a, TSTypeParameterInstantiation<'a>>>> {
if !self.ts_enabled() {
return Ok(None);
}
let span = self.start_span();
self.re_lex_ts_l_angle();
if !self.at(Kind::LAngle) {
return Ok(None);
}
self.try_parse(|p| {
p.re_lex_ts_l_angle();
let params = TSTypeArgumentList::parse(self, /* in_expression */ true)?.params;
let params = TSTypeArgumentList::parse(p, true)?.params;
let token = p.cur_token();
if token.is_on_new_line || token.kind.can_follow_type_arguments_in_expr() {
Ok(params)
} else {
Err(p.unexpected())
}
})
.ok()
.map(|types| self.ast.ts_type_arguments(self.end_span(span), types))
let token = self.cur_token();
if token.is_on_new_line || token.kind.can_follow_type_arguments_in_expr() {
return Ok(Some(self.ast.ts_type_arguments(self.end_span(span), params)));
}
Err(self.unexpected())
}
fn parse_ts_tuple_type(&mut self) -> Result<TSType<'a>> {

View file

@ -3,7 +3,7 @@ commit: 4bd1b2c2
parser_babel Summary:
AST Parsed : 2093/2099 (99.71%)
Positive Passed: 2086/2099 (99.38%)
Negative Passed: 1363/1501 (90.81%)
Negative Passed: 1362/1501 (90.74%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
@ -25,6 +25,7 @@ Expect Syntax Error: "es2015/for-of/invalid-let-as-identifier/input.js"
Expect Syntax Error: "es2015/object/disallow-duplicate-method-params/input.js"
Expect Syntax Error: "es2015/uncategorised/297/input.js"
Expect Syntax Error: "es2015/uncategorised/335/input.js"
Expect Syntax Error: "es2017/async-functions/async-await-as-arrow-binding-identifier/input.js"
Expect Syntax Error: "es2017/async-functions/await-binding-inside-arrow-params-inside-async-arrow-params/input.js"
Expect Syntax Error: "es2017/trailing-function-commas/7/input.js"
Expect Syntax Error: "es2018/object-rest-spread/24/input.js"
@ -4842,12 +4843,6 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
3 │ }
╰────
× Cannot use `await` as an identifier in an async context
╭─[es2017/async-functions/async-await-as-arrow-binding-identifier/input.js:1:7]
1 │ async await => {}
· ─────
╰────
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[es2017/async-functions/async-function-and-non-bmp-character/input.js:1:6]
1 │ async function𝐬 f() {}

View file

@ -3,7 +3,7 @@ commit: 64d2eeea
parser_typescript Summary:
AST Parsed : 5240/5243 (99.94%)
Positive Passed: 5233/5243 (99.81%)
Negative Passed: 1064/4879 (21.81%)
Negative Passed: 1065/4879 (21.83%)
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
@ -58,7 +58,6 @@ Expect Syntax Error: "compiler/ambientExternalModuleWithRelativeModuleName.ts"
Expect Syntax Error: "compiler/ambientGetters.ts"
Expect Syntax Error: "compiler/ambientPropertyDeclarationInJs.ts"
Expect Syntax Error: "compiler/ambientStatement1.ts"
Expect Syntax Error: "compiler/ambiguousGenericAssertion1.ts"
Expect Syntax Error: "compiler/ambiguousOverload.ts"
Expect Syntax Error: "compiler/amdDependencyComment1.ts"
Expect Syntax Error: "compiler/amdDependencyComment2.ts"
@ -4123,6 +4122,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
26 │ }
╰────
× Unexpected token
╭─[compiler/ambiguousGenericAssertion1.ts:4:10]
3 │ var r2 = < <T>(x: T) => T>f; // valid
4 │ var r3 = <<T>(x: T) => T>f; // ambiguous, appears to the parser as a << operation
· ──
╰────
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[compiler/anonymousModules.ts:1:7]
1 │ module {
@ -5365,10 +5371,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
× Unexpected token
╭─[compiler/conflictMarkerDiff3Trivia2.ts:3:2]
╭─[compiler/conflictMarkerDiff3Trivia2.ts:3:1]
2 │ foo() {
3 │ <<<<<<< B
· ──
· ──
4 │ a();
╰────
@ -5381,10 +5387,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
× Unexpected token
╭─[compiler/conflictMarkerTrivia2.ts:3:2]
╭─[compiler/conflictMarkerTrivia2.ts:3:1]
2 │ foo() {
3 │ <<<<<<< B
· ──
· ──
4 │ a();
╰────
@ -5396,10 +5402,10 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
× Unexpected token
╭─[compiler/conflictMarkerTrivia4.ts:2:2]
╭─[compiler/conflictMarkerTrivia4.ts:2:1]
1 │ const x = <div>
2 │ <<<<<<< HEAD
· ──
· ──
╰────
× Identifier `y` has already been declared