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

Code before:
    // values.
    return context.TODO(node_id,
                        "local `let :!` bindings are currently unsupported");
  }

  // Allocate an instruction of the appropriate kind, linked to the name for
  // error locations.
  switch (context.full_pattern_stack().CurrentKind()) {
    case FullPatternStack::Kind::ImplicitParamList:
    case FullPatternStack::Kind::ExplicitParamList: {
      if (!IsValidParamForIntroducer(context, node_id, name_id, introducer.kind,
                                     is_generic)) {
        if (name_id != SemIR::NameId::Underscore) {
          AddNameToLookup(context, name_id, SemIR::ErrorInst::InstId);
        }
        // Replace the parameter with `ErrorInst` so that we don't try
        // constructing a generic based on it.
        context.node_stack().Push(node_id, SemIR::ErrorInst::InstId);
        break;
      }

      // Using `AsConcreteType` here causes `fn F[var self: Self]();`
      // to fail since `Self` is an incomplete type.
      if (node_kind == Parse::NodeKind::VarBindingPattern) {
        auto unqualified_type_id =
            context.types().GetUnqualifiedType(cast_type_id);
        if (context.types().Is<SemIR::ClassType>(unqualified_type_id)) {
          auto class_type =
              context.types().GetAs<SemIR::ClassType>(unqualified_type_id);
          auto& class_info = context.classes().Get(class_type.class_id);
          if (class_info.inheritance_kind ==
              SemIR::Class::InheritanceKind::Abstract) {
            auto builder = abstract_diagnoser();
            CARBON_DIAGNOSTIC(
                ClassAbstractHere, Note,
                "{0:=0:uses class that|=1:class} was declared abstract here",
                Diagnostics::IntAsSelect);
            builder.Note(class_info.definition_id, ClassAbstractHere, 1);
            builder.Emit();
            cast_type_id = SemIR::ErrorInst::TypeId;
          }
        }
      }

      auto result_inst_id = make_binding_pattern();

      // A binding pattern in a function signature is a `Call` parameter
      // unless it's nested inside a `var` pattern (because then the
      // enclosing `var` pattern is), or it's a compile-time binding pattern
      // (because then it's not passed to the `Call` inst).
      if (node_kind == Parse::NodeKind::LetBindingPattern) {

Review comment (refactor):
Actually, a `partial C` for `abstract C` should be valid here -- you might need to include qualifiers

(partial types are always complete (if defined))

Code after:
    // values.
    return context.TODO(node_id,
                        "local `let :!` bindings are currently unsupported");
  }

  // Allocate an instruction of the appropriate kind, linked to the name for
  // error locations.
  switch (context.full_pattern_stack().CurrentKind()) {
    case FullPatternStack::Kind::ImplicitParamList:
    case FullPatternStack::Kind::ExplicitParamList: {
      if (!IsValidParamForIntroducer(context, node_id, name_id, introducer.kind,
                                     is_generic)) {
        if (name_id != SemIR::NameId::Underscore) {
          AddNameToLookup(context, name_id, SemIR::ErrorInst::InstId);
        }
        // Replace the parameter with `ErrorInst` so that we don't try
        // constructing a generic based on it.
        context.node_stack().Push(node_id, SemIR::ErrorInst::InstId);
        break;
      }

      // Using `AsConcreteType` here causes `fn F[var self: Self]();`
      // to fail since `Self` is an incomplete type.
      if (node_kind == Parse::NodeKind::VarBindingPattern) {
        auto [unqualified_type_id, qualifiers] =
            context.types().GetUnqualifiedTypeAndQualifiers(cast_type_id);
        if ((qualifiers & SemIR::TypeQualifiers::Partial) !=
                SemIR::TypeQualifiers::Partial &&
            context.types().Is<SemIR::ClassType>(unqualified_type_id)) {
          auto class_type =
              context.types().GetAs<SemIR::ClassType>(unqualified_type_id);
          auto& class_info = context.classes().Get(class_type.class_id);
          if (class_info.inheritance_kind ==
              SemIR::Class::InheritanceKind::Abstract) {
            auto builder = abstract_diagnoser();
            auto direct_use = true;
            NoteAbstractClass(context, class_type.class_id, direct_use,
                              builder);
            builder.Emit();
            cast_type_id = SemIR::ErrorInst::TypeId;
          }
        }
      }

      auto result_inst_id = make_binding_pattern();

      // A binding pattern in a function signature is a `Call` parameter
      // unless it's nested inside a `var` pattern (because then the
      // enclosing `var` pattern is), or it's a compile-time binding pattern
      // (because then it's not passed to the `Call` inst).
      if (node_kind == Parse::NodeKind::LetBindingPattern) {