Require extend before base: BaseType; (#3459)

This commit is contained in:
josh11b
2023-12-06 20:14:16 +00:00
committed by GitHub
parent f4677eea8d
commit a970b1e587
18 changed files with 383 additions and 181 deletions
+7 -5
View File
@@ -23,9 +23,10 @@ enum class KeywordModifierSet {
Abstract = 1 << 2,
Base = 1 << 3,
Default = 1 << 4,
Final = 1 << 5,
Impl = 1 << 6,
Virtual = 1 << 7,
Extend = 1 << 5,
Final = 1 << 6,
Impl = 1 << 7,
Virtual = 1 << 8,
// Sets of modifiers:
Access = Private | Protected,
@@ -45,7 +46,7 @@ inline auto operator!(KeywordModifierSet k) -> bool {
// declaration and the keyword modifiers that apply to that declaration.
struct DeclState {
// What kind of declaration
enum DeclKind { FileScope, Class, Constraint, Fn, Interface, Let, Var };
enum DeclKind { FileScope, Class, Base, Constraint, Fn, Interface, Let, Var };
explicit DeclState(DeclKind decl_kind, Parse::NodeId parse_node)
: kind(decl_kind), first_node(parse_node) {}
@@ -86,7 +87,8 @@ class DeclStateStack {
// Exits a declaration of kind `k`.
auto Pop(DeclState::DeclKind k) -> void {
CARBON_CHECK(stack_.back().kind == k);
CARBON_CHECK(stack_.back().kind == k)
<< "Found: " << stack_.back().kind << " expected: " << k;
stack_.pop_back();
CARBON_CHECK(!stack_.empty());
}
+14 -2
View File
@@ -165,8 +165,8 @@ auto HandleClassDefinitionStart(Context& context, Parse::NodeId parse_node)
return true;
}
auto HandleBaseIntroducer(Context& /*context*/, Parse::NodeId /*parse_node*/)
-> bool {
auto HandleBaseIntroducer(Context& context, Parse::NodeId parse_node) -> bool {
context.decl_state_stack().Push(DeclState::Base, parse_node);
return true;
}
@@ -178,6 +178,18 @@ auto HandleBaseColon(Context& /*context*/, Parse::NodeId /*parse_node*/)
auto HandleBaseDecl(Context& context, Parse::NodeId parse_node) -> bool {
auto base_type_expr_id = context.node_stack().PopExpr();
// Process modifiers. `extend` is required, none others are allowed.
LimitModifiersOnDecl(context, KeywordModifierSet::Extend,
Lex::TokenKind::Base);
auto modifiers = context.decl_state_stack().innermost().modifier_set;
if (!(modifiers & KeywordModifierSet::Extend)) {
CARBON_DIAGNOSTIC(BaseMissingExtend, Error,
"Missing `extend` before `base` declaration in class.");
context.emitter().Emit(context.decl_state_stack().innermost().first_node,
BaseMissingExtend);
}
context.decl_state_stack().Pop(DeclState::Base);
auto enclosing_class_decl = context.GetCurrentScopeAs<SemIR::ClassDecl>();
if (!enclosing_class_decl) {
CARBON_DIAGNOSTIC(BaseOutsideClass, Error,
+2
View File
@@ -83,6 +83,8 @@ static auto GetDeclModifierEnum(Lex::TokenKind token_kind)
return KeywordModifierSet::Base;
case Lex::TokenKind::Default:
return KeywordModifierSet::Default;
case Lex::TokenKind::Extend:
return KeywordModifierSet::Extend;
case Lex::TokenKind::Final:
return KeywordModifierSet::Final;
case Lex::TokenKind::Impl:
+44 -45
View File
@@ -9,8 +9,7 @@ base class Base {
}
class Derived {
// TODO: `extend base: Base;`
base: Base;
extend base: Base;
var d: i32;
}
@@ -28,14 +27,14 @@ fn Access(d: Derived) -> (i32, i32) {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.loc9: type = struct_type {.b: i32}
// CHECK:STDOUT: %.loc7: type = ptr_type {.b: i32}
// CHECK:STDOUT: %.loc16_1.1: type = struct_type {.base: Base, .d: i32}
// CHECK:STDOUT: %.loc16_1.2: type = struct_type {.base: {.b: i32}*, .d: i32}
// CHECK:STDOUT: %.loc16_1.3: type = ptr_type {.base: {.b: i32}*, .d: i32}
// CHECK:STDOUT: %.loc15_1.1: type = struct_type {.base: Base, .d: i32}
// CHECK:STDOUT: %.loc15_1.2: type = struct_type {.base: {.b: i32}*, .d: i32}
// CHECK:STDOUT: %.loc15_1.3: type = ptr_type {.base: {.b: i32}*, .d: i32}
// CHECK:STDOUT: %.loc11: type = ptr_type {.base: Base, .d: i32}
// CHECK:STDOUT: %.loc19: type = struct_type {.base: {.b: i32}, .d: i32}
// CHECK:STDOUT: %.loc22_35.1: type = tuple_type (type, type)
// CHECK:STDOUT: %.loc22_35.2: type = tuple_type (i32, i32)
// CHECK:STDOUT: %.loc22_35.3: type = ptr_type (i32, i32)
// CHECK:STDOUT: %.loc18: type = struct_type {.base: {.b: i32}, .d: i32}
// CHECK:STDOUT: %.loc21_35.1: type = tuple_type (type, type)
// CHECK:STDOUT: %.loc21_35.2: type = tuple_type (i32, i32)
// CHECK:STDOUT: %.loc21_35.3: type = ptr_type (i32, i32)
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -59,52 +58,52 @@ fn Access(d: Derived) -> (i32, i32) {
// CHECK:STDOUT:
// CHECK:STDOUT: class @Derived {
// CHECK:STDOUT: %Base.ref: type = name_ref Base, file.%Base
// CHECK:STDOUT: %.loc13_13.1: type = unbound_element_type Derived, Base
// CHECK:STDOUT: %.loc13_13.2: <unbound element of class Derived> = base_decl Base, element0
// CHECK:STDOUT: %.loc15_8.1: type = unbound_element_type Derived, i32
// CHECK:STDOUT: %.loc15_8.2: <unbound element of class Derived> = field_decl d, element1
// CHECK:STDOUT: %d: <unbound element of class Derived> = bind_name d, %.loc15_8.2
// CHECK:STDOUT: %.loc12_20.1: type = unbound_element_type Derived, Base
// CHECK:STDOUT: %.loc12_20.2: <unbound element of class Derived> = base_decl Base, element0
// CHECK:STDOUT: %.loc14_8.1: type = unbound_element_type Derived, i32
// CHECK:STDOUT: %.loc14_8.2: <unbound element of class Derived> = field_decl d, element1
// CHECK:STDOUT: %d: <unbound element of class Derived> = bind_name d, %.loc14_8.2
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc13_13.2
// CHECK:STDOUT: .base = %.loc12_20.2
// CHECK:STDOUT: .d = %d
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Make() -> %return: Derived {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc19_25: i32 = int_literal 4
// CHECK:STDOUT: %.loc19_26.1: {.b: i32} = struct_literal (%.loc19_25)
// CHECK:STDOUT: %.loc19_34: i32 = int_literal 7
// CHECK:STDOUT: %.loc19_35.1: {.base: {.b: i32}, .d: i32} = struct_literal (%.loc19_26.1, %.loc19_34)
// CHECK:STDOUT: %.loc19_35.2: ref Base = class_element_access %return, element0
// CHECK:STDOUT: %.loc19_26.2: ref i32 = class_element_access %.loc19_35.2, element0
// CHECK:STDOUT: %.loc19_26.3: init i32 = initialize_from %.loc19_25 to %.loc19_26.2
// CHECK:STDOUT: %.loc19_26.4: init Base = class_init (%.loc19_26.3), %.loc19_35.2
// CHECK:STDOUT: %.loc19_26.5: init Base = converted %.loc19_26.1, %.loc19_26.4
// CHECK:STDOUT: %.loc19_35.3: ref i32 = class_element_access %return, element1
// CHECK:STDOUT: %.loc19_35.4: init i32 = initialize_from %.loc19_34 to %.loc19_35.3
// CHECK:STDOUT: %.loc19_35.5: init Derived = class_init (%.loc19_26.5, %.loc19_35.4), %return
// CHECK:STDOUT: %.loc19_35.6: init Derived = converted %.loc19_35.1, %.loc19_35.5
// CHECK:STDOUT: return %.loc19_35.6
// CHECK:STDOUT: %.loc18_25: i32 = int_literal 4
// CHECK:STDOUT: %.loc18_26.1: {.b: i32} = struct_literal (%.loc18_25)
// CHECK:STDOUT: %.loc18_34: i32 = int_literal 7
// CHECK:STDOUT: %.loc18_35.1: {.base: {.b: i32}, .d: i32} = struct_literal (%.loc18_26.1, %.loc18_34)
// CHECK:STDOUT: %.loc18_35.2: ref Base = class_element_access %return, element0
// CHECK:STDOUT: %.loc18_26.2: ref i32 = class_element_access %.loc18_35.2, element0
// CHECK:STDOUT: %.loc18_26.3: init i32 = initialize_from %.loc18_25 to %.loc18_26.2
// CHECK:STDOUT: %.loc18_26.4: init Base = class_init (%.loc18_26.3), %.loc18_35.2
// CHECK:STDOUT: %.loc18_26.5: init Base = converted %.loc18_26.1, %.loc18_26.4
// CHECK:STDOUT: %.loc18_35.3: ref i32 = class_element_access %return, element1
// CHECK:STDOUT: %.loc18_35.4: init i32 = initialize_from %.loc18_34 to %.loc18_35.3
// CHECK:STDOUT: %.loc18_35.5: init Derived = class_init (%.loc18_26.5, %.loc18_35.4), %return
// CHECK:STDOUT: %.loc18_35.6: init Derived = converted %.loc18_35.1, %.loc18_35.5
// CHECK:STDOUT: return %.loc18_35.6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Access(%d: Derived) -> %return: (i32, i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref.loc23_11: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc23_12.1: ref i32 = class_element_access %d.ref.loc23_11, element1
// CHECK:STDOUT: %.loc23_12.2: i32 = bind_value %.loc23_12.1
// CHECK:STDOUT: %d.ref.loc23_16: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc23_17.1: ref Base = class_element_access %d.ref.loc23_16, element0
// CHECK:STDOUT: %.loc23_17.2: Base = bind_value %.loc23_17.1
// CHECK:STDOUT: %.loc23_22.1: ref i32 = class_element_access %.loc23_17.2, element0
// CHECK:STDOUT: %.loc23_22.2: i32 = bind_value %.loc23_22.1
// CHECK:STDOUT: %.loc23_24.1: (i32, i32) = tuple_literal (%.loc23_12.2, %.loc23_22.2)
// CHECK:STDOUT: %.loc23_24.2: ref i32 = tuple_access %return, element0
// CHECK:STDOUT: %.loc23_24.3: init i32 = initialize_from %.loc23_12.2 to %.loc23_24.2
// CHECK:STDOUT: %.loc23_24.4: ref i32 = tuple_access %return, element1
// CHECK:STDOUT: %.loc23_24.5: init i32 = initialize_from %.loc23_22.2 to %.loc23_24.4
// CHECK:STDOUT: %.loc23_24.6: init (i32, i32) = tuple_init (%.loc23_24.3, %.loc23_24.5) to %return
// CHECK:STDOUT: %.loc23_24.7: init (i32, i32) = converted %.loc23_24.1, %.loc23_24.6
// CHECK:STDOUT: return %.loc23_24.7
// CHECK:STDOUT: %d.ref.loc22_11: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc22_12.1: ref i32 = class_element_access %d.ref.loc22_11, element1
// CHECK:STDOUT: %.loc22_12.2: i32 = bind_value %.loc22_12.1
// CHECK:STDOUT: %d.ref.loc22_16: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc22_17.1: ref Base = class_element_access %d.ref.loc22_16, element0
// CHECK:STDOUT: %.loc22_17.2: Base = bind_value %.loc22_17.1
// CHECK:STDOUT: %.loc22_22.1: ref i32 = class_element_access %.loc22_17.2, element0
// CHECK:STDOUT: %.loc22_22.2: i32 = bind_value %.loc22_22.1
// CHECK:STDOUT: %.loc22_24.1: (i32, i32) = tuple_literal (%.loc22_12.2, %.loc22_22.2)
// CHECK:STDOUT: %.loc22_24.2: ref i32 = tuple_access %return, element0
// CHECK:STDOUT: %.loc22_24.3: init i32 = initialize_from %.loc22_12.2 to %.loc22_24.2
// CHECK:STDOUT: %.loc22_24.4: ref i32 = tuple_access %return, element1
// CHECK:STDOUT: %.loc22_24.5: init i32 = initialize_from %.loc22_22.2 to %.loc22_24.4
// CHECK:STDOUT: %.loc22_24.6: init (i32, i32) = tuple_init (%.loc22_24.3, %.loc22_24.5) to %return
// CHECK:STDOUT: %.loc22_24.7: init (i32, i32) = converted %.loc22_24.1, %.loc22_24.6
// CHECK:STDOUT: return %.loc22_24.7
// CHECK:STDOUT: }
// CHECK:STDOUT:
+34 -35
View File
@@ -9,8 +9,7 @@ abstract class Abstract {
}
class Derived {
// TODO: `extend base: Base;`
base: Abstract;
extend base: Abstract;
var d: i32;
}
@@ -32,14 +31,14 @@ fn Access(d: Derived) -> (i32, i32) {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.loc9: type = struct_type {.a: i32}
// CHECK:STDOUT: %.loc7: type = ptr_type {.a: i32}
// CHECK:STDOUT: %.loc16_1.1: type = struct_type {.base: Abstract, .d: i32}
// CHECK:STDOUT: %.loc16_1.2: type = struct_type {.base: {.a: i32}*, .d: i32}
// CHECK:STDOUT: %.loc16_1.3: type = ptr_type {.base: {.a: i32}*, .d: i32}
// CHECK:STDOUT: %.loc15_1.1: type = struct_type {.base: Abstract, .d: i32}
// CHECK:STDOUT: %.loc15_1.2: type = struct_type {.base: {.a: i32}*, .d: i32}
// CHECK:STDOUT: %.loc15_1.3: type = ptr_type {.base: {.a: i32}*, .d: i32}
// CHECK:STDOUT: %.loc11: type = ptr_type {.base: Abstract, .d: i32}
// CHECK:STDOUT: %.loc23: type = struct_type {.base: {.a: i32}, .d: i32}
// CHECK:STDOUT: %.loc26_35.1: type = tuple_type (type, type)
// CHECK:STDOUT: %.loc26_35.2: type = tuple_type (i32, i32)
// CHECK:STDOUT: %.loc26_35.3: type = ptr_type (i32, i32)
// CHECK:STDOUT: %.loc22: type = struct_type {.base: {.a: i32}, .d: i32}
// CHECK:STDOUT: %.loc25_35.1: type = tuple_type (type, type)
// CHECK:STDOUT: %.loc25_35.2: type = tuple_type (i32, i32)
// CHECK:STDOUT: %.loc25_35.3: type = ptr_type (i32, i32)
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -63,43 +62,43 @@ fn Access(d: Derived) -> (i32, i32) {
// CHECK:STDOUT:
// CHECK:STDOUT: class @Derived {
// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract
// CHECK:STDOUT: %.loc13_17.1: type = unbound_element_type Derived, Abstract
// CHECK:STDOUT: %.loc13_17.2: <unbound element of class Derived> = base_decl Abstract, element0
// CHECK:STDOUT: %.loc15_8.1: type = unbound_element_type Derived, i32
// CHECK:STDOUT: %.loc15_8.2: <unbound element of class Derived> = field_decl d, element1
// CHECK:STDOUT: %d: <unbound element of class Derived> = bind_name d, %.loc15_8.2
// CHECK:STDOUT: %.loc12_24.1: type = unbound_element_type Derived, Abstract
// CHECK:STDOUT: %.loc12_24.2: <unbound element of class Derived> = base_decl Abstract, element0
// CHECK:STDOUT: %.loc14_8.1: type = unbound_element_type Derived, i32
// CHECK:STDOUT: %.loc14_8.2: <unbound element of class Derived> = field_decl d, element1
// CHECK:STDOUT: %d: <unbound element of class Derived> = bind_name d, %.loc14_8.2
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc13_17.2
// CHECK:STDOUT: .base = %.loc12_24.2
// CHECK:STDOUT: .d = %d
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Make() -> %return: Derived {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc23_25: i32 = int_literal 1
// CHECK:STDOUT: %.loc23_26: {.a: i32} = struct_literal (%.loc23_25)
// CHECK:STDOUT: %.loc23_34: i32 = int_literal 7
// CHECK:STDOUT: %.loc23_35: {.base: {.a: i32}, .d: i32} = struct_literal (%.loc23_26, %.loc23_34)
// CHECK:STDOUT: %.loc22_25: i32 = int_literal 1
// CHECK:STDOUT: %.loc22_26: {.a: i32} = struct_literal (%.loc22_25)
// CHECK:STDOUT: %.loc22_34: i32 = int_literal 7
// CHECK:STDOUT: %.loc22_35: {.base: {.a: i32}, .d: i32} = struct_literal (%.loc22_26, %.loc22_34)
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Access(%d: Derived) -> %return: (i32, i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref.loc27_11: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc27_12.1: ref i32 = class_element_access %d.ref.loc27_11, element1
// CHECK:STDOUT: %.loc27_12.2: i32 = bind_value %.loc27_12.1
// CHECK:STDOUT: %d.ref.loc27_16: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc27_17.1: ref Abstract = class_element_access %d.ref.loc27_16, element0
// CHECK:STDOUT: %.loc27_17.2: Abstract = bind_value %.loc27_17.1
// CHECK:STDOUT: %.loc27_22.1: ref i32 = class_element_access %.loc27_17.2, element0
// CHECK:STDOUT: %.loc27_22.2: i32 = bind_value %.loc27_22.1
// CHECK:STDOUT: %.loc27_24.1: (i32, i32) = tuple_literal (%.loc27_12.2, %.loc27_22.2)
// CHECK:STDOUT: %.loc27_24.2: ref i32 = tuple_access %return, element0
// CHECK:STDOUT: %.loc27_24.3: init i32 = initialize_from %.loc27_12.2 to %.loc27_24.2
// CHECK:STDOUT: %.loc27_24.4: ref i32 = tuple_access %return, element1
// CHECK:STDOUT: %.loc27_24.5: init i32 = initialize_from %.loc27_22.2 to %.loc27_24.4
// CHECK:STDOUT: %.loc27_24.6: init (i32, i32) = tuple_init (%.loc27_24.3, %.loc27_24.5) to %return
// CHECK:STDOUT: %.loc27_24.7: init (i32, i32) = converted %.loc27_24.1, %.loc27_24.6
// CHECK:STDOUT: return %.loc27_24.7
// CHECK:STDOUT: %d.ref.loc26_11: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc26_12.1: ref i32 = class_element_access %d.ref.loc26_11, element1
// CHECK:STDOUT: %.loc26_12.2: i32 = bind_value %.loc26_12.1
// CHECK:STDOUT: %d.ref.loc26_16: Derived = name_ref d, %d
// CHECK:STDOUT: %.loc26_17.1: ref Abstract = class_element_access %d.ref.loc26_16, element0
// CHECK:STDOUT: %.loc26_17.2: Abstract = bind_value %.loc26_17.1
// CHECK:STDOUT: %.loc26_22.1: ref i32 = class_element_access %.loc26_17.2, element0
// CHECK:STDOUT: %.loc26_22.2: i32 = bind_value %.loc26_22.1
// CHECK:STDOUT: %.loc26_24.1: (i32, i32) = tuple_literal (%.loc26_12.2, %.loc26_22.2)
// CHECK:STDOUT: %.loc26_24.2: ref i32 = tuple_access %return, element0
// CHECK:STDOUT: %.loc26_24.3: init i32 = initialize_from %.loc26_12.2 to %.loc26_24.2
// CHECK:STDOUT: %.loc26_24.4: ref i32 = tuple_access %return, element1
// CHECK:STDOUT: %.loc26_24.5: init i32 = initialize_from %.loc26_22.2 to %.loc26_24.4
// CHECK:STDOUT: %.loc26_24.6: init (i32, i32) = tuple_init (%.loc26_24.3, %.loc26_24.5) to %return
// CHECK:STDOUT: %.loc26_24.7: init (i32, i32) = converted %.loc26_24.1, %.loc26_24.6
// CHECK:STDOUT: return %.loc26_24.7
// CHECK:STDOUT: }
// CHECK:STDOUT:
+49 -49
View File
@@ -8,52 +8,52 @@ base class Base {}
class Final {}
class DeriveFromNonType {
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:11: ERROR: Cannot implicitly convert from `i32` to `type`.
// CHECK:STDERR: base: 32;
// CHECK:STDERR: ^
base: 32;
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:18: ERROR: Cannot implicitly convert from `i32` to `type`.
// CHECK:STDERR: extend base: 32;
// CHECK:STDERR: ^
extend base: 32;
}
class DeriveFromi32 {
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:12: ERROR: Deriving from final type `i32`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: base: i32;
// CHECK:STDERR: ^
base: i32;
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:19: ERROR: Deriving from final type `i32`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: extend base: i32;
// CHECK:STDERR: ^
extend base: i32;
}
class DeriveFromTuple {
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:16: ERROR: Deriving from final type `(Base,)`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: base: (Base,);
// CHECK:STDERR: ^
base: (Base,);
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:23: ERROR: Deriving from final type `(Base,)`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: extend base: (Base,);
// CHECK:STDERR: ^
extend base: (Base,);
}
// TODO: Should we allow this?
// We do allow `{.base = {.a: i32, .b: i32}}`.
class DeriveFromStruct {
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:27: ERROR: Deriving from final type `{.a: i32, .b: i32}`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: base: {.a: i32, .b: i32};
// CHECK:STDERR: ^
base: {.a: i32, .b: i32};
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:34: ERROR: Deriving from final type `{.a: i32, .b: i32}`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: extend base: {.a: i32, .b: i32};
// CHECK:STDERR: ^
extend base: {.a: i32, .b: i32};
}
base class Incomplete;
class DeriveFromIncomplete {
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+6]]:19: ERROR: Base `Incomplete` is an incomplete type.
// CHECK:STDERR: base: Incomplete;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+6]]:26: ERROR: Base `Incomplete` is an incomplete type.
// CHECK:STDERR: extend base: Incomplete;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE-6]]:1: Class was forward declared here.
// CHECK:STDERR: base class Incomplete;
// CHECK:STDERR: ^~~~
base: Incomplete;
extend base: Incomplete;
}
class DeriveFromFinal {
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:14: ERROR: Deriving from final type `Final`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: base: Final;
// CHECK:STDERR: ^
base: Final;
// CHECK:STDERR: fail_base_bad_type.carbon:[[@LINE+3]]:21: ERROR: Deriving from final type `Final`. Base type must be an `abstract` or `base` class.
// CHECK:STDERR: extend base: Final;
// CHECK:STDERR: ^
extend base: Final;
}
// CHECK:STDOUT: --- fail_base_bad_type.carbon
@@ -62,11 +62,11 @@ class DeriveFromFinal {
// CHECK:STDOUT: %.loc7_18.1: type = struct_type {}
// CHECK:STDOUT: %.loc15: type = struct_type {.base: <error>}
// CHECK:STDOUT: %.loc22: type = struct_type {.base: i32}
// CHECK:STDOUT: %.loc28_15: type = tuple_type (type)
// CHECK:STDOUT: %.loc28_16.1: type = tuple_type (Base)
// CHECK:STDOUT: %.loc28_22: type = tuple_type (type)
// CHECK:STDOUT: %.loc28_23.1: type = tuple_type (Base)
// CHECK:STDOUT: %.loc7_18.2: type = tuple_type ()
// CHECK:STDOUT: %.loc7_1: type = ptr_type {}
// CHECK:STDOUT: %.loc28_16.2: type = tuple_type ({}*)
// CHECK:STDOUT: %.loc28_23.2: type = tuple_type ({}*)
// CHECK:STDOUT: %.loc29: type = struct_type {.base: (Base,)}
// CHECK:STDOUT: %.loc37: type = ptr_type {.a: i32, .b: i32}
// CHECK:STDOUT: %.loc38: type = struct_type {.base: {.a: i32, .b: i32}}
@@ -106,59 +106,59 @@ class DeriveFromFinal {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @DeriveFromNonType {
// CHECK:STDOUT: %.loc14_9: i32 = int_literal 32
// CHECK:STDOUT: %.loc14_11.1: type = unbound_element_type DeriveFromNonType, <error>
// CHECK:STDOUT: %.loc14_11.2: <unbound element of class DeriveFromNonType> = base_decl <error>, element0
// CHECK:STDOUT: %.loc14_16: i32 = int_literal 32
// CHECK:STDOUT: %.loc14_18.1: type = unbound_element_type DeriveFromNonType, <error>
// CHECK:STDOUT: %.loc14_18.2: <unbound element of class DeriveFromNonType> = base_decl <error>, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc14_11.2
// CHECK:STDOUT: .base = %.loc14_18.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @DeriveFromi32 {
// CHECK:STDOUT: %.loc21_12.1: type = unbound_element_type DeriveFromi32, i32
// CHECK:STDOUT: %.loc21_12.2: <unbound element of class DeriveFromi32> = base_decl i32, element0
// CHECK:STDOUT: %.loc21_19.1: type = unbound_element_type DeriveFromi32, i32
// CHECK:STDOUT: %.loc21_19.2: <unbound element of class DeriveFromi32> = base_decl i32, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc21_12.2
// CHECK:STDOUT: .base = %.loc21_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @DeriveFromTuple {
// CHECK:STDOUT: %Base.ref: type = name_ref Base, file.%Base
// CHECK:STDOUT: %.loc28_15: (type,) = tuple_literal (%Base.ref)
// CHECK:STDOUT: %.loc28_16.1: type = converted %.loc28_15, constants.%.loc28_16.1
// CHECK:STDOUT: %.loc28_16.2: type = unbound_element_type DeriveFromTuple, (Base,)
// CHECK:STDOUT: %.loc28_16.3: <unbound element of class DeriveFromTuple> = base_decl (Base,), element0
// CHECK:STDOUT: %.loc28_22: (type,) = tuple_literal (%Base.ref)
// CHECK:STDOUT: %.loc28_23.1: type = converted %.loc28_22, constants.%.loc28_23.1
// CHECK:STDOUT: %.loc28_23.2: type = unbound_element_type DeriveFromTuple, (Base,)
// CHECK:STDOUT: %.loc28_23.3: <unbound element of class DeriveFromTuple> = base_decl (Base,), element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc28_16.3
// CHECK:STDOUT: .base = %.loc28_23.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @DeriveFromStruct {
// CHECK:STDOUT: %.loc37_26: type = struct_type {.a: i32, .b: i32}
// CHECK:STDOUT: %.loc37_27.1: type = unbound_element_type DeriveFromStruct, {.a: i32, .b: i32}
// CHECK:STDOUT: %.loc37_27.2: <unbound element of class DeriveFromStruct> = base_decl {.a: i32, .b: i32}, element0
// CHECK:STDOUT: %.loc37_33: type = struct_type {.a: i32, .b: i32}
// CHECK:STDOUT: %.loc37_34.1: type = unbound_element_type DeriveFromStruct, {.a: i32, .b: i32}
// CHECK:STDOUT: %.loc37_34.2: <unbound element of class DeriveFromStruct> = base_decl {.a: i32, .b: i32}, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc37_27.2
// CHECK:STDOUT: .base = %.loc37_34.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Incomplete;
// CHECK:STDOUT:
// CHECK:STDOUT: class @DeriveFromIncomplete {
// CHECK:STDOUT: %Incomplete.ref: type = name_ref Incomplete, file.%Incomplete
// CHECK:STDOUT: %.loc49_19.1: type = unbound_element_type DeriveFromIncomplete, <error>
// CHECK:STDOUT: %.loc49_19.2: <unbound element of class DeriveFromIncomplete> = base_decl <error>, element0
// CHECK:STDOUT: %.loc49_26.1: type = unbound_element_type DeriveFromIncomplete, <error>
// CHECK:STDOUT: %.loc49_26.2: <unbound element of class DeriveFromIncomplete> = base_decl <error>, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc49_19.2
// CHECK:STDOUT: .base = %.loc49_26.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @DeriveFromFinal {
// CHECK:STDOUT: %Final.ref: type = name_ref Final, file.%Final
// CHECK:STDOUT: %.loc56_14.1: type = unbound_element_type DeriveFromFinal, Final
// CHECK:STDOUT: %.loc56_14.2: <unbound element of class DeriveFromFinal> = base_decl Final, element0
// CHECK:STDOUT: %.loc56_21.1: type = unbound_element_type DeriveFromFinal, Final
// CHECK:STDOUT: %.loc56_21.2: <unbound element of class DeriveFromFinal> = base_decl Final, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc56_14.2
// CHECK:STDOUT: .base = %.loc56_21.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+9 -9
View File
@@ -6,19 +6,19 @@
base class B {}
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:8: ERROR: `base` declaration can only be used in a class.
// CHECK:STDERR: base: B;
// CHECK:STDERR: ^
base: B;
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:15: ERROR: `base` declaration can only be used in a class.
// CHECK:STDERR: extend base: B;
// CHECK:STDERR: ^
extend base: B;
fn F() {
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+6]]:3: ERROR: Expected expression.
// CHECK:STDERR: base: B;
// CHECK:STDERR: ^~~~
// CHECK:STDERR: extend base: B;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_base_misplaced.carbon:[[@LINE+3]]:3: ERROR: Semantics TODO: `HandleInvalidParse`.
// CHECK:STDERR: base: B;
// CHECK:STDERR: ^~~~
base: B;
// CHECK:STDERR: extend base: B;
// CHECK:STDERR: ^~~~~~
extend base: B;
}
// CHECK:STDOUT: --- fail_base_misplaced.carbon
@@ -0,0 +1,109 @@
// 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
base class B {}
class C1 {
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+3]]:3: ERROR: `private` not allowed on `base` declaration.
// CHECK:STDERR: private extend base: B;
// CHECK:STDERR: ^~~~~~~
private extend base: B;
}
class C2 {
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+6]]:3: ERROR: `abstract` not allowed on `base` declaration.
// CHECK:STDERR: abstract base: B;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+3]]:3: ERROR: Missing `extend` before `base` declaration in class.
// CHECK:STDERR: abstract base: B;
// CHECK:STDERR: ^~~~~~~~
abstract base: B;
}
class C3 {
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+6]]:10: ERROR: `default` not allowed on declaration with `extend`.
// CHECK:STDERR: extend default base: B;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+3]]:3: `extend` previously appeared here.
// CHECK:STDERR: extend default base: B;
// CHECK:STDERR: ^~~~~~
extend default base: B;
}
class C4 {
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+6]]:10: ERROR: `extend` repeated on declaration.
// CHECK:STDERR: extend extend base: B;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_base_modifiers.carbon:[[@LINE+3]]:3: `extend` previously appeared here.
// CHECK:STDERR: extend extend base: B;
// CHECK:STDERR: ^~~~~~
extend extend base: B;
}
// CHECK:STDOUT: --- fail_base_modifiers.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.loc7_15.1: type = struct_type {}
// CHECK:STDOUT: %.loc7_15.2: type = tuple_type ()
// CHECK:STDOUT: %.loc7_1: type = ptr_type {}
// CHECK:STDOUT: %.loc14: type = struct_type {.base: B}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace {.B = %B.decl, .C1 = %C1.decl, .C2 = %C2.decl, .C3 = %C3.decl, .C4 = %C4.decl}
// CHECK:STDOUT: %B.decl = class_decl @B, ()
// CHECK:STDOUT: %B: type = class_type @B
// CHECK:STDOUT: %C1.decl = class_decl @C1, ()
// CHECK:STDOUT: %C1: type = class_type @C1
// CHECK:STDOUT: %C2.decl = class_decl @C2, ()
// CHECK:STDOUT: %C2: type = class_type @C2
// CHECK:STDOUT: %C3.decl = class_decl @C3, ()
// CHECK:STDOUT: %C3: type = class_type @C3
// CHECK:STDOUT: %C4.decl = class_decl @C4, ()
// CHECK:STDOUT: %C4: type = class_type @C4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @B {
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C1 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B
// CHECK:STDOUT: %.loc13_25.1: type = unbound_element_type C1, B
// CHECK:STDOUT: %.loc13_25.2: <unbound element of class C1> = base_decl B, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc13_25.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C2 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B
// CHECK:STDOUT: %.loc23_19.1: type = unbound_element_type C2, B
// CHECK:STDOUT: %.loc23_19.2: <unbound element of class C2> = base_decl B, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc23_19.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C3 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B
// CHECK:STDOUT: %.loc33_25.1: type = unbound_element_type C3, B
// CHECK:STDOUT: %.loc33_25.2: <unbound element of class C3> = base_decl B, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc33_25.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C4 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B
// CHECK:STDOUT: %.loc43_24.1: type = unbound_element_type C4, B
// CHECK:STDOUT: %.loc43_24.2: <unbound element of class C4> = base_decl B, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc43_24.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -0,0 +1,46 @@
// 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
base class B {}
class C {
// CHECK:STDERR: fail_base_no_extend.carbon:[[@LINE+3]]:3: ERROR: Missing `extend` before `base` declaration in class.
// CHECK:STDERR: base: B;
// CHECK:STDERR: ^~~~
base: B;
}
// CHECK:STDOUT: --- fail_base_no_extend.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.loc7_15.1: type = struct_type {}
// CHECK:STDOUT: %.loc7_15.2: type = tuple_type ()
// CHECK:STDOUT: %.loc7_1: type = ptr_type {}
// CHECK:STDOUT: %.loc14: type = struct_type {.base: B}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace {.B = %B.decl, .C = %C.decl}
// CHECK:STDOUT: %B.decl = class_decl @B, ()
// CHECK:STDOUT: %B: type = class_type @B
// CHECK:STDOUT: %C.decl = class_decl @C, ()
// CHECK:STDOUT: %C: type = class_type @C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @B {
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B
// CHECK:STDOUT: %.loc13_10.1: type = unbound_element_type C, B
// CHECK:STDOUT: %.loc13_10.2: <unbound element of class C> = base_decl B, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc13_10.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+22 -22
View File
@@ -8,26 +8,26 @@ base class B1 {}
base class B2 {}
class C {
base: B1;
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE+6]]:11: ERROR: Multiple `base` declarations in class. Multiple inheritance is not permitted.
// CHECK:STDERR: base: B2;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE-4]]:11: Previous `base` declaration is here.
// CHECK:STDERR: base: B1;
// CHECK:STDERR: ^
base: B2;
extend base: B1;
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE+6]]:18: ERROR: Multiple `base` declarations in class. Multiple inheritance is not permitted.
// CHECK:STDERR: extend base: B2;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE-4]]:18: Previous `base` declaration is here.
// CHECK:STDERR: extend base: B1;
// CHECK:STDERR: ^
extend base: B2;
}
class D {
// TODO: Consider adding a custom diagnostic for this case.
base: B1;
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE+6]]:11: ERROR: Multiple `base` declarations in class. Multiple inheritance is not permitted.
// CHECK:STDERR: base: B1;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE-4]]:11: Previous `base` declaration is here.
// CHECK:STDERR: base: B1;
// CHECK:STDERR: ^
base: B1;
extend base: B1;
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE+6]]:18: ERROR: Multiple `base` declarations in class. Multiple inheritance is not permitted.
// CHECK:STDERR: extend base: B1;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_base_repeated.carbon:[[@LINE-4]]:18: Previous `base` declaration is here.
// CHECK:STDERR: extend base: B1;
// CHECK:STDERR: ^
extend base: B1;
}
// CHECK:STDOUT: --- fail_base_repeated.carbon
@@ -63,21 +63,21 @@ class D {
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %B1.ref: type = name_ref B1, file.%B1
// CHECK:STDOUT: %.loc11_11.1: type = unbound_element_type C, B1
// CHECK:STDOUT: %.loc11_11.2: <unbound element of class C> = base_decl B1, element0
// CHECK:STDOUT: %.loc11_18.1: type = unbound_element_type C, B1
// CHECK:STDOUT: %.loc11_18.2: <unbound element of class C> = base_decl B1, element0
// CHECK:STDOUT: %B2.ref: type = name_ref B2, file.%B2
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc11_11.2
// CHECK:STDOUT: .base = %.loc11_18.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @D {
// CHECK:STDOUT: %B1.ref.loc23: type = name_ref B1, file.%B1
// CHECK:STDOUT: %.loc23_11.1: type = unbound_element_type D, B1
// CHECK:STDOUT: %.loc23_11.2: <unbound element of class D> = base_decl B1, element0
// CHECK:STDOUT: %.loc23_18.1: type = unbound_element_type D, B1
// CHECK:STDOUT: %.loc23_18.2: <unbound element of class D> = base_decl B1, element0
// CHECK:STDOUT: %B1.ref.loc30: type = name_ref B1, file.%B1
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc23_11.2
// CHECK:STDOUT: .base = %.loc23_18.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+5 -5
View File
@@ -7,7 +7,7 @@
base class B {}
class C {
base: B;
extend base: B;
}
// CHECK:STDERR: fail_base_unbound.carbon:[[@LINE+3]]:13: ERROR: Expression cannot be used as a value.
@@ -32,7 +32,7 @@ let b: B = C.base;
// CHECK:STDOUT: %C: type = class_type @C
// CHECK:STDOUT: %B.ref: type = name_ref B, %B
// CHECK:STDOUT: %C.ref: type = name_ref C, %C
// CHECK:STDOUT: %base.ref: <unbound element of class C> = name_ref base, @C.%.loc10_10.2
// CHECK:STDOUT: %base.ref: <unbound element of class C> = name_ref base, @C.%.loc10_17.2
// CHECK:STDOUT: %b: B = bind_name b, <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -43,10 +43,10 @@ let b: B = C.base;
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B
// CHECK:STDOUT: %.loc10_10.1: type = unbound_element_type C, B
// CHECK:STDOUT: %.loc10_10.2: <unbound element of class C> = base_decl B, element0
// CHECK:STDOUT: %.loc10_17.1: type = unbound_element_type C, B
// CHECK:STDOUT: %.loc10_17.2: <unbound element of class C> = base_decl B, element0
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .base = %.loc10_10.2
// CHECK:STDOUT: .base = %.loc10_17.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+3 -1
View File
@@ -214,7 +214,9 @@ class DiagnosticEmitter {
// A builder-pattern type to provide a fluent interface for constructing
// a more complex diagnostic. See `DiagnosticEmitter::Build` for the
// expected usage.
class DiagnosticBuilder {
// This is nodiscard to protect against accidentally building a diagnostic
// without emitting it.
class [[nodiscard]] DiagnosticBuilder {
public:
// DiagnosticBuilder is move-only and cannot be copied.
DiagnosticBuilder(DiagnosticBuilder&&) noexcept = default;
@@ -147,6 +147,7 @@ CARBON_DIAGNOSTIC_KIND(MissingObjectInMethodCall)
// Class checking.
CARBON_DIAGNOSTIC_KIND(BaseIsFinal)
CARBON_DIAGNOSTIC_KIND(BaseMissingExtend)
CARBON_DIAGNOSTIC_KIND(BaseOutsideClass)
CARBON_DIAGNOSTIC_KIND(BasePrevious)
CARBON_DIAGNOSTIC_KIND(BaseRepeated)
+1 -2
View File
@@ -9,8 +9,7 @@ base class Base {
}
class Derived {
// TODO: `extend base: Base;`
base: Base;
extend base: Base;
var d: i32;
}
@@ -41,6 +41,7 @@ static auto TokenIsModifierOrIntroducer(Lex::TokenKind token_kind) -> bool {
case Lex::TokenKind::Class:
case Lex::TokenKind::Constraint:
case Lex::TokenKind::Default:
case Lex::TokenKind::Extend:
case Lex::TokenKind::Final:
case Lex::TokenKind::Fn:
case Lex::TokenKind::Impl:
@@ -188,6 +189,21 @@ auto HandleDeclScopeLoop(Context& context) -> void {
break;
}
case Lex::TokenKind::Extend: {
// `extend` is considered a declaration modifier if it is followed by
// another modifier or an introducer.
if (TokenIsModifierOrIntroducer(
context.PositionKind(Lookahead::NextToken))) {
context.AddLeafNode(NodeKind::DeclModifierKeyword, context.Consume());
saw_modifier = true;
} else {
// TODO: Treat this `extend` token as a declaration introducer
HandleUnrecognizedDecl(context, state.subtree_start);
return;
}
break;
}
// If we see a declaration introducer keyword token, replace the
// placeholder node and switch to a state to parse the rest of the
// declaration. We don't allow namespace or empty declarations here since
+1
View File
@@ -607,6 +607,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(DeclModifierKeyword, 0,
CARBON_TOKEN(Abstract)
CARBON_TOKEN(Base)
CARBON_TOKEN(Default)
CARBON_TOKEN(Extend)
CARBON_TOKEN(Final)
CARBON_TOKEN(Impl)
CARBON_TOKEN(Virtual))
+5 -3
View File
@@ -285,14 +285,16 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterImplicit)
//
// abstract
// ^~~~~~~~
// base
// base class
// ^~~~
// default
// ^~~~~~~
// extend base
// ^~~~~~
// final
// ^~~~~
// override
// ^~~~~~~~
// impl fn
// ^~~~
// private
// ^~~~~~~
// protected
+15 -3
View File
@@ -7,8 +7,10 @@
base class B {}
class D {
base: B;
base: B1;
extend base: B2;
base class Nested;
private base class PrivateNested;
}
// CHECK:STDOUT: - filename: base.carbon
@@ -24,12 +26,22 @@ class D {
// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3},
// CHECK:STDOUT: {kind: 'BaseIntroducer', text: 'base'},
// CHECK:STDOUT: {kind: 'BaseColon', text: ':'},
// CHECK:STDOUT: {kind: 'NameExpr', text: 'B'},
// CHECK:STDOUT: {kind: 'NameExpr', text: 'B1'},
// CHECK:STDOUT: {kind: 'BaseDecl', text: ';', subtree_size: 4},
// CHECK:STDOUT: {kind: 'BaseIntroducer', text: 'base'},
// CHECK:STDOUT: {kind: 'DeclModifierKeyword', text: 'extend'},
// CHECK:STDOUT: {kind: 'BaseColon', text: ':'},
// CHECK:STDOUT: {kind: 'NameExpr', text: 'B2'},
// CHECK:STDOUT: {kind: 'BaseDecl', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'DeclModifierKeyword', text: 'base'},
// CHECK:STDOUT: {kind: 'Name', text: 'Nested'},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 12},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'AccessModifierKeyword', text: 'private'},
// CHECK:STDOUT: {kind: 'DeclModifierKeyword', text: 'base'},
// CHECK:STDOUT: {kind: 'Name', text: 'PrivateNested'},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 22},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]