Skip to content

Commit 6924239

Browse files
authored
Merge pull request shader-slang#330 from tfoleyNV/implicit-generic-app
Support generic type constraints when implicitly invoking generic
2 parents d1c3852 + fd0b8ca commit 6924239

File tree

4 files changed

+113
-8
lines changed

4 files changed

+113
-8
lines changed

source/slang/ast-legalize.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2623,6 +2623,9 @@ struct LoweringVisitor
26232623
if (auto litVal = dynamic_cast<ConstantIntVal*>(val))
26242624
return val;
26252625

2626+
// We do not use subtype witness for ast lowering, return it unchanged.
2627+
if (auto subtypeWitnessVal = dynamic_cast<SubtypeWitness*>(val))
2628+
return val;
26262629
SLANG_UNEXPECTED("unhandled value kind");
26272630
}
26282631

source/slang/check.cpp

+66-8
Original file line numberDiff line numberDiff line change
@@ -4009,7 +4009,21 @@ namespace Slang
40094009
{
40104010
// For now the "solver" is going to be ridiculously simplistic.
40114011

4012-
// The generic itself will have some constraints, so we need to try and solve those too
4012+
// The generic itself will have some constraints, and for now we add these
4013+
// to the system of constrains we will use for solving for the type variables.
4014+
//
4015+
// TODO: we need to decide whether constraints are used like this to influence
4016+
// how we solve for type/value variables, or whether constraints in the parameter
4017+
// list just work as a validation step *after* we've solved for the types.
4018+
//
4019+
// That is, should we allow `<T : Int>` to be written, and cause us to "infer"
4020+
// that `T` should be the type `Int`? That seems a little silly.
4021+
//
4022+
// Eventually, though, we may want to support type identity constraints, especially
4023+
// on associated types, like `<C where C : IContainer && C.IndexType == Int>`
4024+
// These seem more reasonable to have influence constraint solving, since it could
4025+
// conceivably let us specialize a `X<T> : IContainer` to `X<Int>` if we find
4026+
// that `X<T>.IndexType == T`.
40134027
for( auto constraintDeclRef : getMembersOfType<GenericTypeConstraintDecl>(genericDeclRef) )
40144028
{
40154029
if(!TryUnifyTypes(*system, GetSub(constraintDeclRef), GetSup(constraintDeclRef)))
@@ -4101,6 +4115,57 @@ namespace Slang
41014115
}
41024116
}
41034117

4118+
// After we've solved for the explicit arguments, we need to
4119+
// make a second pass and consider the implicit arguments,
4120+
// based on what we've already determined to be the values
4121+
// for the explicit arguments.
4122+
4123+
// Before we begin, we are going to go ahead and create the
4124+
// "solved" substitution that we will return if everything works.
4125+
// This is because we are going to use this substitution,
4126+
// partially filled in with the results we know so far,
4127+
// in order to specialize any constraints on the generic.
4128+
//
4129+
// E.g., if the generic parameters were `<T : ISidekick>`, and
4130+
// we've already decided that `T` is `Robin`, then we want to
4131+
// search for a conformance `Robin : ISidekick`, which involved
4132+
// apply the substitutions we already know...
4133+
4134+
RefPtr<GenericSubstitution> solvedSubst = new GenericSubstitution();
4135+
solvedSubst->genericDecl = genericDeclRef.getDecl();
4136+
solvedSubst->outer = genericDeclRef.substitutions;
4137+
solvedSubst->args = args;
4138+
4139+
for( auto constraintDecl : genericDeclRef.getDecl()->getMembersOfType<GenericTypeConstraintDecl>() )
4140+
{
4141+
DeclRef<GenericTypeConstraintDecl> constraintDeclRef(
4142+
constraintDecl,
4143+
solvedSubst);
4144+
4145+
// Extract the (substituted) sub- and super-type from the constraint.
4146+
auto sub = GetSub(constraintDeclRef);
4147+
auto sup = GetSup(constraintDeclRef);
4148+
4149+
// Search for a witness that shows the constraint is satisfied.
4150+
auto subTypeWitness = tryGetSubtypeWitness(sub, sup);
4151+
if(subTypeWitness)
4152+
{
4153+
// We found a witness, so it will become an (implicit) argument.
4154+
solvedSubst->args.Add(subTypeWitness);
4155+
}
4156+
else
4157+
{
4158+
// No witness was found, so the inference will now fail.
4159+
//
4160+
// TODO: Ideally we should print an error message in
4161+
// this case, to let the user know why things failed.
4162+
return nullptr;
4163+
}
4164+
4165+
// TODO: We may need to mark some constrains in our constraint
4166+
// system as being solved now, as a result of the witness we found.
4167+
}
4168+
41044169
// Make sure we haven't constructed any spurious constraints
41054170
// that we aren't able to satisfy:
41064171
for (auto c : system->constraints)
@@ -4111,13 +4176,6 @@ namespace Slang
41114176
}
41124177
}
41134178

4114-
// Consruct a reference to the extension with our constraint variables
4115-
// as the
4116-
RefPtr<GenericSubstitution> solvedSubst = new GenericSubstitution();
4117-
solvedSubst->genericDecl = genericDeclRef.getDecl();
4118-
solvedSubst->outer = genericDeclRef.substitutions;
4119-
solvedSubst->args = args;
4120-
41214179
return solvedSubst;
41224180
}
41234181

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir
2+
3+
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
4+
5+
// Testing that we can implicitly specialize a generic
6+
// that has a constrained type parameter.
7+
8+
9+
interface ISimple
10+
{
11+
int getVal();
12+
}
13+
14+
struct Simple : ISimple
15+
{
16+
int val;
17+
18+
int getVal() { return val; }
19+
};
20+
21+
int doIt<T : ISimple>(T obj)
22+
{
23+
return obj.getVal();
24+
}
25+
26+
int test(int val)
27+
{
28+
Simple simple;
29+
simple.val = val;
30+
return doIt(simple);
31+
}
32+
33+
RWStructuredBuffer<int> outputBuffer : register(u0);
34+
[numthreads(4, 1, 1)]
35+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
36+
{
37+
int tid = (int) dispatchThreadID.x;
38+
int outVal = test(tid);
39+
outputBuffer[tid] = outVal;
40+
}
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)