Files
carbon-lang/toolchain/check/testdata/interface/incomplete.carbon
T
Dana Jansens 201e408252 Type completion of facet types is separate from Identifying (#6385)
Identifying a facet type is an operation on a pair of (self type, facet
type). It substitutes that self in as the `Self` of any require
declarations in order to form the set of (self type, SpecificInterface)
pairs that constitute the requirements of the IdentifiedFacetType.
Currently we don't pass around any self type, and assume all require
declarations are written against `Self` but this will change in the
future.

By contrast, type completion is done in the abstract and does not form
specifics for the require declarations. The purpose of type completion
is to enumerate the scopes where name lookup can occur and ensure they
are completed.

With this change, type completion is:
- No longer built on top of identification for facet types.
- Recursively ensures all `extend` scopes are complete since name lookup
can find symbols in them.

We add some test cases that demonstrate consistency between a resolving
the specific of a generic class, and a generic interface/constraint,
both used in a type position. In all cases, an invalid specific is not
materialized for the type completion when the specific's arguments are
used in a non-extend context. But they specific is materialized and
checked for type completion when in an extend context (extend impl or
extend require).

Type completion itself does not need to recurse into named constraints
or interfaces as the `extend require` declarations require the type to
be complete immediately, just as for `extend impl` in a class.

We had a test (`fail_incomplete_where.carbon`) with `impl as J where
.Self impls K` and `J` is incomplete, which used to be diagnosed but no
longer is, because we don't require non-extend interfaces to be complete
in type completion, nor in identification. The test was trying to test
the presence of rewrite constraints though, which it didn't even use. So
we remove the diagnostic that we can't hit anymore and replaced it with
a TODO, and add a test that should reach that TODO once qualified
rewrite constraints work.
2025-11-21 22:28:08 +00:00

268 lines
12 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
// 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/interface/incomplete.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/incomplete.carbon
// --- fail_incomplete_type.carbon
library "[[@TEST_NAME]]";
class C;
interface I {
// CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE+7]]:11: error: associated constant has incomplete type `C` [IncompleteTypeInAssociatedConstantDecl]
// CHECK:STDERR: let T:! C;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
let T:! C;
}
// --- fail_incomplete_extend_constraint.carbon
library "[[@TEST_NAME]]";
constraint A;
interface B {
// CHECK:STDERR: fail_incomplete_extend_constraint.carbon:[[@LINE+7]]:24: error: facet type `A` cannot be identified in `require` declaration [RequireImplsUnidentifiedFacetType]
// CHECK:STDERR: extend require impls A;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_incomplete_extend_constraint.carbon:[[@LINE-6]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint A;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
extend require impls A;
}
// --- fail_extend_require_enclosing.carbon
library "[[@TEST_NAME]]";
interface A {
// CHECK:STDERR: fail_extend_require_enclosing.carbon:[[@LINE+7]]:24: error: `extend require` of incomplete facet type `A` [RequireImplsIncompleteFacetType]
// CHECK:STDERR: extend require impls A;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_extend_require_enclosing.carbon:[[@LINE-4]]:1: note: interface is currently being defined [InterfaceIncompleteWithinDefinition]
// CHECK:STDERR: interface A {
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
extend require impls A;
}
// --- fail_extend_require_enclosing_generic.carbon
library "[[@TEST_NAME]]";
interface A(T:! type) {
// CHECK:STDERR: fail_extend_require_enclosing_generic.carbon:[[@LINE+7]]:24: error: `extend require` of incomplete facet type `A({})` [RequireImplsIncompleteFacetType]
// CHECK:STDERR: extend require impls A({});
// CHECK:STDERR: ^~~~~
// CHECK:STDERR: fail_extend_require_enclosing_generic.carbon:[[@LINE-4]]:1: note: interface is currently being defined [InterfaceIncompleteWithinDefinition]
// CHECK:STDERR: interface A(T:! type) {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
extend require impls A({});
}
// CHECK:STDOUT: --- fail_incomplete_type.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic]
// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I [concrete]
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.%T [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .I = %I.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I {
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT: %T: <error> = assoc_const_decl @T [concrete] {
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.%T [concrete = constants.%assoc0]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: .C = <poisoned>
// CHECK:STDOUT: .T = @T.%assoc0
// CHECK:STDOUT: witness = (%T)
// CHECK:STDOUT:
// CHECK:STDOUT: !requires:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic assoc_const @T(@I.%Self: %I.type) {
// CHECK:STDOUT: assoc_const T:! <error>;
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
// CHECK:STDOUT:
// CHECK:STDOUT: specific @T(constants.%Self) {}
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_incomplete_extend_constraint.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %A.type: type = facet_type <@A> [concrete]
// CHECK:STDOUT: %B.type: type = facet_type <@B> [concrete]
// CHECK:STDOUT: %Self: %B.type = symbolic_binding Self, 0 [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .A = %A.decl
// CHECK:STDOUT: .B = %B.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %A.decl: type = constraint_decl @A [concrete = constants.%A.type] {} {}
// CHECK:STDOUT: %B.decl: type = interface_decl @B [concrete = constants.%B.type] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @B {
// CHECK:STDOUT: %Self: %B.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: .A = <poisoned>
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT:
// CHECK:STDOUT: !requires:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: constraint @A;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_extend_require_enclosing.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %A.type: type = facet_type <@A> [concrete]
// CHECK:STDOUT: %Self: %A.type = symbolic_binding Self, 0 [symbolic]
// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .A = %A.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %A.decl: type = interface_decl @A [concrete = constants.%A.type] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @A {
// CHECK:STDOUT: %Self: %A.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT: %A.require0.decl = require_decl @A.require0 [concrete] {
// CHECK:STDOUT: require %Self.as_type impls <@A>
// CHECK:STDOUT: } {
// CHECK:STDOUT: %Self.as_type: type = facet_access_type @A.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
// CHECK:STDOUT: %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A.type]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: .A = <poisoned>
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT:
// CHECK:STDOUT: !requires:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic require @A.require0(@A.%Self: %A.type) {
// CHECK:STDOUT: %Self: %A.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @A.require0(constants.%Self) {
// CHECK:STDOUT: %Self => constants.%Self
// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_extend_require_enclosing_generic.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %type: type = facet_type <type> [concrete]
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self]
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %pattern_type: type = pattern_type type [concrete]
// CHECK:STDOUT: %A.type.495: type = generic_interface_type @A [concrete]
// CHECK:STDOUT: %A.generic: %A.type.495 = struct_value () [concrete]
// CHECK:STDOUT: %A.type.c1c: type = facet_type <@A, @A(%T)> [symbolic]
// CHECK:STDOUT: %Self: %A.type.c1c = symbolic_binding Self, 1 [symbolic]
// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete]
// CHECK:STDOUT: %A.type.23f: type = facet_type <@A, @A(%empty_struct_type)> [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .A = %A.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %A.decl: %A.type.495 = interface_decl @A [concrete = constants.%A.generic] {
// CHECK:STDOUT: %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
// CHECK:STDOUT: %T.loc3_13.2: type = symbolic_binding T, 0 [symbolic = %T.loc3_13.1 (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic interface @A(%T.loc3_13.2: type) {
// CHECK:STDOUT: %T.loc3_13.1: type = symbolic_binding T, 0 [symbolic = %T.loc3_13.1 (constants.%T)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %A.type: type = facet_type <@A, @A(%T.loc3_13.1)> [symbolic = %A.type (constants.%A.type.c1c)]
// CHECK:STDOUT: %Self.loc3_23.2: @A.%A.type (%A.type.c1c) = symbolic_binding Self, 1 [symbolic = %Self.loc3_23.2 (constants.%Self)]
// CHECK:STDOUT:
// CHECK:STDOUT: interface {
// CHECK:STDOUT: %Self.loc3_23.1: @A.%A.type (%A.type.c1c) = symbolic_binding Self, 1 [symbolic = %Self.loc3_23.2 (constants.%Self)]
// CHECK:STDOUT: %A.require0.decl = require_decl @A.require0 [concrete] {
// CHECK:STDOUT: require %Self.as_type impls <@A, @A(constants.%empty_struct_type)>
// CHECK:STDOUT: } {
// CHECK:STDOUT: %Self.as_type: type = facet_access_type @A.%Self.loc3_23.1 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
// CHECK:STDOUT: %A.ref: %A.type.495 = name_ref A, file.%A.decl [concrete = constants.%A.generic]
// CHECK:STDOUT: %.loc11_27: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc11_28: type = converted %.loc11_27, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
// CHECK:STDOUT: %A.type.loc11_28: type = facet_type <@A, @A(constants.%empty_struct_type)> [concrete = constants.%A.type.23f]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self.loc3_23.1
// CHECK:STDOUT: .A = <poisoned>
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT:
// CHECK:STDOUT: !requires:
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic require @A.require0(@A.%T.loc3_13.2: type, @A.%Self.loc3_23.1: @A.%A.type (%A.type.c1c)) {
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %A.type.loc11_18: type = facet_type <@A, @A(%T)> [symbolic = %A.type.loc11_18 (constants.%A.type.c1c)]
// CHECK:STDOUT: %Self: @A.require0.%A.type.loc11_18 (%A.type.c1c) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @A(constants.%T) {
// CHECK:STDOUT: %T.loc3_13.1 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @A(constants.%empty_struct_type) {
// CHECK:STDOUT: %T.loc3_13.1 => constants.%empty_struct_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @A.require0(constants.%T, constants.%Self) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: %A.type.loc11_18 => constants.%A.type.c1c
// CHECK:STDOUT: %Self => constants.%Self
// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT: