mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-02 22:02:51 +01:00
A nested designator like `.(X.X1).(Y.Y1)` results in nested ImplWitnessAccess instructions, which can produce cycles in the toolchain easily when replacing `.Self`. First, when constructing a facet type like `V:! Z where .Z1 impls (Y where .Y1 = U)` we substitute replace `.Self` in the nested facet type, and in this case we replace `.Self` with `.Z1` which contains a `.Self` of its own. This was coming from us being lazy about replacing `.Self` in an `impl as` declaration, such as `impl C as Z where .Z1 = .Self`. The self type is known there, so we can more eagerly replace `.Self` as we do in a `require impls` declaration. Then the replacement for `.Self` never comes with a `.Self` that needs to also be replaced. Any resulting `.Self` would always be the top-level one. Second, when evaluating ImplWitnessAccess, we were replacing .Self in the LHS of rewrite constraints, but the `.Self` may itself have a type that contains rewrite constraints. If one of those rewrite constraints has nested ImplWitnessAccess instructions, we evaluate the new ImplWitnessAccess, which again finds rewrite constraints to replace `.Self` in, and we repeat forever. For this one we just stop replacing .Self in the LHS of rewrite constraints. Since they are always against .Self, we can always look in the access facet's type for a value. While fixing ImplWitness access, also correct the lookup to search through the types of nested ImplWitnessAccess instructions to find a rewrite value, since it may find it at any level up to the eventual `.Self`. --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
242 lines
11 KiB
Plaintext
242 lines
11 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/primitives.carbon
|
|
// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only".
|
|
// EXTRA-ARGS: --dump-sem-ir-ranges=if-present
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/fail_impl_bad_interface.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/fail_impl_bad_interface.carbon
|
|
|
|
// --- fail_impl_as_false.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
// CHECK:STDERR: fail_impl_as_false.carbon:[[@LINE+7]]:13: error: cannot implicitly convert non-type value of type `bool` to `type` [ConversionFailureNonTypeToFacet]
|
|
// CHECK:STDERR: impl i32 as false {}
|
|
// CHECK:STDERR: ^~~~~
|
|
// CHECK:STDERR: fail_impl_as_false.carbon:[[@LINE+4]]:13: note: type `bool` does not implement interface `Core.ImplicitAs(type)` [MissingImplInMemberAccessInContext]
|
|
// CHECK:STDERR: impl i32 as false {}
|
|
// CHECK:STDERR: ^~~~~
|
|
// CHECK:STDERR:
|
|
impl i32 as false {}
|
|
|
|
// --- fail_impl_as_type.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
// CHECK:STDERR: fail_impl_as_type.carbon:[[@LINE+4]]:1: error: impl as non-facet type `type` [ImplAsNonFacetType]
|
|
// CHECK:STDERR: impl bool as type {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl bool as type {}
|
|
|
|
// --- fail_impl_as_type_where.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
// CHECK:STDERR: fail_impl_as_type_where.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
|
// CHECK:STDERR: impl f64 as type where .Self impls type {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl f64 as type where .Self impls type {}
|
|
|
|
// --- fail_impl_as_type_where_impls_interface.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
interface I {}
|
|
|
|
// CHECK:STDERR: fail_impl_as_type_where_impls_interface.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
|
// CHECK:STDERR: impl {.a: bool} as type where .Self impls I {}
|
|
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// CHECK:STDERR:
|
|
impl {.a: bool} as type where .Self impls I {}
|
|
|
|
// CHECK:STDOUT: --- fail_impl_as_false.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
|
|
// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete]
|
|
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
|
|
// CHECK:STDOUT: %false: bool = bool_literal false [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
|
|
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: imports {
|
|
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
|
// CHECK:STDOUT: .Int = %Core.Int
|
|
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
|
|
// CHECK:STDOUT: import Core//prelude
|
|
// CHECK:STDOUT: import Core//prelude/...
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic]
|
|
// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/parts/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: file {
|
|
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
|
// CHECK:STDOUT: .Core = imports.%Core
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.import = import Core
|
|
// CHECK:STDOUT: %.loc11: type = converted @i32.as.<error>.impl.%false, <error> [concrete = <error>]
|
|
// CHECK:STDOUT: impl_decl @i32.as.<error>.impl [concrete] {} {
|
|
// CHECK:STDOUT: %i32: type = type_literal constants.%i32 [concrete = constants.%i32]
|
|
// CHECK:STDOUT: %false: bool = bool_literal false [concrete = constants.%false]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: impl @i32.as.<error>.impl: %i32 as <error> {
|
|
// CHECK:STDOUT: !members:
|
|
// CHECK:STDOUT: witness = <error>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: --- fail_impl_as_type.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete]
|
|
// CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: imports {
|
|
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
|
// CHECK:STDOUT: .Bool = %Core.Bool
|
|
// CHECK:STDOUT: import Core//prelude
|
|
// CHECK:STDOUT: import Core//prelude/...
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.Bool: %Bool.type = import_ref Core//prelude/parts/bool, Bool, loaded [concrete = constants.%Bool]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: file {
|
|
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
|
// CHECK:STDOUT: .Core = imports.%Core
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.import = import Core
|
|
// CHECK:STDOUT: impl_decl @bool.as.<error>.impl [concrete] {} {
|
|
// CHECK:STDOUT: %.loc8_6: type = type_literal bool [concrete = bool]
|
|
// CHECK:STDOUT: %.loc8_14: type = type_literal type [concrete = type]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: impl @bool.as.<error>.impl: %.loc8_6 as <error> {
|
|
// CHECK:STDOUT: !members:
|
|
// CHECK:STDOUT: witness = <error>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: --- fail_impl_as_type_where.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete]
|
|
// CHECK:STDOUT: %Float.type: type = generic_class_type @Float [concrete]
|
|
// CHECK:STDOUT: %Float.generic: %Float.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %f64: type = class_type @Float, @Float(%int_64) [concrete]
|
|
// CHECK:STDOUT: %type: type = facet_type <type> [concrete]
|
|
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self]
|
|
// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self [symbolic_self]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: imports {
|
|
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
|
// CHECK:STDOUT: .Float = %Core.Float
|
|
// CHECK:STDOUT: import Core//prelude
|
|
// CHECK:STDOUT: import Core//prelude/...
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.Float: %Float.type = import_ref Core//prelude/parts/float, Float, loaded [concrete = constants.%Float.generic]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: file {
|
|
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
|
// CHECK:STDOUT: .Core = imports.%Core
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.import = import Core
|
|
// CHECK:STDOUT: impl_decl @f64.as.<error>.impl [concrete] {} {
|
|
// CHECK:STDOUT: %f64: type = type_literal constants.%f64 [concrete = constants.%f64]
|
|
// CHECK:STDOUT: %.loc8_13: type = type_literal type [concrete = type]
|
|
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
|
|
// CHECK:STDOUT: %.Self.ref: %type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
|
|
// CHECK:STDOUT: %.loc8_36: type = type_literal type [concrete = type]
|
|
// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.as_type]
|
|
// CHECK:STDOUT: %.loc8_24: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
|
|
// CHECK:STDOUT: %.loc8_18: type = where_expr [concrete = constants.%type] {
|
|
// CHECK:STDOUT: requirement_base_facet_type %.loc8_13
|
|
// CHECK:STDOUT: requirement_impls %.loc8_24, %.loc8_36
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: impl @f64.as.<error>.impl: %f64 as <error> {
|
|
// CHECK:STDOUT: !members:
|
|
// CHECK:STDOUT: witness = <error>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: --- fail_impl_as_type_where_impls_interface.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
|
|
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic]
|
|
// CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete]
|
|
// CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete]
|
|
// CHECK:STDOUT: %struct_type.a: type = struct_type {.a: bool} [concrete]
|
|
// CHECK:STDOUT: %type: type = facet_type <type> [concrete]
|
|
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self]
|
|
// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self [symbolic_self]
|
|
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls @I> [concrete]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: imports {
|
|
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
|
// CHECK:STDOUT: .Bool = %Core.Bool
|
|
// CHECK:STDOUT: import Core//prelude
|
|
// CHECK:STDOUT: import Core//prelude/...
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.Bool: %Bool.type = import_ref Core//prelude/parts/bool, Bool, loaded [concrete = constants.%Bool]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: file {
|
|
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
|
// CHECK:STDOUT: .Core = imports.%Core
|
|
// CHECK:STDOUT: .I = %I.decl
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %Core.import = import Core
|
|
// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
|
|
// CHECK:STDOUT: impl_decl @struct_type.a.as.<error>.impl [concrete] {} {
|
|
// CHECK:STDOUT: %.loc10_11: type = type_literal bool [concrete = bool]
|
|
// CHECK:STDOUT: %struct_type.a: type = struct_type {.a: bool} [concrete = constants.%struct_type.a]
|
|
// CHECK:STDOUT: %.loc10_20: type = type_literal type [concrete = type]
|
|
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
|
|
// CHECK:STDOUT: %.Self.ref: %type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
|
|
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
|
|
// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.as_type]
|
|
// CHECK:STDOUT: %.loc10_31: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type]
|
|
// CHECK:STDOUT: %.loc10_25: type = where_expr [concrete = constants.%type_where] {
|
|
// CHECK:STDOUT: requirement_base_facet_type %.loc10_20
|
|
// CHECK:STDOUT: requirement_impls %.loc10_31, %I.ref
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: interface @I {
|
|
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
|
|
// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I [concrete]
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: !members:
|
|
// CHECK:STDOUT: .Self = %Self
|
|
// CHECK:STDOUT: witness = ()
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: !requires:
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: impl @struct_type.a.as.<error>.impl: %struct_type.a as <error> {
|
|
// CHECK:STDOUT: !members:
|
|
// CHECK:STDOUT: witness = <error>
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: specific @I.WithSelf(constants.%Self) {}
|
|
// CHECK:STDOUT:
|