Files
carbon-lang/toolchain/check/testdata/impl/no_prelude/impl_cycle.carbon
T
Dana JansensandGeoff Romer 53e4367c58 Add and correct tests of impl lookup on generic interfaces (#4974)
These tests expose cycles during deduction, when the generic parameters
in an impl statement require deduction and the impl clause that
satisfies them comes after the one containing the generic parameters.
This causes the same impl to be looked at repeatedly, and produces a
cycle diagnostic.

---------

Co-authored-by: Geoff Romer <gromer@google.com>
2025-02-20 15:48:15 +00:00

238 lines
9.4 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
//
// EXTRA-ARGS: --no-dump-sem-ir
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/no_prelude/impl_cycle.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/impl_cycle.carbon
// --- core.carbon
package Core;
interface As(Dest:! type) {
fn Convert[self: Self]() -> Dest;
}
interface ImplicitAs(Dest:! type) {
fn Convert[self: Self]() -> Dest;
}
// --- fail_impl_simple_cycle.carbon
library "[[@TEST_NAME]]";
interface Z {}
// This creates a dependency cycle with itself.
impl forall [T:! Z] T as Z {}
class Point {
impl as Z {}
}
fn F() {
// CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE+7]]:21: error: cycle found in lookup of interface <TODO: interface name> for type `Point` [ImplLookupCycle]
// CHECK:STDERR: ({} as Point) as (Point as Z);
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE-10]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [T:! Z] T as Z {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
({} as Point) as (Point as Z);
}
// --- fail_impl_cycle_one_generic_param.carbon
library "[[@TEST_NAME]]";
import Core;
interface ComparableWith(T:! type) {}
// This creates a dependency cycle with itself.
impl forall [U:! type, T:! ComparableWith(U)]
U as ComparableWith(T) {}
class C {}
class D {}
impl C as ComparableWith(D) {}
fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {}
fn F() {
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+20]]:3: error: cycle found in lookup of interface <TODO: interface name> for type `C` [ImplLookupCycle]
// CHECK:STDERR: Compare({} as C, {} as C);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-13]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)]
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-9]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+10]]:3: error: cannot implicitly convert from `type` to `ComparableWith(C)` [ImplicitAsConversionFailure]
// CHECK:STDERR: Compare({} as C, {} as C);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+7]]:3: note: type `type` does not implement interface `Core.ImplicitAs(ComparableWith(C))` [MissingImplInMemberAccessNote]
// CHECK:STDERR: Compare({} as C, {} as C);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-19]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
Compare({} as C, {} as C);
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+13]]:3: error: cycle found in lookup of interface <TODO: interface name> for type `D` [ImplLookupCycle]
// CHECK:STDERR: Compare({} as C, {} as D);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-35]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)]
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-38]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)]
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-34]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
Compare({} as C, {} as D);
}
// --- impl_recurse_with_simpler_type_no_cycle.carbon
library "[[@TEST_NAME]]";
import Core;
class Wraps(T:! type) {}
interface Printable {}
// If T is printable, so is Wraps(T).
impl forall [T:! Printable] Wraps(T) as Printable {}
class C {}
impl C as Printable {}
fn F() {
({} as C) as (C as Printable);
({} as Wraps(C)) as (Wraps(C) as Printable);
}
// --- impl_recurse_with_simpler_type_in_generic_param_no_cycle.carbon
library "[[@TEST_NAME]]";
import Core;
class Wraps(T:! type) {}
interface ComparableTo(T:! type) {}
// If U is comparable to T, then U is comparable to Wraps(T).
impl forall [T:! type, U:! ComparableTo(T)] U as ComparableTo(Wraps(T)) {}
// If U is comparable to T then Wraps(U) is comparable to T.
impl forall [T:! type, U:! ComparableTo(T)] Wraps(U) as ComparableTo(T) {}
class C {}
class D {}
impl C as ComparableTo(D) {}
fn F() {
({} as C) as (C as ComparableTo(D));
({} as C) as (C as ComparableTo(Wraps(D)));
({} as Wraps(C)) as (Wraps(C) as ComparableTo(D));
({} as Wraps(C)) as (Wraps(C) as ComparableTo(Wraps(D)));
}
// --- impl_recurse_with_simpler_type_in_generic_param_bidirectional_no_cycle.carbon
library "[[@TEST_NAME]]";
import Core;
// Implement this for a type in one direction.
interface ComparableTo(T:! type) {}
// Use this as a bound with two types in any direction.
interface ComparableWith(T:! type) {}
class C {}
class D {}
// C is comparable to D. This should imply:
// - C is ComparableWith(C).
// - C is ComparableWith(D).
// - D is ComparableWith(C).
impl C as ComparableTo(D) {}
// T is always ComparableWith(T).
impl forall [T:! type] T as ComparableWith(T) {}
// If U is ComparableTo(T), U is ComparableWith(T).
impl forall [T:! type, U:! ComparableTo(T)] U as ComparableWith(T) {}
// If U is ComparableTo(T), T is ComparableWith(U).
impl forall [T:! type, U:! ComparableTo(T)] T as ComparableWith(U) {}
fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {}
fn F() {
Compare({} as C, {} as C);
Compare({} as C, {} as D);
Compare({} as D, {} as C);
}
// --- deduce_cycle_without_symbolic.carbon
library "[[@TEST_NAME]]";
interface First {}
interface Second {}
// When answering a query "does T impl Second", we must avoid trying to deduce
// parameters for this impl. Not only is doing so unnecessary, it would start a new
// "does T impl Second" query, leading to a "cycle in impl lookup" error.
impl forall [T:! Second] T as First {}
impl forall [T:! type] T as Second {}
class C {}
fn F() {
({} as C) as (C as Second);
({} as C) as (C as First);
}
// --- fail_todo_deduce_cycle_with_symbolic.carbon
library "[[@TEST_NAME]]";
interface First(T:! type) {}
interface Second {}
// When answering a query "does T impl Second", we must avoid trying to deduce
// parameters for this impl. Not only is doing so unnecessary, it would start a new
// "does T impl Second" query, leading to a "cycle in impl lookup" error.
impl forall [T:! Second, U:! type] T as First(U) {}
impl forall [T:! type] T as Second {}
class C {}
// TODO: See the TODO in impl_lookup.cpp to reject impls where the interface
// does not match the query.
fn F() {
// CHECK:STDERR: fail_todo_deduce_cycle_with_symbolic.carbon:[[@LINE+7]]:17: error: cycle found in lookup of interface <TODO: interface name> for type `C` [ImplLookupCycle]
// CHECK:STDERR: ({} as C) as (C as Second);
// CHECK:STDERR: ^~~~~~~~~~~
// CHECK:STDERR: fail_todo_deduce_cycle_with_symbolic.carbon:[[@LINE-11]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [T:! Second, U:! type] T as First(U) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
({} as C) as (C as Second);
// CHECK:STDERR: fail_todo_deduce_cycle_with_symbolic.carbon:[[@LINE+10]]:17: error: cycle found in lookup of interface <TODO: interface name> for type `C` [ImplLookupCycle]
// CHECK:STDERR: ({} as C) as (C as First(C));
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_deduce_cycle_with_symbolic.carbon:[[@LINE-20]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [T:! Second, U:! type] T as First(U) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_deduce_cycle_with_symbolic.carbon:[[@LINE-23]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: impl forall [T:! Second, U:! type] T as First(U) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
({} as C) as (C as First(C));
}