mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 18:31:08 +01:00
Require extend before base: BaseType; (#3459)
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -285,14 +285,16 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterImplicit)
|
||||
//
|
||||
// abstract
|
||||
// ^~~~~~~~
|
||||
// base
|
||||
// base class
|
||||
// ^~~~
|
||||
// default
|
||||
// ^~~~~~~
|
||||
// extend base
|
||||
// ^~~~~~
|
||||
// final
|
||||
// ^~~~~
|
||||
// override
|
||||
// ^~~~~~~~
|
||||
// impl fn
|
||||
// ^~~~
|
||||
// private
|
||||
// ^~~~~~~
|
||||
// protected
|
||||
|
||||
+15
-3
@@ -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: ]
|
||||
|
||||
Reference in New Issue
Block a user