Skip to content

Commit

Permalink
make a few additions/changes to init list logic:
Browse files Browse the repository at this point in the history
1. allow a more formalized init-list logic for flattened init-lists's
2. fixing invalid tests
  • Loading branch information
ArielG-NV committed Aug 16, 2024
1 parent f8bf220 commit 1e7819a
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 52 deletions.
61 changes: 37 additions & 24 deletions source/slang/slang-check-conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,29 @@ namespace Slang
return nullptr;
}

bool _allowCStyleInitList(List<ConstructorDecl*> ctorList)
{
bool foundNonDefaultInit = false;
for (auto i : ctorList)
{
// Default ctor do not affect this logic.
if (i->getParameters().getCount() == 0)
continue;

// Cannot contain user defined ctor which is a non default ctor
if (!i->containsOption(ConstructorTags::Synthesized))
return false;

// Cannot contain 2+ non-default init's, this is ambigious for a c-style init list:
// `MyStruct[3] tmp = {1,2, 1,2, 1,2};`
// if `__init(int, int)` and `__init(int)` were both defined we would have ambiguity.
if (foundNonDefaultInit)
return false;
foundNonDefaultInit = true;
}
return true;
}

bool SemanticsVisitor::_readAggregateValueFromInitializerList(
Type* inToType,
Expr** outToExpr,
Expand Down Expand Up @@ -443,15 +466,16 @@ namespace Slang
{
auto toTypeDeclRef = toDeclRefType->getDeclRef();
// Trying to initialize a `struct` type given an initializer list.
// We will try to coerce the initializer list into a constructor.
if(auto toStructDeclRef = toTypeDeclRef.as<StructDecl>())
{
auto toStructDecl = toStructDeclRef.getDecl();
ensureDecl(toStructDecl, DeclCheckState::DefaultConstructorReadyForUse);

// We will try to coerce the initializer list (in order) into a constructor.
List<ConstructorDecl*> ctorList = _getCtorList(this->getASTBuilder(), this, toStructDecl, nullptr);

// Easy case of default constructor
bool allowCStyleInitList = _allowCStyleInitList(ctorList);

// Easy case of default constructor or equivalent
if (argCount == 0)
{
if (outToExpr)
Expand All @@ -465,26 +489,19 @@ namespace Slang
Index ioArgIndexMirror = ioArgIndex;
UInt ioArgIndexCandidate = 0;

// We also need to maximize the ctor arg count which is valid when processing ctor.
ctorList.stableSort(
[&](ConstructorDecl* a, ConstructorDecl* b)
{
return a->getParameters().getCount() > b->getParameters().getCount();
}
);

for (auto& ctor : ctorList)
{
// Don't try to init default ctor with this logic
auto ctorParamCount = ctor->getParameters().getCount();
if (ctorParamCount == 0)
continue;

ioArgIndexCandidate = ioArgIndexMirror;
ioArgIndex = ctorParamCount;

// Skip processing ctor if too many params expected by ctor
// We need to allow non-exact param counts to support array to constructor init-list syntax
if (ctorParamCount > Index(argCount))
// if allowCStyleInitList, process any ctor which comes next. ioArgIndex may not be 0
// if !allowCStyleInitList, process any ctor that exactly matched our argument count. ioArgIndex must start at 0.
if (!allowCStyleInitList && ctorParamCount != Index(argCount))
continue;

List<ConstructorDecl*> maybeCandidate;
Expand All @@ -495,17 +512,14 @@ namespace Slang
{
auto ctorParam = parameters[index];
auto paramType = ctorParam.getDecl()->type.type;
// Find 'equivlent typed' parameter if a member of the struct to allow subsitution
// in an attempt to resolve the generic of a type
// (required for vector/matrix/array resolution)
for (auto i : getMembersOfType<VarDecl>(m_astBuilder, toStructDeclRef, MemberFilterStyle::Instance))
if (i.getDecl()->type.type == paramType)
paramType = getType(m_astBuilder, i);

Expr* coercedArg = nullptr;
_readValueFromInitializerList(
paramType,
outToExpr ? &coercedArg : nullptr,
&coercedArg,
fromInitializerListExpr,
ioArgIndexCandidate);

Expand All @@ -515,7 +529,7 @@ namespace Slang
break;
}

if (maybeArgList.getCount() != ctor->getParameters().getCount())
if (maybeArgList.getCount() != ctorParamCount)
continue;

// Skip non-visible constructors.
Expand Down Expand Up @@ -551,21 +565,20 @@ namespace Slang
constructorExpr->type = toType;

*outToExpr = CheckExpr(constructorExpr);

return true;
}
return true;
}

// If we have a generic being compared to another generic (with different generic arguments)
// coerce logic will fail regardless of if generics are valid together. Example is below:
//
// MyStruct<T> tmp = {MyStructBase<U>(), 1}; // assume 'U' is unresolved at this point in time but equal to T
//
//
// To handle this since this is not verifiable coerce logic:
// 1. We need to ensure we don't have any matching constructors
// 2. if '1.' is true we can assign the possibly compatible generics and let generic resolution diagnose
// if something makes zero sense.

if (auto toGenericType = _getGenericAppDeclRefType(toType))
{
auto arg = fromInitializerListExpr->args[ioArgIndexMirror];
Expand Down Expand Up @@ -644,7 +657,7 @@ namespace Slang
{
if( outToExpr )
{
getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argCount);
getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argCount, toType);
}
}

Expand Down
36 changes: 18 additions & 18 deletions source/slang/slang-check-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,7 @@ namespace Slang
SemanticsDeclVisitorBase* visitor,
ASTBuilder* m_astBuilder,
AggTypeDecl* decl,
List<TypeExp>&& argList,
List<VarDeclBase*>&& argList,
DeclVisibility visibility)
{
auto ctor = m_astBuilder->create<ConstructorDecl>();
Expand Down Expand Up @@ -1850,7 +1850,7 @@ namespace Slang
for (auto arg : argList)
{
auto param = m_astBuilder->create<ParamDecl>();
param->type = (TypeExp)arg;
param->type = (TypeExp)arg->type;
param->parentDecl = ctor;
param->loc = ctor->loc;
ctor->members.add(param);
Expand Down Expand Up @@ -7972,7 +7972,7 @@ namespace Slang
memberExpr->scope = ctor->ownedScope;
memberExpr->loc = member->loc;
memberExpr->name = member->getName();
memberExpr->type = DeclRefType::create(getASTBuilder(), member->getDefaultDeclRef());
memberExpr->type = DeclRefType::create(getASTBuilder(), memberExpr->declRef);

auto assign = m_astBuilder->create<AssignExpr>();
assign->left = memberExpr;
Expand All @@ -7988,7 +7988,7 @@ namespace Slang
seqStmt->stmts.insert(ctorInfo.insertOffset++, seqStmtChild);
}

// compiler generated ctor may be destroyed if unused
// Compiler generated ctor may be destroyed
if(structDeclInfo.defaultCtor
&& structDeclInfo.defaultCtor->containsOption(ConstructorTags::Synthesized))
{
Expand Down Expand Up @@ -10224,7 +10224,7 @@ namespace Slang
static ConstructorDecl* _tryToGenerateCtorWithArgList(
SemanticsDeclVisitorBase* visitor,
ASTBuilder* astBuilder,
List<TypeExp>&& args,
List<VarDeclBase*>&& args,
List<ConstructorDecl*>& existingCtorList,
StructDecl* structDecl,
DeclVisibility visibility)
Expand All @@ -10250,7 +10250,7 @@ namespace Slang
{
auto newCtorArg = args[i];
auto existingCtorArg = existingCtorArgs[i];
if (visitor->getConversionCost(newCtorArg, existingCtorArg->getType()) == kConversionCost_Impossible)
if (visitor->getConversionCost(newCtorArg->getType(), existingCtorArg->getType()) == kConversionCost_Impossible)
{
equalCtor = false;
break;
Expand Down Expand Up @@ -10284,11 +10284,11 @@ namespace Slang
// Add an empty constructor for all combinations of visibility and access
// which is possible:
// 1. public constructor - usable *outside class scope* in a *different module*
List<TypeExp> publicCtorArgs;
List<VarDeclBase*> publicCtorArgs;
// 2. public-internal constructor - usable *outside class scope* in the *same module*
List<TypeExp> publicInternalCtorArgs;
List<VarDeclBase*> publicInternalCtorArgs;
// 3. public-private-internal constructor - usable *inside class scope* in the *same module*
List<TypeExp> publicPrivateInternalCtorArgs;
List<VarDeclBase*> publicPrivateInternalCtorArgs;

// Harvest parameters which map to the base type ctor.
if(auto baseStructRef = findBaseStructDeclRef(m_astBuilder, structDecl))
Expand Down Expand Up @@ -10321,12 +10321,12 @@ namespace Slang
{
for (auto i : ctorForPublic->getParameters())
{
publicCtorArgs.add(i->type);
publicCtorArgs.add(i);
}
for (auto i : ctorForInternal->getParameters())
{
publicInternalCtorArgs.add(i->type);
publicPrivateInternalCtorArgs.add(i->type);
publicInternalCtorArgs.add(i);
publicPrivateInternalCtorArgs.add(i);
}
}
}
Expand All @@ -10347,20 +10347,20 @@ namespace Slang
switch (declVisibility)
{
case DeclVisibility::Private:
publicPrivateInternalCtorArgs.add(varDeclType);
publicPrivateInternalCtorArgs.add(varDecl);
if(!varDecl->initExpr)
maxVisibilityToGenerateCtor = DeclVisibility::Private;
break;
case DeclVisibility::Internal:
publicPrivateInternalCtorArgs.add(varDeclType);
publicInternalCtorArgs.add(varDeclType);
publicPrivateInternalCtorArgs.add(varDecl);
publicInternalCtorArgs.add(varDecl);
if (!varDecl->initExpr)
maxVisibilityToGenerateCtor = DeclVisibility::Internal;
break;
case DeclVisibility::Public:
publicPrivateInternalCtorArgs.add(varDeclType);
publicInternalCtorArgs.add(varDeclType);
publicCtorArgs.add(varDeclType);
publicPrivateInternalCtorArgs.add(varDecl);
publicInternalCtorArgs.add(varDecl);
publicCtorArgs.add(varDecl);
break;
default:
// Unknown visibility
Expand Down
2 changes: 1 addition & 1 deletion source/slang/slang-diagnostic-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ DIAGNOSTIC(30400, Error, genericTypeNeedsArgs, "generic type '$0' used without a
DIAGNOSTIC(30401, Error, invalidTypeForConstraint, "type '$0' cannot be used as a constraint.")

// 305xx: initializer lists
DIAGNOSTIC(30500, Error, tooManyInitializers, "cannot find matching constructor to call with arguments count of '$0'")
DIAGNOSTIC(30500, Error, tooManyInitializers, "cannot find matching constructor to call with arguments count of '$0' for '$1'")
DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'")
DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'")
DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows")
Expand Down
4 changes: 3 additions & 1 deletion tests/autodiff/reverse-addr-eliminate.slang
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ A f(A a, int i)
[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
A a = {1.0, 2.0};
A a;
a.x = 1;
a.y = 2;

var dpa = diffPair(a);

Expand Down
2 changes: 1 addition & 1 deletion tests/bugs/gh-3601.slang
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void main(int id : SV_DispatchThreadID)
*pData1 = 3;
*(int2*)pData = int2(1, 2);
pData1[-1] = 2;
buffer[0].pNext[1] = {5};
buffer[0].pNext[1] = {5, 0};
// CHECK: OpConvertPtrToU
// CHECK: OpINotEqual
if (pData1)
Expand Down
15 changes: 15 additions & 0 deletions tests/compute/struct-default-init.slang
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ struct Test
int b = 1;
int c = 0;
int d = 1 + 1;
__init(int a_in)
{
a = a_in;
}
__init(int a_in, int b_in)
{
a = a_in;
b = b_in;
}
__init(int a_in, int b_in, int c_in)
{
a = a_in;
b = b_in;
c = c_in;
}
}

int test(int inVal)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//TEST:SIMPLE(filecheck=ERROR): -target hlsl -entry computeMain -stage compute

public struct Test
{
// note: we need an initExpr here for an error because else Slang will disallow
// synthisis of a 'public' constructor, meaning nothing has to fail.
internal uint a = 5;
public uint b;
};


//ERROR: error 30500

RWStructuredBuffer<uint> outputBuffer;

[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
Test test[3] = {1, 2, 3, 4, 5, 6};

outputBuffer[0] = true
&& test[0].a == 1
&& test[0].b == 2

&& test[1].a == 1
&& test[1].b == 2

&& test[2].a == 1
&& test[2].b == 2
;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//TEST:SIMPLE(filecheck=ERROR): -target hlsl -entry computeMain -stage compute

struct Test
{
uint a;
uint b;
__init(int a_in, int b_in)
{
a_in = 0;
b_in = 0;
}
};


//ERROR: error 30500

RWStructuredBuffer<uint> outputBuffer;

[numthreads(1, 1, 1)]
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
Test test[3] = {1, 2, 3, 4, 5, 6};

outputBuffer[0] = true
&& test[0].a == 1
&& test[0].b == 2

&& test[1].a == 1
&& test[1].b == 2

&& test[2].a == 1
&& test[2].b == 2
;
}
4 changes: 2 additions & 2 deletions tests/language-feature/zero-initialize/shared-memory.slang
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ RWStructuredBuffer<uint> outputBuffer;
// GLSL-NOT: error 30623
// HLSL-NOT: error 30623

// GLSL-NOT: {{.*}}={{.*}}0{{.}};
// HLSL-NOT: {{.*}}={{.*}}0{{.}};
// GLSL-NOT: globalMem{{.*}} =
// HLSL-NOT: globalMem{{.*}} =

groupshared uint globalMem;

Expand Down
2 changes: 1 addition & 1 deletion tests/metal/sv_target-complex-1.slang
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ struct Output
[shader("fragment")]
Output fragmentMain()
{
return { float4(1), {float4(2)}, float4(3) };
return { float4(1), { float4(2) }, float4(3), {} };
}
Loading

0 comments on commit 1e7819a

Please sign in to comment.