diff --git a/tsc/internal/scanner/scanner.go b/tsc/internal/scanner/scanner.go index 785fe50a4e7df..7f206b673a847 100644 --- a/tsc/internal/scanner/scanner.go +++ b/tsc/internal/scanner/scanner.go @@ -530,6 +530,15 @@ func (s *Scanner) Scan() ast.Kind { case '`': s.token = s.scanTemplateAndSetTokenValue(false /*shouldEmitInvalidEscapeError*/) case '%': + if s.charAt(1) == '%' && isConflictMarkerTrivia(s.text, s.pos) { + s.pos = scanConflictMarkerTrivia(s.text, s.pos, s.errorAt) + if s.skipTrivia { + continue + } else { + s.token = ast.KindConflictMarkerTrivia + return s.token + } + } if s.charAt(1) == '=' { s.pos += 2 s.token = ast.KindPercentEqualsToken @@ -584,6 +593,15 @@ func (s *Scanner) Scan() ast.Kind { s.token = ast.KindAsteriskToken } case '+': + if s.charAt(1) == '+' && isConflictMarkerTrivia(s.text, s.pos) { + s.pos = scanConflictMarkerTrivia(s.text, s.pos, s.errorAt) + if s.skipTrivia { + continue + } else { + s.token = ast.KindConflictMarkerTrivia + return s.token + } + } next := s.charAt(1) if next == '=' { s.pos += 2 @@ -896,6 +914,15 @@ func (s *Scanner) Scan() ast.Kind { s.pos++ s.token = ast.KindAtToken case '\\': + if s.charAt(1) == '\\' && isConflictMarkerTrivia(s.text, s.pos) { + s.pos = scanConflictMarkerTrivia(s.text, s.pos, s.errorAt) + if s.skipTrivia { + continue + } else { + s.token = ast.KindConflictMarkerTrivia + return s.token + } + } if s.scanIdentifier(0, identifierVariantStandard) { s.token = GetIdentifierToken(s.tokenValue) } else { @@ -2288,7 +2315,7 @@ func couldStartTrivia(text string, pos int) bool { // Characters that could start normal trivia case '\r', '\n', '\t', '\v', '\f', ' ', '/', // Characters that could start conflict marker trivia - '<', '|', '=', '>': + '<', '|', '=', '%', '\\', '+', '>': return true case '#': // Only if its the beginning can we have #! trivia @@ -2371,7 +2398,7 @@ func SkipTriviaEx(text string, pos int, options *SkipTriviaOptions) int { continue } } - case '<', '|', '=', '>': + case '<', '|', '=', '%', '\\', '+', '>': if isConflictMarkerTrivia(text, pos) { pos = scanConflictMarkerTrivia(text, pos, nil) canConsumeStar = false @@ -2412,8 +2439,8 @@ func isConflictMarkerTrivia(text string, pos int) bool { } // Fast reject: a conflict marker is the same byte repeated seven times. If the - // second byte differs (the overwhelmingly common case for `<`, `>`, `=`, `|` - // tokens), it cannot be a marker, so skip the line-start check entirely. + // second byte differs (the overwhelmingly common case), it cannot be a marker, + // so skip the line-start check entirely. if pos+1 >= len(text) || text[pos+1] != text[pos] { return false } @@ -2454,14 +2481,14 @@ func scanConflictMarkerTrivia(text string, pos int, reportError func(diag *diagn ch, size = utf8.DecodeRuneInString(text[pos:]) } } else { - if ch != '|' && ch != '=' { - panic("Assertion failed: ch must be either '|' or '='") + if ch != '|' && ch != '=' && ch != '%' && ch != '\\' && ch != '+' { + panic("Assertion failed: ch must be '|', '=', '%', '\\', or '+'") } - // Consume everything from the start of a ||||||| or ======= marker to the start - // of the next ======= or >>>>>>> marker. + // Consume everything from the start of an intermediate marker to the + // start of the next intermediate marker or the overall >>>>>>> marker. for pos < length { currentChar := text[pos] - if (currentChar == '=' || currentChar == '>') && rune(currentChar) != ch && isConflictMarkerTrivia(text, pos) { + if (currentChar == '=' || currentChar == '%' || currentChar == '\\' || currentChar == '+' || currentChar == '>') && rune(currentChar) != ch && isConflictMarkerTrivia(text, pos) { break } diff --git a/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.errors.txt b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.errors.txt new file mode 100644 index 0000000000000..cc6d9cf09d09c --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.errors.txt @@ -0,0 +1,33 @@ +conflictMarkerJujutsuTrivia1.ts(3,1): error TS1185: Merge conflict marker encountered. +conflictMarkerJujutsuTrivia1.ts(4,1): error TS1185: Merge conflict marker encountered. +conflictMarkerJujutsuTrivia1.ts(5,1): error TS1185: Merge conflict marker encountered. +conflictMarkerJujutsuTrivia1.ts(8,1): error TS1185: Merge conflict marker encountered. +conflictMarkerJujutsuTrivia1.ts(10,1): error TS1185: Merge conflict marker encountered. + + +==== conflictMarkerJujutsuTrivia1.ts (5 errors) ==== + class C { + foo() { + <<<<<<< conflict 1 of 1 + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + %%%%%%% diff from: puqzxvrm 9be6077e "call c()" + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + \\\\\\\ to: lnqukurm 3504bbcc "call a()" + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + - c(); + + a(); + +++++++ uxvuvmmx 392ce8b5 "call b()" + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + b(); + >>>>>>> conflict 1 of 1 ends + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. + } + + public bar() { } + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.js b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.js new file mode 100644 index 0000000000000..8e28d49b42731 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.js @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/conflictMarkerJujutsuTrivia1.ts] //// + +//// [conflictMarkerJujutsuTrivia1.ts] +class C { + foo() { +<<<<<<< conflict 1 of 1 +%%%%%%% diff from: puqzxvrm 9be6077e "call c()" +\\\\\\\ to: lnqukurm 3504bbcc "call a()" +- c(); ++ a(); ++++++++ uxvuvmmx 392ce8b5 "call b()" + b(); +>>>>>>> conflict 1 of 1 ends + } + + public bar() { } +} + + +//// [conflictMarkerJujutsuTrivia1.js] +"use strict"; +class C { + foo() { + } + bar() { } +} diff --git a/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.symbols b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.symbols new file mode 100644 index 0000000000000..3c809b9b6fb36 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.symbols @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/conflictMarkerJujutsuTrivia1.ts] //// + +=== conflictMarkerJujutsuTrivia1.ts === +class C { +>C : Symbol(C, Decl(conflictMarkerJujutsuTrivia1.ts, 0, 0)) + + foo() { +>foo : Symbol(C.foo, Decl(conflictMarkerJujutsuTrivia1.ts, 0, 9)) + +<<<<<<< conflict 1 of 1 +%%%%%%% diff from: puqzxvrm 9be6077e "call c()" +\\\\\\\ to: lnqukurm 3504bbcc "call a()" +- c(); ++ a(); ++++++++ uxvuvmmx 392ce8b5 "call b()" + b(); +>>>>>>> conflict 1 of 1 ends + } + + public bar() { } +>bar : Symbol(C.bar, Decl(conflictMarkerJujutsuTrivia1.ts, 10, 3)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.types b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.types new file mode 100644 index 0000000000000..b1e6191c294f3 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/conflictMarkerJujutsuTrivia1.types @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/conflictMarkerJujutsuTrivia1.ts] //// + +=== conflictMarkerJujutsuTrivia1.ts === +class C { +>C : C + + foo() { +>foo : () => void + +<<<<<<< conflict 1 of 1 +%%%%%%% diff from: puqzxvrm 9be6077e "call c()" +\\\\\\\ to: lnqukurm 3504bbcc "call a()" +- c(); ++ a(); ++++++++ uxvuvmmx 392ce8b5 "call b()" + b(); +>>>>>>> conflict 1 of 1 ends + } + + public bar() { } +>bar : () => void +} + diff --git a/tsc/testdata/tests/cases/compiler/conflictMarkerJujutsuTrivia1.ts b/tsc/testdata/tests/cases/compiler/conflictMarkerJujutsuTrivia1.ts new file mode 100644 index 0000000000000..9718daf171da2 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/conflictMarkerJujutsuTrivia1.ts @@ -0,0 +1,15 @@ +// @target: es2015 +class C { + foo() { +<<<<<<< conflict 1 of 1 +%%%%%%% diff from: puqzxvrm 9be6077e "call c()" +\\\\\\\ to: lnqukurm 3504bbcc "call a()" +- c(); ++ a(); ++++++++ uxvuvmmx 392ce8b5 "call b()" + b(); +>>>>>>> conflict 1 of 1 ends + } + + public bar() { } +}