mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Add an interface-with-self generic to each interface and same for constraints (#6667)
Currently each interface has a `Self` facet internally that becomes a binding to every entity inside the interface: associated constants, functions, and require decls. Each of these has to be independently generic as a result. This makes is challenging in extended name lookup to move into an extended scope of an interface, as we have a specific for the interface, but the names within require a different specific that includes a `Self` facet value. We generalize this relationship by adding a second generic to Interface, called `generic_with_self`. When we want to work with entities inside the interface, we move from the interface-without-specific to the interface-with-self specific by adding a Self to the specific. This is done independently of any particular entity inside the Interface, as those entities are now all members of the interface-with-self generic. Associated constants no longer need a generic of their own, as they do not have separate generic bindings. Functions retain a generic, but if the function has no generic arguments, it will have no bindings of its own now. Require decls retain a generic so that their specific can be instantiated separately from the interface. Requiring the interface to be complete does not require the types in a require decl to be complete unless it is modified by `extend`. So we allow them to be completed later by keeping them in a separate generic. Named constraints look like interfaces and gain the additional inner generic-with-self, with the same relationship to require decls. This removes the need for name lookup to perform Substitution of a Self facet into the extended scope instruction. Instead, the `SpecificConstant` instruction inserted by a `require` decl is part of the interface-with-self generic. When looking through a FacetType for extended scopes, for each interface, we push the scope with the specific for the interface-with-self. Then the constant value of the `SpecificConstant` is correctly modified by the provided self automatically through applying that specific.
This commit is contained in:
+41
-22
@@ -19,7 +19,6 @@
|
||||
#include "toolchain/check/merge.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/check/name_scope.h"
|
||||
#include "toolchain/check/require_impls.h"
|
||||
#include "toolchain/check/thunk.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/check/type_completion.h"
|
||||
@@ -46,7 +45,6 @@ static auto NoteAssociatedFunction(Context& context, DiagnosticBuilder& builder,
|
||||
auto CheckAssociatedFunctionImplementation(
|
||||
Context& context, SemIR::FunctionType interface_function_type,
|
||||
SemIR::SpecificId enclosing_specific_id, SemIR::InstId impl_decl_id,
|
||||
SemIR::TypeId self_type_id, SemIR::InstId witness_inst_id,
|
||||
bool defer_thunk_definition) -> SemIR::InstId {
|
||||
auto impl_function_decl =
|
||||
context.insts().TryGetAs<SemIR::FunctionDecl>(impl_decl_id);
|
||||
@@ -76,7 +74,7 @@ auto CheckAssociatedFunctionImplementation(
|
||||
context.functions()
|
||||
.Get(interface_function_type.function_id)
|
||||
.generic_id,
|
||||
enclosing_specific_id, self_type_id, witness_inst_id);
|
||||
enclosing_specific_id);
|
||||
|
||||
return BuildThunk(context, interface_function_type.function_id,
|
||||
interface_function_specific_id, impl_decl_id,
|
||||
@@ -236,7 +234,7 @@ static auto ApplyExtendImplAs(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
|
||||
if (!impl.generic_id.has_value()) {
|
||||
parent_scope.AddExtendedScope({impl.constraint_id});
|
||||
parent_scope.AddExtendedScope(impl.constraint_id);
|
||||
} else {
|
||||
// The extended scope instruction must be part of the enclosing scope (and
|
||||
// generic). A specific for the enclosing scope will be applied to it when
|
||||
@@ -248,7 +246,7 @@ static auto ApplyExtendImplAs(Context& context, SemIR::LocId loc_id,
|
||||
{.type_id = SemIR::TypeType::TypeId,
|
||||
.inst_id = impl.constraint_id,
|
||||
.specific_id = context.generics().GetSelfSpecific(impl.generic_id)});
|
||||
parent_scope.AddExtendedScope({constraint_id_in_self_specific});
|
||||
parent_scope.AddExtendedScope(constraint_id_in_self_specific);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -459,12 +457,15 @@ auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id,
|
||||
// value to that type now we know the value of `Self`.
|
||||
SemIR::TypeId assoc_const_type_id = assoc_constant_decl->type_id;
|
||||
if (assoc_const_type_id.is_symbolic()) {
|
||||
auto self_facet = GetConstantFacetValueForType(context, impl.self_id);
|
||||
auto interface_with_self_specific_id = MakeSpecificWithInnerSelf(
|
||||
context, loc_id, interface.generic_id, interface.generic_with_self_id,
|
||||
impl.interface.specific_id, self_facet);
|
||||
|
||||
// Get the type of the associated constant in this interface with this
|
||||
// value for `Self`.
|
||||
assoc_const_type_id = GetTypeForSpecificAssociatedEntity(
|
||||
context, SemIR::LocId(impl.constraint_id), impl.interface.specific_id,
|
||||
decl_id, context.types().GetTypeIdForTypeInstId(impl.self_id),
|
||||
witness_inst_id);
|
||||
context, interface_with_self_specific_id, decl_id);
|
||||
// Perform the conversion of the value to the type. We skipped this when
|
||||
// forming the facet type because the type of the associated constant
|
||||
// was symbolic.
|
||||
@@ -603,17 +604,22 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl) -> void {
|
||||
auto witness_block =
|
||||
context.inst_blocks().GetMutable(witness_table.elements_id);
|
||||
auto& impl_scope = context.name_scopes().Get(impl.scope_id);
|
||||
auto self_type_id = context.types().GetTypeIdForTypeInstId(impl.self_id);
|
||||
const auto& interface = context.interfaces().Get(impl.interface.interface_id);
|
||||
auto assoc_entities =
|
||||
context.inst_blocks().Get(interface.associated_entities_id);
|
||||
llvm::SmallVector<SemIR::InstId> used_decl_ids;
|
||||
|
||||
auto self_facet = GetConstantFacetValueForTypeAndInterface(
|
||||
context, impl.self_id, impl.interface, impl.witness_id);
|
||||
auto interface_with_self_specific_id = MakeSpecificWithInnerSelf(
|
||||
context, SemIR::LocId(impl.definition_id), interface.generic_id,
|
||||
interface.generic_with_self_id, impl.interface.specific_id, self_facet);
|
||||
|
||||
for (auto [assoc_entity, witness_value] :
|
||||
llvm::zip_equal(assoc_entities, witness_block)) {
|
||||
auto decl_id =
|
||||
context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
|
||||
context.sem_ir(), impl.interface.specific_id, assoc_entity));
|
||||
context.sem_ir(), interface_with_self_specific_id, assoc_entity));
|
||||
CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
|
||||
auto decl = context.insts().Get(decl_id);
|
||||
CARBON_KIND_SWITCH(decl) {
|
||||
@@ -636,7 +642,7 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl) -> void {
|
||||
witness_value = CheckAssociatedFunctionImplementation(
|
||||
context, *fn_type,
|
||||
context.generics().GetSelfSpecific(impl.generic_id),
|
||||
lookup_result.target_inst_id(), self_type_id, impl.witness_id,
|
||||
lookup_result.target_inst_id(),
|
||||
/*defer_thunk_definition=*/true);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(
|
||||
@@ -690,18 +696,29 @@ auto CheckRequireDeclsSatisfied(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
|
||||
// Make a facet value for the self type.
|
||||
auto self_facet_value = GetConstantFacetValueForType(context, impl.self_id);
|
||||
auto self_facet = GetConstantFacetValueForType(context, impl.self_id);
|
||||
auto interface_with_self_specific_id = MakeSpecificWithInnerSelf(
|
||||
context, loc_id, interface.generic_id, interface.generic_with_self_id,
|
||||
impl.interface.specific_id, self_facet);
|
||||
|
||||
for (auto require_id : require_ids) {
|
||||
const auto& require = context.require_impls().Get(require_id);
|
||||
|
||||
auto require_specific =
|
||||
GetRequireImplsSpecificFromEnclosingSpecificWithSelfFacetValue(
|
||||
context, require, impl.interface.specific_id, self_facet_value);
|
||||
auto self_const_id = GetConstantValueInRequireImplsSpecific(
|
||||
context, require_specific, require.self_id);
|
||||
auto facet_type_const_id = GetConstantValueInRequireImplsSpecific(
|
||||
context, require_specific, require.facet_type_inst_id);
|
||||
// Each require is in its own generic, with no additional bindings and no
|
||||
// definition, so that they can have their specifics independently
|
||||
// instantiated.
|
||||
auto require_specific_id = CopySpecificToGeneric(
|
||||
context, SemIR::LocId(require.decl_id), interface_with_self_specific_id,
|
||||
require.generic_id);
|
||||
auto self_const_id = GetConstantValueInSpecific(
|
||||
context.sem_ir(), require_specific_id, require.self_id);
|
||||
auto facet_type_const_id = GetConstantValueInSpecific(
|
||||
context.sem_ir(), require_specific_id, require.facet_type_inst_id);
|
||||
if (self_const_id == SemIR::ErrorInst::ConstantId ||
|
||||
facet_type_const_id == SemIR::ErrorInst::ConstantId) {
|
||||
FillImplWitnessWithErrors(context, impl);
|
||||
break;
|
||||
}
|
||||
|
||||
auto result =
|
||||
LookupImplWitness(context, loc_id, self_const_id, facet_type_const_id);
|
||||
@@ -762,11 +779,13 @@ auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id,
|
||||
SemIR::InstId self_id,
|
||||
SemIR::TypeInstId constraint_id)
|
||||
-> SemIR::SpecificInterface {
|
||||
auto facet_type_id = context.types().GetTypeIdForTypeInstId(constraint_id);
|
||||
if (facet_type_id == SemIR::ErrorInst::TypeId) {
|
||||
auto facet_type_as_type_id =
|
||||
context.types().GetTypeIdForTypeInstId(constraint_id);
|
||||
if (facet_type_as_type_id == SemIR::ErrorInst::TypeId) {
|
||||
return SemIR::SpecificInterface::None;
|
||||
}
|
||||
auto facet_type = context.types().TryGetAs<SemIR::FacetType>(facet_type_id);
|
||||
auto facet_type =
|
||||
context.types().TryGetAs<SemIR::FacetType>(facet_type_as_type_id);
|
||||
if (!facet_type) {
|
||||
CARBON_DIAGNOSTIC(ImplAsNonFacetType, Error, "impl as non-facet type {0}",
|
||||
InstIdAsType);
|
||||
|
||||
Reference in New Issue
Block a user