Skip to content

Commit 43950e2

Browse files
committedFeb 5, 2019
Fix checking of interface conformances for nested types
Before this change, code like the following would crash the compiler: ```hlsl interface IThing { /* ... */ } struct Outer { struct Inner : IThing {} } /* go on to use Outer.Inner */ ``` The problem was that the front-end logic for checking interface conformances was *only* checking declarations at the top level of a module, or nested under a generic. This change fixes the logic to recurse through the entire tree of declarations. I have added a test case that uses a nested `struct` type to satisfy an associated type requirement, to confirm that the new check works as intended.
1 parent 314795b commit 43950e2

File tree

3 files changed

+105
-12
lines changed

3 files changed

+105
-12
lines changed
 

‎source/slang/check.cpp

+40-12
Original file line numberDiff line numberDiff line change
@@ -2883,6 +2883,45 @@ namespace Slang
28832883
syntaxNode->modifiers.first = resultModifiers;
28842884
}
28852885

2886+
/// Perform checking of interface conformaces for this decl and all its children
2887+
void checkInterfaceConformancesRec(Decl* decl)
2888+
{
2889+
// Any user-defined type may have declared interface conformances,
2890+
// which we should check.
2891+
//
2892+
if( auto aggTypeDecl = as<AggTypeDecl>(decl) )
2893+
{
2894+
checkAggTypeConformance(aggTypeDecl);
2895+
}
2896+
// Conformances can also come via `extension` declarations, and
2897+
// we should check them against the type(s) being extended.
2898+
//
2899+
else if(auto extensionDecl = as<ExtensionDecl>(decl))
2900+
{
2901+
checkExtensionConformance(extensionDecl);
2902+
}
2903+
2904+
// We need to handle the recursive cases here, the first
2905+
// of which is a generic decl, where we want to recurivsely
2906+
// check the inner declaration.
2907+
//
2908+
if(auto genericDecl = as<GenericDecl>(decl))
2909+
{
2910+
checkInterfaceConformancesRec(genericDecl->inner);
2911+
}
2912+
// For any other kind of container declaration, we will
2913+
// recurse into all of its member declarations, so that
2914+
// we can handle, e.g., nested `struct` types.
2915+
//
2916+
else if(auto containerDecl = as<ContainerDecl>(decl))
2917+
{
2918+
for(auto member : containerDecl->Members)
2919+
{
2920+
checkInterfaceConformancesRec(member);
2921+
}
2922+
}
2923+
}
2924+
28862925
void visitModuleDecl(ModuleDecl* programNode)
28872926
{
28882927
// Try to register all the builtin decls
@@ -2988,18 +3027,7 @@ namespace Slang
29883027

29893028
if (pass == 0)
29903029
{
2991-
// now we can check all interface conformances
2992-
for (auto & s : programNode->getMembersOfType<AggTypeDecl>())
2993-
checkAggTypeConformance(s);
2994-
for (auto & s : programNode->getMembersOfType<ExtensionDecl>())
2995-
checkExtensionConformance(s);
2996-
for (auto & g : programNode->getMembersOfType<GenericDecl>())
2997-
{
2998-
if (auto innerAggDecl = as<AggTypeDecl>(g->inner))
2999-
checkAggTypeConformance(innerAggDecl);
3000-
else if (auto innerExtDecl = as<ExtensionDecl>(g->inner))
3001-
checkExtensionConformance(innerExtDecl);
3002-
}
3030+
checkInterfaceConformancesRec(programNode);
30033031
}
30043032
}
30053033
}

‎tests/compute/assoctype-nested.slang

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// assoctype-nested.slang
2+
3+
// Confirm that an associated type can be declared nested in its parent.
4+
5+
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
6+
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
7+
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
8+
9+
interface IRandomGenerator
10+
{
11+
[mutating] int generateVal();
12+
}
13+
14+
interface IRandomStrategy
15+
{
16+
associatedtype Generator : IRandomGenerator;
17+
Generator makeGenerator(int seed);
18+
}
19+
20+
int helper<T:IRandomStrategy>(T strategy, int seed)
21+
{
22+
var generator = strategy.makeGenerator(seed);
23+
let val = generator.generateVal();
24+
return val;
25+
}
26+
27+
struct CounterStrategy : IRandomStrategy
28+
{
29+
struct Generator : IRandomGenerator
30+
{
31+
int state;
32+
[mutating] int generateVal()
33+
{
34+
return state++;
35+
}
36+
}
37+
38+
Generator makeGenerator(int seed)
39+
{
40+
Generator generator = { seed };
41+
return generator;
42+
}
43+
}
44+
45+
int test(int val)
46+
{
47+
CounterStrategy strategy;
48+
return helper(strategy, val);
49+
}
50+
51+
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
52+
RWStructuredBuffer<int> gOutputBuffer;
53+
54+
[numthreads(4, 1, 1)]
55+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
56+
{
57+
uint tid = dispatchThreadID.x;
58+
int inputVal = tid;
59+
int outputVal = test(inputVal);
60+
gOutputBuffer[tid] = outputVal;
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
0
2+
1
3+
2
4+
3

0 commit comments

Comments
 (0)