Skip to content

Commit fbd4368

Browse files
committed
less-completing-impl-as-chain-2
1 parent 78f03c4 commit fbd4368

File tree

3 files changed

+102
-106
lines changed

3 files changed

+102
-106
lines changed

toolchain/check/handle_impl.cpp

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -230,28 +230,34 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id,
230230
SemIR::ImplDecl{.impl_id = SemIR::ImplId::None,
231231
.decl_block_id = decl_block_id});
232232

233-
SemIR::Impl impl_info = {name_context.MakeEntityWithParamsBase(
234-
name, impl_decl_id,
235-
/*is_extern=*/false, SemIR::LibraryNameId::None),
236-
{.self_id = self_type_inst_id,
237-
.constraint_id = constraint_type_inst_id,
238-
// This requires that the facet type is identified.
239-
.interface = CheckConstraintIsInterface(
240-
context, impl_decl_id, constraint_type_inst_id),
241-
.is_final = is_final}};
242-
243-
std::optional<ExtendImplDecl> extend_impl;
244-
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
245-
extend_impl = ExtendImplDecl{
246-
.self_type_node_id = self_type_node,
247-
.constraint_type_id = constraint_type_id,
248-
.extend_node_id = introducer.modifier_node_id(ModifierOrder::Extend),
249-
};
233+
// This requires that the facet type is identified. It returns None if an
234+
// error was diagnosed.
235+
auto specific_interface = CheckConstraintIsInterface(context, impl_decl_id,
236+
constraint_type_inst_id);
237+
238+
auto impl_id = SemIR::ImplId::None;
239+
{
240+
SemIR::Impl impl_info = {
241+
name_context.MakeEntityWithParamsBase(name, impl_decl_id,
242+
/*is_extern=*/false,
243+
SemIR::LibraryNameId::None),
244+
{.self_id = self_type_inst_id,
245+
.constraint_id = constraint_type_inst_id,
246+
.interface = specific_interface,
247+
.is_final = is_final}};
248+
auto extend_node = introducer.modifier_node_id(ModifierOrder::Extend);
249+
impl_id = GetOrAddImpl(context, node_id, name.implicit_params_loc_id,
250+
impl_info, is_definition, extend_node);
250251
}
251252

252-
return StartImplDecl(context, SemIR::LocId(node_id),
253-
name.implicit_params_loc_id, impl_info, is_definition,
254-
extend_impl);
253+
// `GetOrAddImpl` either filled in the `impl_info` and returned a fresh
254+
// ImplId, or if we're redeclaring a previous impl, returned an existing
255+
// ImplId. Write that ImplId into the ImplDecl instruction and finish it.
256+
auto impl_decl = context.insts().GetAs<SemIR::ImplDecl>(impl_decl_id);
257+
impl_decl.impl_id = impl_id;
258+
ReplaceInstBeforeConstantUse(context, impl_decl_id, impl_decl);
259+
260+
return {impl_id, impl_decl_id};
255261
}
256262

257263
auto HandleParseNode(Context& context, Parse::ImplDeclId node_id) -> bool {

toolchain/check/impl.cpp

Lines changed: 67 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -399,13 +399,13 @@ static auto TryAsClassScope(Context& context, SemIR::NameScopeId scope_id)
399399
return context.insts().TryGetAs<SemIR::ClassDecl>(scope.inst_id());
400400
}
401401

402-
// Process an `extend impl` declaration by extending the impl scope with the
403-
// `impl`'s scope.
404-
static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
405-
SemIR::LocId loc_id, SemIR::ImplId impl_id,
406-
SemIR::LocId implicit_params_loc_id,
407-
SemIR::TypeInstId constraint_type_inst_id,
408-
SemIR::TypeId constraint_type_id) -> bool {
402+
// Apply an `extend impl` declaration by extending the parent scope with the
403+
// `impl`. If there's an error it is diagnosed and false is returned.
404+
static auto ApplyExtendImplAs(Context& context, Parse::NodeId extend_node,
405+
SemIR::LocId loc_id, SemIR::ImplId impl_id,
406+
SemIR::LocId implicit_params_loc_id,
407+
SemIR::TypeInstId constraint_type_inst_id)
408+
-> bool {
409409
auto parent_scope_id = context.decl_name_stack().PeekParentScopeId();
410410
if (!parent_scope_id.has_value()) {
411411
DiagnoseExtendImplOutsideClass(context, loc_id);
@@ -432,6 +432,8 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node,
432432
if (impl.witness_id == SemIR::ErrorInst::InstId) {
433433
parent_scope.set_has_error();
434434
} else {
435+
auto constraint_type_id =
436+
context.types().GetTypeIdForTypeInstId(constraint_type_inst_id);
435437
bool is_complete = RequireCompleteType(
436438
context, constraint_type_id, SemIR::LocId(constraint_type_inst_id),
437439
[&] {
@@ -484,11 +486,10 @@ static auto DiagnoseUnusedGenericBinding(Context& context, SemIR::LocId loc_id,
484486
FillImplWitnessWithErrors(context, context.impls().Get(impl_id));
485487
}
486488

487-
auto StartImplDecl(Context& context, SemIR::LocId loc_id,
488-
SemIR::LocId implicit_params_loc_id, SemIR::Impl impl,
489-
bool is_definition,
490-
std::optional<ExtendImplDecl> extend_impl)
491-
-> std::pair<SemIR::ImplId, SemIR::InstId> {
489+
auto GetOrAddImpl(Context& context, SemIR::LocId loc_id,
490+
SemIR::LocId implicit_params_loc_id, SemIR::Impl impl,
491+
bool is_definition, Parse::NodeId extend_node)
492+
-> SemIR::ImplId {
492493
auto impl_id = SemIR::ImplId::None;
493494

494495
// Add the impl declaration.
@@ -500,72 +501,70 @@ auto StartImplDecl(Context& context, SemIR::LocId loc_id,
500501
if (IsValidImplRedecl(context, impl, prev_impl_id)) {
501502
impl_id = prev_impl_id;
502503
} else {
503-
// IsValidImplRedecl() has issued a diagnostic, avoid generating more
504-
// diagnostics for this declaration.
504+
// IsValidImplRedecl() has issued a diagnostic, take care to avoid
505+
// generating more diagnostics for this declaration.
505506
impl.witness_id = SemIR::ErrorInst::InstId;
506507
}
507508
break;
508509
}
509510
}
510511

511-
// Create a new impl if this isn't a valid redeclaration.
512-
if (!impl_id.has_value()) {
513-
impl.generic_id = BuildGeneric(context, impl.latest_decl_id());
514-
if (impl.witness_id != SemIR::ErrorInst::InstId) {
515-
if (impl.interface.interface_id.has_value()) {
516-
impl.witness_id =
517-
ImplWitnessForDeclaration(context, impl, is_definition);
518-
} else {
519-
impl.witness_id = SemIR::ErrorInst::InstId;
520-
// TODO: We might also want to mark that the name scope for the impl has
521-
// an error -- at least once we start making name lookups within the
522-
// impl also look into the facet (eg, so you can name associated
523-
// constants from within the impl).
524-
}
512+
if (impl_id.has_value()) {
513+
// This is a redeclaration of another impl, now held in `impl_id`.
514+
auto& prev_impl = context.impls().Get(impl_id);
515+
FinishGenericRedecl(context, prev_impl.generic_id);
516+
return impl_id;
517+
}
518+
519+
// This is a new declaration (possibly with an attached definition). Create a
520+
// new `impl_id`, filling the missing generic and witness in the provided
521+
// `Impl`.
522+
523+
impl.generic_id = BuildGeneric(context, impl.latest_decl_id());
524+
if (impl.witness_id != SemIR::ErrorInst::InstId) {
525+
if (impl.interface.interface_id.has_value()) {
526+
impl.witness_id = ImplWitnessForDeclaration(context, impl, is_definition);
527+
} else {
528+
impl.witness_id = SemIR::ErrorInst::InstId;
529+
// TODO: We might also want to mark that the name scope for the impl has
530+
// an error -- at least once we start making name lookups within the
531+
// impl also look into the facet (eg, so you can name associated
532+
// constants from within the impl).
525533
}
526-
FinishGenericDecl(context, SemIR::LocId(impl.latest_decl_id()),
527-
impl.generic_id);
528-
// From here on, use the `Impl` from the `ImplStore` instead of `impl`
529-
// in order to make and see any changes to the `Impl`.
530-
impl_id = context.impls().Add(impl);
531-
lookup_bucket_ref.push_back(impl_id);
532-
533-
AssignImplIdInWitness(context, impl_id, impl.witness_id);
534-
535-
// Looking to see if there are any generic bindings on the `impl`
536-
// declaration that are not deducible. If so, and the `impl` does not
537-
// actually use all its generic bindings, and will never be matched. This
538-
// should be diagnossed to the user.
539-
bool has_error_in_implicit_pattern = false;
540-
if (impl.implicit_param_patterns_id.has_value()) {
541-
for (auto inst_id :
542-
context.inst_blocks().Get(impl.implicit_param_patterns_id)) {
543-
if (inst_id == SemIR::ErrorInst::InstId) {
544-
has_error_in_implicit_pattern = true;
545-
break;
546-
}
534+
}
535+
FinishGenericDecl(context, SemIR::LocId(impl.latest_decl_id()),
536+
impl.generic_id);
537+
// From here on, use the `Impl` from the `ImplStore` instead of `impl`
538+
// in order to make and see any changes to the `Impl`.
539+
impl_id = context.impls().Add(impl);
540+
lookup_bucket_ref.push_back(impl_id);
541+
542+
AssignImplIdInWitness(context, impl_id, impl.witness_id);
543+
544+
auto& stored_impl_info = context.impls().Get(impl_id);
545+
546+
// Looking to see if there are any generic bindings on the `impl`
547+
// declaration that are not deducible. If so, and the `impl` does not
548+
// actually use all its generic bindings, and will never be matched. This
549+
// should be diagnossed to the user.
550+
bool has_error_in_implicit_pattern = false;
551+
if (impl.implicit_param_patterns_id.has_value()) {
552+
for (auto inst_id :
553+
context.inst_blocks().Get(impl.implicit_param_patterns_id)) {
554+
if (inst_id == SemIR::ErrorInst::InstId) {
555+
has_error_in_implicit_pattern = true;
556+
break;
547557
}
548558
}
549-
550-
if (!has_error_in_implicit_pattern) {
551-
DiagnoseUnusedGenericBinding(context, loc_id, implicit_params_loc_id,
552-
impl_id);
553-
}
554-
} else {
555-
auto& stored_impl = context.impls().Get(impl_id);
556-
FinishGenericRedecl(context, stored_impl.generic_id);
557559
}
558560

559-
// Write the impl ID into the ImplDecl.
560-
auto impl_decl =
561-
context.insts().GetAs<SemIR::ImplDecl>(impl.first_owning_decl_id);
562-
CARBON_CHECK(!impl_decl.impl_id.has_value());
563-
impl_decl.impl_id = impl_id;
564-
ReplaceInstBeforeConstantUse(context, impl.first_owning_decl_id, impl_decl);
561+
if (!has_error_in_implicit_pattern) {
562+
DiagnoseUnusedGenericBinding(context, loc_id, implicit_params_loc_id,
563+
impl_id);
564+
}
565565

566566
// For an `extend impl` declaration, mark the impl as extending this `impl`.
567-
if (extend_impl) {
568-
auto& stored_impl_info = context.impls().Get(impl_decl.impl_id);
567+
if (extend_node.has_value()) {
569568
auto self_type_id =
570569
context.types().GetTypeIdForTypeInstId(stored_impl_info.self_id);
571570
if (self_type_id != SemIR::ErrorInst::TypeId) {
@@ -578,9 +577,8 @@ auto StartImplDecl(Context& context, SemIR::LocId loc_id,
578577
.specific_id = context.generics().GetSelfSpecific(
579578
stored_impl_info.generic_id)});
580579
}
581-
if (!ExtendImpl(context, extend_impl->extend_node_id, loc_id,
582-
impl_decl.impl_id, implicit_params_loc_id, constraint_id,
583-
extend_impl->constraint_type_id)) {
580+
if (!ApplyExtendImplAs(context, extend_node, loc_id, impl_id,
581+
implicit_params_loc_id, constraint_id)) {
584582
// Don't allow the invalid impl to be used.
585583
FillImplWitnessWithErrors(context, stored_impl_info);
586584
}
@@ -598,7 +596,7 @@ auto StartImplDecl(Context& context, SemIR::LocId loc_id,
598596
}
599597
}
600598

601-
return {impl_id, impl.latest_decl_id()};
599+
return impl_id;
602600
}
603601

604602
} // namespace Carbon::Check

toolchain/check/impl.h

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,16 @@ auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id,
5252
SemIR::TypeInstId constraint_id)
5353
-> SemIR::SpecificInterface;
5454

55-
// For `StartImplDecl`, additional details for an `extend impl` declaration.
56-
struct ExtendImplDecl {
57-
Parse::NodeId self_type_node_id;
58-
SemIR::TypeId constraint_type_id;
59-
Parse::NodeId extend_node_id;
60-
};
61-
62-
// Starts an impl declaration. The caller is responsible for ensuring a generic
63-
// declaration has been started. This returns the produced `ImplId` and
64-
// `ImplDecl`'s `InstId`.
55+
// Finds an existing `Impl` if the `impl` is a redeclaration. Otherwise,
56+
// finishes construction of the `impl`, adds it to the ImplStore, and returns
57+
// the new `ImplId`. This ensures all redeclarations share the same `ImplId`.
6558
//
66-
// The `impl` should be constructed with a placeholder `ImplDecl` which this
67-
// will add the `ImplId` to.
68-
auto StartImplDecl(Context& context, SemIR::LocId loc_id,
69-
SemIR::LocId implicit_params_loc_id, SemIR::Impl impl,
70-
bool is_definition,
71-
std::optional<ExtendImplDecl> extend_impl)
72-
-> std::pair<SemIR::ImplId, SemIR::InstId>;
59+
// If the impl is modified with `extend` then the parent's scope is extended
60+
// with it.
61+
auto GetOrAddImpl(Context& context, SemIR::LocId loc_id,
62+
SemIR::LocId implicit_params_loc_id, SemIR::Impl impl,
63+
bool is_definition, Parse::NodeId extend_node)
64+
-> SemIR::ImplId;
7365

7466
} // namespace Carbon::Check
7567

0 commit comments

Comments
 (0)