mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-15 09:58:34 +00:00
Lexer diagnostics used a single `const char*` as their source location, which only allowed pointing at a single character rather than a run of characters. This limited the underlining of unrecognized tokens, and also made escape sequence diagnostics particularly strange by stopping at whatever point the lexer discovered the error and pointing only at that location. For example: `"\w"` was reported at the `w`, and `"\x"` at the closing `"`. This change tries to always keep the primary location of a diagnostic the point at which typing (inserting or deleting) might fix the error. So for `"\x"`, `\x` is underlined, but the position is at the `"` as that's where you would type a hex code. The lexer's emitter now takes a special lexing source location that represents either a single position _between_ two characters, a single character, or a range of the source buffer. The lexer diagnostics are updated to construct these for the character range as appropriate. Parser diagnostics for a missing token were located at the _next_ token, which is particularly confusing for terminators like missing `;`s. Now they are located at a position after the previous token, with or without a space depending on the token, but typically on the same line. Diagnostics still sort by how far the parser has read. The parser diagnostics for unclosed groups also now attaches a label to the opening token when it is on a separate line. And the diagnostics for mismatched indent in a multi-line string attaches a label to the closing `'''` that establishes that indent. There are likely more location improvements we should do here, but this seemed like a reasonable incremental improvement and is what Claude found when doing an initial audit. One example where I think we should make further improvements is around suggesting raw identifiers when we find an unexpected `Cpp` or `Core` or `base`. We do this consistently now, but raw identifiers should be rare. A TODO is added for these cases. Assisted-by: Claude Code --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
268 lines
8.7 KiB
Plaintext
268 lines
8.7 KiB
Plaintext
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/redeclaration.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/redeclaration.carbon
|
|
|
|
// --- redeclaration_no_class.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
impl {} as Z;
|
|
impl {} as Z {}
|
|
|
|
// --- redeclaration_in_class.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
// `impl as Z` is normalized to `impl Self as Z` so they are treated as
|
|
// syntactically the same.
|
|
class C {
|
|
impl as Z;
|
|
impl as Z;
|
|
impl Self as Z {}
|
|
}
|
|
|
|
class D {
|
|
impl Self as Z;
|
|
impl Self as Z;
|
|
impl as Z {}
|
|
}
|
|
|
|
// --- fail_todo_redeclaration_reenter_class.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C;
|
|
|
|
class C {
|
|
impl as Z;
|
|
}
|
|
|
|
// TODO: This should typecheck (see #5366).
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class.carbon:[[@LINE+6]]:9: error: expected expression [ExpectedExpr]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class.carbon:[[@LINE+4]]:9-10: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class.carbon:[[@LINE+2]]:14: error: expected `as` in `impl` declaration [ImplExpectedAs]
|
|
// CHECK:STDERR:
|
|
impl C.(as Z) {}
|
|
|
|
// --- fail_todo_redeclaration_reenter_class_explicit_self.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C;
|
|
|
|
class C {
|
|
impl Self as Z;
|
|
}
|
|
|
|
// TODO: This should typecheck (see #5366).
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_explicit_self.carbon:[[@LINE+6]]:9-12: error: name `Self` not found [NameNotFound]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_explicit_self.carbon:[[@LINE+4]]:19: error: expected `as` in `impl` declaration [ImplExpectedAs]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_explicit_self.carbon:[[@LINE+2]]:1-21: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
|
|
// CHECK:STDERR:
|
|
impl C.(Self as Z) {}
|
|
|
|
// --- fail_todo_redeclaration_reenter_class_mixed_self_outside.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C {
|
|
impl as Z;
|
|
}
|
|
|
|
// TODO: This should typecheck (see #5366).
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_mixed_self_outside.carbon:[[@LINE+6]]:9-12: error: name `Self` not found [NameNotFound]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_mixed_self_outside.carbon:[[@LINE+4]]:19: error: expected `as` in `impl` declaration [ImplExpectedAs]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_mixed_self_outside.carbon:[[@LINE+2]]:1-21: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
|
|
// CHECK:STDERR:
|
|
impl C.(Self as Z) {}
|
|
|
|
// --- fail_todo_redeclaration_reenter_class_mixed_self_inside.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C {
|
|
impl Self as Z;
|
|
}
|
|
|
|
// TODO: This should typecheck (see #5366).
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_mixed_self_inside.carbon:[[@LINE+6]]:9: error: expected expression [ExpectedExpr]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_mixed_self_inside.carbon:[[@LINE+4]]:9-10: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_todo_redeclaration_reenter_class_mixed_self_inside.carbon:[[@LINE+2]]:14: error: expected `as` in `impl` declaration [ImplExpectedAs]
|
|
// CHECK:STDERR:
|
|
impl C.(as Z) {}
|
|
|
|
// --- fail_redeclaration_inside_class_is_separate_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C;
|
|
impl C as Z;
|
|
|
|
class C {
|
|
// CHECK:STDERR: fail_redeclaration_inside_class_is_separate_impl.carbon:[[@LINE+1]]:3-15: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure]
|
|
impl C as Z {}
|
|
}
|
|
|
|
// CHECK:STDERR: fail_redeclaration_inside_class_is_separate_impl.carbon:[[@LINE+2]]:1-13: note: other `impl` here [ImplNonFinalSameTypeStructureNote]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
|
|
// --- fail_redeclaration_outside_class_is_separate_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C {
|
|
impl C as Z {}
|
|
}
|
|
|
|
// CHECK:STDERR: fail_redeclaration_outside_class_is_separate_impl.carbon:[[@LINE+3]]:1-13: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure]
|
|
// CHECK:STDERR: fail_redeclaration_outside_class_is_separate_impl.carbon:[[@LINE-4]]:3-15: note: other `impl` here [ImplNonFinalSameTypeStructureNote]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
|
|
// --- fail_redeclaration_in_block_scope_is_separate_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
fn F() {
|
|
musteval fn G() -> auto {
|
|
class C {}
|
|
impl C as Z {}
|
|
return C;
|
|
}
|
|
// This is not a redeclaration, since it's in a different scope.
|
|
// CHECK:STDERR: fail_redeclaration_in_block_scope_is_separate_impl.carbon:[[@LINE+3]]:3-17: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure]
|
|
// CHECK:STDERR: fail_redeclaration_in_block_scope_is_separate_impl.carbon:[[@LINE-5]]:5-17: note: other `impl` here [ImplNonFinalSameTypeStructureNote]
|
|
// CHECK:STDERR:
|
|
impl G() as Z {}
|
|
}
|
|
|
|
// --- redecl_of_imported_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
class C {}
|
|
impl C as Z {}
|
|
|
|
// --- fail_redecl_of_imported_impl.impl.carbon
|
|
impl library "[[@TEST_NAME]]";
|
|
|
|
// CHECK:STDERR: fail_redecl_of_imported_impl.impl.carbon:[[@LINE+2]]:1-13: error: redeclaration of imported impl [RedeclImportedImpl]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
|
|
// --- decl_of_imported_impl_in_new_scope.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
class C {}
|
|
impl C as Z {}
|
|
|
|
// --- fail_decl_of_imported_impl_in_new_scope.impl.carbon
|
|
impl library "[[@TEST_NAME]]";
|
|
|
|
class D {
|
|
// This is not treated as a redeclaration since it is in a different scope.
|
|
// But that means it overlaps fully with the impl from the api file, which is
|
|
// a separate error.
|
|
|
|
// CHECK:STDERR: fail_decl_of_imported_impl_in_new_scope.impl.carbon:[[@LINE+3]]:3-15: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure]
|
|
// CHECK:STDERR: decl_of_imported_impl_in_new_scope.carbon:5:1-13: note: other `impl` here [ImplNonFinalSameTypeStructureNote]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
}
|
|
|
|
// --- fail_redecl_in_fn_scope.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
fn F() {
|
|
class C {}
|
|
impl C as Z;
|
|
// CHECK:STDERR: fail_redecl_in_fn_scope.carbon:[[@LINE+4]]:3-15: error: impl redeclaration not in a declarative scope; redeclaration is allowed only in a class or namespace [ImplDeclInInvalidScope]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_redecl_in_fn_scope.carbon:[[@LINE-3]]:3-14: error: impl declared but not defined [ImplMissingDefinition]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
}
|
|
|
|
// --- fail_redecl_in_different_fn_scope.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
class C {}
|
|
|
|
fn F() {
|
|
impl C as Z;
|
|
}
|
|
|
|
fn G() {
|
|
// CHECK:STDERR: fail_redecl_in_different_fn_scope.carbon:[[@LINE+4]]:3-15: error: impl redeclaration not in a declarative scope; redeclaration is allowed only in a class or namespace [ImplDeclInInvalidScope]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_redecl_in_different_fn_scope.carbon:[[@LINE-6]]:3-14: error: impl declared but not defined [ImplMissingDefinition]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
}
|
|
|
|
// --- fail_redecl_in_block_scope.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
fn F() {
|
|
if (true) {
|
|
class C {}
|
|
impl C as Z;
|
|
// CHECK:STDERR: fail_redecl_in_block_scope.carbon:[[@LINE+4]]:5-17: error: impl redeclaration not in a declarative scope; redeclaration is allowed only in a class or namespace [ImplDeclInInvalidScope]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_redecl_in_block_scope.carbon:[[@LINE-3]]:5-16: error: impl declared but not defined [ImplMissingDefinition]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
}
|
|
}
|
|
|
|
// --- fail_redecl_in_different_block_scope.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
class C {}
|
|
|
|
fn F() {
|
|
if (true) {
|
|
impl C as Z;
|
|
}
|
|
if (true) {
|
|
// CHECK:STDERR: fail_redecl_in_different_block_scope.carbon:[[@LINE+4]]:5-17: error: impl redeclaration not in a declarative scope; redeclaration is allowed only in a class or namespace [ImplDeclInInvalidScope]
|
|
// CHECK:STDERR:
|
|
// CHECK:STDERR: fail_redecl_in_different_block_scope.carbon:[[@LINE-5]]:5-16: error: impl declared but not defined [ImplMissingDefinition]
|
|
// CHECK:STDERR:
|
|
impl C as Z {}
|
|
}
|
|
}
|