|
14 | 14 | #include "toolchain/check/inst.h" |
15 | 15 | #include "toolchain/check/modifiers.h" |
16 | 16 | #include "toolchain/check/name_lookup.h" |
| 17 | +#include "toolchain/check/name_scope.h" |
17 | 18 | #include "toolchain/check/pattern_match.h" |
18 | 19 | #include "toolchain/check/type.h" |
19 | 20 | #include "toolchain/check/type_completion.h" |
|
24 | 25 |
|
25 | 26 | namespace Carbon::Check { |
26 | 27 |
|
| 28 | +// Returns the implicit `Self` type for an `impl` when it's in a `class` |
| 29 | +// declaration. |
| 30 | +// |
| 31 | +// TODO: Mixin scopes also have a default `Self` type. |
| 32 | +static auto GetImplDefaultSelfType(Context& context, |
| 33 | + const ClassScope& class_scope) |
| 34 | + -> SemIR::TypeId { |
| 35 | + return context.classes().Get(class_scope.class_decl.class_id).self_type_id; |
| 36 | +} |
| 37 | + |
27 | 38 | auto HandleParseNode(Context& context, Parse::ImplIntroducerId node_id) |
28 | 39 | -> bool { |
29 | 40 | // This might be a generic impl. |
@@ -56,23 +67,57 @@ auto HandleParseNode(Context& context, Parse::ForallId /*node_id*/) -> bool { |
56 | 67 |
|
57 | 68 | auto HandleParseNode(Context& context, Parse::ImplTypeAsId node_id) -> bool { |
58 | 69 | auto [self_node, self_id] = context.node_stack().PopExprWithNodeId(); |
59 | | - auto self_type_inst_id = ExprAsType(context, self_node, self_id).inst_id; |
60 | | - context.node_stack().Push(node_id, self_type_inst_id); |
| 70 | + auto self_type = ExprAsType(context, self_node, self_id); |
| 71 | + |
| 72 | + const auto& introducer = context.decl_introducer_state_stack().innermost(); |
| 73 | + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { |
| 74 | + // TODO: Also handle the parent scope being a mixin. |
| 75 | + auto class_scope = |
| 76 | + TryAsClassScope(context, context.decl_name_stack().PeekParentScopeId()); |
| 77 | + if (class_scope) { |
| 78 | + // If we're not inside a class at all, that will be diagnosed against the |
| 79 | + // `extend` elsewhere. |
| 80 | + auto extend_node = introducer.modifier_node_id(ModifierOrder::Extend); |
| 81 | + CARBON_DIAGNOSTIC(ExtendImplSelfAs, Error, |
| 82 | + "cannot `extend` an `impl` with an explicit self type"); |
| 83 | + auto diag = context.emitter().Build(extend_node, ExtendImplSelfAs); |
| 84 | + |
| 85 | + if (self_type.type_id == GetImplDefaultSelfType(context, *class_scope)) { |
| 86 | + // If the explicit self type is the default, suggest removing it with a |
| 87 | + // diagnostic, but continue as if no error occurred since the self-type |
| 88 | + // is semantically valid. |
| 89 | + CARBON_DIAGNOSTIC(ExtendImplSelfAsDefault, Note, |
| 90 | + "remove the explicit `Self` type here"); |
| 91 | + diag.Note(self_node, ExtendImplSelfAsDefault); |
| 92 | + if (self_type.type_id != SemIR::ErrorInst::TypeId) { |
| 93 | + diag.Emit(); |
| 94 | + } |
| 95 | + } else if (self_type.type_id != SemIR::ErrorInst::TypeId) { |
| 96 | + // Otherwise, the self-type is an error. |
| 97 | + diag.Emit(); |
| 98 | + class_scope->name_scope->set_has_error(); |
| 99 | + self_type.inst_id = SemIR::ErrorInst::TypeInstId; |
| 100 | + } |
| 101 | + } |
| 102 | + } |
61 | 103 |
|
62 | 104 | // Introduce `Self`. Note that we add this name lexically rather than adding |
63 | 105 | // to the `NameScopeId` of the `impl`, because this happens before we enter |
64 | 106 | // the `impl` scope or even identify which `impl` we're declaring. |
65 | 107 | // TODO: Revisit this once #3714 is resolved. |
66 | | - AddNameToLookup(context, SemIR::NameId::SelfType, self_type_inst_id); |
| 108 | + AddNameToLookup(context, SemIR::NameId::SelfType, self_type.inst_id); |
| 109 | + context.node_stack().Push(node_id, self_type.inst_id); |
67 | 110 | return true; |
68 | 111 | } |
69 | 112 |
|
70 | 113 | auto HandleParseNode(Context& context, Parse::ImplDefaultSelfAsId node_id) |
71 | 114 | -> bool { |
72 | 115 | auto self_inst_id = SemIR::TypeInstId::None; |
73 | 116 |
|
74 | | - if (auto self_type_id = GetImplDefaultSelfType(context); |
75 | | - self_type_id.has_value()) { |
| 117 | + auto class_scope = |
| 118 | + TryAsClassScope(context, context.decl_name_stack().PeekParentScopeId()); |
| 119 | + if (class_scope) { |
| 120 | + auto self_type_id = GetImplDefaultSelfType(context, *class_scope); |
76 | 121 | // Build the implicit access to the enclosing `Self`. |
77 | 122 | // TODO: Consider calling `HandleNameAsExpr` to build this implicit `Self` |
78 | 123 | // expression. We've already done the work to check that the enclosing |
|
0 commit comments