mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
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.
268 lines
12 KiB
Plaintext
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:
|