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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
|
// slang-decl-defs.h
#pragma once
#include "slang-ast-base.h"
#include "slang-fossil.h"
//
#include "slang-ast-decl.h.fiddle"
FIDDLE()
namespace Slang
{
// Syntax class definitions for declarations.
// A group of declarations that should be treated as a unit
FIDDLE()
class DeclGroup : public DeclBase
{
FIDDLE(...)
FIDDLE() List<Decl*> decls;
};
FIDDLE()
class UnresolvedDecl : public Decl
{
FIDDLE(...)
};
/// Holds the direct member declarations of a `ContainerDecl`.
///
/// This type is used to encapsulate the logic the creating
/// and maintaing the acceleration structures used for member
/// lookup.
///
struct ContainerDeclDirectMemberDecls
{
public:
List<Decl*> const& getDecls() const;
Count getDeclCount() const;
Decl* getDecl(Index index) const;
Decl* findLastDeclOfName(Name* name) const;
Dictionary<Name*, Decl*> getMapFromNameToLastDeclOfThatName() const;
List<Decl*> const& getTransparentDecls() const;
bool isUsingOnDemandDeserialization() const;
void _initForOnDemandDeserialization(
RefObject* deserializationContext,
void const* deserializationData,
Count declCount);
private:
friend class ContainerDecl;
friend class ModuleDecl;
friend struct ASTDumpContext;
bool _areLookupAcceleratorsValid() const;
void _invalidateLookupAccelerators() const;
void _ensureLookupAcceleratorsAreValid() const;
void _readSerializedTransparentDecls() const;
Decl* _readSerializedDeclAtIndex(Index index) const;
Decl* _readSerializedDeclsOfName(Name* name) const;
void _readAllSerializedDecls() const;
mutable List<Decl*> decls;
mutable struct
{
Count declCountWhenLastUpdated = 0;
Dictionary<Name*, Decl*> mapNameToLastDeclOfThatName;
List<Decl*> filteredListOfTransparentDecls;
} accelerators;
mutable struct
{
RefPtr<RefObject> context;
void const* data = nullptr;
} onDemandDeserialization;
};
/// A conceptual list of declarations of the same name, in the same container.
struct DeclsOfNameList
{
public:
DeclsOfNameList() {}
explicit DeclsOfNameList(Decl* decl)
: _lastDecl(decl)
{
}
struct Iterator
{
public:
Iterator() {}
Iterator(Decl* decl)
: _decl(decl)
{
}
Decl* operator*() const { return _decl; }
Iterator& operator++()
{
SLANG_ASSERT(_decl);
_decl = _decl->_prevInContainerWithSameName;
return *this;
}
bool operator!=(const Iterator& other) const { return _decl != other._decl; }
private:
Decl* _decl = nullptr;
};
Iterator begin() const { return _lastDecl; }
Iterator end() const { return nullptr; }
private:
Decl* _lastDecl = nullptr;
};
// A "container" decl is a parent to other declarations
FIDDLE(abstract)
class ContainerDecl : public Decl
{
FIDDLE(...)
SourceLoc closingSourceLoc;
// The associated scope owned by this decl.
Scope* ownedScope = nullptr;
/// Get all of the direct member declarations inside this container decl.
///
List<Decl*> const& getDirectMemberDecls();
/// Get the number of direct member declarations inside this container decl.
///
Count getDirectMemberDeclCount();
/// Get the direct member declaration of this container decl at the given `index`.
///
Decl* getDirectMemberDecl(Index index);
/// Get the first direct member declaration inside of this container decl, if any.
///
/// If the container has no direct member declarations, returns null.
///
Decl* getFirstDirectMemberDecl();
/// Get all of the direct member declarations inside of this container decl
/// that are instances of the specified AST node type `T`.
///
template<typename T>
FilteredMemberList<T> getDirectMemberDeclsOfType()
{
return FilteredMemberList<T>(getDirectMemberDecls());
}
/// Find the first direct member declaration of this container decl that
/// is an instance of the specified AST node type `T`.
///
/// If there are no direct member declrations of type `T`, then returns null.
/// Otherwise, returns the first matching member, in declaration order.
///
template<typename T>
T* findFirstDirectMemberDeclOfType()
{
auto count = getDirectMemberDeclCount();
for (Index i = 0; i < count; ++i)
{
auto decl = getDirectMemberDecl(i);
if (auto found = as<T>(decl))
return found;
}
return nullptr;
}
/// Find all direct member declarations of this container decl that have the given name.
///
DeclsOfNameList getDirectMemberDeclsOfName(Name* name);
/// Find the last direct member declaration of this container decl that has the given name.
///
Decl* findLastDirectMemberDeclOfName(Name* name);
/// Get the previous direct member declaration that has the same name as `decl`.
///
Decl* getPrevDirectMemberDeclWithSameName(Decl* decl);
/// Append the given `decl` to the direct member declarations of this container decl.
///
void addDirectMemberDecl(Decl* decl);
/// Get the subset of direct member declarations that are "transparent."
///
/// Transparent members will themselves be considered when performing
/// looking on the parent. E.g., if `a` has a transparent member `b`,
/// then a lookup like `a.x` will also consider `a.b.x` as a possible
/// result.
///
List<Decl*> const& getTransparentDirectMemberDecls();
// Note: Just an alias for `getDirectMemberDecls()`,
// but left in place because of just how many call sites were
// already using this name.
//
List<Decl*> const& getMembers() { return getDirectMemberDecls(); }
// Note: Just an alias for `getDirectMemberDeclsOfType()`,
// but left in place because of just how many call sites were
// already using this name.
//
template<typename T>
FilteredMemberList<T> getMembersOfType()
{
return getDirectMemberDeclsOfType<T>();
}
// Note: Just an alias for `addDirectMemberDecl()`,
// but left in place because of just how many call sites were
// already using this name.
//
void addMember(Decl* member) { addDirectMemberDecl(member); }
/// Is this declaration using on-demand deserialization for its direct members?
///
bool isUsingOnDemandDeserializationForDirectMembers();
//
// NOTE: The operations after this point are *not* considered part of
// the public API of `ContainerDecl`, and new code should not be
// written that uses them.
//
// They are being left in place because the existing code that uses
// them would be difficult or impossible to refactor to use the public
// API, but such parts of the codebase should *not* be considered as
// examples of how to interact with the Slang AST.
//
/// Remove a constructor declaration from the direct member declarations of this container.
///
/// This operation is seemingly used when a default constructor declaration has been synthesized
/// for a type, but that type already contained a default constructor of its own.
///
/// TODO: Somebody should investigate why this operation is even needed; it seems like an
/// indication that we are doing something Deeply Wrong in the way that default constructors are
/// being handled and synthesized (on top of the things that we know are Wrong By Design).
///
void _removeDirectMemberConstructorDeclBecauseSynthesizedAnotherDefaultConstructorInstead(
ConstructorDecl* decl);
/// Replace the given `oldVarDecl` with the given `newPropertyDecl` in the direct member
/// declarations of this container decl, because the variable declaration had a bit-field
/// specification on it, and the property was synthesized to stand in for that variable
/// by providing a getter/settter pair.
///
/// This operation cannot be expressed in terms of the rest of the public API, because there
/// is currently no other example of parsing a declaration as one AST node class, and
/// then determining as part of semantic checking that it should *actually* be represented
/// as a different class of declaration entirely.
///
/// TODO: In the long run we would either eliminate support for C-style bit-field specifications
/// on what would otherwise be an ordinary member variable declaration. Some other syntax, or
/// a type-based solution, should be introduced to server the same use cases, without requiring
/// us to parse something as a variable that is semantically *not* a variable in almost any
/// of the ways that count.
///
void _replaceDirectMemberBitFieldVariableDeclAtIndexWithPropertyDeclThatWasSynthesizedForIt(
Index index,
VarDecl* oldVarDecl,
PropertyDecl* newPropertyDecl);
/// Insert `backingVarDecl` into this container declaration at `index`, to handle the case
/// where the backing variable has been synthesized to store the bits of one or more bitfield
/// properties.
///
/// This operation cannot be expressed in terms of the rest of the public API because the usual
/// assumption is that member declarations may be added to a declaration but that, once added,
/// their indices in the member list are consistent and stable.
///
/// The reason the code that calls this operation can't just add `backingVarDecl` to the end of
/// the declaration is that there is an underlying assumption made by users that any
/// non-bitfield members before/after a bitfield declaration will have their storage laid out
/// before/after the storage for that bitfield.
///
/// TODO: A simple cleanup would be to *not* guarantee the order of storage layout for bitfield
/// members relative to other member variables, but the real long-term fix is to have an
/// alternative means for users to define bitfields that does not inherit the C-like syntax, and
/// that can make the storage that is introduced clear at parse time, so that the relevant
/// declaration(s) can already be in the correct order.
///
void _insertDirectMemberDeclAtIndexForBitfieldPropertyBackingMember(
Index index,
VarDecl* backingVarDecl);
// TODO: The following should be a private member, but currently
// we have auto-generated code for things like dumping and serialization
// that expect to have access to it.
//
FIDDLE() ContainerDeclDirectMemberDecls _directMemberDecls;
private:
bool _areLookupAcceleratorsValid();
void _invalidateLookupAccelerators();
void _ensureLookupAcceleratorsAreValid();
};
// Base class for all variable declarations
FIDDLE(abstract)
class VarDeclBase : public Decl
{
FIDDLE(...)
// type of the variable
FIDDLE() TypeExp type;
Type* getType() { return type.type; }
// Initializer expression (optional)
FIDDLE() Expr* initExpr = nullptr;
// Folded IntVal if the initializer is a constant integer.
FIDDLE() IntVal* val = nullptr;
};
// Ordinary potentially-mutable variables (locals, globals, and member variables)
FIDDLE()
class VarDecl : public VarDeclBase
{
FIDDLE(...)
};
// A variable declaration that is always immutable (whether local, global, or member variable)
FIDDLE()
class LetDecl : public VarDecl
{
FIDDLE(...)
};
// An `AggTypeDeclBase` captures the shared functionality
// between true aggregate type declarations and extension
// declarations:
//
// - Both can contain members (they are `ContainerDecl`s)
// - Both can have declared bases
// - Both expose a `this` variable in their body
//
FIDDLE(abstract)
class AggTypeDeclBase : public ContainerDecl
{
FIDDLE(...)
};
// An extension to apply to an existing type
FIDDLE()
class ExtensionDecl : public AggTypeDeclBase
{
FIDDLE(...)
FIDDLE() TypeExp targetType;
};
enum class TypeTag
{
None = 0,
Unsized = 1,
Incomplete = 2,
LinkTimeSized = 4,
Opaque = 8,
NonAddressable = 16,
};
// Declaration of a type that represents some sort of aggregate
FIDDLE(abstract)
class AggTypeDecl : public AggTypeDeclBase
{
FIDDLE(...)
FIDDLE() TypeTag typeTags = TypeTag::None;
// When user defines an agg type in the syntax of
// `struct FooAlias : IFoo = Foo;`
// The user is defining a link-time type alias. In contrast
// to an ordinary typealias, a link-time alias is not folded in
// the front-end, and resolved during linking.
// `aliasedType` is used to store the alised type (in this case `Foo`)
// when the agg type decl is declared in the link-time alias syntax.
//
TypeExp aliasedType;
bool hasBody = true;
void unionTagsWith(TypeTag other);
void addTag(TypeTag tag);
bool hasTag(TypeTag tag);
FilteredMemberList<VarDecl> getFields() { return getMembersOfType<VarDecl>(); }
};
FIDDLE()
class StructDecl : public AggTypeDecl
{
FIDDLE(...)
// We will use these auxiliary to help in synthesizing the member initialize constructor.
Slang::HashSet<VarDeclBase*> m_membersVisibleInCtor;
};
FIDDLE()
class ClassDecl : public AggTypeDecl
{
FIDDLE(...)
};
FIDDLE()
class GLSLInterfaceBlockDecl : public AggTypeDecl
{
FIDDLE(...)
};
// TODO: Is it appropriate to treat an `enum` as an aggregate type?
// Most code that looks for, e.g., conformances assumes user-defined
// types are all `AggTypeDecl`, so this is the right choice for now
// if we want `enum` types to be able to implement interfaces, etc.
//
FIDDLE()
class EnumDecl : public AggTypeDecl
{
FIDDLE(...)
FIDDLE() Type* tagType = nullptr;
};
// A single case in an enum.
//
// E.g., in a declaration like:
//
// enum Color { Red = 0, Green, Blue };
//
// The `Red = 0` is the declaration of the `Red`
// case, with `0` as an explicit expression for its
// _tag value_.
//
FIDDLE()
class EnumCaseDecl : public Decl
{
FIDDLE(...)
// type of the parent `enum`
FIDDLE() TypeExp type;
Type* getType() { return type.type; }
// Tag value
FIDDLE() Expr* tagExpr = nullptr;
FIDDLE() IntVal* tagVal = nullptr;
};
// A member of InterfaceDecl representing the abstract ThisType.
FIDDLE()
class ThisTypeDecl : public AggTypeDecl
{
FIDDLE(...)
};
// An interface which other types can conform to
FIDDLE()
class InterfaceDecl : public AggTypeDecl
{
FIDDLE(...)
ThisTypeDecl* getThisTypeDecl();
};
FIDDLE(abstract)
class TypeConstraintDecl : public Decl
{
FIDDLE(...)
const TypeExp& getSup() const;
// Overrides should be public so base classes can access
// Implement _getSupOverride on derived classes to change behavior of getSup, as if getSup is
// virtual
const TypeExp& _getSupOverride() const;
};
FIDDLE()
class ThisTypeConstraintDecl : public TypeConstraintDecl
{
FIDDLE(...)
FIDDLE() TypeExp base;
const TypeExp& _getSupOverride() const { return base; }
InterfaceDecl* getInterfaceDecl();
};
// A kind of pseudo-member that represents an explicit
// or implicit inheritance relationship.
//
FIDDLE()
class InheritanceDecl : public TypeConstraintDecl
{
FIDDLE(...)
// The type expression as written
FIDDLE() TypeExp base;
// After checking, this dictionary will map members
// required by the base type to their concrete
// implementations in the type that contains
// this inheritance declaration.
FIDDLE() RefPtr<WitnessTable> witnessTable;
// If the inheritance decl is in a link-time type declaration
// (e.g. `export struct Foo : IFoo = FooImpl;`), then we will
// store the witness that `FooImpl:IFoo` here.
// TODO: If we made `WitnessTable` a `Val`, we should be able
// to unify these two cases.
FIDDLE() Witness* witnessVal = nullptr;
// Overrides should be public so base classes can access
const TypeExp& _getSupOverride() const { return base; }
};
// TODO: may eventually need sub-classes for explicit/direct vs. implicit/indirect inheritance
// A declaration that represents a simple (non-aggregate) type
//
// TODO: probably all types will be aggregate decls eventually,
// so that we can easily store conformances/constraints on type variables
FIDDLE(abstract)
class SimpleTypeDecl : public Decl
{
FIDDLE(...)
};
// A `typedef` declaration
FIDDLE()
class TypeDefDecl : public SimpleTypeDecl
{
FIDDLE(...)
FIDDLE() TypeExp type;
};
FIDDLE()
class TypeAliasDecl : public TypeDefDecl
{
FIDDLE(...)
};
// An 'assoctype' declaration, it is a container of inheritance clauses
FIDDLE()
class AssocTypeDecl : public AggTypeDecl
{
FIDDLE(...)
};
// A 'type_param' declaration, which defines a generic
// entry-point parameter. Is a container of GenericTypeConstraintDecl
FIDDLE()
class GlobalGenericParamDecl : public AggTypeDecl
{
FIDDLE(...)
};
// A `__generic_value_param` declaration, which defines an existential
// value parameter (not a type parameter.
FIDDLE()
class GlobalGenericValueParamDecl : public VarDeclBase
{
FIDDLE(...)
};
// A scope for local declarations (e.g., as part of a statement)
FIDDLE()
class ScopeDecl : public ContainerDecl
{
FIDDLE(...)
};
// A function/initializer/subscript parameter (potentially mutable)
FIDDLE()
class ParamDecl : public VarDeclBase
{
FIDDLE(...)
};
// A parameter of a function declared in "modern" types (immutable unless explicitly `out` or
// `inout`)
FIDDLE()
class ModernParamDecl : public ParamDecl
{
FIDDLE(...)
};
// Base class for things that have parameter lists and can thus be applied to arguments ("called")
FIDDLE(abstract)
class CallableDecl : public ContainerDecl
{
FIDDLE(...)
FilteredMemberList<ParamDecl> getParameters() { return getMembersOfType<ParamDecl>(); }
FIDDLE() TypeExp returnType;
// If this callable throws an error code, `errorType` is the type of the error code.
FIDDLE() TypeExp errorType;
// Fields related to redeclaration, so that we
// can support multiple specialized variations
// of the "same" logical function.
//
// This should also help us to support redeclaration
// of functions when handling HLSL/GLSL.
// The "primary" declaration of the function, which will
// be used whenever we need to unique things.
FIDDLE() CallableDecl* primaryDecl = nullptr;
// The next declaration of the "same" function (that is,
// with the same `primaryDecl`).
FIDDLE() CallableDecl* nextDecl = nullptr;
};
// Base class for callable things that may also have a body that is evaluated to produce their
// result
FIDDLE(abstract)
class FunctionDeclBase : public CallableDecl
{
FIDDLE(...)
Stmt* body = nullptr;
};
// A constructor/initializer to create instances of a type
FIDDLE()
class ConstructorDecl : public FunctionDeclBase
{
FIDDLE(...)
enum class ConstructorFlavor : int
{
UserDefined = 0x00,
// Indicates whether the declaration was synthesized by
// Slang and not explicitly provided by the user
SynthesizedDefault = 0x01,
// Member initialize constructor is a synthesized ctor,
// but it takes parameters.
SynthesizedMemberInit = 0x02
};
FIDDLE() int m_flavor = (int)ConstructorFlavor::UserDefined;
void addFlavor(ConstructorFlavor flavor) { m_flavor |= (int)flavor; }
bool containsFlavor(ConstructorFlavor flavor) { return m_flavor & (int)flavor; }
};
FIDDLE()
class LambdaDecl : public StructDecl
{
FIDDLE(...)
FIDDLE() FunctionDeclBase* funcDecl;
};
// A subscript operation used to index instances of a type
FIDDLE()
class SubscriptDecl : public CallableDecl
{
FIDDLE(...)
};
/// A property declaration that abstracts over storage with a getter/setter/etc.
FIDDLE()
class PropertyDecl : public ContainerDecl
{
FIDDLE(...)
FIDDLE() TypeExp type;
};
// An "accessor" for a subscript or property
FIDDLE(abstract)
class AccessorDecl : public FunctionDeclBase
{
FIDDLE(...)
};
FIDDLE()
class GetterDecl : public AccessorDecl
{
FIDDLE(...)
};
FIDDLE()
class SetterDecl : public AccessorDecl
{
FIDDLE(...)
};
FIDDLE()
class RefAccessorDecl : public AccessorDecl
{
FIDDLE(...)
};
FIDDLE()
class FuncDecl : public FunctionDeclBase
{
FIDDLE(...)
};
FIDDLE(abstract)
class NamespaceDeclBase : public ContainerDecl
{
FIDDLE(...)
};
// A `namespace` declaration inside some module, that provides
// a named scope for declarations inside it.
//
// Note: Multiple `namespace` declarations with the same name
// in a given module/file will be collapsed into a single
// `NamespaceDecl` during parsing, so this declaration does
// not directly represent what is present in the input syntax.
//
FIDDLE()
class NamespaceDecl : public NamespaceDeclBase
{
FIDDLE(...)
};
// A "module" of code (essentially, a single translation unit)
// that provides a scope for some number of declarations.
FIDDLE()
class ModuleDecl : public NamespaceDeclBase
{
FIDDLE(...)
// The API-level module that this declaration belong to.
//
// This field allows lookup of the `Module` based on a
// declaration nested under a `ModuleDecl` by following
// its chain of parents.
//
Module* module = nullptr;
/// Map a decl to the list of its associated decls.
///
/// This mapping is filled in during semantic checking, as the decl declarations get checked or
/// generated.
///
FIDDLE() OrderedDictionary<Decl*, RefPtr<DeclAssociationList>> mapDeclToAssociatedDecls;
/// Whether Slang language version the module is defined in.
/// The legacy Slang language (2025) does not have visibility modifiers and everything is
/// treated as `public`. Newer version of the language introduces visibility and makes
/// `internal` as the default. To prevent this from breaking existing code, we need to know
/// whether a module is written in the legacy language. We detect this by checking whether the
/// module has any visibility modifiers, or if the module uses new language constructs, e.g.
/// `module`, `__include`, `__implementing` etc.
FIDDLE() SlangLanguageVersion languageVersion = SLANG_LANGAUGE_VERSION_DEFAULT;
FIDDLE() DeclVisibility defaultVisibility = DeclVisibility::Internal;
/// Map a type to the list of extensions of that type (if any) declared in this module
///
/// This mapping is filled in during semantic checking, as `ExtensionDecl`s get checked.
///
FIDDLE() Dictionary<AggTypeDecl*, RefPtr<CandidateExtensionList>> mapTypeToCandidateExtensions;
/// Is this module using on-demand deserialization for its exports?
///
bool isUsingOnDemandDeserializationForExports();
/// Find a declaration exported from this module by its `mangledName`.
///
Decl* _findSerializedDeclByMangledExportName(UnownedStringSlice const& mangledName);
};
// Represents a transparent scope of declarations that are defined in a single source file.
FIDDLE()
class FileDecl : public ContainerDecl
{
FIDDLE(...)
};
/// A declaration that brings members of another declaration or namespace into scope
FIDDLE()
class UsingDecl : public Decl
{
FIDDLE(...)
/// An expression that identifies the entity (e.g., a namespace) to be brought into `scope`
Expr* arg = nullptr;
/// The scope that the entity named by `arg` will be brought into
Scope* scope = nullptr;
};
FIDDLE()
class FileReferenceDeclBase : public Decl
{
FIDDLE(...)
// The name of the module we are trying to import
NameLoc moduleNameAndLoc;
SourceLoc startLoc;
SourceLoc endLoc;
// The scope that we want to import into
Scope* scope = nullptr;
};
FIDDLE()
class ImportDecl : public FileReferenceDeclBase
{
FIDDLE(...)
// The module that actually got imported
FIDDLE() ModuleDecl* importedModuleDecl = nullptr;
};
FIDDLE(abstract)
class IncludeDeclBase : public FileReferenceDeclBase
{
FIDDLE(...)
FileDecl* fileDecl = nullptr;
};
FIDDLE()
class IncludeDecl : public IncludeDeclBase
{
FIDDLE(...)
};
FIDDLE()
class ImplementingDecl : public IncludeDeclBase
{
FIDDLE(...)
};
FIDDLE()
class ModuleDeclarationDecl : public Decl
{
FIDDLE(...)
};
FIDDLE()
class RequireCapabilityDecl : public Decl
{
FIDDLE(...)
};
// A generic declaration, parameterized on types/values
FIDDLE()
class GenericDecl : public ContainerDecl
{
FIDDLE(...)
// The decl that is genericized...
FIDDLE() Decl* inner = nullptr;
/// A cached list of arguments that can be used when forming
/// a reference to the inner declaration with "default
/// substitutions" (for each generic parameter, the coresponding
/// argument will be a reference to the parameter itself).
///
List<Val*> _cachedArgsForDefaultSubstitution;
};
FIDDLE()
class InterfaceDefaultImplDecl : public GenericDecl
{
FIDDLE(...)
FIDDLE() GenericTypeParamDecl* thisTypeDecl;
FIDDLE() GenericTypeConstraintDecl* thisTypeConstraintDecl;
};
FIDDLE(abstract)
class GenericTypeParamDeclBase : public SimpleTypeDecl
{
FIDDLE(...)
// The index of the generic parameter.
int parameterIndex = -1;
};
FIDDLE()
class GenericTypeParamDecl : public GenericTypeParamDeclBase
{
FIDDLE(...)
// The bound for the type parameter represents a trait that any
// type used as this parameter must conform to
// TypeExp bound;
// The "initializer" for the parameter represents a default value
FIDDLE() TypeExp initType;
};
FIDDLE()
class GenericTypePackParamDecl : public GenericTypeParamDeclBase
{
FIDDLE(...)
};
// A constraint placed as part of a generic declaration
FIDDLE()
class GenericTypeConstraintDecl : public TypeConstraintDecl
{
FIDDLE(...)
// A type constraint like `T : U` is constraining `T` to be "below" `U`
// on a lattice of types. This may not be a subtyping relationship
// per se, but it makes sense to use that terminology here, so we
// think of these fields as the sub-type and super-type, respectively.
FIDDLE() TypeExp sub;
FIDDLE() TypeExp sup;
// If this decl is defined in a where clause, store the source location of the where token.
SourceLoc whereTokenLoc = SourceLoc();
FIDDLE() bool isEqualityConstraint = false;
// Overrides should be public so base classes can access
const TypeExp& _getSupOverride() const { return sup; }
};
FIDDLE()
class TypeCoercionConstraintDecl : public Decl
{
FIDDLE(...)
SourceLoc whereTokenLoc = SourceLoc();
FIDDLE() TypeExp fromType;
FIDDLE() TypeExp toType;
};
FIDDLE()
class GenericValueParamDecl : public VarDeclBase
{
FIDDLE(...)
// The index of the generic parameter.
int parameterIndex = 0;
};
// An empty declaration (which might still have modifiers attached).
//
// An empty declaration is uncommon in HLSL, but
// in GLSL it is often used at the global scope
// to declare metadata that logically belongs
// to the entry point, e.g.:
//
// layout(local_size_x = 16) in;
//
FIDDLE()
class EmptyDecl : public Decl
{
FIDDLE(...)
};
// A declaration used by the implementation to put syntax keywords
// into the current scope.
//
FIDDLE()
class SyntaxDecl : public Decl
{
FIDDLE(...)
// What type of syntax node will be produced when parsing with this keyword?
FIDDLE()
SyntaxClass<NodeBase> syntaxClass;
// Callback to invoke in order to parse syntax with this keyword.
SyntaxParseCallback parseCallback = nullptr;
void* parseUserData = nullptr;
};
// A declaration of an attribute to be used with `[name(...)]` syntax.
//
FIDDLE()
class AttributeDecl : public ContainerDecl
{
FIDDLE(...)
// What type of syntax node will be produced to represent this attribute.
FIDDLE() SyntaxClass<NodeBase> syntaxClass;
};
// A synthesized decl used as a placeholder for a differentiable function requirement. This decl
// will be a child of interface decl. This allows us to form an interface requirement key for the
// derivative of an interface function. The synthesized `DerivativeRequirementDecl` will be a child
// of the original function requirement decl after an interface type is checked.
FIDDLE()
class DerivativeRequirementDecl : public FunctionDeclBase
{
FIDDLE(...)
// The original requirement decl.
FIDDLE() Decl* originalRequirementDecl = nullptr;
// Type to use for 'ThisType'
FIDDLE() Type* diffThisType;
};
// A reference to a synthesized decl representing a differentiable function requirement, this decl
// will be a child in the orignal function.
FIDDLE()
class DerivativeRequirementReferenceDecl : public Decl
{
FIDDLE(...)
FIDDLE() DerivativeRequirementDecl* referencedDecl;
};
FIDDLE()
class ForwardDerivativeRequirementDecl : public DerivativeRequirementDecl
{
FIDDLE(...)
};
FIDDLE()
class BackwardDerivativeRequirementDecl : public DerivativeRequirementDecl
{
FIDDLE(...)
};
bool isInterfaceRequirement(Decl* decl);
InterfaceDecl* findParentInterfaceDecl(Decl* decl);
bool isLocalVar(const Decl* decl);
// Add a sibling lookup scope for `dest` to refer to `source`.
void addSiblingScopeForContainerDecl(
ASTBuilder* builder,
ContainerDecl* dest,
ContainerDecl* source);
void addSiblingScopeForContainerDecl(ASTBuilder* builder, Scope* destScope, ContainerDecl* source);
// Cast `decl` to a valid `ContainerDecl*` if its members will become global scope symbols after
// lowering to IR. This currently includes: `NamespaceDecl`, `ModuleDecl` and `FileDecl`.
ContainerDecl* isStaticScopeDecl(Decl* decl);
} // namespace Slang
|