Identify and complete facet types as needed for p5168 (#6369)

Proposal #5168 defines when a facet type must be identified or complete,
and what it means for an interface and a named constraint to be
identified or complete. This updates the toolchain to match the
requirements.

This implements identification of a facet type to require completed
named constraints and to include any interfaces from named constraints
into the resulting IdentifiedFacetType.

To complete a facet type, each interface in the IdentifiedFacetType, and
any interface named though a require declaration from them, must be
complete.
This commit is contained in:
Dana Jansens
2025-11-14 19:24:02 +00:00
committed by GitHub
parent 0183fa301f
commit e62678e682
13 changed files with 326 additions and 180 deletions
+13
View File
@@ -13,6 +13,7 @@
#include "toolchain/check/subst.h"
#include "toolchain/check/type.h"
#include "toolchain/check/type_completion.h"
#include "toolchain/diagnostics/diagnostic.h"
#include "toolchain/parse/node_ids.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/named_constraint.h"
@@ -81,6 +82,15 @@ auto HandleParseNode(Context& context, Parse::RequireDefaultSelfImplsId node_id)
auto HandleParseNode(Context& context, Parse::RequireTypeImplsId node_id)
-> bool {
auto [self_node_id, self_inst_id] = context.node_stack().PopExprWithNodeId();
auto introducer = context.decl_introducer_state_stack().innermost();
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
CARBON_DIAGNOSTIC(RequireImplsExtendWithExplicitSelf, Error,
"`extend require impls` with explicit type");
context.emitter().Emit(self_node_id, RequireImplsExtendWithExplicitSelf);
self_inst_id = SemIR::ErrorInst::InstId;
}
auto self_type = ExprAsType(context, self_node_id, self_inst_id);
context.node_stack().Push(node_id, self_type.inst_id);
return true;
@@ -241,6 +251,8 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
return true;
}
bool extend = introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend);
auto require_impls_decl =
SemIR::RequireImplsDecl{// To be filled in after.
.require_impls_id = SemIR::RequireImplsId::None,
@@ -251,6 +263,7 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
.facet_type_inst_id =
context.types().GetAsTypeInstId(constraint_inst_id),
.facet_type_id = constraint_facet_type.facet_type_id,
.extend_self = extend,
.decl_id = decl_id,
.parent_scope_id = context.scope_stack().PeekNameScopeId(),
.generic_id = BuildGenericDecl(context, decl_id)});
+1
View File
@@ -121,6 +121,7 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
witness_block.empty()) {
if (!RequireCompleteFacetTypeForImplDefinition(
context, SemIR::LocId(impl.latest_decl_id()), impl.constraint_id)) {
FillImplWitnessWithErrors(context, impl);
return;
}
+4 -4
View File
@@ -203,10 +203,10 @@ static auto GetInterfacesFromConstantId(
context.facet_types().Get(facet_type_inst.facet_type_id);
auto identified_id =
RequireIdentifiedFacetType(context, facet_type_inst, [&] {
CARBON_DIAGNOSTIC(ImplLookupInIncompleteFacetType, Error,
"facet type {0} is incomplete", InstIdAsType);
return context.emitter().Build(loc_id, ImplLookupInIncompleteFacetType,
facet_type_inst_id);
CARBON_DIAGNOSTIC(ImplLookupInUnidentifiedFacetType, Error,
"facet type {0} can not be identified", InstIdAsType);
return context.emitter().Build(
loc_id, ImplLookupInUnidentifiedFacetType, facet_type_inst_id);
});
if (!identified_id.has_value()) {
return std::nullopt;
+1
View File
@@ -2468,6 +2468,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
resolver.local_insts().GetAs<SemIR::FacetType>(
new_canonical_facet_type_inst_id);
new_require.facet_type_id = new_canonical_facet_type.facet_type_id;
new_require.extend_self = import_require.extend_self;
new_require.parent_scope_id = parent_scope_id;
SetGenericData(resolver, import_require.generic_id, new_require.generic_id,
+99 -80
View File
@@ -2,7 +2,7 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
//
// AUTOUPDATE
// TIP: To test this file alone, run:
@@ -13,95 +13,114 @@
// --- fail_incomplete_interface.carbon
library "[[@TEST_NAME]]";
interface A;
interface B {}
interface X;
class C {}
fn G[T:! A](t: T) {}
fn H[T:! A & B](t: T) {}
// Requires X identified.
impl C as X;
fn F() {
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+4]]:3: error: cannot convert type `C` into type implementing `A` [ConversionFailureTypeToFacet]
// CHECK:STDERR: C as A;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
C as A;
// Requires X complete.
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+7]]:1: error: definition of impl as incomplete facet type `X` [ImplAsIncompleteFacetTypeDefinition]
// CHECK:STDERR: impl C as X {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE-10]]:1: note: interface was forward declared here [InterfaceForwardDeclaredHere]
// CHECK:STDERR: interface X;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
impl C as X {}
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+4]]:3: error: cannot convert type `C` into type implementing `A & B` [ConversionFailureTypeToFacet]
// CHECK:STDERR: C as (A & B);
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
C as (A & B);
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `A` [ConversionFailureTypeToFacet]
// CHECK:STDERR: G({} as C);
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE-19]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn G[T:! A](t: T) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
G({} as C);
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `A & B` [ConversionFailureTypeToFacet]
// CHECK:STDERR: H({} as C);
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE-27]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn H[T:! A & B](t: T) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
H({} as C);
}
// --- fail_incomplete_constraint.carbon
// --- fail_incomplete_interface_without_forward_decl.carbon
library "[[@TEST_NAME]]";
constraint A;
interface B {}
interface X;
class C {}
fn G[T:! A](t: T) {}
fn H[T:! A & B](t: T) {}
// Requires X complete.
// CHECK:STDERR: fail_incomplete_interface_without_forward_decl.carbon:[[@LINE+7]]:1: error: definition of impl as incomplete facet type `X` [ImplAsIncompleteFacetTypeDefinition]
// CHECK:STDERR: impl C as X {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_interface_without_forward_decl.carbon:[[@LINE-7]]:1: note: interface was forward declared here [InterfaceForwardDeclaredHere]
// CHECK:STDERR: interface X;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
impl C as X {}
// --- fail_unidentified_constraint.carbon
library "[[@TEST_NAME]]";
constraint X;
class C {}
// Requires X identified.
// CHECK:STDERR: fail_unidentified_constraint.carbon:[[@LINE+7]]:1: error: facet type `X` cannot be identified in `impl as` [ImplOfUnidentifiedFacetType]
// CHECK:STDERR: impl C as X;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR: fail_unidentified_constraint.carbon:[[@LINE-7]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint X;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
impl C as X;
// --- nested_require_incomplete_interface.carbon
library "[[@TEST_NAME]]";
interface Z;
constraint Y {
require impls Z;
}
interface X {
require impls Y;
}
class C {}
// Requires X identified.
impl C as X;
// Requires X complete.
impl C as X {}
// --- fail_incomplete_through_constraint.carbon
library "[[@TEST_NAME]]";
interface Z;
constraint Y {
extend require impls Z;
}
class C {}
// Requires Y identified.
impl C as Y;
// Requires Y complete.
// CHECK:STDERR: fail_incomplete_through_constraint.carbon:[[@LINE+7]]:1: error: definition of impl as incomplete facet type `Y` [ImplAsIncompleteFacetTypeDefinition]
// CHECK:STDERR: impl C as Y {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_through_constraint.carbon:[[@LINE-14]]:1: note: interface was forward declared here [InterfaceForwardDeclaredHere]
// CHECK:STDERR: interface Z;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
impl C as Y {}
// --- fail_impl_lookup_incomplete.carbon
library "[[@TEST_NAME]]";
constraint Z;
fn AsZ(T:! Z) {}
fn F() {
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+7]]:3: error: facet type `A` is incomplete [ImplLookupInIncompleteFacetType]
// CHECK:STDERR: C as A;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-11]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint A;
// Requires Z identified.
// CHECK:STDERR: fail_impl_lookup_incomplete.carbon:[[@LINE+10]]:3: error: facet type `Z` can not be identified [ImplLookupInUnidentifiedFacetType]
// CHECK:STDERR: AsZ(());
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_impl_lookup_incomplete.carbon:[[@LINE-9]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint Z;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_lookup_incomplete.carbon:[[@LINE-10]]:8: note: initializing generic parameter `T` declared here [InitializingGenericParam]
// CHECK:STDERR: fn AsZ(T:! Z) {}
// CHECK:STDERR: ^
// CHECK:STDERR:
C as A;
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+7]]:3: error: facet type `B & A` is incomplete [ImplLookupInIncompleteFacetType]
// CHECK:STDERR: C as (A & B);
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-20]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint A;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
C as (A & B);
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+10]]:3: error: facet type `A` is incomplete [ImplLookupInIncompleteFacetType]
// CHECK:STDERR: G({} as C);
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-29]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint A;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-28]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn G[T:! A](t: T) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
G({} as C);
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+10]]:3: error: facet type `B & A` is incomplete [ImplLookupInIncompleteFacetType]
// CHECK:STDERR: H({} as C);
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-41]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint A;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-39]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
// CHECK:STDERR: fn H[T:! A & B](t: T) {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
H({} as C);
AsZ(());
}
+13
View File
@@ -110,3 +110,16 @@ class C {
// CHECK:STDERR:
require impls Y;
}
// --- fail_extend_require_type.carbon
library "[[@TEST_NAME]]";
interface Y {}
interface Z {
// CHECK:STDERR: fail_extend_require_type.carbon:[[@LINE+4]]:18: error: `extend require impls` with explicit type [RequireImplsExtendWithExplicitSelf]
// CHECK:STDERR: extend require () impls Y;
// CHECK:STDERR: ^~
// CHECK:STDERR:
extend require () impls Y;
}
+88 -47
View File
@@ -10,34 +10,16 @@
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/impl_as_named_constraint.carbon
// --- fail_incomplete_constraint.carbon
library "[[@TEST_NAME]]";
constraint A;
class C {}
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+7]]:1: error: facet type `A` cannot be identified in `impl as` [ImplOfUnidentifiedFacetType]
// CHECK:STDERR: impl C as A {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-7]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
// CHECK:STDERR: constraint A;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
impl C as A {}
// --- fail_empty_constraint.carbon
library "[[@TEST_NAME]]";
constraint A {}
class C {}
// CHECK:STDERR: fail_empty_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl C as A {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: impl () as A {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
impl C as A {}
impl () as A {}
// --- fail_too_many_interfaces_in_constraint.carbon
library "[[@TEST_NAME]]";
@@ -45,50 +27,109 @@ library "[[@TEST_NAME]]";
interface A1;
interface A2;
constraint B {
require impls A1;
require impls A2;
extend require impls A1;
extend require impls A2;
}
class C {}
// TODO: This should fail since B does not name a single interface, it names
// more than one.
// CHECK:STDERR: fail_too_many_interfaces_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl C as B {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_too_many_interfaces_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 2 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl () as B {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
impl C as B {}
impl () as B {}
// --- fail_todo_one_declared_interface_in_constraint.carbon
// --- one_extend_impls_interface_in_constraint.carbon
library "[[@TEST_NAME]]";
// TODO: This should work since B can be identified to have one interface.
interface A;
constraint B {
extend require impls A;
}
// Requries B identified.
impl () as B;
interface A {}
// Requries B complete.
impl () as B {}
// --- fail_one_impls_interface_in_constraint.carbon
library "[[@TEST_NAME]]";
interface A;
constraint B {
require impls A;
}
class C {}
// CHECK:STDERR: fail_todo_one_declared_interface_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl C as B {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_one_impls_interface_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl () as B {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
impl C as B {}
impl () as B {}
// --- fail_todo_one_defined_interface_in_constraint.carbon
// --- nested_constraints.carbon
library "[[@TEST_NAME]]";
// TODO: This should work since B can be identified to have one interface.
interface A {}
constraint B {
require impls A;
extend require impls A;
}
constraint C {
extend require impls B;
}
class C {}
// CHECK:STDERR: fail_todo_one_defined_interface_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl C as B {}
// CHECK:STDERR: ^~~~~~~~~~~~~
impl () as C {}
// --- fail_nested_constraints_not_extend_outer.carbon
library "[[@TEST_NAME]]";
interface A {}
constraint B {
extend require impls A;
}
constraint C {
require impls B;
}
// CHECK:STDERR: fail_nested_constraints_not_extend_outer.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl () as C {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
impl C as B {}
impl () as C {}
// --- fail_nested_constraints_not_extend_inner.carbon
library "[[@TEST_NAME]]";
interface A {}
constraint B {
require impls A;
}
constraint C {
extend require impls B;
}
// CHECK:STDERR: fail_nested_constraints_not_extend_inner.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl () as C {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
impl () as C {}
// --- fail_nested_constraints_not_extend_both.carbon
library "[[@TEST_NAME]]";
interface A {}
constraint B {
require impls A;
}
constraint C {
require impls B;
}
// CHECK:STDERR: fail_nested_constraints_not_extend_both.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl () as C {}
// CHECK:STDERR: ^~~~~~~~~~~~~~
// CHECK:STDERR:
impl () as C {}
@@ -49,7 +49,7 @@ class C {}
// CHECK:STDERR:
impl C as A;
// --- fail_todo_import_complete.carbon
// --- import_complete.carbon
library "[[@TEST_NAME]]";
import library "b";
@@ -57,19 +57,9 @@ import library "b";
class C {}
// This requires that B is identified.
// TODO: This should work.
// CHECK:STDERR: fail_todo_import_complete.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl C as B;
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR:
impl C as B;
// This requires that B is complete.
// TODO: This should work.
// CHECK:STDERR: fail_todo_import_complete.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
// CHECK:STDERR: impl C as B {}
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
impl C as B {}
// CHECK:STDOUT: --- a.impl.carbon
+4 -16
View File
@@ -29,14 +29,10 @@ fn F(T:! Z) {
// CHECK:STDERR: ^~~~
// CHECK:STDERR:
T.YY();
// CHECK:STDERR: fail_todo_extend.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `Y` [ConversionFailureFacetToFacet]
// CHECK:STDERR: T.(Y.YY)();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
T.(Y.YY)();
}
// --- fail_todo_implicit_self_impls.carbon
// --- implicit_self_impls.carbon
library "[[@TEST_NAME]]";
interface Y {
@@ -50,14 +46,10 @@ constraint Z {
//@dump-sem-ir-end
fn F(T:! Z) {
// CHECK:STDERR: fail_todo_implicit_self_impls.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `Y` [ConversionFailureFacetToFacet]
// CHECK:STDERR: T.(Y.YY)();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
T.(Y.YY)();
}
// --- fail_todo_explicit_self_impls.carbon
// --- explicit_self_impls.carbon
library "[[@TEST_NAME]]";
interface Y {
@@ -71,10 +63,6 @@ constraint Z {
//@dump-sem-ir-end
fn F(T:! Z) {
// CHECK:STDERR: fail_todo_explicit_self_impls.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `Y` [ConversionFailureFacetToFacet]
// CHECK:STDERR: T.(Y.YY)();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
T.(Y.YY)();
}
@@ -342,7 +330,7 @@ constraint Z {
// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_implicit_self_impls.carbon
// CHECK:STDOUT: --- implicit_self_impls.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete]
@@ -387,7 +375,7 @@ constraint Z {
// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_explicit_self_impls.carbon
// CHECK:STDOUT: --- explicit_self_impls.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete]
+93 -18
View File
@@ -4,6 +4,7 @@
#include "toolchain/check/type_completion.h"
#include "common/concepts.h"
#include "llvm/ADT/SmallVector.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/cpp/import.h"
@@ -69,6 +70,18 @@ static auto NoteIncompleteNamedConstraint(
}
}
template <typename T>
requires SameAsOneOf<T, SemIR::Interface, SemIR::NamedConstraint>
static auto ForEachRequireImpls(
Context& context, const T& entity,
llvm::function_ref<auto(const SemIR::RequireImpls&)->void> f) -> void {
for (auto require_impls_id :
context.require_impls_blocks().Get(entity.require_impls_block_id)) {
const auto& require = context.require_impls().Get(require_impls_id);
f(require);
}
}
namespace {
// Worklist-based type completion mechanism.
//
@@ -397,15 +410,15 @@ auto TypeCompleter::AddNestedIncompleteTypes(SemIR::Inst type_inst) -> bool {
break;
}
case CARBON_KIND(SemIR::FacetType inst): {
// TODO: Get the complete facet type here.
auto identified_id =
RequireIdentifiedFacetType(*context_, inst, diagnoser_);
if (!identified_id.has_value()) {
return false;
}
const auto& identified =
context_->identified_facet_types().Get(identified_id);
// Every mentioned interface needs to be complete.
for (auto req_interface : identified.required_interfaces()) {
auto interface_id = req_interface.interface_id;
const auto& interface = context_->interfaces().Get(interface_id);
@@ -771,18 +784,11 @@ auto RequireConcreteType(Context& context, SemIR::TypeId type_id,
return true;
}
auto RequireIdentifiedFacetType(Context& context,
const SemIR::FacetType& facet_type,
MakeDiagnosticBuilderFn diagnoser)
-> SemIR::IdentifiedFacetTypeId {
if (auto identified_id =
context.identified_facet_types().TryGetId(facet_type.facet_type_id);
identified_id.has_value()) {
return identified_id;
}
const auto& facet_type_info =
context.facet_types().Get(facet_type.facet_type_id);
// Require all named constraints in the facet type are identified. For a named
// constraint, this means the constraint definition is complete.
static auto RequireIdentifiedNamedConstraints(
Context& context, const SemIR::FacetTypeInfo& facet_type_info,
MakeDiagnosticBuilderFn diagnoser) -> bool {
auto named_constraint_ids = llvm::map_range(
llvm::concat<const SemIR::SpecificNamedConstraint>(
facet_type_info.extend_named_constraints,
@@ -797,15 +803,84 @@ auto RequireIdentifiedFacetType(Context& context,
NoteIncompleteNamedConstraint(context, named_constraint_id, builder);
builder.Emit();
}
return false;
}
}
return true;
}
auto RequireIdentifiedFacetType(Context& context,
const SemIR::FacetType& facet_type,
MakeDiagnosticBuilderFn diagnoser)
-> SemIR::IdentifiedFacetTypeId {
if (auto identified_id =
context.identified_facet_types().TryGetId(facet_type.facet_type_id);
identified_id.has_value()) {
return identified_id;
}
// Work queue.
llvm::SmallVector<SemIR::FacetTypeId> extend_facet_types = {
facet_type.facet_type_id};
llvm::SmallVector<SemIR::FacetTypeId> impls_facet_types;
// Outputs for the IdentifiedFacetType.
llvm::SmallVector<SemIR::SpecificInterface> extends;
llvm::SmallVector<SemIR::SpecificInterface> self_impls;
while (true) {
auto next_facet_type_id = SemIR::FacetTypeId::None;
bool facet_type_extends = false;
if (!extend_facet_types.empty()) {
next_facet_type_id = extend_facet_types.pop_back_val();
facet_type_extends = true;
} else if (!impls_facet_types.empty()) {
next_facet_type_id = impls_facet_types.pop_back_val();
facet_type_extends = false;
} else {
break;
}
const auto& facet_type_info = context.facet_types().Get(next_facet_type_id);
if (!RequireIdentifiedNamedConstraints(context, facet_type_info,
diagnoser)) {
return SemIR::IdentifiedFacetTypeId::None;
}
if (facet_type_extends) {
llvm::append_range(extends, facet_type_info.extend_constraints);
} else {
llvm::append_range(self_impls, facet_type_info.extend_constraints);
}
llvm::append_range(self_impls, facet_type_info.self_impls_constraints);
for (auto extend : facet_type_info.extend_named_constraints) {
const auto& constraint =
context.named_constraints().Get(extend.named_constraint_id);
ForEachRequireImpls(
context, constraint, [&](const SemIR::RequireImpls& require) {
if (facet_type_extends && require.extend_self) {
extend_facet_types.push_back(require.facet_type_id);
} else {
impls_facet_types.push_back(require.facet_type_id);
}
});
}
for (auto impls : facet_type_info.self_impls_named_constraints) {
const auto& constraint =
context.named_constraints().Get(impls.named_constraint_id);
ForEachRequireImpls(context, constraint,
[&](const SemIR::RequireImpls& require) {
impls_facet_types.push_back(require.facet_type_id);
});
}
}
// TODO: expand named constraints
// TODO: Process other kinds of requirements.
return context.identified_facet_types().Add(
facet_type.facet_type_id, {facet_type_info.extend_constraints,
facet_type_info.self_impls_constraints});
return context.identified_facet_types().Add(facet_type.facet_type_id,
{extends, self_impls});
}
auto AsCompleteType(Context& context, SemIR::TypeId type_id,
+3 -2
View File
@@ -360,13 +360,14 @@ CARBON_DIAGNOSTIC_KIND(MissingImplInMemberAccess)
CARBON_DIAGNOSTIC_KIND(MissingImplInMemberAccessNote)
CARBON_DIAGNOSTIC_KIND(ImplLookupCycle)
CARBON_DIAGNOSTIC_KIND(ImplLookupCycleNote)
CARBON_DIAGNOSTIC_KIND(ImplLookupInIncompleteFacetType)
CARBON_DIAGNOSTIC_KIND(ImplLookupInUnidentifiedFacetType)
// Require checking.
CARBON_DIAGNOSTIC_KIND(RequireImplsExtendWithExplicitSelf)
CARBON_DIAGNOSTIC_KIND(RequireImplsMissingFacetType)
CARBON_DIAGNOSTIC_KIND(RequireImplsMissingSelf)
CARBON_DIAGNOSTIC_KIND(RequireInWrongScope)
CARBON_DIAGNOSTIC_KIND(RequireImplsUnidentifiedFacetType)
CARBON_DIAGNOSTIC_KIND(RequireInWrongScope)
// Let declaration checking.
CARBON_DIAGNOSTIC_KIND(ExpectedInitializerAfterLet)
+4 -2
View File
@@ -246,8 +246,10 @@ struct Worklist {
auto Add(RequireImplsId require_id) -> void {
CARBON_CHECK(require_id.has_value());
const auto& require = sem_ir->require_impls().Get(require_id);
Add(require.self_id);
Add(require.facet_type_id);
Add(sem_ir->constant_values().Get(require.self_id));
Add(sem_ir->constant_values().Get(require.facet_type_inst_id));
contents.push_back(require.extend_self);
Add(require.parent_scope_id);
}
auto Add(AssociatedConstantId assoc_const_id) -> void {
+2
View File
@@ -24,6 +24,8 @@ struct RequireImpls : Printable<RequireImpls> {
TypeInstId facet_type_inst_id;
// The `FacetTypeInfo` derived from the `facet_type_inst_id` instruction.
FacetTypeId facet_type_id;
// If the facet type extends `Self`. When true, the `self_id` will be `Self`.
bool extend_self;
// The location of the `require` declaration.
InstId decl_id;