From a2ba7f1262dd5bae0ae31165c0e360cd7c667574 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Fri, 27 Mar 2026 12:36:52 -0700 Subject: [PATCH] Have Specific track whether regions contain errors (#6982) This removes some loops in type completion, but is motivated by the thought that eval probably wants to query it. Assisted-by: Google Antigravity with Gemini --- toolchain/check/eval.cpp | 8 +- toolchain/check/eval.h | 7 +- toolchain/check/generic.cpp | 12 ++- toolchain/check/import_ref.cpp | 3 + .../basics/raw_sem_ir/one_file.carbon | 78 +++++++++---------- toolchain/check/type_completion.cpp | 40 +++------- toolchain/sem_ir/dump.cpp | 23 ++++-- toolchain/sem_ir/generic.h | 22 +++++- 8 files changed, 101 insertions(+), 92 deletions(-) diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 706747fca221..b0fc9ac3535e 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -2599,7 +2599,7 @@ auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id, auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id, SemIR::SpecificId specific_id, SemIR::GenericInstIndex::Region region) - -> SemIR::InstBlockId { + -> std::pair { auto generic_id = context.specifics().Get(specific_id).generic_id; auto eval_block_id = context.generics().Get(generic_id).GetEvalBlock(region); auto eval_block = context.inst_blocks().Get(eval_block_id); @@ -2621,15 +2621,19 @@ auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id, builder.Context(loc_id, ResolvingSpecificHere, specific_id); }); + bool has_error = false; for (auto [i, inst_id] : llvm::enumerate(eval_block)) { auto const_id = TryEvalInstInContext(eval_context, inst_id, context.insts().Get(inst_id)); + if (const_id == SemIR::ErrorInst::ConstantId) { + has_error = true; + } result[i] = context.constant_values().GetInstId(const_id); CARBON_CHECK(result[i].has_value(), "Failed to evaluate {0} in eval block", context.insts().Get(inst_id)); } - return context.inst_blocks().Add(result); + return {context.inst_blocks().Add(result), has_error}; } // Information about the function call we are currently executing. Unlike diff --git a/toolchain/check/eval.h b/toolchain/check/eval.h index 8dd13d52f4b9..67430c184298 100644 --- a/toolchain/check/eval.h +++ b/toolchain/check/eval.h @@ -6,6 +6,7 @@ #define CARBON_TOOLCHAIN_CHECK_EVAL_H_ #include "toolchain/check/context.h" +#include "toolchain/sem_ir/generic.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/inst_kind.h" @@ -51,13 +52,11 @@ auto TryEvalInst(Context& context, InstT inst) -> SemIR::ConstantId { // Evaluates the eval block for a region of a specific. Produces a block // containing the evaluated constant values of the instructions in the eval -// block. -// -// TODO: Return whether any of the instructions produced contain an ErrorInst. +// block. The returned bool indicates whether the region has an error. auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id, SemIR::SpecificId specific_id, SemIR::GenericInstIndex::Region region) - -> SemIR::InstBlockId; + -> std::pair; } // namespace Carbon::Check diff --git a/toolchain/check/generic.cpp b/toolchain/check/generic.cpp index aee00116d8fc..5036892c9fd9 100644 --- a/toolchain/check/generic.cpp +++ b/toolchain/check/generic.cpp @@ -666,9 +666,7 @@ auto ResolveSpecificDecl(Context& context, SemIR::LocId loc_id, // recursively resolve the same specific. specific.decl_block_id = SemIR::InstBlockId::Empty; - // TODO: Store in the specific whether the declaration contains any - // ErrorInst values. - specific.decl_block_id = + std::tie(specific.decl_block_id, specific.decl_block_has_error) = TryEvalBlockForSpecific(context, loc_id, specific_id, SemIR::GenericInstIndex::Region::Declaration); } @@ -734,10 +732,10 @@ auto ResolveSpecificDefinition(Context& context, SemIR::LocId loc_id, // The generic is not defined yet. return false; } - // TODO: Store in the specific whether the definition contains any ErrorInst - // values. - specific.definition_block_id = TryEvalBlockForSpecific( - context, loc_id, specific_id, SemIR::GenericInstIndex::Definition); + std::tie(specific.definition_block_id, + specific.definition_block_has_error) = + TryEvalBlockForSpecific(context, loc_id, specific_id, + SemIR::GenericInstIndex::Definition); } return true; } diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 5be74f39fa84..f3841d68a7e2 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -1068,9 +1068,12 @@ static auto TryFinishSpecific(ImportRefResolver& resolver, if (!local_specific.decl_block_id.has_value()) { local_specific.decl_block_id = GetLocalCanonicalInstBlockId( resolver, import_specific.decl_block_id, decl_block); + local_specific.decl_block_has_error = import_specific.decl_block_has_error; } local_specific.definition_block_id = GetLocalCanonicalInstBlockId( resolver, import_specific.definition_block_id, definition_block); + local_specific.definition_block_has_error = + import_specific.definition_block_has_error; return true; } diff --git a/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon b/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon index 40d4799a090b..80aa33326b72 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon @@ -371,45 +371,45 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: generic78000009: {decl: inst7800011F, bindings: inst_block7800007F, self_specific_id: specific78000017, decl_block_id: inst_block78000083, definition_block_id: inst_block78000085} // CHECK:STDOUT: generic7800000A: {decl: inst78000126, bindings: inst_block78000070, self_specific_id: specific7800001A, decl_block_id: inst_block78000072, definition_block_id: inst_block7800007C} // CHECK:STDOUT: specifics: -// CHECK:STDOUT: specific78000000: {generic: generic78000000, args: inst_block78000016, decl_block_id: inst_block78000018, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000001: {generic: generic78000001, args: inst_block7800001D, decl_block_id: inst_block_empty, definition_block_id: inst_block7800001E} -// CHECK:STDOUT: specific78000002: {generic: generic78000002, args: inst_block7800001D, decl_block_id: inst_block78000024, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000003: {generic: generic78000001, args: inst_block78000025, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000004: {generic: generic78000003, args: inst_block78000028, decl_block_id: inst_block78000029, definition_block_id: inst_block7800002A} -// CHECK:STDOUT: specific78000005: {generic: generic78000001, args: inst_block78000028, decl_block_id: inst_block_empty, definition_block_id: inst_block78000030} -// CHECK:STDOUT: specific78000006: {generic: generic78000002, args: inst_block78000028, decl_block_id: inst_block78000031, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000007: {generic: generic78000004, args: inst_block78000028, decl_block_id: inst_block78000035, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000008: {generic: generic78000001, args: inst_block78000032, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000009: {generic: generic78000002, args: inst_block78000032, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800000A: {generic: generic78000003, args: inst_block78000038, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800000B: {generic: generic78000005, args: inst_block78000016, decl_block_id: inst_block7800003D, definition_block_id: inst_block78000086} -// CHECK:STDOUT: specific7800000C: {generic: generic78000005, args: inst_block78000040, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800000D: {generic: generic78000006, args: inst_block78000016, decl_block_id: inst_block78000047, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800000E: {generic: generic78000007, args: inst_block7800004C, decl_block_id: inst_block7800004E, definition_block_id: inst_block7800004F} -// CHECK:STDOUT: specific7800000F: {generic: generic78000001, args: inst_block78000056, decl_block_id: inst_block_empty, definition_block_id: inst_block78000057} -// CHECK:STDOUT: specific78000010: {generic: generic78000002, args: inst_block78000056, decl_block_id: inst_block78000058, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000011: {generic: generic78000008, args: inst_block7800004C, decl_block_id: inst_block7800005E, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000012: {generic: generic78000001, args: inst_block78000059, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000013: {generic: generic78000002, args: inst_block78000059, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000014: {generic: generic78000001, args: inst_block7800005B, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000015: {generic: generic78000002, args: inst_block7800005B, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000016: {generic: generic78000007, args: inst_block78000061, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000017: {generic: generic78000009, args: inst_block78000069, decl_block_id: inst_block7800006B, definition_block_id: inst_block7800006C} -// CHECK:STDOUT: specific78000018: {generic: generic78000001, args: inst_block78000073, decl_block_id: inst_block_empty, definition_block_id: inst_block78000074} -// CHECK:STDOUT: specific78000019: {generic: generic78000002, args: inst_block78000073, decl_block_id: inst_block78000075, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800001A: {generic: generic7800000A, args: inst_block78000069, decl_block_id: inst_block7800007D, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800001B: {generic: generic78000001, args: inst_block78000076, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800001C: {generic: generic78000002, args: inst_block78000076, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800001D: {generic: generic78000001, args: inst_block78000078, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800001E: {generic: generic78000002, args: inst_block78000078, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific7800001F: {generic: generic78000001, args: inst_block7800007A, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000020: {generic: generic78000002, args: inst_block7800007A, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000021: {generic: generic78000009, args: inst_block78000080, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000022: {generic: generic78000005, args: inst_block78000087, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000023: {generic: generic78000001, args: inst_block78000089, decl_block_id: inst_block_empty, definition_block_id: inst_block7800008A} -// CHECK:STDOUT: specific78000024: {generic: generic78000001, args: inst_block7800008C, decl_block_id: inst_block, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000025: {generic: generic78000002, args: inst_block78000089, decl_block_id: inst_block7800008D, definition_block_id: inst_block} -// CHECK:STDOUT: specific78000026: {generic: generic78000002, args: inst_block7800008C, decl_block_id: inst_block, definition_block_id: inst_block} +// CHECK:STDOUT: specific78000000: {generic: generic78000000, args: inst_block78000016, decl_block_id: inst_block78000018, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000001: {generic: generic78000001, args: inst_block7800001D, decl_block_id: inst_block_empty, decl_has_error: 0, definition_block_id: inst_block7800001E, definition_has_error: 0} +// CHECK:STDOUT: specific78000002: {generic: generic78000002, args: inst_block7800001D, decl_block_id: inst_block78000024, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000003: {generic: generic78000001, args: inst_block78000025, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000004: {generic: generic78000003, args: inst_block78000028, decl_block_id: inst_block78000029, decl_has_error: 0, definition_block_id: inst_block7800002A, definition_has_error: 0} +// CHECK:STDOUT: specific78000005: {generic: generic78000001, args: inst_block78000028, decl_block_id: inst_block_empty, decl_has_error: 0, definition_block_id: inst_block78000030, definition_has_error: 0} +// CHECK:STDOUT: specific78000006: {generic: generic78000002, args: inst_block78000028, decl_block_id: inst_block78000031, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000007: {generic: generic78000004, args: inst_block78000028, decl_block_id: inst_block78000035, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000008: {generic: generic78000001, args: inst_block78000032, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000009: {generic: generic78000002, args: inst_block78000032, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800000A: {generic: generic78000003, args: inst_block78000038, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800000B: {generic: generic78000005, args: inst_block78000016, decl_block_id: inst_block7800003D, decl_has_error: 0, definition_block_id: inst_block78000086, definition_has_error: 0} +// CHECK:STDOUT: specific7800000C: {generic: generic78000005, args: inst_block78000040, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800000D: {generic: generic78000006, args: inst_block78000016, decl_block_id: inst_block78000047, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800000E: {generic: generic78000007, args: inst_block7800004C, decl_block_id: inst_block7800004E, decl_has_error: 0, definition_block_id: inst_block7800004F, definition_has_error: 0} +// CHECK:STDOUT: specific7800000F: {generic: generic78000001, args: inst_block78000056, decl_block_id: inst_block_empty, decl_has_error: 0, definition_block_id: inst_block78000057, definition_has_error: 0} +// CHECK:STDOUT: specific78000010: {generic: generic78000002, args: inst_block78000056, decl_block_id: inst_block78000058, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000011: {generic: generic78000008, args: inst_block7800004C, decl_block_id: inst_block7800005E, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000012: {generic: generic78000001, args: inst_block78000059, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000013: {generic: generic78000002, args: inst_block78000059, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000014: {generic: generic78000001, args: inst_block7800005B, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000015: {generic: generic78000002, args: inst_block7800005B, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000016: {generic: generic78000007, args: inst_block78000061, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000017: {generic: generic78000009, args: inst_block78000069, decl_block_id: inst_block7800006B, decl_has_error: 0, definition_block_id: inst_block7800006C, definition_has_error: 0} +// CHECK:STDOUT: specific78000018: {generic: generic78000001, args: inst_block78000073, decl_block_id: inst_block_empty, decl_has_error: 0, definition_block_id: inst_block78000074, definition_has_error: 0} +// CHECK:STDOUT: specific78000019: {generic: generic78000002, args: inst_block78000073, decl_block_id: inst_block78000075, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800001A: {generic: generic7800000A, args: inst_block78000069, decl_block_id: inst_block7800007D, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800001B: {generic: generic78000001, args: inst_block78000076, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800001C: {generic: generic78000002, args: inst_block78000076, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800001D: {generic: generic78000001, args: inst_block78000078, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800001E: {generic: generic78000002, args: inst_block78000078, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific7800001F: {generic: generic78000001, args: inst_block7800007A, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000020: {generic: generic78000002, args: inst_block7800007A, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000021: {generic: generic78000009, args: inst_block78000080, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000022: {generic: generic78000005, args: inst_block78000087, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000023: {generic: generic78000001, args: inst_block78000089, decl_block_id: inst_block_empty, decl_has_error: 0, definition_block_id: inst_block7800008A, definition_has_error: 0} +// CHECK:STDOUT: specific78000024: {generic: generic78000001, args: inst_block7800008C, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000025: {generic: generic78000002, args: inst_block78000089, decl_block_id: inst_block7800008D, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} +// CHECK:STDOUT: specific78000026: {generic: generic78000002, args: inst_block7800008C, decl_block_id: inst_block, decl_has_error: 0, definition_block_id: inst_block, definition_has_error: 0} // CHECK:STDOUT: specific_interfaces: // CHECK:STDOUT: specific_interface78000000: {interface_id: interface78000000, specific_id: specific} // CHECK:STDOUT: struct_type_fields: diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index b83ba1c7da87..fbed8a147c85 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -104,29 +104,11 @@ static auto DiagnoseIncompleteNamedConstraint( } } -// TODO: Have the resolved specific know whether any instructions in the -// declaration or definition contain an ErrorInst, instead of having to do a -// linear scan here. -static auto SpecificContainsError(Context& context, - SemIR::SpecificId specific_id) -> bool { - if (!specific_id.has_value()) { - return false; - } - - const auto& specific = context.specifics().Get(specific_id); - auto block_ids = {specific.decl_block_id, specific.definition_block_id}; - - for (auto block_id : block_ids) { - if (block_id.has_value()) { - for (auto inst_id : context.inst_blocks().Get(block_id)) { - if (context.constant_values().Get(inst_id) == - SemIR::ErrorInst::ConstantId) { - return true; - } - } - } - } - return false; +// Returns true if either eval block contains an error. +static auto SpecificHasError(Context& context, SemIR::SpecificId specific_id) + -> bool { + return specific_id.has_value() && + context.specifics().Get(specific_id).HasError(); } static auto RequireCompleteFacetType(Context& context, SemIR::LocId loc_id, @@ -146,7 +128,7 @@ static auto RequireCompleteFacetType(Context& context, SemIR::LocId loc_id, } if (interface.generic_id.has_value()) { ResolveSpecificDefinition(context, loc_id, extends.specific_id); - if (SpecificContainsError(context, extends.specific_id)) { + if (SpecificHasError(context, extends.specific_id)) { return false; } } @@ -158,7 +140,7 @@ static auto RequireCompleteFacetType(Context& context, SemIR::LocId loc_id, auto interface_with_self_specific_id = MakeSpecificWithInnerSelf( context, loc_id, interface.generic_id, interface.generic_with_self_id, extends.specific_id, context.constant_values().Get(self_facet)); - if (SpecificContainsError(context, interface_with_self_specific_id)) { + if (SpecificHasError(context, interface_with_self_specific_id)) { return false; } } @@ -175,7 +157,7 @@ static auto RequireCompleteFacetType(Context& context, SemIR::LocId loc_id, } if (constraint.generic_id.has_value()) { ResolveSpecificDefinition(context, loc_id, extends.specific_id); - if (SpecificContainsError(context, extends.specific_id)) { + if (SpecificHasError(context, extends.specific_id)) { return false; } } @@ -187,7 +169,7 @@ static auto RequireCompleteFacetType(Context& context, SemIR::LocId loc_id, auto constraint_with_self_specific_id = MakeSpecificWithInnerSelf( context, loc_id, constraint.generic_id, constraint.generic_with_self_id, extends.specific_id, context.constant_values().Get(self_facet)); - if (SpecificContainsError(context, constraint_with_self_specific_id)) { + if (SpecificHasError(context, constraint_with_self_specific_id)) { return false; } } @@ -972,7 +954,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, auto constraint_with_self_specific_id = MakeSpecificWithInnerSelf( context, loc_id, constraint.generic_id, constraint.generic_with_self_id, extends.specific_id, self_facet); - if (SpecificContainsError(context, constraint_with_self_specific_id)) { + if (SpecificHasError(context, constraint_with_self_specific_id)) { return SemIR::IdentifiedFacetTypeId::None; } @@ -1031,7 +1013,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, auto constraint_with_self_specific_id = MakeSpecificWithInnerSelf( context, loc_id, constraint.generic_id, constraint.generic_with_self_id, impls.specific_id, self_facet); - if (SpecificContainsError(context, constraint_with_self_specific_id)) { + if (SpecificHasError(context, constraint_with_self_specific_id)) { return SemIR::IdentifiedFacetTypeId::None; } diff --git a/toolchain/sem_ir/dump.cpp b/toolchain/sem_ir/dump.cpp index ff8e3f13a6eb..8551bc22234a 100644 --- a/toolchain/sem_ir/dump.cpp +++ b/toolchain/sem_ir/dump.cpp @@ -405,6 +405,16 @@ LLVM_DUMP_METHOD auto Dump(const File& file, RequireImplsId require_impls_id) return out.TakeStr(); } +static auto DumpEvalBlock(const File& file, llvm::StringRef region_name, + InstBlockId block_id, bool has_error) -> std::string { + RawStringOstream out; + if (block_id.has_value()) { + out << "\nspecific " << region_name << " block" + << (has_error ? " (has error)" : "") << ": " << Dump(file, block_id); + } + return out.TakeStr(); +} + LLVM_DUMP_METHOD auto Dump(const File& file, SpecificId specific_id) -> std::string { RawStringOstream out; @@ -413,14 +423,11 @@ LLVM_DUMP_METHOD auto Dump(const File& file, SpecificId specific_id) const auto& specific = file.specifics().Get(specific_id); out << '\n' << Dump(file, specific.args_id) << '\n' - << DumpGenericSummary(file, specific.generic_id); - if (specific.decl_block_id.has_value()) { - out << "\nspecific decl block: " << Dump(file, specific.decl_block_id); - } - if (specific.definition_block_id.has_value()) { - out << "\nspecific definition block: " - << Dump(file, specific.definition_block_id); - } + << DumpGenericSummary(file, specific.generic_id) + << DumpEvalBlock(file, "decl", specific.decl_block_id, + specific.decl_block_has_error) + << DumpEvalBlock(file, "definition", specific.definition_block_id, + specific.definition_block_has_error); } return out.TakeStr(); } diff --git a/toolchain/sem_ir/generic.h b/toolchain/sem_ir/generic.h index 421b32f2931f..4cb2975ea1c6 100644 --- a/toolchain/sem_ir/generic.h +++ b/toolchain/sem_ir/generic.h @@ -72,9 +72,15 @@ class GenericStore : public ValueStore> { // values for the compile-time parameters themselves. struct Specific : Printable { auto Print(llvm::raw_ostream& out) const -> void { - out << "{generic: " << generic_id << ", args: " << args_id - << ", decl_block_id: " << decl_block_id - << ", definition_block_id: " << definition_block_id << "}"; + auto print_block = [&](llvm::StringLiteral region, InstBlockId id, + bool has_error) { + out << ", " << region << "_block_id: " << id << ", " << region + << "_has_error: " << has_error; + }; + out << "{generic: " << generic_id << ", args: " << args_id; + print_block("decl", decl_block_id, decl_block_has_error); + print_block("definition", definition_block_id, definition_block_has_error); + out << "}"; } // Returns true if this specific has never been resolved. Such specifics are @@ -95,6 +101,11 @@ struct Specific : Printable { : definition_block_id; } + // Returns whether either block has an error. + auto HasError() const -> bool { + return decl_block_has_error || definition_block_has_error; + } + // The generic that this is a specific version of. GenericId generic_id; // Argument values, corresponding to the bindings in `Generic::bindings_id`. @@ -107,6 +118,11 @@ struct Specific : Printable { InstBlockId decl_block_id = InstBlockId::None; // The value block for the definition region of the specific. InstBlockId definition_block_id = InstBlockId::None; + + // Whether the corresponding block contains an error. These are stored + // directly on Specific so that they pack together. + bool decl_block_has_error = false; + bool definition_block_has_error = false; }; // Provides storage for deduplicated specifics, which represent generics plus