1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
// slang-ast-val.h
#pragma once
#include "slang-ast-base.h"
namespace Slang {
// Syntax class definitions for compile-time values.
// A compile-time integer (may not have a specific concrete value)
class IntVal : public Val
{
SLANG_ABSTRACT_AST_CLASS(IntVal)
};
// Trivial case of a value that is just a constant integer
class ConstantIntVal : public IntVal
{
SLANG_AST_CLASS(ConstantIntVal)
IntegerLiteralValue value;
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
protected:
ConstantIntVal(IntegerLiteralValue inValue)
: value(inValue)
{}
};
// The logical "value" of a reference to a generic value parameter
class GenericParamIntVal : public IntVal
{
SLANG_AST_CLASS(GenericParamIntVal)
DeclRef<VarDeclBase> declRef;
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
protected:
GenericParamIntVal(DeclRef<VarDeclBase> inDeclRef)
: declRef(inDeclRef)
{}
};
/// An unknown integer value indicating an erroneous sub-expression
class ErrorIntVal : public IntVal
{
SLANG_AST_CLASS(ErrorIntVal)
// TODO: We should probably eventually just have an `ErrorVal` here
// and have all `Val`s that represent ordinary values hold their
// `Type` so that we can have an `ErrorVal` of any type.
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
// A witness to the fact that some proposition is true, encoded
// at the level of the type system.
//
// Given a generic like:
//
// void example<L>(L light)
// where L : ILight
// { ... }
//
// a call to `example()` needs two things for us to be sure
// it is valid:
//
// 1. We need a type `X` to use as the argument for the
// parameter `L`. We might supply this explicitly, or
// via inference.
//
// 2. We need a *proof* that whatever `X` we chose conforms
// to the `ILight` interface.
//
// The easiest way to make such a proof is by construction,
// and a `Witness` represents such a constructive proof.
// Conceptually a proposition like `X : ILight` can be
// seen as a type, and witness prooving that proposition
// is a value of that type.
//
// We construct and store witnesses explicitly during
// semantic checking because they can help us with
// generating downstream code. By following the structure
// of a witness (the structure of a proof) we can, e.g.,
// navigate from the knowledge that `X : ILight` to
// the concrete declarations that provide the implementation
// of `ILight` for `X`.
//
class Witness : public Val
{
SLANG_ABSTRACT_AST_CLASS(Witness)
};
// A witness that one type is a subtype of another
// (where by "subtype" we include both inheritance
// relationships and type-conforms-to-interface relationships)
//
// TODO: we may need to tease those apart.
class SubtypeWitness : public Witness
{
SLANG_ABSTRACT_AST_CLASS(SubtypeWitness)
Type* sub = nullptr;
Type* sup = nullptr;
};
class TypeEqualityWitness : public SubtypeWitness
{
SLANG_AST_CLASS(TypeEqualityWitness)
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
// A witness that one type is a subtype of another
// because some in-scope declaration says so
class DeclaredSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(DeclaredSubtypeWitness)
DeclRef<Decl> declRef;
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
// A witness that `sub : sup` because `sub : mid` and `mid : sup`
class TransitiveSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(TransitiveSubtypeWitness)
// Witness that `sub : mid`
SubtypeWitness* subToMid = nullptr;
// Witness that `mid : sup`
SubtypeWitness* midToSup = nullptr;
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
// A witness taht `sub : sup` because `sub` was wrapped into
// an existential of type `sup`.
class ExtractExistentialSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(ExtractExistentialSubtypeWitness)
// The declaration of the existential value that has been opened
DeclRef<VarDeclBase> declRef;
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
// A witness that `sub : sup`, because `sub` is a tagged union
// of the form `A | B | C | ...` and each of `A : sup`,
// `B : sup`, `C : sup`, etc.
//
class TaggedUnionSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(TaggedUnionSubtypeWitness)
// Witnesses that each of the "case" types in the union
// is a subtype of `sup`.
//
List<Val*> caseWitnesses;
// Overrides should be public so base classes can access
bool _equalsValOverride(Val* val);
void _toTextOverride(StringBuilder& out);
HashCode _getHashCodeOverride();
Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff);
};
/// A witness of the fact that `ThisType(someInterface) : someInterface`
class ThisTypeSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(ThisTypeSubtypeWitness)
};
/// A witness of the fact that a user provided "__Dynamic" type argument is a
/// subtype to the existential type parameter.
class DynamicSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(DynamicSubtypeWitness)
};
/// A witness that `T : L & R` because `T : L` and `T : R`
class ConjunctionSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(ConjunctionSubtypeWitness)
/// Witness that `sub : sup->left`
Val* leftWitness;
/// Witness that `sub : sup->right`
Val* rightWitness;
};
/// A witness that `T : X` because `T : X & Y` or `T : Y & X`
class ExtractFromConjunctionSubtypeWitness : public SubtypeWitness
{
SLANG_AST_CLASS(ExtractFromConjunctionSubtypeWitness)
/// Witness that `T : L & R` for some `R`
Val* conunctionWitness;
/// The zero-based index of the super-type we care about in the conjunction
///
/// If `conunctionWitness` is `T : X & Y` then this index should be zero if
/// we want to represent `T : X` and one if we want `T : Y`.
///
int indexInConjunction;
};
} // namespace Slang
|