Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SP004: implement initialize list translation to ctor #5215

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
55 changes: 54 additions & 1 deletion docs/proposals/004-initialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,39 @@ MyType x = MyType(y); // equivalent to `x = y`.

The compiler will attempt to resolve all type casts using type coercion rules, if that failed, will fall back to resolve it as a constructor call.

### Inheritance Initialization
For derived struct, slang will synthesized the constructor by bring the parameters from the base struct's constructor if the base struct also has a synthesized constructor. For example:
```csharp
struct Base
{
int x;
// compiler synthesizes:
// __init(int x) { ... }
}
struct Derived : Base
{
int y;
// compiler synthesizes:
// __init(int x, int y) { ... }
}
```

However, if the base struct has explicit ctors, the compiler will not synthesize a constructor for the derived struct.
For example, given
```csharp
struct Base { int x; __init(int x) { this.x = x; } }
struct Derived : Base { int y;}
```
The compiler will not synthesize a constructor for `Derived`, and the following code will fail to compile:
```csharp

Derived d = {1}; // error, no matching ctor.
Derived d = {1, 2}; // error, no matching ctor.
Derived d = Derived(1); // error, no matching ctor.
Derived d = Derived(1, 2); // error, no matching ctor.
```


### Initialization List

Slang allows initialization of a variable by assigning it with an initialization list.
Expand Down Expand Up @@ -168,6 +201,7 @@ If the above code passes type check, then it will be used as the way to initiali
If the above code does not pass type check, and if there is only one constructor for`MyType` that is synthesized as described in the previous section (and therefore marked as `[Synthesized]`, Slang continues to check if `S` meets the standard of a "legacy C-style struct` type.
A type is a "legacy C-Style struct" if all of the following conditions are met:
- It is a user-defined struct type or a basic scalar, vector or matrix type, e.g. `int`, `float4x4`.
- It does not inherit from any other types.
- It does not contain any explicit constructors defined by the user.
- All its members have the same visibility as the type itself.
- All its members are legacy C-Style structs or arrays of legacy C-style structs.
Expand Down Expand Up @@ -372,6 +406,25 @@ internal void test9()
Visibility4 t1 = {3}; // OK, initialized to {3,2} via ctor call.
Visibility4 t2 = {}; // OK, initialized to {1,2} via ctor call.
}

struct Base
{
int x;
int y;
// compiler synthesizes:
// internal __init(int x, int y);
}
struct Derived : Base
{
int z;
// compiler synthesizes:
// internal __init(int x, int y, int z);
}

void test10()
{
Derived t = {1, 2, 3}; // OK, initialized to {1, 2, 3} via ctor call.
}
```

### Zero Initialization
Expand Down Expand Up @@ -405,4 +458,4 @@ Alternatives Considered

One important decision point is whether or not Slang should allow variables to be left in uninitialized state after its declaration as it is allowed in C++. In contrast, C# forces everything to be default initialized at its declaration site, which come at the cost of incurring the burden to developers to come up with a way to define the default value for each type.
Our opinion is we want to allow things as uninitialized, and to have the compiler validation checks to inform
the developer something is wrong if they try to use a variable in uninitialized state. We believe it is desirable to tell the developer what's wrong instead of using a heavyweight mechanism to ensure everything is initialized at declaration sites, which can have non-trivial performance consequences for GPU programs, especially when the variable is declared in groupshared memory.
the developer something is wrong if they try to use a variable in uninitialized state. We believe it is desirable to tell the developer what's wrong instead of using a heavyweight mechanism to ensure everything is initialized at declaration sites, which can have non-trivial performance consequences for GPU programs, especially when the variable is declared in groupshared memory.
23 changes: 20 additions & 3 deletions source/slang/slang-ast-decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ class AggTypeDecl : public AggTypeDeclBase
class StructDecl: public AggTypeDecl
{
SLANG_AST_CLASS(StructDecl);

SLANG_UNREFLECTED
// We will use these auxiliary to help in synthesizing the member initialize constructor.
Slang::HashSet<VarDeclBase*> m_membersVisibleInCtor;
Dictionary<int, ConstructorDecl*> m_synthesizedCtorMap;
bool m_hasExplicitCtorInExtension = false;
};

class ClassDecl : public AggTypeDecl
Expand Down Expand Up @@ -372,9 +378,20 @@ class ConstructorDecl : public FunctionDeclBase
{
SLANG_AST_CLASS(ConstructorDecl)

// Indicates whether the declaration was synthesized by
// slang and not actually provided by the user
bool isSynthesized = false;
enum class ConstructorTags : int
{
None = 0x00,
// Indicates whether the declaration was synthesized by
// Slang and not actually provided by the user
Synthesized = 0x01,
// Member initialize constructor is definitely a synthesized ctor,
// but it takes parameters.
MemberInitCtor = 0x02
};

int m_tags = (int)ConstructorTags::None;
void addTag(ConstructorTags tag) { m_tags |= (int)tag; }
bool containsTag(ConstructorTags tag) { return m_tags & (int)tag; }
};

// A subscript operation used to index instances of a type
Expand Down
Loading
Loading