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

Code before:
                      "redefinition of `impl {0} as {1}`", InstIdAsRawType,
                      InstIdAsRawType);
    CARBON_DIAGNOSTIC(ImplPreviousDefinition, Note,
                      "previous definition was here");
    context.emitter()
        .Build(new_impl.latest_decl_id(), ImplRedefinition, new_impl.self_id,
               new_impl.constraint_id)
        .Note(prev_impl.definition_id, ImplPreviousDefinition)
        .Emit();
    return false;
  }

  // TODO: Only allow redeclaration in a match_first/impl_priority block.

  return true;
}

// Apply an `extend impl` declaration by extending the parent scope with the
// `impl`. If there's an error it is diagnosed and false is returned.
static auto ApplyExtendImplAs(Context& context, SemIR::LocId loc_id,
                              const SemIR::Impl& impl,
                              Parse::NodeId extend_node,
                              SemIR::LocId implicit_params_loc_id) -> bool {
  auto parent_scope_id = context.decl_name_stack().PeekParentScopeId();

  // TODO: Also handle the parent scope being a mixin.
  auto class_scope = TryAsClassScope(context, parent_scope_id);
  if (!class_scope) {
    if (impl.witness_id != SemIR::ErrorInst::InstId) {
      CARBON_DIAGNOSTIC(ExtendImplOutsideClass, Error,
                        "`extend impl` can only be used in a class");
      context.emitter().Emit(loc_id, ExtendImplOutsideClass);
    }
    return false;
  }

  auto& parent_scope = *class_scope->name_scope;

  // An error was already diagnosed, but this is `extend impl as` inside a
  // class, so propagate the error into the enclosing class scope.
  if (impl.witness_id == SemIR::ErrorInst::InstId) {
    parent_scope.set_has_error();
    return false;
  }

  if (implicit_params_loc_id.has_value()) {
    CARBON_DIAGNOSTIC(ExtendImplForall, Error,
                      "cannot `extend` a parameterized `impl`");
    context.emitter().Emit(extend_node, ExtendImplForall);
    parent_scope.set_has_error();
    return false;

Review comment (suggestion):
https://docs.carbon-lang.dev/proposals/p5337.html#proposal defines `extend impl as` as having a meaning in an `interface` scope as well.

Code after:
                      "redefinition of `impl {0} as {1}`", InstIdAsRawType,
                      InstIdAsRawType);
    CARBON_DIAGNOSTIC(ImplPreviousDefinition, Note,
                      "previous definition was here");
    context.emitter()
        .Build(new_impl.latest_decl_id(), ImplRedefinition, new_impl.self_id,
               new_impl.constraint_id)
        .Note(prev_impl.definition_id, ImplPreviousDefinition)
        .Emit();
    return false;
  }

  // TODO: Only allow redeclaration in a match_first/impl_priority block.

  return true;
}

// Apply an `extend impl` declaration by extending the parent scope with the
// `impl`. If there's an error it is diagnosed and false is returned.
static auto ApplyExtendImplAs(Context& context, SemIR::LocId loc_id,
                              const SemIR::Impl& impl,
                              Parse::NodeId extend_node,
                              SemIR::LocId implicit_params_loc_id) -> bool {
  auto parent_scope_id = context.decl_name_stack().PeekParentScopeId();

  // TODO: Also handle the parent scope being a mixin or an interface.
  auto class_scope = TryAsClassScope(context, parent_scope_id);
  if (!class_scope) {
    if (impl.witness_id != SemIR::ErrorInst::InstId) {
      CARBON_DIAGNOSTIC(
          ExtendImplOutsideClass, Error,
          "`extend impl` can only be used in an interface or class");
      context.emitter().Emit(loc_id, ExtendImplOutsideClass);
    }
    return false;
  }

  auto& parent_scope = *class_scope->name_scope;

  // An error was already diagnosed, but this is `extend impl as` inside a
  // class, so propagate the error into the enclosing class scope.
  if (impl.witness_id == SemIR::ErrorInst::InstId) {
    parent_scope.set_has_error();
    return false;
  }

  if (implicit_params_loc_id.has_value()) {
    CARBON_DIAGNOSTIC(ExtendImplForall, Error,
                      "cannot `extend` a parameterized `impl`");
    context.emitter().Emit(extend_node, ExtendImplForall);
    parent_scope.set_has_error();