Просмотр исходного кода

Implement syntax changes from #2760 in Explorer (#2906)

Implement syntax changes from #2760 in Explorer
josh11b 2 лет назад
Родитель
Сommit
1505a634a4
100 измененных файлов с 561 добавлено и 341 удалено
  1. 9 4
      common/fuzzing/carbon.proto
  2. 24 13
      common/fuzzing/proto_to_carbon.cpp
  3. 4 3
      explorer/ast/ast_kinds.h
  4. 35 13
      explorer/ast/declaration.cpp
  5. 37 23
      explorer/ast/declaration.h
  6. 36 36
      explorer/data/prelude.carbon
  7. 19 9
      explorer/fuzzing/ast_to_proto.cpp
  8. 1 1
      explorer/fuzzing/fuzzer_corpus/2291d3e5898c9c430cc6ecf3855f87bcae68cfbc
  9. 1 1
      explorer/fuzzing/fuzzer_corpus/29cb786e12d8db536d5f0748863f751ef4db52ce
  10. 1 1
      explorer/fuzzing/fuzzer_corpus/2b342d5ea73ce8b83dd29a47bda07bb050f62d56
  11. 1 1
      explorer/fuzzing/fuzzer_corpus/2bbd64b5c75365c1644b9823f9cd572ce53acdd4
  12. 2 2
      explorer/fuzzing/fuzzer_corpus/e16ea66236bb097cd84a5366b1b0035149a138f8
  13. 2 2
      explorer/fuzzing/fuzzer_corpus/e2d470d716b0c66b140be21c060b3cf401703c31
  14. 1 1
      explorer/fuzzing/fuzzer_corpus/efa240ed14717324b4e69b96dd37978d9205e4b5
  15. 3 2
      explorer/interpreter/interpreter.cpp
  16. 3 2
      explorer/interpreter/resolve_control_flow.cpp
  17. 17 11
      explorer/interpreter/resolve_names.cpp
  18. 3 2
      explorer/interpreter/resolve_unformed.cpp
  19. 74 38
      explorer/interpreter/type_checker.cpp
  20. 4 4
      explorer/syntax/lexer.lpp
  21. 53 27
      explorer/syntax/parser.ypp
  22. 1 1
      explorer/testdata/alias/member_name_alias.carbon
  23. 1 1
      explorer/testdata/array/element_convertible_to_type.carbon
  24. 1 1
      explorer/testdata/as/convert.carbon
  25. 1 1
      explorer/testdata/as/implicit_as.carbon
  26. 1 1
      explorer/testdata/assert/convert.carbon
  27. 1 1
      explorer/testdata/assert/fail_convert.carbon
  28. 1 1
      explorer/testdata/assert/fail_intrinsic_bool_type.carbon
  29. 1 1
      explorer/testdata/assert/fail_intrinsic_no_args.carbon
  30. 1 1
      explorer/testdata/assert/fail_intrinsic_no_convert.carbon
  31. 1 1
      explorer/testdata/assert/fail_intrinsic_str_type.carbon
  32. 2 2
      explorer/testdata/assoc_const/bug_multi_impl_scoping.carbon
  33. 2 2
      explorer/testdata/assoc_const/fail_different_type.carbon
  34. 2 2
      explorer/testdata/assoc_const/fail_different_value.carbon
  35. 1 1
      explorer/testdata/assoc_const/fail_equal_indirectly.carbon
  36. 1 1
      explorer/testdata/assoc_const/fail_equal_to_dependent_type.carbon
  37. 1 1
      explorer/testdata/assoc_const/fail_incomplete_impl_1.carbon
  38. 1 1
      explorer/testdata/assoc_const/fail_incomplete_impl_2.carbon
  39. 1 1
      explorer/testdata/assoc_const/fail_indirectly_equal.carbon
  40. 1 1
      explorer/testdata/assoc_const/fail_match_in_deduction.carbon
  41. 1 1
      explorer/testdata/assoc_const/fail_overspecified_impl.carbon
  42. 1 1
      explorer/testdata/assoc_const/impl_lookup.carbon
  43. 1 1
      explorer/testdata/assoc_const/implement.carbon
  44. 4 4
      explorer/testdata/assoc_const/lookup_in_rewrite.carbon
  45. 1 1
      explorer/testdata/assoc_const/member_of_value.carbon
  46. 1 1
      explorer/testdata/assoc_const/pass_equal_to_rewrite.carbon
  47. 1 1
      explorer/testdata/assoc_const/pass_rewrite_to_equal.carbon
  48. 1 1
      explorer/testdata/assoc_const/resolve_rewrites.carbon
  49. 1 1
      explorer/testdata/assoc_const/rewrite_large_type.carbon
  50. 2 1
      explorer/testdata/class/abstract_class.carbon
  51. 2 1
      explorer/testdata/class/base_constructor.carbon
  52. 2 1
      explorer/testdata/class/class_inheritance_function_call.carbon
  53. 2 1
      explorer/testdata/class/class_inheritance_methods.carbon
  54. 4 2
      explorer/testdata/class/class_inheritance_multiple.carbon
  55. 2 1
      explorer/testdata/class/class_inheritance_shadow.carbon
  56. 2 1
      explorer/testdata/class/class_inheritance_variables.carbon
  57. 4 2
      explorer/testdata/class/class_subtyping_argument.carbon
  58. 2 1
      explorer/testdata/class/class_subtyping_basic.carbon
  59. 4 2
      explorer/testdata/class/class_subtyping_multiple.carbon
  60. 2 1
      explorer/testdata/class/fail_abstract_method_not_supported.carbon
  61. 2 1
      explorer/testdata/class/fail_direct_base_class_init.carbon
  62. 20 0
      explorer/testdata/class/fail_extend_after_var.carbon
  63. 3 2
      explorer/testdata/class/fail_extend_final_class.carbon
  64. 3 2
      explorer/testdata/class/fail_extend_non_class.carbon
  65. 23 0
      explorer/testdata/class/fail_extend_twice.carbon
  66. 2 1
      explorer/testdata/class/fail_field_access_mismatch_base.carbon
  67. 2 1
      explorer/testdata/class/fail_field_assign_mismatch_base.carbon
  68. 2 1
      explorer/testdata/class/fail_impl_method_not_existing.carbon
  69. 2 1
      explorer/testdata/class/fail_impl_method_not_virtual.carbon
  70. 2 1
      explorer/testdata/class/fail_override_virtual_with_non_virtual.carbon
  71. 2 1
      explorer/testdata/class/fail_redeclare_virtual_method.carbon
  72. 2 1
      explorer/testdata/class/fail_virtual_method_absent.carbon
  73. 2 1
      explorer/testdata/class/new_and_delete_hierarchy.carbon
  74. 2 1
      explorer/testdata/class/non_virtual_dispatch.carbon
  75. 2 1
      explorer/testdata/class/non_virtual_dispatch_abstract.carbon
  76. 3 2
      explorer/testdata/class/parametrized_base_class.carbon
  77. 4 2
      explorer/testdata/class/pointer_conversion.carbon
  78. 2 1
      explorer/testdata/class/virtual_method.carbon
  79. 4 2
      explorer/testdata/class/virtual_method_self.carbon
  80. 2 1
      explorer/testdata/class/virtual_method_shadowed_attr.carbon
  81. 1 1
      explorer/testdata/comparison/custom_equality.carbon
  82. 1 1
      explorer/testdata/comparison/empty_struct.carbon
  83. 1 1
      explorer/testdata/constraint/rewrite.carbon
  84. 1 1
      explorer/testdata/constraint/rewrite_compound.carbon
  85. 1 1
      explorer/testdata/constraint/rewrite_compound_2.carbon
  86. 1 1
      explorer/testdata/constraint/rewrite_in_qualifier.carbon
  87. 1 1
      explorer/testdata/constraint/rewrite_in_qualifier_and_type.carbon
  88. 1 1
      explorer/testdata/constraint/where_impls.carbon
  89. 13 11
      explorer/testdata/destructor/destroy_base_class.carbon
  90. 4 2
      explorer/testdata/destructor/destroy_base_class_and_members.carbon
  91. 7 6
      explorer/testdata/destructor/fail_delete_base_without_virtual_destructor.carbon
  92. 4 3
      explorer/testdata/destructor/fail_override_virtual_virtual.carbon
  93. 16 14
      explorer/testdata/destructor/virtual_destructor.carbon
  94. 23 22
      explorer/testdata/destructor/virtual_destructor_nested.carbon
  95. 3 3
      explorer/testdata/function/convert_args.carbon
  96. 1 1
      explorer/testdata/function/return_convertible_to_type.carbon
  97. 1 1
      explorer/testdata/generic_class/class_function.carbon
  98. 1 1
      explorer/testdata/generic_class/generic_class_substitution.carbon
  99. 1 1
      explorer/testdata/generic_class/generic_fun_and_class.carbon
  100. 1 1
      explorer/testdata/generic_class/impl_with_argument.carbon

+ 9 - 4
common/fuzzing/carbon.proto

@@ -371,6 +371,10 @@ message ClassDeclaration {
   optional TuplePattern type_params = 3;
 }
 
+message ExtendBaseDeclaration {
+  optional Expression base_class = 1;
+}
+
 message AlternativeSignature {
   optional string name = 1;
   optional TupleLiteralExpression signature = 3;
@@ -392,11 +396,11 @@ message LetDeclaration {
   // `let` declarations in general.
 }
 
-message InterfaceExtendsDeclaration {
+message InterfaceExtendDeclaration {
   optional Expression base = 1;
 }
 
-message InterfaceImplDeclaration {
+message InterfaceRequireDeclaration {
   optional Expression impl_type = 1;
   optional Expression constraint = 2;
 }
@@ -465,11 +469,12 @@ message Declaration {
     MixinDeclaration mixin = 9;
     MixDeclaration mix = 10;
     DestructorDeclaration destructor = 11;
-    InterfaceExtendsDeclaration interface_extends = 12;
-    InterfaceImplDeclaration interface_impl = 13;
+    InterfaceExtendDeclaration interface_extend = 12;
+    InterfaceRequireDeclaration interface_require = 13;
     ConstraintDeclaration constraint = 14;
     MatchFirstDeclaration match_first = 15;
     NamespaceDeclaration namespace = 16;
+    ExtendBaseDeclaration extend_base = 17;
   }
 }
 

+ 24 - 13
common/fuzzing/proto_to_carbon.cpp

@@ -801,6 +801,14 @@ static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
       break;
     }
 
+    case Fuzzing::Declaration::kExtendBase: {
+      const auto& extend_base_declaration = declaration.extend_base();
+      out << "  extend base: ";
+      ExpressionToCarbon(extend_base_declaration.base_class(), out);
+      out << ";\n";
+      break;
+    }
+
     // EXPERIMENTAL MIXIN FEATURE
     case Fuzzing::Declaration::kMixin: {
       const auto& mixin_declaration = declaration.mixin();
@@ -877,19 +885,19 @@ static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
       break;
     }
 
-    case Fuzzing::Declaration::kInterfaceExtends: {
-      const auto& extends = declaration.interface_extends();
-      out << "extends ";
-      ExpressionToCarbon(extends.base(), out);
+    case Fuzzing::Declaration::kInterfaceExtend: {
+      const auto& extend = declaration.interface_extend();
+      out << "extend ";
+      ExpressionToCarbon(extend.base(), out);
       out << ";";
       break;
     }
 
-    case Fuzzing::Declaration::kInterfaceImpl: {
-      const auto& impl = declaration.interface_impl();
-      out << "impl ";
+    case Fuzzing::Declaration::kInterfaceRequire: {
+      const auto& impl = declaration.interface_require();
+      out << "require ";
       ExpressionToCarbon(impl.impl_type(), out);
-      out << " as ";
+      out << " impls ";
       ExpressionToCarbon(impl.constraint(), out);
       out << ";";
       break;
@@ -923,8 +931,8 @@ static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
 
     case Fuzzing::Declaration::kImpl: {
       const auto& impl = declaration.impl();
-      if (impl.kind() == Fuzzing::ImplDeclaration::ExternalImpl) {
-        out << "external ";
+      if (impl.kind() == Fuzzing::ImplDeclaration::InternalImpl) {
+        out << "extend ";
       }
       out << "impl ";
       if (!impl.deduced_parameters().empty()) {
@@ -934,10 +942,13 @@ static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
           out << sep;
           GenericBindingToCarbon(p, out);
         }
-        out << "]";
+        out << "] ";
       }
-      ExpressionToCarbon(impl.impl_type(), out);
-      out << " as ";
+      if (impl.kind() != Fuzzing::ImplDeclaration::InternalImpl) {
+        ExpressionToCarbon(impl.impl_type(), out);
+        out << " ";
+      }
+      out << "as ";
       ExpressionToCarbon(impl.interface(), out);
       out << " {\n";
       for (const auto& member : impl.members()) {

+ 4 - 3
explorer/ast/ast_kinds.h

@@ -78,12 +78,13 @@
   FINAL(VariableDeclaration)                              \
   CARBON_ConstraintTypeDeclaration_KINDS(ABSTRACT, FINAL) \
       ABSTRACT(ConstraintTypeDeclaration)                 \
-  FINAL(InterfaceExtendsDeclaration)                      \
-  FINAL(InterfaceImplDeclaration)                         \
+  FINAL(InterfaceExtendDeclaration)                       \
+  FINAL(InterfaceRequireDeclaration)                      \
   FINAL(AssociatedConstantDeclaration)                    \
   FINAL(ImplDeclaration)                                  \
   FINAL(MatchFirstDeclaration)                            \
-  FINAL(AliasDeclaration)
+  FINAL(AliasDeclaration)                                 \
+  FINAL(ExtendBaseDeclaration)
 
 #define CARBON_CallableDeclaration_KINDS(ABSTRACT, FINAL) \
   FINAL(FunctionDeclaration)                              \

+ 35 - 13
explorer/ast/declaration.cpp

@@ -108,8 +108,8 @@ void Declaration::Print(llvm::raw_ostream& out) const {
       break;
     }
 
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::AssociatedConstantDeclaration: {
       PrintID(out);
       out << ";\n";
@@ -127,6 +127,12 @@ void Declaration::Print(llvm::raw_ostream& out) const {
       out << " = " << alias.target() << ";\n";
       break;
     }
+
+    case DeclarationKind::ExtendBaseDeclaration: {
+      PrintID(out);
+      out << ";\n";
+      break;
+    }
   }
 }
 
@@ -149,9 +155,9 @@ void Declaration::PrintID(llvm::raw_ostream& out) const {
       const auto& impl_decl = cast<ImplDeclaration>(*this);
       switch (impl_decl.kind()) {
         case ImplKind::InternalImpl:
+          out << "extend ";
           break;
         case ImplKind::ExternalImpl:
-          out << "external ";
           break;
       }
       out << "impl ";
@@ -163,7 +169,10 @@ void Declaration::PrintID(llvm::raw_ostream& out) const {
         }
         out << "] ";
       }
-      out << *impl_decl.impl_type() << " as " << impl_decl.interface();
+      if (impl_decl.kind() != ImplKind::InternalImpl) {
+        out << *impl_decl.impl_type() << " ";
+      }
+      out << "as " << impl_decl.interface();
       break;
     }
     case DeclarationKind::MatchFirstDeclaration:
@@ -204,15 +213,15 @@ void Declaration::PrintID(llvm::raw_ostream& out) const {
       break;
     }
 
-    case DeclarationKind::InterfaceExtendsDeclaration: {
-      const auto& extends = cast<InterfaceExtendsDeclaration>(*this);
-      out << "extends " << *extends.base();
+    case DeclarationKind::InterfaceExtendDeclaration: {
+      const auto& extend = cast<InterfaceExtendDeclaration>(*this);
+      out << "extend " << *extend.base();
       break;
     }
 
-    case DeclarationKind::InterfaceImplDeclaration: {
-      const auto& impl = cast<InterfaceImplDeclaration>(*this);
-      out << "impl " << *impl.impl_type() << " as " << *impl.constraint();
+    case DeclarationKind::InterfaceRequireDeclaration: {
+      const auto& impl = cast<InterfaceRequireDeclaration>(*this);
+      out << "require " << *impl.impl_type() << " impls " << *impl.constraint();
       break;
     }
 
@@ -232,6 +241,12 @@ void Declaration::PrintID(llvm::raw_ostream& out) const {
       out << "alias " << alias.name();
       break;
     }
+
+    case DeclarationKind::ExtendBaseDeclaration: {
+      const auto& extend = cast<ExtendBaseDeclaration>(*this);
+      out << "extend base: " << *extend.base_class();
+      break;
+    }
   }
 }
 
@@ -268,8 +283,8 @@ auto GetName(const Declaration& declaration)
       return cast<VariableDeclaration>(declaration).binding().name();
     case DeclarationKind::AssociatedConstantDeclaration:
       return cast<AssociatedConstantDeclaration>(declaration).binding().name();
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::ImplDeclaration:
     case DeclarationKind::MatchFirstDeclaration:
       return std::nullopt;
@@ -278,6 +293,9 @@ auto GetName(const Declaration& declaration)
     case DeclarationKind::AliasDeclaration: {
       return cast<AliasDeclaration>(declaration).name().inner_name();
     }
+    case DeclarationKind::ExtendBaseDeclaration: {
+      return "extend base";
+    }
   }
 }
 
@@ -417,10 +435,14 @@ ClassDeclaration::ClassDeclaration(CloneContext& context,
       extensibility_(other.extensibility_),
       self_decl_(context.Clone(other.self_decl_)),
       type_params_(context.Clone(other.type_params_)),
-      base_expr_(context.Clone(other.base_expr_)),
       members_(context.Clone(other.members_)),
       base_type_(context.Clone(other.base_type_)) {}
 
+ExtendBaseDeclaration::ExtendBaseDeclaration(CloneContext& context,
+                                             const ExtendBaseDeclaration& other)
+    : Declaration(context, other),
+      base_class_(context.Clone(other.base_class_)) {}
+
 ConstraintTypeDeclaration::ConstraintTypeDeclaration(
     CloneContext& context, const ConstraintTypeDeclaration& other)
     : Declaration(context, other),

+ 37 - 23
explorer/ast/declaration.h

@@ -375,14 +375,12 @@ class ClassDeclaration : public Declaration {
                    Nonnull<SelfDeclaration*> self_decl,
                    ClassExtensibility extensibility,
                    std::optional<Nonnull<TuplePattern*>> type_params,
-                   std::optional<Nonnull<Expression*>> base,
                    std::vector<Nonnull<Declaration*>> members)
       : Declaration(AstNodeKind::ClassDeclaration, source_loc),
         name_(std::move(name)),
         extensibility_(extensibility),
         self_decl_(self_decl),
         type_params_(type_params),
-        base_expr_(base),
         members_(std::move(members)) {}
 
   explicit ClassDeclaration(CloneContext& context,
@@ -420,10 +418,6 @@ class ClassDeclaration : public Declaration {
     return ExpressionCategory::Value;
   }
 
-  auto base_expr() const -> std::optional<Nonnull<Expression*>> {
-    return base_expr_;
-  }
-
   // Returns the original base type, before instantiation & substitutions
   // Use `NominalClassType::base()` to get the instantiated type.
   auto base_type() const -> std::optional<Nonnull<const NominalClassType*>> {
@@ -439,7 +433,6 @@ class ClassDeclaration : public Declaration {
   ClassExtensibility extensibility_;
   Nonnull<SelfDeclaration*> self_decl_;
   std::optional<Nonnull<TuplePattern*>> type_params_;
-  std::optional<Nonnull<Expression*>> base_expr_;
   std::vector<Nonnull<Declaration*>> members_;
   std::optional<Nonnull<const NominalClassType*>> base_type_;
 };
@@ -520,6 +513,27 @@ class MixDeclaration : public Declaration {
   std::optional<Nonnull<const MixinPseudoType*>> mixin_value_;
 };
 
+class ExtendBaseDeclaration : public Declaration {
+ public:
+  ExtendBaseDeclaration(SourceLocation source_loc,
+                        Nonnull<Expression*> base_class)
+      : Declaration(AstNodeKind::ExtendBaseDeclaration, source_loc),
+        base_class_(base_class) {}
+
+  explicit ExtendBaseDeclaration(CloneContext& context,
+                                 const ExtendBaseDeclaration& other);
+
+  static auto classof(const AstNode* node) -> bool {
+    return InheritsFromExtendBaseDeclaration(node->kind());
+  }
+
+  auto base_class() const -> Nonnull<const Expression*> { return base_class_; }
+  auto base_class() -> Nonnull<Expression*> { return base_class_; }
+
+ private:
+  Nonnull<Expression*> base_class_;
+};
+
 class AlternativeSignature : public AstNode {
  public:
   AlternativeSignature(SourceLocation source_loc, std::string name,
@@ -789,19 +803,19 @@ class ConstraintDeclaration : public ConstraintTypeDeclaration {
 };
 
 // An `extends` declaration in an interface.
-class InterfaceExtendsDeclaration : public Declaration {
+class InterfaceExtendDeclaration : public Declaration {
  public:
-  InterfaceExtendsDeclaration(SourceLocation source_loc,
-                              Nonnull<Expression*> base)
-      : Declaration(AstNodeKind::InterfaceExtendsDeclaration, source_loc),
+  InterfaceExtendDeclaration(SourceLocation source_loc,
+                             Nonnull<Expression*> base)
+      : Declaration(AstNodeKind::InterfaceExtendDeclaration, source_loc),
         base_(base) {}
 
-  explicit InterfaceExtendsDeclaration(CloneContext& context,
-                                       const InterfaceExtendsDeclaration& other)
+  explicit InterfaceExtendDeclaration(CloneContext& context,
+                                      const InterfaceExtendDeclaration& other)
       : Declaration(context, other), base_(context.Clone(other.base_)) {}
 
   static auto classof(const AstNode* node) -> bool {
-    return InheritsFromInterfaceExtendsDeclaration(node->kind());
+    return InheritsFromInterfaceExtendDeclaration(node->kind());
   }
 
   auto base() const -> const Expression* { return base_; }
@@ -811,24 +825,24 @@ class InterfaceExtendsDeclaration : public Declaration {
   Nonnull<Expression*> base_;
 };
 
-// An `impl ... as` declaration in an interface.
-class InterfaceImplDeclaration : public Declaration {
+// A `require ... impls` declaration in an interface.
+class InterfaceRequireDeclaration : public Declaration {
  public:
-  InterfaceImplDeclaration(SourceLocation source_loc,
-                           Nonnull<Expression*> impl_type,
-                           Nonnull<Expression*> constraint)
-      : Declaration(AstNodeKind::InterfaceImplDeclaration, source_loc),
+  InterfaceRequireDeclaration(SourceLocation source_loc,
+                              Nonnull<Expression*> impl_type,
+                              Nonnull<Expression*> constraint)
+      : Declaration(AstNodeKind::InterfaceRequireDeclaration, source_loc),
         impl_type_(impl_type),
         constraint_(constraint) {}
 
-  explicit InterfaceImplDeclaration(CloneContext& context,
-                                    const InterfaceImplDeclaration& other)
+  explicit InterfaceRequireDeclaration(CloneContext& context,
+                                       const InterfaceRequireDeclaration& other)
       : Declaration(context, other),
         impl_type_(context.Clone(other.impl_type_)),
         constraint_(context.Clone(other.constraint_)) {}
 
   static auto classof(const AstNode* node) -> bool {
-    return InheritsFromInterfaceImplDeclaration(node->kind());
+    return InheritsFromInterfaceRequireDeclaration(node->kind());
   }
 
   auto impl_type() const -> const Expression* { return impl_type_; }

+ 36 - 36
explorer/data/prelude.carbon

@@ -15,7 +15,7 @@ interface As(T:! type) {
 
 // Implicitly convert `Self` to `T`.
 interface ImplicitAs(T:! type) {
-  extends As(T);
+  extend As(T);
 }
 
 // TODO: This should be private.
@@ -87,7 +87,7 @@ interface EqWith(U:! type) {
 }
 
 constraint Eq {
-  extends EqWith(Self);
+  extend EqWith(Self);
 }
 
 // TODO: Simplify this once we have variadics
@@ -151,7 +151,7 @@ interface CompareWith(U:! type) {
   // TODO: Add `default fn` for Less, LessOrEquivalent, Greater, and GreaterOrEquivalent once it's available.
 }
 constraint Ordered {
-  extends CompareWith(Self);
+  extend CompareWith(Self);
 }
 
 impl i32 as CompareWith(Self) {
@@ -327,7 +327,7 @@ interface AddWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint Add {
-  extends AddWith(Self) where .Result = Self;
+  extend AddWith(Self) where .Result = Self;
 }
 
 interface SubWith(U:! type) {
@@ -336,7 +336,7 @@ interface SubWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint Sub {
-  extends SubWith(Self) where .Result = Self;
+  extend SubWith(Self) where .Result = Self;
 }
 
 interface MulWith(U:! type) {
@@ -345,7 +345,7 @@ interface MulWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint Mul {
-  extends MulWith(Self) where .Result = Self;
+  extend MulWith(Self) where .Result = Self;
 }
 
 interface DivWith(U:! type) {
@@ -354,7 +354,7 @@ interface DivWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint Div {
-  extends DivWith(Self) where .Result = Self;
+  extend DivWith(Self) where .Result = Self;
 }
 
 interface ModWith(U:! type) {
@@ -363,26 +363,26 @@ interface ModWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint Mod {
-  extends ModWith(Self) where .Result = Self;
+  extend ModWith(Self) where .Result = Self;
 }
 
 // Note, these impl declarations use the builtin addition for i32.
-external impl i32 as Negate where .Result = i32 {
+impl i32 as Negate where .Result = i32 {
   fn Op[self: i32]() -> i32 { return -self; }
 }
-external impl i32 as AddWith(i32) where .Result = i32 {
+impl i32 as AddWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 { return self + other; }
 }
-external impl i32 as SubWith(i32) where .Result = i32 {
+impl i32 as SubWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 { return self - other; }
 }
-external impl i32 as MulWith(i32) where .Result = i32 {
+impl i32 as MulWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 { return self * other; }
 }
-external impl i32 as DivWith(i32) where .Result = i32 {
+impl i32 as DivWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 { return self / other; }
 }
-external impl i32 as ModWith(i32) where .Result = i32 {
+impl i32 as ModWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 { return self % other; }
 }
 
@@ -404,7 +404,7 @@ interface BitAndWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint BitAnd {
-  extends BitAndWith(Self) where .Result = Self;
+  extend BitAndWith(Self) where .Result = Self;
 }
 
 // Binary `|`.
@@ -414,7 +414,7 @@ interface BitOrWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint BitOr {
-  extends BitOrWith(Self) where .Result = Self;
+  extend BitOrWith(Self) where .Result = Self;
 }
 
 // Binary `^`.
@@ -424,7 +424,7 @@ interface BitXorWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint BitXor {
-  extends BitXorWith(Self) where .Result = Self;
+  extend BitXorWith(Self) where .Result = Self;
 }
 
 // Binary `<<`.
@@ -434,7 +434,7 @@ interface LeftShiftWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint LeftShift {
-  extends LeftShiftWith(Self) where .Result = Self;
+  extend LeftShiftWith(Self) where .Result = Self;
 }
 
 // Binary `>>`.
@@ -444,35 +444,35 @@ interface RightShiftWith(U:! type) {
   fn Op[self: Self](other: U) -> Result;
 }
 constraint RightShift {
-  extends RightShiftWith(Self) where .Result = Self;
+  extend RightShiftWith(Self) where .Result = Self;
 }
 
-external impl i32 as BitComplement where .Result = i32 {
+impl i32 as BitComplement where .Result = i32 {
   fn Op[self: i32]() -> i32 {
     return __intrinsic_int_bit_complement(self);
   }
 }
-external impl i32 as BitAndWith(i32) where .Result = i32 {
+impl i32 as BitAndWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 {
     return __intrinsic_int_bit_and(self, other);
   }
 }
-external impl i32 as BitOrWith(i32) where .Result = i32 {
+impl i32 as BitOrWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 {
     return __intrinsic_int_bit_or(self, other);
   }
 }
-external impl i32 as BitXorWith(i32) where .Result = i32 {
+impl i32 as BitXorWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 {
     return __intrinsic_int_bit_xor(self, other);
   }
 }
-external impl i32 as LeftShiftWith(i32) where .Result = i32 {
+impl i32 as LeftShiftWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 {
     return __intrinsic_int_left_shift(self, other);
   }
 }
-external impl i32 as RightShiftWith(i32) where .Result = i32 {
+impl i32 as RightShiftWith(i32) where .Result = i32 {
   fn Op[self: i32](other: i32) -> i32 {
     return __intrinsic_int_right_shift(self, other);
   }
@@ -485,57 +485,57 @@ external impl i32 as RightShiftWith(i32) where .Result = i32 {
 interface AssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint Assign { extends AssignWith(Self); }
+constraint Assign { extend AssignWith(Self); }
 
 interface AddAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint AddAssign { extends AddAssignWith(Self); }
+constraint AddAssign { extend AddAssignWith(Self); }
 
 interface SubAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint SubAssign { extends SubAssignWith(Self); }
+constraint SubAssign { extend SubAssignWith(Self); }
 
 interface MulAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint MulAssign { extends MulAssignWith(Self); }
+constraint MulAssign { extend MulAssignWith(Self); }
 
 interface DivAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint DivAssign { extends DivAssignWith(Self); }
+constraint DivAssign { extend DivAssignWith(Self); }
 
 interface ModAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint ModAssign { extends ModAssignWith(Self); }
+constraint ModAssign { extend ModAssignWith(Self); }
 
 interface BitAndAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint BitAssignAnd { extends BitAndAssignWith(Self); }
+constraint BitAssignAnd { extend BitAndAssignWith(Self); }
 
 interface BitOrAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint BitAssignOr { extends BitOrAssignWith(Self); }
+constraint BitAssignOr { extend BitOrAssignWith(Self); }
 
 interface BitXorAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint BitAssignXor { extends BitXorAssignWith(Self); }
+constraint BitAssignXor { extend BitXorAssignWith(Self); }
 
 interface LeftShiftAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint LeftShiftAssign { extends LeftShiftAssignWith(Self); }
+constraint LeftShiftAssign { extend LeftShiftAssignWith(Self); }
 
 interface RightShiftAssignWith(U:! type) {
   fn Op[addr self: Self*](other: U);
 }
-constraint RightShiftAssign { extends RightShiftAssignWith(Self); }
+constraint RightShiftAssign { extend RightShiftAssignWith(Self); }
 
 // TODO: This is temporary, and should eventually be replaced by
 // something more fine-grained. Not all class types should be

+ 19 - 9
explorer/fuzzing/ast_to_proto.cpp

@@ -756,18 +756,20 @@ static auto DeclarationToProto(const Declaration& declaration)
       break;
     }
 
-    case DeclarationKind::InterfaceExtendsDeclaration: {
-      const auto& extends = cast<InterfaceExtendsDeclaration>(declaration);
-      auto* extends_proto = declaration_proto.mutable_interface_extends();
-      *extends_proto->mutable_base() = ExpressionToProto(*extends.base());
+    case DeclarationKind::InterfaceExtendDeclaration: {
+      const auto& extend = cast<InterfaceExtendDeclaration>(declaration);
+      auto* extend_proto = declaration_proto.mutable_interface_extend();
+      *extend_proto->mutable_base() = ExpressionToProto(*extend.base());
       break;
     }
 
-    case DeclarationKind::InterfaceImplDeclaration: {
-      const auto& impl = cast<InterfaceImplDeclaration>(declaration);
-      auto* impl_proto = declaration_proto.mutable_interface_impl();
-      *impl_proto->mutable_impl_type() = ExpressionToProto(*impl.impl_type());
-      *impl_proto->mutable_constraint() = ExpressionToProto(*impl.constraint());
+    case DeclarationKind::InterfaceRequireDeclaration: {
+      const auto& require = cast<InterfaceRequireDeclaration>(declaration);
+      auto* require_proto = declaration_proto.mutable_interface_require();
+      *require_proto->mutable_impl_type() =
+          ExpressionToProto(*require.impl_type());
+      *require_proto->mutable_constraint() =
+          ExpressionToProto(*require.constraint());
       break;
     }
 
@@ -841,6 +843,14 @@ static auto DeclarationToProto(const Declaration& declaration)
       *alias_proto->mutable_target() = ExpressionToProto(alias.target());
       break;
     }
+
+    case DeclarationKind::ExtendBaseDeclaration: {
+      const auto& extend_base = cast<ExtendBaseDeclaration>(declaration);
+      auto* extend_base_proto = declaration_proto.mutable_extend_base();
+      *extend_base_proto->mutable_base_class() =
+          ExpressionToProto(*extend_base.base_class());
+      break;
+    }
   }
   return declaration_proto;
 }

+ 1 - 1
explorer/fuzzing/fuzzer_corpus/9a435ff6608006cf717e4ea6d7e22a793081b096 → explorer/fuzzing/fuzzer_corpus/2291d3e5898c9c430cc6ecf3855f87bcae68cfbc

@@ -9,7 +9,7 @@ compilation_unit {
         name: "Vector"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             int_type_literal {
             }

+ 1 - 1
explorer/fuzzing/fuzzer_corpus/f4442e613969488b64b568701f015baa552df409 → explorer/fuzzing/fuzzer_corpus/29cb786e12d8db536d5f0748863f751ef4db52ce

@@ -137,7 +137,7 @@ compilation_unit {
         name: "Constraint"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             identifier {
               name: "Iface"

+ 1 - 1
explorer/fuzzing/fuzzer_corpus/693b9959c2755a9a294266be5333fe1a08dd7732 → explorer/fuzzing/fuzzer_corpus/2b342d5ea73ce8b83dd29a47bda07bb050f62d56

@@ -74,7 +74,7 @@ compilation_unit {
         name: "MyAdd"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             where {
               base {

+ 1 - 1
explorer/fuzzing/fuzzer_corpus/a6cbb1c4cbbae44391bce60832b7f9b034f3839e → explorer/fuzzing/fuzzer_corpus/2bbd64b5c75365c1644b9823f9cd572ce53acdd4

@@ -47,7 +47,7 @@ compilation_unit {
         name: "Banana"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             call {
               function {

+ 2 - 2
explorer/fuzzing/fuzzer_corpus/6740e9ab30860f2c0277ff36e850c53ca4091e89 → explorer/fuzzing/fuzzer_corpus/e16ea66236bb097cd84a5366b1b0035149a138f8

@@ -47,7 +47,7 @@ compilation_unit {
         name: "IndirectMaker"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             call {
               function {
@@ -81,7 +81,7 @@ compilation_unit {
         name: "MoreIndirectMaker"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             call {
               function {

+ 2 - 2
explorer/fuzzing/fuzzer_corpus/1ac93b3166a73257d35daabe1224a4fa02b91438 → explorer/fuzzing/fuzzer_corpus/e2d470d716b0c66b140be21c060b3cf401703c31

@@ -83,7 +83,7 @@ compilation_unit {
         name: "Traversible"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             identifier {
               name: "Runnable"
@@ -92,7 +92,7 @@ compilation_unit {
         }
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             identifier {
               name: "Walkable"

+ 1 - 1
explorer/fuzzing/fuzzer_corpus/c1dda40eae19225720932d324f3f0610f31ab471 → explorer/fuzzing/fuzzer_corpus/efa240ed14717324b4e69b96dd37978d9205e4b5

@@ -28,7 +28,7 @@ compilation_unit {
         name: "Extension"
       }
       members {
-        interface_extends {
+        interface_extend {
           base {
             identifier {
               name: "Base"

+ 3 - 2
explorer/interpreter/interpreter.cpp

@@ -2334,13 +2334,14 @@ auto Interpreter::StepDeclaration() -> ErrorOr<Success> {
     case DeclarationKind::ChoiceDeclaration:
     case DeclarationKind::InterfaceDeclaration:
     case DeclarationKind::ConstraintDeclaration:
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::AssociatedConstantDeclaration:
     case DeclarationKind::ImplDeclaration:
     case DeclarationKind::MatchFirstDeclaration:
     case DeclarationKind::SelfDeclaration:
     case DeclarationKind::AliasDeclaration:
+    case DeclarationKind::ExtendBaseDeclaration:
       // These declarations have no run-time effects.
       return todo_.FinishAction();
   }

+ 3 - 2
explorer/interpreter/resolve_control_flow.cpp

@@ -183,12 +183,13 @@ auto ResolveControlFlow(Nonnull<Declaration*> declaration) -> ErrorOr<Success> {
     case DeclarationKind::NamespaceDeclaration:
     case DeclarationKind::ChoiceDeclaration:
     case DeclarationKind::VariableDeclaration:
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::AssociatedConstantDeclaration:
     case DeclarationKind::SelfDeclaration:
     case DeclarationKind::AliasDeclaration:
     case DeclarationKind::MixDeclaration:
+    case DeclarationKind::ExtendBaseDeclaration:
       // do nothing
       break;
   }

+ 17 - 11
explorer/interpreter/resolve_names.cpp

@@ -264,8 +264,9 @@ auto NameResolver::AddExposedNames(const Declaration& declaration,
     case DeclarationKind::ImplDeclaration:
     case DeclarationKind::MatchFirstDeclaration:
     case DeclarationKind::MixDeclaration:
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration: {
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
+    case DeclarationKind::ExtendBaseDeclaration: {
       // These declarations don't have a name to expose.
       break;
     }
@@ -806,9 +807,6 @@ auto NameResolver::ResolveNamesImpl(Declaration& declaration,
           ResolveQualifier(class_decl.name(), enclosing_scope));
       StaticScope class_scope(scope);
       scope->MarkDeclared(class_decl.name().inner_name());
-      if (auto base_expr = class_decl.base_expr()) {
-        CARBON_RETURN_IF_ERROR(ResolveNames(**base_expr, class_scope));
-      }
       if (auto type_params = class_decl.type_params()) {
         CARBON_RETURN_IF_ERROR(ResolveNames(**type_params, class_scope));
       }
@@ -818,6 +816,12 @@ auto NameResolver::ResolveNamesImpl(Declaration& declaration,
           ResolveMemberNames(class_decl.members(), class_scope, bodies));
       break;
     }
+    case DeclarationKind::ExtendBaseDeclaration: {
+      auto& extend_base_decl = cast<ExtendBaseDeclaration>(declaration);
+      CARBON_RETURN_IF_ERROR(
+          ResolveNames(*extend_base_decl.base_class(), enclosing_scope));
+      break;
+    }
     case DeclarationKind::MixinDeclaration: {
       auto& mixin_decl = cast<MixinDeclaration>(declaration);
       CARBON_ASSIGN_OR_RETURN(
@@ -874,15 +878,17 @@ auto NameResolver::ResolveNamesImpl(Declaration& declaration,
       }
       break;
     }
-    case DeclarationKind::InterfaceExtendsDeclaration: {
-      auto& extends = cast<InterfaceExtendsDeclaration>(declaration);
+    case DeclarationKind::InterfaceExtendDeclaration: {
+      auto& extends = cast<InterfaceExtendDeclaration>(declaration);
       CARBON_RETURN_IF_ERROR(ResolveNames(*extends.base(), enclosing_scope));
       break;
     }
-    case DeclarationKind::InterfaceImplDeclaration: {
-      auto& impl = cast<InterfaceImplDeclaration>(declaration);
-      CARBON_RETURN_IF_ERROR(ResolveNames(*impl.impl_type(), enclosing_scope));
-      CARBON_RETURN_IF_ERROR(ResolveNames(*impl.constraint(), enclosing_scope));
+    case DeclarationKind::InterfaceRequireDeclaration: {
+      auto& require = cast<InterfaceRequireDeclaration>(declaration);
+      CARBON_RETURN_IF_ERROR(
+          ResolveNames(*require.impl_type(), enclosing_scope));
+      CARBON_RETURN_IF_ERROR(
+          ResolveNames(*require.constraint(), enclosing_scope));
       break;
     }
     case DeclarationKind::AssociatedConstantDeclaration: {

+ 3 - 2
explorer/interpreter/resolve_unformed.cpp

@@ -371,11 +371,12 @@ static auto ResolveUnformed(Nonnull<const Declaration*> declaration)
     case DeclarationKind::MatchFirstDeclaration:
     case DeclarationKind::ChoiceDeclaration:
     case DeclarationKind::VariableDeclaration:
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::AssociatedConstantDeclaration:
     case DeclarationKind::SelfDeclaration:
     case DeclarationKind::AliasDeclaration:
+    case DeclarationKind::ExtendBaseDeclaration:
       // do nothing
       break;
     case DeclarationKind::ClassDeclaration:

+ 74 - 38
explorer/interpreter/type_checker.cpp

@@ -5189,29 +5189,55 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
 
   ImplScope class_scope(scope_info.innermost_scope);
 
+  // Find base class declaration, if any. Verify that is before any data member
+  // declarations, and there is at most one.
   std::optional<Nonnull<const NominalClassType*>> base_class;
-  if (class_decl->base_expr().has_value()) {
-    Nonnull<Expression*> base_class_expr = *class_decl->base_expr();
-    CARBON_ASSIGN_OR_RETURN(const auto base_type,
-                            TypeCheckTypeExp(base_class_expr, class_scope));
-    if (base_type->kind() != Value::Kind::NominalClassType) {
-      return ProgramError(class_decl->source_loc())
-             << "Unsupported base class type for class `" << class_decl->name()
-             << "`. Only simple classes are currently supported as base "
-                "class.";
-    }
-
-    base_class = cast<NominalClassType>(base_type);
-    if (base_class.value()->declaration().extensibility() ==
-        ClassExtensibility::None) {
-      return ProgramError(class_decl->source_loc())
-             << "Base class `" << base_class.value()->declaration().name()
-             << "` is `final` and cannot be inherited. Add the `base` or "
-                "`abstract` class prefix to `"
-             << base_class.value()->declaration().name()
-             << "` to allow it to be inherited";
-    }
-    class_decl->set_base_type(base_class);
+  bool after_data_member = false;
+  for (Nonnull<Declaration*> m : class_decl->members()) {
+    switch (m->kind()) {
+      case DeclarationKind::VariableDeclaration:
+      case DeclarationKind::MixDeclaration: {
+        after_data_member = true;
+        break;
+      }
+      case DeclarationKind::ExtendBaseDeclaration: {
+        if (after_data_member) {
+          return ProgramError(m->source_loc())
+                 << "`extend base:` declaration must not be after `var` or "
+                    "`mix` declarations in a class.";
+        }
+        if (base_class.has_value()) {
+          return ProgramError(m->source_loc())
+                 << "At most one `extend base:` declaration in a class.";
+        }
+        Nonnull<Expression*> base_class_expr =
+            cast<ExtendBaseDeclaration>(*m).base_class();
+        CARBON_ASSIGN_OR_RETURN(const auto base_type,
+                                TypeCheckTypeExp(base_class_expr, class_scope));
+        if (base_type->kind() != Value::Kind::NominalClassType) {
+          return ProgramError(m->source_loc())
+                 << "Unsupported base class type for class `"
+                 << class_decl->name()
+                 << "`. Only simple classes are currently supported as base "
+                    "class.";
+        }
+
+        base_class = cast<NominalClassType>(base_type);
+        if (base_class.value()->declaration().extensibility() ==
+            ClassExtensibility::None) {
+          return ProgramError(m->source_loc())
+                 << "Base class `" << base_class.value()->declaration().name()
+                 << "` is `final` and cannot be inherited. Add the `base` or "
+                    "`abstract` class prefix to `"
+                 << base_class.value()->declaration().name()
+                 << "` to allow it to be inherited";
+        }
+        class_decl->set_base_type(base_class);
+        break;
+      }
+      default:
+        break;
+    }
   }
 
   std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
@@ -5592,16 +5618,16 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
     // TODO: This should probably live in `DeclareDeclaration`, but it needs
     // to update state that's not available from there.
     switch (m->kind()) {
-      case DeclarationKind::InterfaceExtendsDeclaration: {
-        // For an `extends C;` declaration, add `Self impls C` to our
+      case DeclarationKind::InterfaceExtendDeclaration: {
+        // For an `extend C;` declaration, add `Self impls C` to our
         // constraint.
-        auto* extends = cast<InterfaceExtendsDeclaration>(m);
+        auto* extend = cast<InterfaceExtendDeclaration>(m);
         CARBON_ASSIGN_OR_RETURN(
             Nonnull<const Value*> base,
-            TypeCheckTypeExp(extends->base(), constraint_scope));
+            TypeCheckTypeExp(extend->base(), constraint_scope));
         CARBON_ASSIGN_OR_RETURN(
             Nonnull<const ConstraintType*> constraint_type,
-            ConvertToConstraintType(m->source_loc(), "extends declaration",
+            ConvertToConstraintType(m->source_loc(), "extend declaration",
                                     base));
         CARBON_RETURN_IF_ERROR(builder.AddAndSubstitute(
             *this, constraint_type, builder.GetSelfType(),
@@ -5610,18 +5636,19 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
         break;
       }
 
-      case DeclarationKind::InterfaceImplDeclaration: {
-        // For an `impl X as Y;` declaration, add `X impls Y` to our constraint.
-        auto* impl = cast<InterfaceImplDeclaration>(m);
+      case DeclarationKind::InterfaceRequireDeclaration: {
+        // For an `require X impls Y;` declaration, add `X impls Y` to our
+        // constraint.
+        auto* require = cast<InterfaceRequireDeclaration>(m);
         CARBON_ASSIGN_OR_RETURN(
             Nonnull<const Value*> impl_type,
-            TypeCheckTypeExp(impl->impl_type(), constraint_scope));
+            TypeCheckTypeExp(require->impl_type(), constraint_scope));
         CARBON_ASSIGN_OR_RETURN(
             Nonnull<const Value*> constraint,
-            TypeCheckTypeExp(impl->constraint(), constraint_scope));
+            TypeCheckTypeExp(require->constraint(), constraint_scope));
         CARBON_ASSIGN_OR_RETURN(
             Nonnull<const ConstraintType*> constraint_type,
-            ConvertToConstraintType(m->source_loc(), "impl as declaration",
+            ConvertToConstraintType(m->source_loc(), "require declaration",
                                     constraint));
         CARBON_RETURN_IF_ERROR(
             builder.AddAndSubstitute(*this, constraint_type, impl_type,
@@ -5762,7 +5789,8 @@ auto TypeChecker::CheckImplIsComplete(Nonnull<const InterfaceType*> iface_type,
                << "implementation doesn't provide a concrete value for "
                << *iface_type << "." << assoc->binding().name();
       }
-    } else if (isa<InterfaceImplDeclaration, InterfaceExtendsDeclaration>(m)) {
+    } else if (isa<InterfaceRequireDeclaration, InterfaceExtendDeclaration>(
+                   m)) {
       // These get translated into constraints so there's nothing we need to
       // check here.
     } else {
@@ -6310,8 +6338,8 @@ auto TypeChecker::TypeCheckDeclaration(
       }
       break;
     }
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::AssociatedConstantDeclaration: {
       // Checked in DeclareConstraintTypeDeclaration.
       break;
@@ -6322,6 +6350,10 @@ auto TypeChecker::TypeCheckDeclaration(
     case DeclarationKind::AliasDeclaration: {
       break;
     }
+    case DeclarationKind::ExtendBaseDeclaration: {
+      // Checked in TypeCheckClassDeclaration.
+      break;
+    }
   }
   d->set_is_type_checked();
   return Success();
@@ -6373,6 +6405,10 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
       CARBON_RETURN_IF_ERROR(DeclareClassDeclaration(&class_decl, scope_info));
       break;
     }
+    case DeclarationKind::ExtendBaseDeclaration: {
+      // Handled in DeclareClassDeclaration.
+      break;
+    }
     case DeclarationKind::MixinDeclaration: {
       auto& mixin_decl = cast<MixinDeclaration>(*d);
       CARBON_RETURN_IF_ERROR(DeclareMixinDeclaration(&mixin_decl, scope_info));
@@ -6423,8 +6459,8 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
       break;
     }
 
-    case DeclarationKind::InterfaceExtendsDeclaration:
-    case DeclarationKind::InterfaceImplDeclaration:
+    case DeclarationKind::InterfaceExtendDeclaration:
+    case DeclarationKind::InterfaceRequireDeclaration:
     case DeclarationKind::AssociatedConstantDeclaration: {
       // The semantic effects are handled by DeclareConstraintTypeDeclaration.
       break;

+ 4 - 4
explorer/syntax/lexer.lpp

@@ -60,8 +60,7 @@ DOUBLE_ARROW          "=>"
 ELSE                  "else"
 EQUAL                 "="
 EQUAL_EQUAL           "=="
-EXTENDS               "extends"
-EXTERNAL              "external"
+EXTEND                "extend"
 FALSE                 "false"
 FN                    "fn"
 FN_TYPE               "__Fn"
@@ -106,6 +105,7 @@ PIPE_EQUAL            "|="
 PLUS                  "+"
 PLUS_EQUAL            "+="
 PLUS_PLUS             "++"
+REQUIRE               "require"
 RETURN                "return"
 RETURNED              "returned"
 RIGHT_CURLY_BRACE     "}"
@@ -179,8 +179,7 @@ operand_start         [(A-Za-z0-9_\"]
 {ELSE}                  { return CARBON_SIMPLE_TOKEN(ELSE);                  }
 {EQUAL_EQUAL}           { return CARBON_SIMPLE_TOKEN(EQUAL_EQUAL);           }
 {EQUAL}                 { return CARBON_SIMPLE_TOKEN(EQUAL);                 }
-{EXTENDS}               { return CARBON_SIMPLE_TOKEN(EXTENDS);               }
-{EXTERNAL}              { return CARBON_SIMPLE_TOKEN(EXTERNAL);              }
+{EXTEND}                { return CARBON_SIMPLE_TOKEN(EXTEND);                }
 {FALSE}                 { return CARBON_SIMPLE_TOKEN(FALSE);                 }
 {FN_TYPE}               { return CARBON_SIMPLE_TOKEN(FN_TYPE);               }
 {FN}                    { return CARBON_SIMPLE_TOKEN(FN);                    }
@@ -225,6 +224,7 @@ operand_start         [(A-Za-z0-9_\"]
 {PLUS_EQUAL}            { return CARBON_SIMPLE_TOKEN(PLUS_EQUAL);            }
 {PLUS_PLUS}             { return CARBON_SIMPLE_TOKEN(PLUS_PLUS);             }
 {PLUS}                  { return CARBON_SIMPLE_TOKEN(PLUS);                  }
+{REQUIRE}               { return CARBON_SIMPLE_TOKEN(REQUIRE);               }
 {RETURNED}              { return CARBON_SIMPLE_TOKEN(RETURNED);              }
 {RETURN}                { return CARBON_SIMPLE_TOKEN(RETURN);                }
 {SELF}                  { return CARBON_SIMPLE_TOKEN(SELF);                  }

+ 53 - 27
explorer/syntax/parser.ypp

@@ -97,8 +97,8 @@
 %token <std::string> sized_type_literal
 %token <std::string> string_literal
 %type <std::string> designator
-%type <ImplKind> impl_kind_intro
 %type <Nonnull<Expression*>> impl_type
+%type <Nonnull<Expression*>> no_impl_type
 %type <std::pair<LibraryName, bool>> package_directive
 %type <LibraryName> import_directive
 %type <std::vector<LibraryName>> import_directives
@@ -107,14 +107,15 @@
 %type <VirtualOverride> fn_virtual_override_intro
 %type <VirtualOverride> destructor_virtual_override_intro
 %type <ClassExtensibility> class_declaration_extensibility
-%type <std::optional<Nonnull<Expression*>>> class_declaration_extends
 %type <Nonnull<Declaration*>> declaration
 %type <BisonWrap<DeclaredName>> declared_name
 %type <Nonnull<FunctionDeclaration*>> function_declaration
 %type <Nonnull<DestructorDeclaration*>> destructor_declaration
+%type <Nonnull<ExtendBaseDeclaration*>> extend_base_declaration
 %type <Nonnull<MixDeclaration*>> mix_declaration
 %type <Nonnull<AliasDeclaration*>> alias_declaration
 %type <Nonnull<ImplDeclaration*>> impl_declaration
+%type <Nonnull<ImplDeclaration*>> extend_impl_declaration
 %type <Nonnull<MatchFirstDeclaration*>> match_first_declaration
 %type <std::vector<Nonnull<ImplDeclaration*>>> match_first_declaration_list
 %type <std::vector<Nonnull<Declaration*>>> declaration_list
@@ -236,8 +237,7 @@
   ELSE
   EQUAL
   EQUAL_EQUAL
-  EXTENDS
-  EXTERNAL
+  EXTEND
   FALSE
   FN
   FN_TYPE
@@ -283,6 +283,7 @@
   PLUS
   PLUS_EQUAL
   PLUS_PLUS
+  REQUIRE
   RETURN
   RETURNED
   RIGHT_CURLY_BRACE
@@ -1390,12 +1391,6 @@ class_declaration_extensibility:
 | BASE
     { $$ = Carbon::ClassExtensibility::Base; }
 ;
-class_declaration_extends:
-  // Empty
-    { $$ = std::nullopt; }
-| EXTENDS expression
-    { $$ = $[expression]; }
-;
 declaration:
   NAMESPACE declared_name SEMICOLON
     {
@@ -1407,13 +1402,12 @@ declaration:
 | destructor_declaration
     { $$ = $[destructor_declaration]; }
 | class_declaration_extensibility CLASS declared_name type_params
-  class_declaration_extends LEFT_CURLY_BRACE class_body RIGHT_CURLY_BRACE
+  LEFT_CURLY_BRACE class_body RIGHT_CURLY_BRACE
     {
       $$ = arena->New<ClassDeclaration>(
           context.source_loc(), std::move($[declared_name]),
           arena->New<SelfDeclaration>(context.source_loc()),
-          $[class_declaration_extensibility], $[type_params],
-          $[class_declaration_extends], $[class_body]);
+          $[class_declaration_extensibility], $[type_params], $[class_body]);
     }
 | MIXIN declared_name type_params mixin_import LEFT_CURLY_BRACE mixin_body
   RIGHT_CURLY_BRACE
@@ -1472,12 +1466,28 @@ declaration:
     { $$ = $[alias_declaration]; }
 ;
 impl_declaration:
-  impl_kind_intro impl_deduced_params impl_type AS type_or_where_expression
+  IMPL impl_deduced_params impl_type AS type_or_where_expression
   LEFT_CURLY_BRACE impl_body RIGHT_CURLY_BRACE
     {
       ErrorOr<ImplDeclaration*> impl = ImplDeclaration::Create(
-          arena, context.source_loc(), $[impl_kind_intro], $[impl_type],
-          $[type_or_where_expression], $[impl_deduced_params], $[impl_body]);
+          arena, context.source_loc(), Carbon::ImplKind::ExternalImpl,
+          $[impl_type], $[type_or_where_expression], $[impl_deduced_params],
+          $[impl_body]);
+      if (impl.ok()) {
+        $$ = *impl;
+      } else {
+        context.RecordSyntaxError(std::move(impl).error());
+        YYERROR;
+      }
+    }
+;
+extend_impl_declaration:
+  EXTEND IMPL no_impl_type AS type_or_where_expression
+  LEFT_CURLY_BRACE impl_body RIGHT_CURLY_BRACE
+    {
+      ErrorOr<ImplDeclaration*> impl = ImplDeclaration::Create(
+          arena, context.source_loc(), Carbon::ImplKind::InternalImpl,
+          $[no_impl_type], $[type_or_where_expression], {}, $[impl_body]);
       if (impl.ok()) {
         $$ = *impl;
       } else {
@@ -1485,17 +1495,15 @@ impl_declaration:
         YYERROR;
       }
     }
-impl_kind_intro:
-  IMPL // Internal
-    { $$ = Carbon::ImplKind::InternalImpl; }
-| EXTERNAL IMPL
-    { $$ = Carbon::ImplKind::ExternalImpl; }
 ;
 impl_type:
   // Self
     { $$ = arena->New<IdentifierExpression>(context.source_loc(), "Self"); }
 | type_expression
 ;
+no_impl_type:
+    { $$ = arena->New<IdentifierExpression>(context.source_loc(), "Self"); }
+;
 match_first_declaration:
   MATCH_FIRST LEFT_CURLY_BRACE match_first_declaration_list RIGHT_CURLY_BRACE
     {
@@ -1547,6 +1555,13 @@ declaration_list:
       $$.push_back(Nonnull<Declaration*>($[declaration]));
     }
 ;
+extend_base_declaration:
+  EXTEND BASE COLON expression SEMICOLON
+    {
+      $$ = arena->New<ExtendBaseDeclaration>(context.source_loc(),
+                                             $[expression]);
+    }
+;
 class_body:
   // Empty
     { $$ = {}; }
@@ -1560,6 +1575,16 @@ class_body:
       $$ = std::move($[accumulated_class_body]);
       $$.push_back(Nonnull<Declaration*>($[mix_declaration]));
     }
+| class_body[accumulated_class_body] extend_base_declaration
+    {
+      $$ = std::move($[accumulated_class_body]);
+      $$.push_back(Nonnull<Declaration*>($[extend_base_declaration]));
+    }
+| class_body[accumulated_class_body] extend_impl_declaration
+    {
+      $$ = std::move($[accumulated_class_body]);
+      $$.push_back(Nonnull<Declaration*>($[extend_impl_declaration]));
+    }
 ;
 // EXPERIMENTAL MIXIN FEATURE
 mixin_body:
@@ -1590,18 +1615,19 @@ interface_body:
       $$.push_back(arena->New<AssociatedConstantDeclaration>(
           context.source_loc(), $[generic_binding]));
     }
-| interface_body[accumulated_interface_body] EXTENDS expression SEMICOLON
+| interface_body[accumulated_interface_body] EXTEND expression SEMICOLON
     {
       $$ = std::move($[accumulated_interface_body]);
-      $$.push_back(arena->New<InterfaceExtendsDeclaration>(context.source_loc(),
-                                                           $[expression]));
+      $$.push_back(arena->New<InterfaceExtendDeclaration>(context.source_loc(),
+                                                          $[expression]));
     }
-| interface_body[accumulated_interface_body] IMPL impl_type AS
+| interface_body[accumulated_interface_body] REQUIRE type_expression IMPLS
   type_or_where_expression SEMICOLON
     {
       $$ = std::move($[accumulated_interface_body]);
-      $$.push_back(arena->New<InterfaceImplDeclaration>(
-          context.source_loc(), $[impl_type], $[type_or_where_expression]));
+      $$.push_back(arena->New<InterfaceRequireDeclaration>(
+          context.source_loc(), $[type_expression],
+          $[type_or_where_expression]));
     }
 ;
 impl_body:

+ 1 - 1
explorer/testdata/alias/member_name_alias.carbon

@@ -13,7 +13,7 @@ interface I {
 }
 class A {
   var n: i32;
-  impl as I {
+  extend impl as I {
     fn F() -> i32 { return 1; }
     fn M[self: Self]() -> i32 { return 2; }
   }

+ 1 - 1
explorer/testdata/array/element_convertible_to_type.carbon

@@ -8,7 +8,7 @@
 package ExplorerTest api;
 
 class TypeLike {
-  impl as ImplicitAs(type) {
+  extend impl as ImplicitAs(type) {
     fn Convert[self: Self]() -> type { return i32; }
   }
   fn Make() -> Self { return {}; }

+ 1 - 1
explorer/testdata/as/convert.carbon

@@ -9,7 +9,7 @@ package ExplorerTest api;
 
 class A { var n: i32; }
 
-external impl A as As(i32) {
+impl A as As(i32) {
   fn Convert[self: Self]() -> i32 { return self.n; }
 }
 

+ 1 - 1
explorer/testdata/as/implicit_as.carbon

@@ -9,7 +9,7 @@ package ExplorerTest api;
 
 class A { var n: i32; }
 
-external impl A as ImplicitAs(i32) {
+impl A as ImplicitAs(i32) {
   fn Convert[self: Self]() -> i32 { return self.n; }
 }
 

+ 1 - 1
explorer/testdata/assert/convert.carbon

@@ -9,7 +9,7 @@ package ExplorerTest api;
 
 class ConvertTo(T:! type) {
   var v: T;
-  impl as ImplicitAs(T) {
+  extend impl as ImplicitAs(T) {
     fn Convert[self: Self]() -> T { return self.v; }
   }
 }

+ 1 - 1
explorer/testdata/assert/fail_convert.carbon

@@ -9,7 +9,7 @@ package ExplorerTest api;
 
 class ConvertTo(T:! type) {
   var v: T;
-  impl as ImplicitAs(T) {
+  extend impl as ImplicitAs(T) {
     fn Convert[self: Self]() -> T { return self.v; }
   }
 }

+ 1 - 1
explorer/testdata/assert/fail_intrinsic_bool_type.carbon

@@ -8,7 +8,7 @@ package ExplorerTest api;
 
 class ConvertTo(T:! type) {
   var v: T;
-  impl as ImplicitAs(T) {
+  extend impl as ImplicitAs(T) {
     fn Convert[self: Self]() -> T { return self.v; }
   }
 }

+ 1 - 1
explorer/testdata/assert/fail_intrinsic_no_args.carbon

@@ -8,7 +8,7 @@ package ExplorerTest api;
 
 class ConvertTo(T:! type) {
   var v: T;
-  impl as ImplicitAs(T) {
+  extend impl as ImplicitAs(T) {
     fn Convert[self: Self]() -> T { return self.v; }
   }
 }

+ 1 - 1
explorer/testdata/assert/fail_intrinsic_no_convert.carbon

@@ -8,7 +8,7 @@ package ExplorerTest api;
 
 class ConvertTo(T:! type) {
   var v: T;
-  impl as ImplicitAs(T) {
+  extend impl as ImplicitAs(T) {
     fn Convert[self: Self]() -> T { return self.v; }
   }
 }

+ 1 - 1
explorer/testdata/assert/fail_intrinsic_str_type.carbon

@@ -8,7 +8,7 @@ package ExplorerTest api;
 
 class ConvertTo(T:! type) {
   var v: T;
-  impl as ImplicitAs(T) {
+  extend impl as ImplicitAs(T) {
     fn Convert[self: Self]() -> T { return self.v; }
   }
 }

+ 2 - 2
explorer/testdata/assoc_const/bug_multi_impl_scoping.carbon

@@ -24,7 +24,7 @@ interface B {
 }
 
 class C(T:! type) {
-  impl as A & B where .TA = i32 and .TB = i32 {
+  extend impl as A & B where .TA = i32 and .TB = i32 {
     fn FA() -> i32 {
       Print("(C(T) as A).FA()");
       // OK, know that TA is i32 here.
@@ -44,7 +44,7 @@ class C(T:! type) {
   }
 }
 
-external impl C(i32) as A where .TA = (i32, i32) {
+impl C(i32) as A where .TA = (i32, i32) {
   fn FA() -> (i32, i32) {
     Print("(C(i32) as A).FA()");
     return (6, 7);

+ 2 - 2
explorer/testdata/assoc_const/fail_different_type.carbon

@@ -14,8 +14,8 @@ fn F(T:! Iface where .T == i32) {}
 
 class Good {}
 class Bad {}
-external impl Good as Iface where .T = i32 {}
-external impl Bad as Iface where .T = Bad {}
+impl Good as Iface where .T = i32 {}
+impl Bad as Iface where .T = Bad {}
 
 fn Main() -> i32 {
   F(Good);

+ 2 - 2
explorer/testdata/assoc_const/fail_different_value.carbon

@@ -14,8 +14,8 @@ fn F(T:! Iface where .N == 5) {}
 
 class Good {}
 class Bad {}
-external impl Good as Iface where .N = 5 {}
-external impl Bad as Iface where .N = 4 {}
+impl Good as Iface where .N = 5 {}
+impl Bad as Iface where .N = 4 {}
 
 fn Main() -> i32 {
   F(Good);

+ 1 - 1
explorer/testdata/assoc_const/fail_equal_indirectly.carbon

@@ -13,7 +13,7 @@ interface Iface {
 fn F[T:! Iface where .T == i32](x: T) {}
 
 class Class {
-  impl as Iface where .T = i32 {}
+  extend impl as Iface where .T = i32 {}
 }
 
 // OK, constraint on `F` rewritten to `T:! Iface where U == i32`, which we can

+ 1 - 1
explorer/testdata/assoc_const/fail_equal_to_dependent_type.carbon

@@ -22,7 +22,7 @@ fn H[V:! Iface](x: V) {
 }
 
 class Class {
-  impl as Iface where .T = i32 {}
+  extend impl as Iface where .T = i32 {}
 }
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/assoc_const/fail_incomplete_impl_1.carbon

@@ -13,6 +13,6 @@ interface HasThreeTypes {
 }
 
 // CHECK:STDERR: COMPILATION ERROR: fail_incomplete_impl_1.carbon:[[@LINE+1]]: implementation doesn't provide a concrete value for interface HasThreeTypes.B
-external impl i32 as HasThreeTypes where .A = i32 and .C = i32 {}
+impl i32 as HasThreeTypes where .A = i32 and .C = i32 {}
 
 fn Main() -> i32 { return 0; }

+ 1 - 1
explorer/testdata/assoc_const/fail_incomplete_impl_2.carbon

@@ -13,6 +13,6 @@ interface HasThreeTypes {
 }
 
 // CHECK:STDERR: COMPILATION ERROR: fail_incomplete_impl_2.carbon:[[@LINE+1]]: implementation doesn't provide a concrete value for interface HasThreeTypes.C
-external impl i32 as HasThreeTypes where .A = i32 and .B = .C {}
+impl i32 as HasThreeTypes where .A = i32 and .B = .C {}
 
 fn Main() -> i32 { return 0; }

+ 1 - 1
explorer/testdata/assoc_const/fail_indirectly_equal.carbon

@@ -25,7 +25,7 @@ fn F3[T:! A where .T == i32, U:! A where .T == i32](x: T.T) -> U.T {
   return x;
 }
 
-external impl i32 as A where .T == i32 {}
+impl i32 as A where .T == i32 {}
 
 fn Main() -> i32 {
   return F3(0);

+ 1 - 1
explorer/testdata/assoc_const/fail_match_in_deduction.carbon

@@ -11,7 +11,7 @@ package ExplorerTest api;
 interface Vector {
   let Dim:! i32;
 }
-external impl (i32, i32, i32) as Vector where .Dim = 3 {}
+impl (i32, i32, i32) as Vector where .Dim = 3 {}
 
 class Point(Scalar:! type, Dim:! i32) {}
 

+ 1 - 1
explorer/testdata/assoc_const/fail_overspecified_impl.carbon

@@ -13,6 +13,6 @@ interface HasType {
 // CHECK:STDERR: COMPILATION ERROR: fail_overspecified_impl.carbon:[[@LINE+3]]: multiple different rewrites for `(i32).(HasType.T)`:
 // CHECK:STDERR:   i32
 // CHECK:STDERR:   {.a: i32}
-external impl i32 as HasType where .T = i32 and .T = {.a: i32} {}
+impl i32 as HasType where .T = i32 and .T = {.a: i32} {}
 
 fn Main() -> i32 { return 0; }

+ 1 - 1
explorer/testdata/assoc_const/impl_lookup.carbon

@@ -19,7 +19,7 @@ fn Use[T:! Frob](x: T) -> T.Result {
 
 class AlmostI32 {
   var val: i32;
-  impl as ImplicitAs(i32) {
+  extend impl as ImplicitAs(i32) {
     fn Convert[self: Self]() -> i32 { return self.val; }
   }
 }

+ 1 - 1
explorer/testdata/assoc_const/implement.carbon

@@ -14,7 +14,7 @@ interface Vector {
 class Point {
   var x: i32;
   var y: i32;
-  impl as Vector where .Dim = 2 {}
+  extend impl as Vector where .Dim = 2 {}
 }
 
 fn Main() -> i32 {

+ 4 - 4
explorer/testdata/assoc_const/lookup_in_rewrite.carbon

@@ -21,7 +21,7 @@ interface Hashable {
 }
 
 class Potato {
-  external impl as Hashable {
+  impl as Hashable {
     fn Hash[self: Self]() -> i32 {
       Print("Potato.(Hashable.Hash)");
       return 1;
@@ -39,7 +39,7 @@ interface Maker {
   fn Make() -> Result;
 }
 
-external impl i32 as Hashable {
+impl i32 as Hashable {
   fn Hash[self: Self]() -> i32 {
     Print("i32.Hash");
     return self;
@@ -69,13 +69,13 @@ fn I[T:! Maker where .Result = Potato](x: T) -> i32 {
 }
 
 class IntFactory {
-  impl as Maker where .Result = i32 {
+  extend impl as Maker where .Result = i32 {
     fn Make() -> i32 { return 0; }
   }
 }
 
 class PotatoFactory {
-  impl as Maker where .Result = Potato {
+  extend impl as Maker where .Result = Potato {
     fn Make() -> Potato { return {}; }
   }
 }

+ 1 - 1
explorer/testdata/assoc_const/member_of_value.carbon

@@ -14,7 +14,7 @@ interface Vector {
 class Point {
   var x: i32;
   var y: i32;
-  impl as Vector where .Dim = 2 {}
+  extend impl as Vector where .Dim = 2 {}
 }
 
 fn Main() -> i32 {

+ 1 - 1
explorer/testdata/assoc_const/pass_equal_to_rewrite.carbon

@@ -20,7 +20,7 @@ fn B[T:! Container where .Element == i32](x: T) -> T.Element {
   return A(x);
 }
 
-external impl (i32, i32) as Container where .Element = i32 {
+impl (i32, i32) as Container where .Element = i32 {
   fn Front[self: Self]() -> i32 {
     let (a: i32, b: i32) = self;
     return a;

+ 1 - 1
explorer/testdata/assoc_const/pass_rewrite_to_equal.carbon

@@ -20,7 +20,7 @@ fn B[T:! Container where .Element = i32](x: T) -> T.Element {
   return A(x);
 }
 
-external impl (i32, i32) as Container where .Element = i32 {
+impl (i32, i32) as Container where .Element = i32 {
   fn Front[self: Self]() -> i32 {
     let (a: i32, b: i32) = self;
     return a;

+ 1 - 1
explorer/testdata/assoc_const/resolve_rewrites.carbon

@@ -37,7 +37,7 @@ fn F[
 }
 
 class C {
-  impl as ManyTypes where
+  extend impl as ManyTypes where
     .T0 = i32 and
     .T1 = .T0 and
     .T2 = .T1 and

+ 1 - 1
explorer/testdata/assoc_const/rewrite_large_type.carbon

@@ -72,7 +72,7 @@ fn DoFirst(
 }
 
 class C {
-  impl as ManyTypes where
+  extend impl as ManyTypes where
       .T3 = (.T4, .T4, .T4) and
       .T1 = (.T2, .T2, .T2) and
       .T4 = (.T5, .T5, .T5) and

+ 2 - 1
explorer/testdata/class/abstract_class.carbon

@@ -13,7 +13,8 @@ abstract class C {
   var a: i32;
 }
 
-class D extends C {
+class D {
+  extend base: C;
   var b: i32;
 }
 

+ 2 - 1
explorer/testdata/class/base_constructor.carbon

@@ -16,7 +16,8 @@ base class A {
   var value_a: i32;
 }
 
-class B extends A {
+class B {
+  extend base: A;
   fn Create() -> Self {
     return {.base = A.Create(), .value_b = 2};
   }

+ 2 - 1
explorer/testdata/class/class_inheritance_function_call.carbon

@@ -18,7 +18,8 @@ base class C {
   }
 }
 
-class D extends C {
+class D {
+  extend base: C;
   fn FunctionD(var i: i32) {
     C.FunctionC(i);
     Print("Class D, call {0}", i);

+ 2 - 1
explorer/testdata/class/class_inheritance_methods.carbon

@@ -20,7 +20,8 @@ base class C {
   var value_c: i32;
 }
 
-class D extends C {
+class D {
+  extend base: C;
   fn Method2[self: Self]() {
     self.BasePrint(self.value_d);
   }

+ 4 - 2
explorer/testdata/class/class_inheritance_multiple.carbon

@@ -17,12 +17,14 @@ base class A {
   var aa: String;
 }
 
-base class B extends A {
+base class B {
+  extend base: A;
   fn FunctionB() {}
   var b: i32;
 }
 
-class C extends B {
+class C {
+  extend base: B;
   fn FunctionC() {}
   var c: i32;
 }

+ 2 - 1
explorer/testdata/class/class_inheritance_shadow.carbon

@@ -20,7 +20,8 @@ base class C {
   var value: i32;
 }
 
-class D extends C {
+class D {
+  extend base: C;
   fn Method1() {
     Print("Class D");
   }

+ 2 - 1
explorer/testdata/class/class_inheritance_variables.carbon

@@ -15,7 +15,8 @@ base class C {
   var var_c: i32;
 }
 
-class D extends C {
+class D {
+  extend base: C;
   var var_d: i32;
 }
 

+ 4 - 2
explorer/testdata/class/class_subtyping_argument.carbon

@@ -15,11 +15,13 @@ base class C {
   var val: i32;
 }
 
-base class D extends C {
+base class D {
+  extend base: C;
   var val: i32;
 }
 
-class E extends D {
+class E {
+  extend base: D;
   var val: i32;
 }
 

+ 2 - 1
explorer/testdata/class/class_subtyping_basic.carbon

@@ -13,7 +13,8 @@ base class C {
   var a: i32;
 }
 
-class D extends C {
+class D {
+  extend base: C;
 }
 
 fn Foo(c: C*) -> i32 {

+ 4 - 2
explorer/testdata/class/class_subtyping_multiple.carbon

@@ -15,11 +15,13 @@ base class C {
   var val: i32;
 }
 
-base class D extends C {
+base class D {
+  extend base: C;
   var val: i32;
 }
 
-class E extends D {
+class E {
+  extend base: D;
   var val: i32;
 }
 

+ 2 - 1
explorer/testdata/class/fail_abstract_method_not_supported.carbon

@@ -9,7 +9,8 @@ package ExplorerTest api;
 base class C {
 }
 
-class D extends C {
+class D {
+  extend base: C;
   abstract fn Foo[self:Self]() -> i32 {
     return 1;
   // CHECK:STDERR: COMPILATION ERROR: fail_abstract_method_not_supported.carbon:[[@LINE+1]]: Error declaring `Foo`: `abstract` methods are not yet supported.

+ 2 - 1
explorer/testdata/class/fail_direct_base_class_init.carbon

@@ -10,7 +10,8 @@ base class A {
   var a: i32;
 }
 
-class B extends A {
+class B {
+  extend base: A;
   var b: i32;
 }
 

+ 20 - 0
explorer/testdata/class/fail_extend_after_var.carbon

@@ -0,0 +1,20 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+
+package ExplorerTest api;
+
+base class C {
+}
+
+class E {
+  var x: i32;
+  // CHECK:STDERR: COMPILATION ERROR: fail_extend_after_var.carbon:[[@LINE+1]]: `extend base:` declaration must not be after `var` or `mix` declarations in a class.
+  extend base: C;
+}
+
+fn Main() -> i32 {
+  return 0;
+}

+ 3 - 2
explorer/testdata/class/fail_extends_final_class.carbon → explorer/testdata/class/fail_extend_final_class.carbon

@@ -10,9 +10,10 @@ class C {
   fn F() {}
 }
 
-class D extends C {
+class D {
+  // CHECK:STDERR: COMPILATION ERROR: fail_extend_final_class.carbon:[[@LINE+1]]: Base class `C` is `final` and cannot be inherited. Add the `base` or `abstract` class prefix to `C` to allow it to be inherited
+  extend base: C;
   fn G() {}
-// CHECK:STDERR: COMPILATION ERROR: fail_extends_final_class.carbon:[[@LINE+1]]: Base class `C` is `final` and cannot be inherited. Add the `base` or `abstract` class prefix to `C` to allow it to be inherited
 }
 
 fn Main() -> i32 {

+ 3 - 2
explorer/testdata/class/fail_extends_non_class.carbon → explorer/testdata/class/fail_extend_non_class.carbon

@@ -6,8 +6,9 @@
 
 package ExplorerTest api;
 
-// CHECK:STDERR: COMPILATION ERROR: fail_extends_non_class.carbon:[[@LINE+1]]: type error in type expression: 'i32' is not implicitly convertible to 'type'
-class C extends 3 {
+class C {
+  // CHECK:STDERR: COMPILATION ERROR: fail_extend_non_class.carbon:[[@LINE+1]]: type error in type expression: 'i32' is not implicitly convertible to 'type'
+  extend base: 3;
   var x: i32;
   var y: i32;
 }

+ 23 - 0
explorer/testdata/class/fail_extend_twice.carbon

@@ -0,0 +1,23 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+
+package ExplorerTest api;
+
+base class C {
+}
+
+base class D {
+}
+
+class E {
+  extend base: C;
+  // CHECK:STDERR: COMPILATION ERROR: fail_extend_twice.carbon:[[@LINE+1]]: At most one `extend base:` declaration in a class.
+  extend base: D;
+}
+
+fn Main() -> i32 {
+  return 0;
+}

+ 2 - 1
explorer/testdata/class/fail_field_access_mismatch_base.carbon

@@ -11,7 +11,8 @@ base class Point {
   var y: i32;
 }
 
-class Point3D extends Point {
+class Point3D {
+  extend base: Point;
   var z: i32;
 }
 

+ 2 - 1
explorer/testdata/class/fail_field_assign_mismatch_base.carbon

@@ -11,7 +11,8 @@ base class Point {
   var y: i32;
 }
 
-class Point3D extends Point {
+class Point3D {
+  extend base: Point;
   var z: i32;
 }
 

+ 2 - 1
explorer/testdata/class/fail_impl_method_not_existing.carbon

@@ -9,7 +9,8 @@ package ExplorerTest api;
 base class C {
 }
 
-class D extends C {
+class D {
+  extend base: C;
   impl fn Foo[self:Self]() -> i32 {
     return 1;
   // CHECK:STDERR: COMPILATION ERROR: fail_impl_method_not_existing.carbon:[[@LINE+1]]: Error declaring `Foo`: cannot override a method that is not declared `abstract` or `virtual` in base class.

+ 2 - 1
explorer/testdata/class/fail_impl_method_not_virtual.carbon

@@ -12,7 +12,8 @@ base class C {
   }
 }
 
-class D extends C {
+class D {
+  extend base: C;
   impl fn Foo[self:Self]() -> i32 {
     return 1;
   // CHECK:STDERR: COMPILATION ERROR: fail_impl_method_not_virtual.carbon:[[@LINE+1]]: Error declaring `Foo`: cannot override a method that is not declared `abstract` or `virtual` in base class.

+ 2 - 1
explorer/testdata/class/fail_override_virtual_with_non_virtual.carbon

@@ -10,7 +10,8 @@ base class A {
   virtual fn Foo[self: Self]() {}
 }
 
-class B extends A {
+class B {
+  extend base: A;
   // CHECK:STDERR: COMPILATION ERROR: fail_override_virtual_with_non_virtual.carbon:[[@LINE+1]]: Error declaring `Foo`: method is declared virtual in base class, use `impl` to override it.
   fn Foo[self: Self]() {}
 }

+ 2 - 1
explorer/testdata/class/fail_redeclare_virtual_method.carbon

@@ -10,7 +10,8 @@ base class C {
   virtual fn Foo[self:Self]() {}
 }
 
-class D extends C {
+class D {
+  extend base: C;
   // CHECK:STDERR: COMPILATION ERROR: fail_redeclare_virtual_method.carbon:[[@LINE+1]]: Error declaring `Foo`: method is declared virtual in base class, use `impl` to override it.
   virtual fn Foo[self:Self]() {}
 }

+ 2 - 1
explorer/testdata/class/fail_virtual_method_absent.carbon

@@ -8,7 +8,8 @@ package ExplorerTest api;
 
 base class A {}
 
-class B extends A {
+class B {
+  extend base: A;
   virtual fn Foo[self: Self]() -> i32 { return 0; }
 }
 

+ 2 - 1
explorer/testdata/class/new_and_delete_hierarchy.carbon

@@ -21,7 +21,8 @@ base class A{
     }
 }
 
-class B extends A {
+class B {
+  extend base: A;
     fn Create() -> Self{
         return {.base={}};
     }

+ 2 - 1
explorer/testdata/class/non_virtual_dispatch.carbon

@@ -20,7 +20,8 @@ base class C {
   }
 }
 
-class D extends C {
+class D {
+  extend base: C;
   var b: i32;
   fn Foo[self: Self]() -> i32 {
     return 2;

+ 2 - 1
explorer/testdata/class/non_virtual_dispatch_abstract.carbon

@@ -20,7 +20,8 @@ abstract class C {
   }
 }
 
-class D extends C {
+class D {
+  extend base: C;
   var b: i32;
   fn Foo[self: Self]() -> i32 {
     return 2;

+ 3 - 2
explorer/testdata/class/parametrized_base_class.carbon

@@ -14,7 +14,7 @@ interface Number {
   fn Add[self: Self](other: Self) -> Self;
 }
 
-external impl i32 as Number {
+impl i32 as Number {
   fn Zero() -> i32 { return 0; }
   fn Add[self: i32](other: i32) -> i32 { return self + other; }
 }
@@ -23,7 +23,8 @@ base class A(T:! Number) {
   var value_a: T;
 }
 
-class B extends A(i32) {
+class B {
+  extend base: A(i32);
   var value_b: i32;
 }
 

+ 4 - 2
explorer/testdata/class/pointer_conversion.carbon

@@ -14,11 +14,13 @@ base class A {
   var a: i32;
 }
 
-base class B extends A {
+base class B {
+  extend base: A;
   var b: i32;
 }
 
-class C extends B {
+class C {
+  extend base: B;
   var c: i32;
 }
 

+ 2 - 1
explorer/testdata/class/virtual_method.carbon

@@ -22,7 +22,8 @@ base class C {
   }
 }
 
-class D extends C {
+class D {
+  extend base: C;
   impl fn Foo[self: Self]() -> i32 {
     return 3;
   }

+ 4 - 2
explorer/testdata/class/virtual_method_self.carbon

@@ -19,14 +19,16 @@ base class C {
   }
 }
 
-base class D extends C {
+base class D {
+  extend base: C;
   var value_d: i32;
   impl fn Foo[self: Self]() -> i32 {
     return self.value_d;
   }
 }
 
-class E extends D {
+class E {
+  extend base: D;
   var value_e: i32;
   impl fn Foo[self: Self]() -> i32 {
     return self.value_e;

+ 2 - 1
explorer/testdata/class/virtual_method_shadowed_attr.carbon

@@ -17,7 +17,8 @@ base class C {
   }
 }
 
-base class D extends C {
+base class D {
+  extend base: C;
   var value: i32;
   impl fn Foo[self: Self]() -> i32 {
     return self.value;

+ 1 - 1
explorer/testdata/comparison/custom_equality.carbon

@@ -12,7 +12,7 @@ package ExplorerTest api;
 class MyType {
   var value: i32;
 
-  impl as EqWith(Self) {
+  extend impl as EqWith(Self) {
     fn Equal[self: Self](other: Self) -> bool {
       return self.value == other.value;
     }

+ 1 - 1
explorer/testdata/comparison/empty_struct.carbon

@@ -7,7 +7,7 @@
 
 package ExplorerTest api;
 
-external impl {} as EqWith({}) {
+impl {} as EqWith({}) {
   fn Equal[self: Self](other: Self) -> bool {
     return true;
   }

+ 1 - 1
explorer/testdata/constraint/rewrite.carbon

@@ -12,7 +12,7 @@ interface HasAssoc {
   let AssocVal:! i32;
 }
 class X {
-  external impl as HasAssoc where .Assoc = i32 and .AssocVal = 2 {}
+  impl as HasAssoc where .Assoc = i32 and .AssocVal = 2 {}
 }
 
 fn F[T:! HasAssoc where .Assoc = i32](x: T) -> i32 {

+ 1 - 1
explorer/testdata/constraint/rewrite_compound.carbon

@@ -11,7 +11,7 @@ interface HasAssoc {
   let Assoc:! type;
 }
 class X {
-  external impl as HasAssoc where .Assoc = i32 {}
+  impl as HasAssoc where .Assoc = i32 {}
 }
 
 alias WithoutRewrite = HasAssoc where .Assoc == i32;

+ 1 - 1
explorer/testdata/constraint/rewrite_compound_2.carbon

@@ -11,7 +11,7 @@ interface HasAssoc {
   let Assoc:! i32;
 }
 class X {
-  external impl as HasAssoc where .Assoc = 1 {}
+  impl as HasAssoc where .Assoc = 1 {}
 }
 
 alias WithoutRewrite = HasAssoc where .Assoc == 1;

+ 1 - 1
explorer/testdata/constraint/rewrite_in_qualifier.carbon

@@ -11,7 +11,7 @@ interface HasAssoc {
   let Assoc:! type;
 }
 class X {
-  external impl as HasAssoc where .Assoc = i32 {}
+  impl as HasAssoc where .Assoc = i32 {}
 }
 
 alias WithoutRewrite = HasAssoc where .Assoc == i32;

+ 1 - 1
explorer/testdata/constraint/rewrite_in_qualifier_and_type.carbon

@@ -11,7 +11,7 @@ interface HasAssoc {
   let Assoc:! type;
 }
 class X {
-  external impl as HasAssoc where .Assoc = i32 {}
+  impl as HasAssoc where .Assoc = i32 {}
 }
 
 fn H[T:! HasAssoc where .Assoc = i32, U:! type where .Self == i32](a: T, b: U) -> i32 {

+ 1 - 1
explorer/testdata/constraint/where_impls.carbon

@@ -13,7 +13,7 @@ interface Base {
 }
 
 interface Extension {
-  extends Base;
+  extend Base;
 }
 
 fn F[T:! type where .Self impls Extension](x: T) {

+ 13 - 11
explorer/testdata/destructor/destroy_base_class.carbon

@@ -10,21 +10,23 @@
 package ExplorerTest api;
 
 base class A {
-    destructor[self: Self]{
-        Print("DESTRUCTOR A {0}", self.a);
-    }
-    var a: i32;
+  destructor[self: Self]{
+    Print("DESTRUCTOR A {0}", self.a);
+  }
+  var a: i32;
 }
 
-base class B extends A {
-    var b: i32;
+base class B {
+  extend base: A;
+  var b: i32;
 }
 
-class C extends B {
-    destructor[self: Self]{
-        Print("DESTRUCTOR C {0}", self.c);
-    }
-    var c: i32;
+class C {
+  extend base: B;
+  destructor[self: Self]{
+    Print("DESTRUCTOR C {0}", self.c);
+  }
+  var c: i32;
 }
 
 fn Main() -> i32 {

+ 4 - 2
explorer/testdata/destructor/destroy_base_class_and_members.carbon

@@ -33,7 +33,8 @@ base class A {
   var a2: Data;
 }
 
-base class B extends A {
+base class B {
+  extend base: A;
   fn Make() -> B { return {.base = A.Make(), .b1=Data.Make(5), .b2=Data.Make(4)}; }
   destructor[self: Self]{
     Print("Destroying 3 (B)");
@@ -42,7 +43,8 @@ base class B extends A {
   var b2: Data;
 }
 
-class C extends B {
+class C {
+  extend base: B;
   fn Make() -> C { return {.base = B.Make(), .c1=Data.Make(2), .c2=Data.Make(1)}; }
   destructor[self: Self]{
     Print("Destroying 0 (C)");

+ 7 - 6
explorer/testdata/destructor/fail_delete_base_without_virtual_destructor.carbon

@@ -9,14 +9,15 @@ package ExplorerTest api;
 
 
 base class A{
-    destructor[self: Self]{}
+  destructor[self: Self]{}
 }
 
-class B extends A {
-    fn Create() -> Self {
-        return {.base={}};
-    }
-    destructor[self: Self]{}
+class B {
+  extend base: A;
+  fn Create() -> Self {
+    return {.base={}};
+  }
+  destructor[self: Self]{}
 }
 
 fn Main() -> i32 {

+ 4 - 3
explorer/testdata/destructor/fail_override_virtual_virtual.carbon

@@ -11,9 +11,10 @@ base class A {
     virtual destructor[self: Self]{}
 }
 
-class B extends A {
-    // CHECK:STDERR: COMPILATION ERROR: fail_override_virtual_virtual.carbon:[[@LINE+1]]: Error declaring destructor for `B`: use `impl` to implement virtual destructor in child class.
-    virtual destructor[self: Self]{}
+class B {
+  extend base: A;
+  // CHECK:STDERR: COMPILATION ERROR: fail_override_virtual_virtual.carbon:[[@LINE+1]]: Error declaring destructor for `B`: use `impl` to implement virtual destructor in child class.
+  virtual destructor[self: Self]{}
 }
 
 fn Main() -> i32 {

+ 16 - 14
explorer/testdata/destructor/virtual_destructor.carbon

@@ -17,24 +17,26 @@ package ExplorerTest api;
 
 
 base class A {
-    virtual destructor[self: Self] {
-        Print("DESTRUCTOR A");
-    }
+  virtual destructor[self: Self] {
+    Print("DESTRUCTOR A");
+  }
 }
 
-base class B extends A {
-    impl destructor[self: Self] {
-        Print("DESTRUCTOR B");
-    }
+base class B {
+  extend base: A;
+  impl destructor[self: Self] {
+    Print("DESTRUCTOR B");
+  }
 }
 
-class C extends B {
-    fn Create() -> Self{
-        return {.base={.base={}}};
-    }
-    impl destructor[self: Self] {
-        Print("DESTRUCTOR C");
-    }
+class C {
+  extend base: B;
+  fn Create() -> Self{
+    return {.base={.base={}}};
+  }
+  impl destructor[self: Self] {
+    Print("DESTRUCTOR C");
+  }
 }
 
 fn Main() -> i32 {

+ 23 - 22
explorer/testdata/destructor/virtual_destructor_nested.carbon

@@ -18,36 +18,37 @@
 
 package ExplorerTest api;
 
-
 base class A {
-    virtual destructor[self: Self] {
-        Print("DESTRUCTOR A");
-    }
+  virtual destructor[self: Self] {
+    Print("DESTRUCTOR A");
+  }
 }
 
-class B extends A {
-    fn Create() -> Self{
-        return {.base={}};
-    }
-    impl destructor[self: Self] {
-        Print("DESTRUCTOR B");
-    }
+class B {
+  extend base: A;
+  fn Create() -> Self{
+    return {.base={}};
+  }
+  impl destructor[self: Self] {
+    Print("DESTRUCTOR B");
+  }
 }
 
 base class C {
-    virtual destructor[self: Self] {
-        Print("DESTRUCTOR C");
-    }
+  virtual destructor[self: Self] {
+    Print("DESTRUCTOR C");
+  }
 }
 
-class D extends C {
-    fn Create() -> Self{
-        return {.base={}, .d_pa=heap.New(B.Create())};
-    }
-    impl destructor[self: Self] {
-        Print("DESTRUCTOR D");
-    }
-    var d_pa: A*;
+class D {
+  extend base: C;
+  fn Create() -> Self{
+    return {.base={}, .d_pa=heap.New(B.Create())};
+  }
+  impl destructor[self: Self] {
+    Print("DESTRUCTOR D");
+  }
+  var d_pa: A*;
 }
 
 fn Main() -> i32 {

+ 3 - 3
explorer/testdata/function/convert_args.carbon

@@ -8,19 +8,19 @@
 package ExplorerTest api;
 
 class One {
-  impl One as ImplicitAs(i32) {
+  extend impl as ImplicitAs(i32) {
     fn Convert[self: Self]() -> i32 { return 1; }
   }
 }
 
 class Two {
-  impl Two as ImplicitAs(i32) {
+  extend impl as ImplicitAs(i32) {
     fn Convert[self: Self]() -> i32 { return 2; }
   }
 }
 
 class N {
-  impl N as ImplicitAs(i32) {
+  extend impl as ImplicitAs(i32) {
     fn Convert[self: Self]() -> i32 { return self.n; }
   }
   var n: i32;

+ 1 - 1
explorer/testdata/function/return_convertible_to_type.carbon

@@ -8,7 +8,7 @@
 package ExplorerTest api;
 
 class TypeLike {
-  impl as ImplicitAs(type) {
+  extend impl as ImplicitAs(type) {
     fn Convert[self: Self]() -> type { return i32; }
   }
   fn Make() -> Self { return {}; }

+ 1 - 1
explorer/testdata/generic_class/class_function.carbon

@@ -26,7 +26,7 @@ class Point(T:! Number) {
   var y: T;
 }
 
-external impl i32 as Number {
+impl i32 as Number {
   fn Zero() -> i32 { return 0; }
   fn Add[self: i32](other: i32) -> i32 { return self + other; }
 }

+ 1 - 1
explorer/testdata/generic_class/generic_class_substitution.carbon

@@ -20,7 +20,7 @@ class Point(T:! Number) {
   var y: T;
 }
 
-external impl i32 as Number {
+impl i32 as Number {
   fn Zero() -> i32 { return 0; }
   fn Add[self: i32](other: i32) -> i32 { return self + other; }
 }

+ 1 - 1
explorer/testdata/generic_class/generic_fun_and_class.carbon

@@ -29,7 +29,7 @@ fn SumXY[U :! Number](other: Point(U)) -> U {
   return other.x.Add(other.y);
 }
 
-external impl i32 as Number {
+impl i32 as Number {
   fn Zero() -> i32 { return 0; }
   fn Add[self: i32](other: i32) -> i32 { return self + other; }
 }

+ 1 - 1
explorer/testdata/generic_class/impl_with_argument.carbon

@@ -19,7 +19,7 @@ class Point(T:! type) {
 }
 
 // Can implement `Vector` for just `Point(i32)`, not all `Point(T)`.
-external impl Point(i32) as Vector {
+impl Point(i32) as Vector {
   fn Zero() -> Point(i32) {
     return {.x = 0, .y = 0};
   }

Некоторые файлы не были показаны из-за большого количества измененных файлов