mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
If an earlier impl may match a more specific query, then later impls can not be treated as final for the given query. See https://github.com/carbon-language/carbon-lang/blob/de8b03faa3178ae683d8e7124fbcba81eb88e00c/proposals/p005337-interface-extension-and-final-impl-update.md#using-associated-constants-from-impls-in-a-final-match_first
475 lines
15 KiB
Plaintext
475 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/none.carbon
|
|
// ^ARGS: -v compile %s
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/match_first/prioritization.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/match_first/prioritization.carbon
|
|
|
|
// --- overlap_allowed_in_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
// --- fail_overlap_not_allowed_in_different_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
// CHECK:STDERR: fail_overlap_not_allowed_in_different_match_first.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: X] T as Z where .Z1 = {.x: type} {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR: fail_overlap_not_allowed_in_different_match_first.carbon:[[@LINE-4]]:1: note: other `impl` here [ImplNonFinalSameTypeStructureNote]
|
|
// CHECK:STDERR: impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
}
|
|
match_first {
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
// --- lookup_overlapping_impl.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
fn F() {
|
|
class FC;
|
|
impl FC as Y {}
|
|
// Since GC impls Y and not X, the .y impl should be selected.
|
|
{.y = type} as FC.(Z.Z1);
|
|
}
|
|
|
|
fn G() {
|
|
class GC;
|
|
impl GC as X {}
|
|
// Since GC impls X and not Y, the .x impl should be selected.
|
|
{.x = type} as GC.(Z.Z1);
|
|
}
|
|
|
|
// --- prioritization_first_declarared.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
// The match_first block is in the same order that the impls are introduced.
|
|
// This makes us prioritize the first introduced impl.
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
fn F() {
|
|
class C;
|
|
impl C as Y {}
|
|
impl C as X {}
|
|
// Since C impls X and Y, the first one in the match_first block
|
|
// should be selected, which is the .y impl.
|
|
{.y = type} as C.(Z.Z1);
|
|
}
|
|
|
|
// --- prioritization_second_declarared.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
// The match_first block is in the opposite order that the impls are
|
|
// introduced. This makes us prioritize the second introduced impl.
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
}
|
|
|
|
fn F() {
|
|
class C;
|
|
impl C as Y {}
|
|
impl C as X {}
|
|
// Since C impls X and Y, the first one in the match_first block
|
|
// should be selected, which is the .x impl.
|
|
{.x = type} as C.(Z.Z1);
|
|
}
|
|
|
|
// --- fail_prioritization_does_not_choose_second_declarared.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
// The match_first block is in the same order that the impls are introduced.
|
|
// This makes us prioritize the first introduced impl.
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
fn F() {
|
|
class C;
|
|
impl C as Y {}
|
|
impl C as X {}
|
|
// Since C impls X and Y, the first one in the match_first block
|
|
// should be selected, which is the .y impl. So this should fail.
|
|
// CHECK:STDERR: fail_prioritization_does_not_choose_second_declarared.carbon:[[@LINE+4]]:3: error: struct `{.y: type}` has no field named `x` [StructInitUnexpectedFieldInLiteral]
|
|
// CHECK:STDERR: {.x = type} as C.(Z.Z1);
|
|
// CHECK:STDERR: ^~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
{.x = type} as C.(Z.Z1);
|
|
}
|
|
|
|
// --- fail_prioritization_does_not_choose_first_declarared.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
// The match_first block is in the opposite order that the impls are
|
|
// introduced. This makes us prioritize the second introduced impl.
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
}
|
|
|
|
fn F() {
|
|
class C;
|
|
impl C as Y {}
|
|
impl C as X {}
|
|
// Since C impls X and Y, the first one in the match_first block
|
|
// should be selected, which is the .x impl. So this should fail.
|
|
// CHECK:STDERR: fail_prioritization_does_not_choose_first_declarared.carbon:[[@LINE+4]]:3: error: struct `{.x: type}` has no field named `y` [StructInitUnexpectedFieldInLiteral]
|
|
// CHECK:STDERR: {.y = type} as C.(Z.Z1);
|
|
// CHECK:STDERR: ^~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
{.y = type} as C.(Z.Z1);
|
|
}
|
|
|
|
// --- final_prioritization_first_declarared.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
final match_first {
|
|
// The match_first block is in the same order that the impls are introduced.
|
|
// This makes us prioritize the first introduced impl.
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
fn F[U: type where .Self impls X and .Self impls Y]() {
|
|
// Since U impls X and Y, the first one in the match_first block
|
|
// should be selected, which is the .y impl.
|
|
{.y = type} as U.(Z.Z1);
|
|
}
|
|
|
|
// --- final_prioritization_second_declarared.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
final match_first {
|
|
// The match_first block is in the opposite order that the impls are
|
|
// introduced. This makes us prioritize the second introduced impl.
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
}
|
|
|
|
fn F[U: type where .Self impls X and .Self impls Y]() {
|
|
// Since U impls X and Y, the first one in the match_first block
|
|
// should be selected, which is the .x impl.
|
|
{.x = type} as U.(Z.Z1);
|
|
}
|
|
|
|
// --- fail_match_first_does_not_imply_final.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type} {}
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type} {}
|
|
|
|
match_first {
|
|
// The match_first block is in the same order that the impls are introduced.
|
|
// This makes us prioritize the first introduced impl.
|
|
impl forall [T: Y] T as Z where .Z1 = {.y: type};
|
|
impl forall [T: X] T as Z where .Z1 = {.x: type};
|
|
}
|
|
|
|
fn F[U: type where .Self impls X and .Self impls Y]() {
|
|
// The impls are not final, so we can't use the concrete `.Z1` value provided
|
|
// by the impls here. This conversion should fail.
|
|
// CHECK:STDERR: fail_match_first_does_not_imply_final.carbon:[[@LINE+4]]:3: error: `Core.As` implicitly referenced here, but package `Core` not found [CoreNotFound]
|
|
// CHECK:STDERR: {.y = type} as U.(Z.Z1);
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
{.y = type} as U.(Z.Z1);
|
|
}
|
|
|
|
// --- non_final_more_specific_than_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
interface W {}
|
|
|
|
class C(T: type);
|
|
impl forall [T: type] C(T) as W {}
|
|
impl forall [T: type] C(T) as Y {}
|
|
|
|
// These impls have different type structures, but they overlap. For non-final
|
|
// impls we want to choose the most specific one (which will be the middle one),
|
|
// even if there is a match_first block for the others (but not for the middle
|
|
// one).
|
|
impl forall [T: W] () as Z(T) where .Z1 = {.w: type} {}
|
|
impl forall [T: X] () as Z(C(T)) where .Z1 = {.x: type} {}
|
|
impl forall [T: Y] () as Z(T) where .Z1 = {.y: type} {}
|
|
|
|
match_first {
|
|
impl forall [T: W] () as Z(T) where .Z1 = {.w: type};
|
|
impl forall [T: Y] () as Z(T) where .Z1 = {.y: type};
|
|
}
|
|
|
|
fn F() {
|
|
class D;
|
|
impl D as X {}
|
|
{.x = type} as ().(Z(C(D)).Z1);
|
|
}
|
|
|
|
// --- non_final_overlap_in_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
interface W {}
|
|
|
|
class C(T: type);
|
|
impl forall [T: type] C(T) as W {}
|
|
impl forall [T: type] C(T) as Y {}
|
|
|
|
// These impls have different type structures, but they overlap. For non-final
|
|
// impls we would choose the most specific one (which will be the middle one),
|
|
// but then we find it is in a match_first block. So we use the first matching
|
|
// impl in that block instead.
|
|
impl forall [T: W] () as Z(T) where .Z1 = {.w: type} {}
|
|
impl forall [T: X] () as Z(C(T)) where .Z1 = {.x: type} {}
|
|
impl forall [T: Y] () as Z(T) where .Z1 = {.y: type} {}
|
|
|
|
match_first {
|
|
impl forall [T: W] () as Z(T) where .Z1 = {.w: type};
|
|
impl forall [T: X] () as Z(C(T)) where .Z1 = {.x: type};
|
|
impl forall [T: Y] () as Z(T) where .Z1 = {.y: type};
|
|
}
|
|
|
|
fn F() {
|
|
class D;
|
|
impl D as X {}
|
|
{.w = type} as ().(Z(C(D)).Z1);
|
|
}
|
|
|
|
// --- final_overlap_in_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
interface Y {}
|
|
interface X {}
|
|
interface W {}
|
|
|
|
class C(T: type);
|
|
impl forall [T: type] C(T) as W {}
|
|
impl forall [T: type] C(T) as Y {}
|
|
|
|
// These impls have different type structures, but they overlap. Overlapping
|
|
// final impls are always in a match_first block together, so we will use the
|
|
// first impl from that block, not the most specific one.
|
|
impl forall [T: W] () as Z(T) where .Z1 = {.w: type} {}
|
|
impl forall [T: X] () as Z(C(T)) where .Z1 = {.x: type} {}
|
|
impl forall [T: Y] () as Z(T) where .Z1 = {.y: type} {}
|
|
|
|
final match_first {
|
|
impl forall [T: Y] () as Z(T) where .Z1 = {.y: type};
|
|
impl forall [T: X] () as Z(C(T)) where .Z1 = {.x: type};
|
|
impl forall [T: W] () as Z(T) where .Z1 = {.w: type};
|
|
}
|
|
|
|
fn F[U: X]() {
|
|
{.y = type} as ().(Z(C(U)).Z1);
|
|
}
|
|
|
|
// --- fail_non_final_match_first_is_not_final.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
interface Y {}
|
|
|
|
class C(T: type);
|
|
|
|
impl forall [T: Y] () as Z(C(T)) where .Z1 = {.y: type} {}
|
|
|
|
match_first {
|
|
impl forall [T: Y] () as Z(C(T)) where .Z1 = {.y: type};
|
|
}
|
|
|
|
fn F(generic T: Y) {
|
|
// This query is not concrete, so the impl will not give a final witness, so
|
|
// we can't use the rewrite constraint's RHS here.
|
|
// CHECK:STDERR: fail_non_final_match_first_is_not_final.carbon:[[@LINE+4]]:3: error: `Core.As` implicitly referenced here, but package `Core` not found [CoreNotFound]
|
|
// CHECK:STDERR: {.y = type} as ().(Z(C(T)).Z1);
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
{.y = type} as ().(Z(C(T)).Z1);
|
|
}
|
|
|
|
// --- final_not_overlapping_query_in_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
interface W {}
|
|
|
|
class C(T: type);
|
|
class D(T: type);
|
|
|
|
final match_first {
|
|
// Arbitrary impl at the start of the block that doesn't overlap anything.
|
|
impl C({}) as W {}
|
|
|
|
// A more specific impl comes first.
|
|
impl forall [T: type] () as Z(C(T)) where .Z1 = {.c: type} {}
|
|
// Another different but more specific impl comes next.
|
|
impl forall [T: type] () as Z(D(T)) where .Z1 = {.d: type} {}
|
|
// A more general impl comes last. While this catches more things, if T
|
|
// _could_ be specialized as `C(T)` or `D(T)` in the future, we can't use this
|
|
// impl as final.
|
|
impl forall [T: type] () as Z(T) where .Z1 = {.t: type} {}
|
|
}
|
|
|
|
fn F() {
|
|
// The first matching impl in the match_first is also the most specific
|
|
// overlapping impl, so it's considered final.
|
|
{.c = type} as ().(Z(C({})).Z1);
|
|
|
|
// The first matching impl in the match_first is also the most specific
|
|
// overlapping impl, so it's considered final.
|
|
{.d = type} as ().(Z(D({})).Z1);
|
|
|
|
// Since this can't match C(T) or D(T), the first matching impl in the
|
|
// match_first is also the most specific overlapping impl, so it's considered
|
|
// final.
|
|
class E;
|
|
{.t = type} as ().(Z(E).Z1);
|
|
}
|
|
|
|
// --- fail_final_overlapping_query_in_match_first.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
|
|
class C(T: type);
|
|
|
|
final match_first {
|
|
// A more specific impl comes first.
|
|
impl forall [T: type] () as Z(C(T)) where .Z1 = {.c: type} {}
|
|
// A more general impl comes last. While this catches more things, if T
|
|
// _could_ be specialized as `C(T)` in the future, we can't use this impl as
|
|
// final.
|
|
impl forall [T: type] () as Z(T) where .Z1 = {.t: type} {}
|
|
}
|
|
|
|
fn F(generic T: type) {
|
|
// Could match C(T) later, but doesn't yet. So it's not considered final.
|
|
// CHECK:STDERR: fail_final_overlapping_query_in_match_first.carbon:[[@LINE+4]]:3: error: `Core.As` implicitly referenced here, but package `Core` not found [CoreNotFound]
|
|
// CHECK:STDERR: {.t = type} as ().(Z(T).Z1);
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
{.t = type} as ().(Z(T).Z1);
|
|
}
|
|
|
|
// --- fail_final_overlapping_query_in_match_first_reverse_order.carbon
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface Z(T: type) { let Z1: type; }
|
|
|
|
class C(T: type);
|
|
|
|
// The match_first is in the opposite order as the impls are introduced.
|
|
impl forall [T: type] () as Z(T) where .Z1 = {.t: type} {}
|
|
impl forall [T: type] () as Z(C(T)) where .Z1 = {.c: type} {}
|
|
|
|
final match_first {
|
|
// A more specific impl comes first.
|
|
impl forall [T: type] () as Z(C(T)) where .Z1 = {.c: type};
|
|
// A more general impl comes last. While this catches more things, if T
|
|
// _could_ be specialized as `C(T)` in the future, we can't use this impl as
|
|
// final.
|
|
impl forall [T: type] () as Z(T) where .Z1 = {.t: type};
|
|
}
|
|
|
|
fn F(generic T: type) {
|
|
// Could match C(T) later, but doesn't yet. So it's not considered final.
|
|
// CHECK:STDERR: fail_final_overlapping_query_in_match_first_reverse_order.carbon:[[@LINE+4]]:3: error: `Core.As` implicitly referenced here, but package `Core` not found [CoreNotFound]
|
|
// CHECK:STDERR: {.t = type} as ().(Z(T).Z1);
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
{.t = type} as ().(Z(T).Z1);
|
|
}
|