From f3d637ba4d90bc2e23db07f1a9df5a6be7533f08 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 4 Jun 2020 11:53:13 -0700 Subject: First steps toward inheritance for struct types (#1366) * First steps toward inheritance for struct types This change adds the ability for a `struct` type to declare a base type that is another `struct`: ```hlsl struct Base { int baseMember; } struct Derived : Base { int derivedMember; } ``` The semantics of the feature are that code like the above desugars into code like: ```hlsl struct Base { int baseMember; } struct Derived { Base _base; int derivedMember; } ``` At points where a member from the base type is being projected out, or the value is being implicitly cast to the base type, the compiler transforms the code to reference the implicitly-generated `_base` member. That means code like this: ```hlsl void f(Base b); ... Derived d = ...; int x = d.baseMember; f(d); ``` gets transformed into a form like this: ```hlsl void f(Base b); ... Derived d = ...; int x = d._base.baseMember; f(d._base); ``` Note that as a result of this choice, the behavior when passing a `Derived` value to a function that expects a `Base` (including to inherited member functions) is that of "object shearing" from the C++ world: the called function can only "see" the `Base` part of the argument, and any operations performed on it will behave as if the value was indeed a `Base`. There is no polymorphism going on because Slang doesn't currently have `virtual` methods. In an attempt to work toward inheritance being a robust feature, this change adds a bunch of more detailed logic for checking the bases of various declarations: * An `interface` declaration is only allowed to inherit from other `interface`s * An `extension` declaration can only introduce inheritance from `interface`s * A `struct` declaration can only inherit from at most one other `struct`, and that `struct` must be the first entry in the list of bases This change also adds a mechanism to control whether a `struct` or `interface` in one module can inherit from a `struct` or `interface` declared in another module: * If the base declaration is marked `[open]`, then the inheritance is allowed * If the base declaration is marked `[sealed]`, then the inheritance is allowed * If it is not marked otherwise, a `struct` is implicitly `[sealed]` * If it is not marked otherwise, an `interface` is implicitly `[open]` These seem like reasonable defaults. In order to safeguard the standard library a bit, the interfaces for builtin types have been marked `[sealed]` to make sure that a user cannot declare a `struct` and then mark it as a `BuiltinFloatingPointType`. This step should bring us a bit closer to being able to document and expose these interfaces for built-in types so that users can write code that is generic over them. There are some big caveats with this work, such that it really only represents a stepping-stone toward a usable inheritance feature. The most important caveats are: * If a `Derived` type tries to conform to an interface, such that one or more interface requirements are satisfied with members inherited from the `Base` type, that is likely to cause a crash or incorrect code generation. * If a `Derived` type tries to inherit from a `Base` type that conforms to one or more interfaces, the witness table generated for the conformance of `Derived` to that interface is likely to lead to a crash or incorrect code generation. It is clear that solving both of those issues will be necessary before we can really promote `struct` inheritance as a feature for users to try out. * fixup: trying to appease clang error * fixups: review feedback --- source/slang/core.meta.slang | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'source/slang/core.meta.slang') diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 2b43206a3..0c39f2c2f 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -18,9 +18,11 @@ syntax constexpr : ConstExprModifier; syntax globallycoherent : GloballyCoherentModifier; // A type that can be used as an operand for builtins +[sealed] interface __BuiltinType {} // A type that can be used for arithmetic operations +[sealed] interface __BuiltinArithmeticType : __BuiltinType { /// Initialize from a 32-bit signed integer value. @@ -28,19 +30,24 @@ interface __BuiltinArithmeticType : __BuiltinType } /// A type that can be used for logical/bitwsie operations +[sealed] interface __BuiltinLogicalType : __BuiltinType {} // A type that logically has a sign (positive/negative/zero) +[sealed] interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {} // A type that can represent integers +[sealed] interface __BuiltinIntegerType : __BuiltinArithmeticType {} // A type that can represent non-integers +[sealed] interface __BuiltinRealType : __BuiltinSignedArithmeticType {} // A type that uses a floating-point representation +[sealed] interface __BuiltinFloatingPointType : __BuiltinRealType { /// Initialize from a 32-bit floating-point value. @@ -1917,3 +1924,10 @@ attribute_syntax [__extern] : ExternAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [__unsafeForceInlineEarly] : UnsafeForceInlineEarlyAttribute; + +// Inheritance Control +__attributeTarget(AggTypeDecl) +attribute_syntax [sealed] : SealedAttribute; + +__attributeTarget(AggTypeDecl) +attribute_syntax [open] : OpenAttribute; -- cgit v1.2.3