Repository: carbon-language/carbon-lang
File: toolchain/check/handle_impl.cpp (C++)

Code before:

  // An impl doesn't have a name per se, but it makes the processing more
  // consistent to imagine that it does. This also gives us a scope for implicit
  // parameters.
  context.decl_name_stack().PushScopeAndStartName();
  return true;
}

auto HandleParseNode(Context& context, Parse::ForallId /*node_id*/) -> bool {
  // Push a pattern block for the signature of the `forall`.
  context.pattern_block_stack().Push();
  context.full_pattern_stack().PushFullPattern(
      FullPatternStack::Kind::ImplicitParamList);
  return true;
}

auto HandleParseNode(Context& context, Parse::ImplTypeAsId node_id) -> bool {
  auto [self_node, self_id] = context.node_stack().PopExprWithNodeId();
  auto self_type = ExprAsType(context, self_node, self_id);

  const auto& introducer = context.decl_introducer_state_stack().innermost();
  if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
    // TODO: Also handle the parent scope being a mixin.
    auto class_scope =
        TryAsClassScope(context, context.decl_name_stack().PeekParentScopeId());
    if (class_scope) {
      // If we're not inside a class at all, that will be diagnosed against the
      // `extend` elsewhere.
      auto extend_node = introducer.modifier_node_id(ModifierOrder::Extend);
      CARBON_DIAGNOSTIC(ExtendImplSelfAs, Error,
                        "cannot `extend` an `impl` with an explicit self type");
      auto diag = context.emitter().Build(extend_node, ExtendImplSelfAs);

      if (self_type.type_id == GetImplDefaultSelfType(context, *class_scope)) {
        // If the explicit self type is the default, suggest removing it with a
        // diagnostic, but continue as if no error occurred since the self-type
        // is semantically valid.
        CARBON_DIAGNOSTIC(ExtendImplSelfAsDefault, Note,
                          "remove the explicit `Self` type here");
        diag.Note(self_node, ExtendImplSelfAsDefault);
        if (self_type.type_id != SemIR::ErrorInst::TypeId) {
          diag.Emit();
        }
      } else if (self_type.type_id != SemIR::ErrorInst::TypeId) {
        // Otherwise, the self-type is an error.
        diag.Emit();
        class_scope->name_scope->set_has_error();
        self_type.inst_id = SemIR::ErrorInst::TypeInstId;
      }
    }
  }

Review comment (suggestion):
```suggestion
    if (auto class_scope =
            TryAsClassScope(context, context.decl_name_stack().PeekParentScopeId())) {
```

Code after:

  // An impl doesn't have a name per se, but it makes the processing more
  // consistent to imagine that it does. This also gives us a scope for implicit
  // parameters.
  context.decl_name_stack().PushScopeAndStartName();
  return true;
}

auto HandleParseNode(Context& context, Parse::ForallId /*node_id*/) -> bool {
  // Push a pattern block for the signature of the `forall`.
  context.pattern_block_stack().Push();
  context.full_pattern_stack().PushFullPattern(
      FullPatternStack::Kind::ImplicitParamList);
  return true;
}

auto HandleParseNode(Context& context, Parse::ImplTypeAsId node_id) -> bool {
  auto [self_node, self_id] = context.node_stack().PopExprWithNodeId();
  auto self_type = ExprAsType(context, self_node, self_id);

  const auto& introducer = context.decl_introducer_state_stack().innermost();
  if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
    // TODO: Also handle the parent scope being a mixin.
    if (auto class_scope = TryAsClassScope(
            context, context.decl_name_stack().PeekParentScopeId())) {
      // If we're not inside a class at all, that will be diagnosed against the
      // `extend` elsewhere.
      auto extend_node = introducer.modifier_node_id(ModifierOrder::Extend);
      CARBON_DIAGNOSTIC(ExtendImplSelfAs, Error,
                        "cannot `extend` an `impl` with an explicit self type");
      auto diag = context.emitter().Build(extend_node, ExtendImplSelfAs);

      if (self_type.type_id == GetImplDefaultSelfType(context, *class_scope)) {
        // If the explicit self type is the default, suggest removing it with a
        // diagnostic, but continue as if no error occurred since the self-type
        // is semantically valid.
        CARBON_DIAGNOSTIC(ExtendImplSelfAsDefault, Note,
                          "remove the explicit `Self` type here");
        diag.Note(self_node, ExtendImplSelfAsDefault);
        if (self_type.type_id != SemIR::ErrorInst::TypeId) {
          diag.Emit();
        }
      } else if (self_type.type_id != SemIR::ErrorInst::TypeId) {
        // Otherwise, the self-type is an error.
        diag.Emit();
        class_scope->name_scope->set_has_error();
        self_type.inst_id = SemIR::ErrorInst::TypeInstId;
      }
    }
  }