mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Diagnose using named constraint's name inside its definition (#6906)
Using a named constraint inside itself is problematic: - If there were not require decls written above, it identifies as an empty set. This makes `Z(Self)` essentially disappear in the identified facet type, which produces "no use of Self" diagnostics while the user can see a use of Self in the code. - It won't include require decls that are written after, and so `require T impls Z` won't actually enforce that `T` impls all of `Z`. Previously this was an error because using the named constraint would require it to be identified, and it's not identified until it is complete. But this will change in proposal #6902. So that proposal also includes changes to preserve diagnostics for incorrect use of a named constraint before it's complete, which is implemented here. Discussed in open discussion [on 2026-03-12](https://docs.google.com/document/d/1mjllGO3ZCL4qGt9uJHUtcxKoHAGEY7Y999ie4EtBWB8/edit?tab=t.0#heading=h.1dvbbrp5a6t3). The new tests exposed a bug where we're not copying named constraints in a facet type on the RHS of `where .Self impls` into the facet type on the left, which is now fixed. The `fail_require_impls_incomplete_self_in_period_self_impls.carbon` test would not diagnose its error without this fix.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/named_constraint.h"
|
||||
#include "toolchain/sem_ir/specific_named_constraint.h"
|
||||
#include "toolchain/sem_ir/type_iterator.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
@@ -209,6 +210,36 @@ static auto ValidateRequire(Context& context, SemIR::LocId loc_id,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (auto named_constraint =
|
||||
context.insts().TryGetAs<SemIR::NamedConstraintWithSelfDecl>(
|
||||
scope_inst_id)) {
|
||||
const auto& constraint_facet_type_info =
|
||||
context.facet_types().Get(constraint_facet_type->facet_type_id);
|
||||
// TODO: Handle other impls named constraints for the
|
||||
// RequireImplsReferenceCycle diagnostic.
|
||||
if (constraint_facet_type_info.other_requirements) {
|
||||
context.TODO(constraint_inst_id,
|
||||
"facet type has constraints that we don't handle yet");
|
||||
return std::nullopt;
|
||||
}
|
||||
auto named_constraints = llvm::concat<const SemIR::SpecificNamedConstraint>(
|
||||
constraint_facet_type_info.extend_named_constraints,
|
||||
constraint_facet_type_info.self_impls_named_constraints);
|
||||
for (auto c : named_constraints) {
|
||||
if (c.named_constraint_id == named_constraint->named_constraint_id) {
|
||||
const auto& named_constraint =
|
||||
context.named_constraints().Get(c.named_constraint_id);
|
||||
CARBON_DIAGNOSTIC(RequireImplsReferenceCycle, Error,
|
||||
"facet type in `require` declaration refers to the "
|
||||
"named constraint `{0}` from within its definition",
|
||||
SemIR::NameId);
|
||||
context.emitter().Emit(constraint_inst_id, RequireImplsReferenceCycle,
|
||||
named_constraint.name_id);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto identified_facet_type_id = RequireIdentifiedFacetType(
|
||||
context, SemIR::LocId(constraint_inst_id), self_constant_value_id,
|
||||
*constraint_facet_type, [&](auto& builder) {
|
||||
|
||||
Reference in New Issue
Block a user