From b1c7e585f96bddde38d677e193ffc344a2494e23 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 9 Jul 2026 15:09:06 -0400 Subject: [PATCH] Diagnose `.Self` being used in a type that is not a facet type (#7471) `.Self` will only be replaced in a facet type, as the facet type constrains a facet. If it's part of a (non-facet) type, then the object of that type is not a facet, and we can never replace that `.Self`. --- toolchain/check/handle_binding_pattern.cpp | 18 ++++++- .../check/testdata/facet/period_self.carbon | 51 +++++++++++++++---- toolchain/diagnostics/kind.def | 1 + 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/toolchain/check/handle_binding_pattern.cpp b/toolchain/check/handle_binding_pattern.cpp index cd0d5cb16c68..aa77e0b340d1 100644 --- a/toolchain/check/handle_binding_pattern.cpp +++ b/toolchain/check/handle_binding_pattern.cpp @@ -19,6 +19,7 @@ #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" #include "toolchain/check/unused.h" +#include "toolchain/diagnostics/diagnostic.h" #include "toolchain/diagnostics/format_providers.h" #include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/ids.h" @@ -147,7 +148,22 @@ static auto HandleAnyBindingPatternType(Context& context, // We are leaving the scope of the `.Self`; they should no longer be frozen in // the binding's type. - original_inst_id = ThawPeriodSelf(context, original_inst_id); + auto thawed_inst_id = ThawPeriodSelf(context, original_inst_id); + if (thawed_inst_id != original_inst_id) { + // If ThawPeriodSelf changed the instruction, it means there is a `.Self` + // reference in the type. Diagnose if the type is not a facet type. + auto const_inst_id = + context.constant_values().GetConstantInstId(original_inst_id); + if (!context.insts().Is(const_inst_id) && + const_inst_id != SemIR::ErrorInst::InstId) { + CARBON_DIAGNOSTIC(PeriodSelfInNonFacetType, Error, + "`.Self` used in a type that is not a facet type"); + context.emitter().Emit(node_id, PeriodSelfInNonFacetType); + original_inst_id = SemIR::ErrorInst::InstId; + } else { + original_inst_id = thawed_inst_id; + } + } if (node_kind == Parse::FormBindingPattern::Kind) { auto as_form = FormExprAsForm(context, node_id, original_inst_id); diff --git a/toolchain/check/testdata/facet/period_self.carbon b/toolchain/check/testdata/facet/period_self.carbon index 72e6c1b98298..757d68464102 100644 --- a/toolchain/check/testdata/facet/period_self.carbon +++ b/toolchain/check/testdata/facet/period_self.carbon @@ -41,16 +41,11 @@ fn G(_:! I(.Self) where .I1 = ()) {} // --- fail_period_self_as_type.carbon library "[[@TEST_NAME]]"; -// TODO: We should diagnose this use of `.Self` directly rather than later when -// it is converted to `type`. +// CHECK:STDERR: fail_period_self_as_type.carbon:[[@LINE+4]]:17: error: `.Self` used in a type that is not a facet type [PeriodSelfInNonFacetType] +// CHECK:STDERR: interface I(T:! .Self) { +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: interface I(T:! .Self) { - // CHECK:STDERR: fail_period_self_as_type.carbon:[[@LINE+7]]:13: error: cannot implicitly convert non-type value of type `.Self` to `type` [ConversionFailureNonTypeToFacet] - // CHECK:STDERR: fn G() -> T; - // CHECK:STDERR: ^ - // CHECK:STDERR: fail_period_self_as_type.carbon:[[@LINE+4]]:13: note: type `.Self` does not implement interface `Core.ImplicitAs(type)` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: fn G() -> T; - // CHECK:STDERR: ^ - // CHECK:STDERR: fn G() -> T; } @@ -528,6 +523,44 @@ fn F(T:! L where C(.W) impls Z(.Self) and .Self impls M) { C(()) as Z(T); } +// --- fail_period_self_in_class_argument.carbon +library "[[@TEST_NAME]]"; + +class C(T:! type); + +// CHECK:STDERR: fail_period_self_in_class_argument.carbon:[[@LINE+4]]:10: error: `.Self` used in a type that is not a facet type [PeriodSelfInNonFacetType] +// CHECK:STDERR: fn F(_:! C(.Self)) {} +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: +fn F(_:! C(.Self)) {} + +// --- fail_period_self_in_class_argument_in_where.carbon +library "[[@TEST_NAME]]"; + +class C(T:! type); + +// CHECK:STDERR: fail_period_self_in_class_argument_in_where.carbon:[[@LINE+8]]:10: error: left argument of `where` operator must be a facet type [WhereOnNonFacetType] +// CHECK:STDERR: fn F(_:! C(.Self) where type == type) {} +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: +// CHECK:STDERR: fail_period_self_in_class_argument_in_where.carbon:[[@LINE+4]]:25: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] +// CHECK:STDERR: fn F(_:! C(.Self) where type == type) {} +// CHECK:STDERR: ^~~~~~~~~~~~ +// CHECK:STDERR: +fn F(_:! C(.Self) where type == type) {} + +// --- fail_period_self_in_interface_argument_in_class_argument.carbon +library "[[@TEST_NAME]]"; + +class C(T:! type); +interface Z(T:! type); + +// CHECK:STDERR: fail_period_self_in_interface_argument_in_class_argument.carbon:[[@LINE+4]]:10: error: `.Self` used in a type that is not a facet type [PeriodSelfInNonFacetType] +// CHECK:STDERR: fn F(_:! C(Z(.Self))) {} +// CHECK:STDERR: ^~~~~~~~~~~ +// CHECK:STDERR: +fn F(_:! C(Z(.Self))) {} + // CHECK:STDOUT: --- period_self_param.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index 837f170f1616..8f070774ac93 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -512,6 +512,7 @@ CARBON_DIAGNOSTIC_KIND(TupleIndexOnANonTupleType) CARBON_DIAGNOSTIC_KIND(TupleIndexOutOfBounds) CARBON_DIAGNOSTIC_KIND(TupleInitElementCountMismatch) CARBON_DIAGNOSTIC_KIND(PartialOnFinal) +CARBON_DIAGNOSTIC_KIND(PeriodSelfInNonFacetType) CARBON_DIAGNOSTIC_KIND(ReturnedVarHere) CARBON_DIAGNOSTIC_KIND(ReturnedVarNotInit) CARBON_DIAGNOSTIC_KIND(ReturnedVarShadowed)