mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-29 15:34:58 +01:00
The orphan rule is defined here: https://docs.carbon-lang.dev/docs/design/generics/details.html#orphan-rule **Orphan rule:** Some name from the type structure of an `impl` declaration must be defined in the same library as the `impl`, that is some name must be *local*. Update tests that were running afoul of the orphan rule unintentionally. Add tests that do violate the rule intentionally and test edge cases.
423 lines
15 KiB
Plaintext
423 lines
15 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/lookup/impl_overlap.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/impl_overlap.carbon
|
|
|
|
// ============================================================================
|
|
// Setup files
|
|
// ============================================================================
|
|
|
|
// --- interface_z.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
// --- interface_z_with_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
// Add an extra unused interface to bump `Z`'s id up so that it doesn't
|
|
// accidentally match the id assigned to the imported copy of `Z`.
|
|
interface Other(T:! type) {}
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
final impl forall [T:! type] T as Z(T) {}
|
|
|
|
// --- type_d.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
class D(T:! type) {}
|
|
|
|
// ============================================================================
|
|
// Test files
|
|
// ============================================================================
|
|
|
|
// --- final_impl_with_interface_generic_self.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
final impl forall [T:! type] T as Z {}
|
|
|
|
// --- final_impl_with_interface_concrete_self_same_file.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C {}
|
|
|
|
final impl C as Z {}
|
|
|
|
// --- final_impl_with_interface_concrete_self_same_file_defined_after.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C;
|
|
|
|
final impl C as Z {}
|
|
|
|
class C {}
|
|
|
|
// --- final_impl_with_interface_concrete_self_from_other_file.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "type_d";
|
|
|
|
interface Z {}
|
|
|
|
// The final impl is for a root self type from another file, but the interface
|
|
// is in the same file, so this is valid.
|
|
final impl D(()) as Z {}
|
|
|
|
// --- final_impl_with_interface_symbolic_self_from_other_file.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "type_d";
|
|
|
|
interface Z {}
|
|
|
|
// The root self type is from another file, but the interface is from this file.
|
|
// This tests the self type being a symbolic type due to the type parameter T.
|
|
final impl forall [T:! type] D(T) as Z {}
|
|
|
|
// --- fail_multiple_finals_overlap_with_interface.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
final impl forall [T:! type] T as Z(T) {}
|
|
|
|
// The final impl here overlaps with the final impl above, but is not in a
|
|
// match_first.
|
|
//
|
|
// CHECK:STDERR: fail_multiple_finals_overlap_with_interface.carbon:[[@LINE+7]]:1: error: `final impl` overlaps with `final impl` from same file outside a `match_first` block [FinalImplOverlapsSameFile]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_multiple_finals_overlap_with_interface.carbon:[[@LINE-8]]:1: note: other `final impl` here [FinalImplOverlapsSameFileNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl forall [T:! type] T as Z(()) {}
|
|
|
|
class C {}
|
|
|
|
// The final impl here overlaps with the first final impl above, but is not in
|
|
// a match_first.
|
|
//
|
|
// CHECK:STDERR: fail_multiple_finals_overlap_with_interface.carbon:[[@LINE+7]]:1: error: `final impl` overlaps with `final impl` from same file outside a `match_first` block [FinalImplOverlapsSameFile]
|
|
// CHECK:STDERR: final impl C as Z({}) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_multiple_finals_overlap_with_interface.carbon:[[@LINE-22]]:1: note: other `final impl` here [FinalImplOverlapsSameFileNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl C as Z({}) {}
|
|
|
|
// --- fail_multiple_finals_overlap_with_self_type.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z";
|
|
|
|
class C {}
|
|
|
|
final impl C as Z(()) {}
|
|
|
|
// The final impl here overlaps with the first final impl above, but is not in
|
|
// a match_first.
|
|
//
|
|
// CHECK:STDERR: fail_multiple_finals_overlap_with_self_type.carbon:[[@LINE+7]]:1: error: `final impl` overlaps with `final impl` from same file outside a `match_first` block [FinalImplOverlapsSameFile]
|
|
// CHECK:STDERR: final impl forall [T:! type] C as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_multiple_finals_overlap_with_self_type.carbon:[[@LINE-8]]:1: note: other `final impl` here [FinalImplOverlapsSameFileNote]
|
|
// CHECK:STDERR: final impl C as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl forall [T:! type] C as Z(T) {}
|
|
|
|
// --- multiple_finals_with_nonoverlapping_with_interface.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "type_d";
|
|
|
|
interface Z {}
|
|
|
|
// Two final impls for D as Z, but they are not overlapping so they are allowed
|
|
// outside of match_first.
|
|
final impl D(()) as Z {}
|
|
final impl D({}) as Z {}
|
|
|
|
// --- multiple_finals_with_nonoverlapping_with_self_type.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z";
|
|
|
|
class C {}
|
|
|
|
// Two final impls for C as Z, but they are not overlapping so they are allowed
|
|
// outside of match_first.
|
|
final impl C as Z(()) {}
|
|
final impl C as Z({}) {}
|
|
|
|
// --- final_impl_with_root_self_type.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z";
|
|
|
|
class C(T:! type) {}
|
|
|
|
// Can provide a specialized final blanket impl for a type defined in the same
|
|
// file.
|
|
final impl forall [T:! type] C(T) as Z(T) {}
|
|
|
|
// --- fail_final_impl_with_both_interface_and_self_but_different_files.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z_with_impl";
|
|
|
|
class C {}
|
|
|
|
// Can't write a final impl in both the interface's file and the root self
|
|
// type's file (when they are different files).
|
|
//
|
|
// CHECK:STDERR: fail_final_impl_with_both_interface_and_self_but_different_files.carbon:[[@LINE+8]]:1: error: `final impl` overlaps with `final impl` from another file [FinalImplOverlapsDifferentFile]
|
|
// CHECK:STDERR: final impl C as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_impl_with_both_interface_and_self_but_different_files.carbon:[[@LINE-10]]:1: in import [InImport]
|
|
// CHECK:STDERR: interface_z_with_impl.carbon:9:1: note: imported `final impl` here [FinalImplOverlapsDifferentFileNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl C as Z(()) {}
|
|
|
|
// --- fail_final_overlaps_final_from_other_file.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z_with_impl";
|
|
|
|
class C {}
|
|
|
|
// This final impl is overlapped by a final impl in the interface file, and you
|
|
// can't write a final impl in two different files.
|
|
//
|
|
// CHECK:STDERR: fail_final_overlaps_final_from_other_file.carbon:[[@LINE+8]]:1: error: `final impl` overlaps with `final impl` from another file [FinalImplOverlapsDifferentFile]
|
|
// CHECK:STDERR: final impl C as Z(C) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_overlaps_final_from_other_file.carbon:[[@LINE-10]]:1: in import [InImport]
|
|
// CHECK:STDERR: interface_z_with_impl.carbon:9:1: note: imported `final impl` here [FinalImplOverlapsDifferentFileNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl C as Z(C) {}
|
|
|
|
// --- fail_final_overlaps_non_final_from_other_file.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z_with_impl";
|
|
|
|
class C {}
|
|
|
|
// This non-final impl is subsumed by a final impl in the interface file.
|
|
//
|
|
// CHECK:STDERR: fail_final_overlaps_non_final_from_other_file.carbon:[[@LINE+8]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal]
|
|
// CHECK:STDERR: impl C as Z(C) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_overlaps_non_final_from_other_file.carbon:[[@LINE-9]]:1: in import [InImport]
|
|
// CHECK:STDERR: interface_z_with_impl.carbon:9:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl C as Z(C) {}
|
|
|
|
// --- fail_final_root_self_type_not_defined.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z";
|
|
import library "type_d";
|
|
|
|
class C;
|
|
|
|
// The root type must be defined in the same library, not just declared.
|
|
//
|
|
// CHECK:STDERR: fail_final_root_self_type_not_defined.carbon:[[@LINE+4]]:1: error: `final impl` found in file that does not contain the root self type nor the interface definition [FinalImplInvalidFile]
|
|
// CHECK:STDERR: final impl C as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl C as Z(()) {}
|
|
|
|
// --- fail_final_different_file_from_self_and_interface.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z";
|
|
import library "type_d";
|
|
|
|
class C {}
|
|
|
|
// Can't make a final impl that is not in the same file as the self type nor
|
|
// the interface.
|
|
//
|
|
// CHECK:STDERR: fail_final_different_file_from_self_and_interface.carbon:[[@LINE+4]]:1: error: `final impl` found in file that does not contain the root self type nor the interface definition [FinalImplInvalidFile]
|
|
// CHECK:STDERR: final impl D(C) as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl D(C) as Z(()) {}
|
|
|
|
// --- fail_final_different_file_from_self_and_interface_with_generic_self.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import library "interface_z";
|
|
|
|
class C {}
|
|
|
|
// Can't make a final impl that is not in the same file as the self type nor
|
|
// the interface.
|
|
//
|
|
// CHECK:STDERR: fail_final_different_file_from_self_and_interface_with_generic_self.carbon:[[@LINE+4]]:1: error: `final impl` found in file that does not contain the root self type nor the interface definition [FinalImplInvalidFile]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(C) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl forall [T:! type] T as Z(C) {}
|
|
|
|
// --- fail_final_overlaps_earlier_non_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
// CHECK:STDERR: fail_final_overlaps_earlier_non_final_impl.carbon:[[@LINE+3]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal]
|
|
// CHECK:STDERR: impl () as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
|
impl () as Z(()) {}
|
|
|
|
// CHECK:STDERR: fail_final_overlaps_earlier_non_final_impl.carbon:[[@LINE+4]]:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl forall [T:! type] T as Z(T) {}
|
|
|
|
// --- fail_final_overlaps_later_non_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
final impl forall [T:! type] T as Z(T) {}
|
|
|
|
// CHECK:STDERR: fail_final_overlaps_later_non_final_impl.carbon:[[@LINE+7]]:1: error: `impl` will never be used [ImplFinalOverlapsNonFinal]
|
|
// CHECK:STDERR: impl () as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_overlaps_later_non_final_impl.carbon:[[@LINE-5]]:1: note: `final impl` declared here would always be used instead [ImplFinalOverlapsNonFinalNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl () as Z(()) {}
|
|
|
|
// --- fail_final_overlaps_earlier_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
class C {}
|
|
|
|
final impl C as Z(C) {}
|
|
|
|
// CHECK:STDERR: fail_final_overlaps_earlier_final_impl.carbon:[[@LINE+7]]:1: error: `final impl` overlaps with `final impl` from same file outside a `match_first` block [FinalImplOverlapsSameFile]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_overlaps_earlier_final_impl.carbon:[[@LINE-5]]:1: note: other `final impl` here [FinalImplOverlapsSameFileNote]
|
|
// CHECK:STDERR: final impl C as Z(C) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl forall [T:! type] T as Z(T) {}
|
|
|
|
// --- fail_final_overlaps_later_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
class C {}
|
|
|
|
final impl forall [T:! type] T as Z(T) {}
|
|
|
|
// CHECK:STDERR: fail_final_overlaps_later_final_impl.carbon:[[@LINE+7]]:1: error: `final impl` overlaps with `final impl` from same file outside a `match_first` block [FinalImplOverlapsSameFile]
|
|
// CHECK:STDERR: final impl C as Z(C) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_overlaps_later_final_impl.carbon:[[@LINE-5]]:1: note: other `final impl` here [FinalImplOverlapsSameFileNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl C as Z(C) {}
|
|
|
|
// --- fail_non_final_type_structure_matches_non_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
interface Y {}
|
|
|
|
impl forall [T:! Y] T as Z(T) {}
|
|
|
|
class C(T:! type);
|
|
|
|
// No diagnosis here as the type structure is unique.
|
|
impl forall [T:! type] T as Z(C(T)) {}
|
|
|
|
// CHECK:STDERR: fail_non_final_type_structure_matches_non_final_impl.carbon:[[@LINE+7]]:1: error: found non-final `impl` with the same type structure as another non-final `impl` [ImplNonFinalSameTypeStructure]
|
|
// CHECK:STDERR: impl forall [T:! type] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_non_final_type_structure_matches_non_final_impl.carbon:[[@LINE-10]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote]
|
|
// CHECK:STDERR: impl forall [T:! Y] T as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl forall [T:! type] T as Z(T) {}
|
|
|
|
// --- non_final_type_structure_same_shape_but_different_concrete_types.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z {}
|
|
|
|
class C {}
|
|
class D {}
|
|
|
|
impl C as Z {}
|
|
impl D as Z {}
|
|
|
|
// --- partial_overlap_type_structure_of_non_final_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
impl forall [T:! type] T as Z(T) {}
|
|
|
|
class C {}
|
|
// Partially overlaps the blanket impl, which is fine.
|
|
final impl C as Z(C) {}
|
|
|
|
class D {}
|
|
// Partially overlaps the blanket impl, which is fine.
|
|
impl D as Z(D) {}
|
|
|
|
// --- fail_final_overlap_where_each_is_more_specific_than_the_other.carbon
|
|
|
|
interface Z(T:! type) {}
|
|
|
|
class C(T:! type) {}
|
|
|
|
// This should be diagnosed as overlapping final impls outside a `match_first`.
|
|
// The first impl is more specific in the interface constraint. The second is
|
|
// more specific in the self type. They overlap for the query `C(()) as Z(())`
|
|
// but neither impl is completely more specific than the other.
|
|
final impl forall [T:! type] C(T) as Z(()) {}
|
|
// CHECK:STDERR: fail_final_overlap_where_each_is_more_specific_than_the_other.carbon:[[@LINE+7]]:1: error: `final impl` overlaps with `final impl` from same file outside a `match_first` block [FinalImplOverlapsSameFile]
|
|
// CHECK:STDERR: final impl forall [T:! type] C(()) as Z(T) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_final_overlap_where_each_is_more_specific_than_the_other.carbon:[[@LINE-4]]:1: note: other `final impl` here [FinalImplOverlapsSameFileNote]
|
|
// CHECK:STDERR: final impl forall [T:! type] C(T) as Z(()) {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
final impl forall [T:! type] C(()) as Z(T) {}
|