summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-syntax.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-syntax.cpp')
-rw-r--r--source/slang/slang-syntax.cpp2865
1 files changed, 2865 insertions, 0 deletions
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
new file mode 100644
index 000000000..08d671241
--- /dev/null
+++ b/source/slang/slang-syntax.cpp
@@ -0,0 +1,2865 @@
+#include "slang-syntax.h"
+
+#include "slang-compiler.h"
+#include "slang-visitor.h"
+
+#include <typeinfo>
+#include <assert.h>
+
+namespace Slang
+{
+ // BasicExpressionType
+
+ bool BasicExpressionType::EqualsImpl(Type * type)
+ {
+ auto basicType = dynamicCast<const BasicExpressionType>(type);
+ return basicType && basicType->baseType == this->baseType;
+ }
+
+ RefPtr<Type> BasicExpressionType::CreateCanonicalType()
+ {
+ // A basic type is already canonical, in our setup
+ return this;
+ }
+
+ // Generate dispatch logic and other definitions for all syntax classes
+#define SYNTAX_CLASS(NAME, BASE) /* empty */
+#include "slang-object-meta-begin.h"
+
+#include "slang-syntax-base-defs.h"
+#undef SYNTAX_CLASS
+#undef ABSTRACT_SYNTAX_CLASS
+
+#define ABSTRACT_SYNTAX_CLASS(NAME, BASE) \
+ template<> \
+ SyntaxClassBase::ClassInfo const SyntaxClassBase::Impl<NAME>::kClassInfo = { #NAME, &SyntaxClassBase::Impl<BASE>::kClassInfo, nullptr };
+
+#define SYNTAX_CLASS(NAME, BASE) \
+ void NAME::accept(NAME::Visitor* visitor, void* extra) \
+ { visitor->dispatch_##NAME(this, extra); } \
+ template<> \
+ void* SyntaxClassBase::Impl<NAME>::createFunc() { return new NAME(); } \
+ SyntaxClass<NodeBase> NAME::getClass() { return Slang::getClass<NAME>(); } \
+ template<> \
+ SyntaxClassBase::ClassInfo const SyntaxClassBase::Impl<NAME>::kClassInfo = { #NAME, &SyntaxClassBase::Impl<BASE>::kClassInfo, &SyntaxClassBase::Impl<NAME>::createFunc };
+
+template<>
+SyntaxClassBase::ClassInfo const SyntaxClassBase::Impl<RefObject>::kClassInfo = { "RefObject", nullptr, nullptr };
+
+ABSTRACT_SYNTAX_CLASS(NodeBase, RefObject);
+ABSTRACT_SYNTAX_CLASS(SyntaxNodeBase, NodeBase);
+ABSTRACT_SYNTAX_CLASS(SyntaxNode, SyntaxNodeBase);
+ABSTRACT_SYNTAX_CLASS(ModifiableSyntaxNode, SyntaxNode);
+ABSTRACT_SYNTAX_CLASS(DeclBase, ModifiableSyntaxNode);
+ABSTRACT_SYNTAX_CLASS(Decl, DeclBase);
+ABSTRACT_SYNTAX_CLASS(Stmt, ModifiableSyntaxNode);
+ABSTRACT_SYNTAX_CLASS(Val, NodeBase);
+ABSTRACT_SYNTAX_CLASS(Type, Val);
+ABSTRACT_SYNTAX_CLASS(Modifier, SyntaxNodeBase);
+ABSTRACT_SYNTAX_CLASS(Expr, SyntaxNode);
+
+ABSTRACT_SYNTAX_CLASS(Substitutions, SyntaxNode);
+ABSTRACT_SYNTAX_CLASS(GenericSubstitution, Substitutions);
+ABSTRACT_SYNTAX_CLASS(ThisTypeSubstitution, Substitutions);
+ABSTRACT_SYNTAX_CLASS(GlobalGenericParamSubstitution, Substitutions);
+
+#include "slang-expr-defs.h"
+#include "slang-decl-defs.h"
+#include "slang-modifier-defs.h"
+#include "slang-stmt-defs.h"
+#include "slang-type-defs.h"
+#include "slang-val-defs.h"
+#include "slang-object-meta-end.h"
+
+bool SyntaxClassBase::isSubClassOfImpl(SyntaxClassBase const& super) const
+{
+ SyntaxClassBase::ClassInfo const* info = classInfo;
+ while (info)
+ {
+ if (info == super.classInfo)
+ return true;
+
+ info = info->baseClass;
+ }
+
+ return false;
+}
+
+void Type::accept(IValVisitor* visitor, void* extra)
+{
+ accept((ITypeVisitor*)visitor, extra);
+}
+
+ // TypeExp
+
+ bool TypeExp::Equals(Type* other)
+ {
+ return type->Equals(other);
+ }
+
+ bool TypeExp::Equals(RefPtr<Type> other)
+ {
+ return type->Equals(other.Ptr());
+ }
+
+ // BasicExpressionType
+
+ BasicExpressionType* BasicExpressionType::GetScalarType()
+ {
+ return this;
+ }
+
+ //
+
+ Type::~Type()
+ {
+ // If the canonicalType !=nullptr AND it is not set to this (ie the canonicalType is another object)
+ // then it needs to be released because it's owned by this object.
+ if (canonicalType && canonicalType != this)
+ {
+ canonicalType->releaseReference();
+ }
+ }
+
+ bool Type::Equals(Type * type)
+ {
+ return GetCanonicalType()->EqualsImpl(type->GetCanonicalType());
+ }
+
+ bool Type::EqualsVal(Val* val)
+ {
+ if (auto type = dynamicCast<Type>(val))
+ return const_cast<Type*>(this)->Equals(type);
+ return false;
+ }
+
+ RefPtr<Val> Type::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ int diff = 0;
+ auto canSubst = GetCanonicalType()->SubstituteImpl(subst, &diff);
+
+ // If nothing changed, then don't drop any sugar that is applied
+ if (!diff)
+ return this;
+
+ // If the canonical type changed, then we return a canonical type,
+ // rather than try to re-construct any amount of sugar
+ (*ioDiff)++;
+ return canSubst;
+ }
+
+ Type* Type::GetCanonicalType()
+ {
+ Type* et = const_cast<Type*>(this);
+ if (!et->canonicalType)
+ {
+ // TODO(tfoley): worry about thread safety here?
+ auto canType = et->CreateCanonicalType();
+ et->canonicalType = canType;
+
+ // TODO(js): That this detachs when canType == this is a little surprising. It would seem
+ // as if this would create a circular reference on the object, but in practice there are
+ // no leaks so appears correct.
+ // That the dtor only releases if != this, also makes it surprising.
+ canType.detach();
+
+ SLANG_ASSERT(et->canonicalType);
+ }
+ return et->canonicalType;
+ }
+
+ void Session::initializeTypes()
+ {
+ errorType = new ErrorType();
+ errorType->setSession(this);
+
+ initializerListType = new InitializerListType();
+ initializerListType->setSession(this);
+
+ overloadedType = new OverloadGroupType();
+ overloadedType->setSession(this);
+ }
+
+ Type* Session::getBoolType()
+ {
+ return getBuiltinType(BaseType::Bool);
+ }
+
+ Type* Session::getHalfType()
+ {
+ return getBuiltinType(BaseType::Half);
+ }
+
+ Type* Session::getFloatType()
+ {
+ return getBuiltinType(BaseType::Float);
+ }
+
+ Type* Session::getDoubleType()
+ {
+ return getBuiltinType(BaseType::Double);
+ }
+
+ Type* Session::getIntType()
+ {
+ return getBuiltinType(BaseType::Int);
+ }
+
+ Type* Session::getInt64Type()
+ {
+ return getBuiltinType(BaseType::Int64);
+ }
+
+ Type* Session::getUIntType()
+ {
+ return getBuiltinType(BaseType::UInt);
+ }
+
+ Type* Session::getUInt64Type()
+ {
+ return getBuiltinType(BaseType::UInt64);
+ }
+
+ Type* Session::getVoidType()
+ {
+ return getBuiltinType(BaseType::Void);
+ }
+
+ Type* Session::getBuiltinType(BaseType flavor)
+ {
+ return RefPtr<Type>(builtinTypes[(int)flavor]);
+ }
+
+ Type* Session::getInitializerListType()
+ {
+ return initializerListType;
+ }
+
+ Type* Session::getOverloadedType()
+ {
+ return overloadedType;
+ }
+
+ Type* Session::getErrorType()
+ {
+ return errorType;
+ }
+
+ Type* Session::getStringType()
+ {
+ if (stringType == nullptr)
+ {
+ auto stringTypeDecl = findMagicDecl(this, "StringType");
+ stringType = DeclRefType::Create(this, makeDeclRef<Decl>(stringTypeDecl));
+ }
+ return stringType;
+ }
+
+ Type* Session::getEnumTypeType()
+ {
+ if (enumTypeType == nullptr)
+ {
+ auto enumTypeTypeDecl = findMagicDecl(this, "EnumTypeType");
+ enumTypeType = DeclRefType::Create(this, makeDeclRef<Decl>(enumTypeTypeDecl));
+ }
+ return enumTypeType;
+ }
+
+ RefPtr<PtrType> Session::getPtrType(
+ RefPtr<Type> valueType)
+ {
+ return getPtrType(valueType, "PtrType").dynamicCast<PtrType>();
+ }
+
+ // Construct the type `Out<valueType>`
+ RefPtr<OutType> Session::getOutType(RefPtr<Type> valueType)
+ {
+ return getPtrType(valueType, "OutType").dynamicCast<OutType>();
+ }
+
+ RefPtr<InOutType> Session::getInOutType(RefPtr<Type> valueType)
+ {
+ return getPtrType(valueType, "InOutType").dynamicCast<InOutType>();
+ }
+
+ RefPtr<RefType> Session::getRefType(RefPtr<Type> valueType)
+ {
+ return getPtrType(valueType, "RefType").dynamicCast<RefType>();
+ }
+
+ RefPtr<PtrTypeBase> Session::getPtrType(RefPtr<Type> valueType, char const* ptrTypeName)
+ {
+ auto genericDecl = findMagicDecl(this, ptrTypeName).dynamicCast<GenericDecl>();
+ return getPtrType(valueType, genericDecl);
+ }
+
+ RefPtr<PtrTypeBase> Session::getPtrType(RefPtr<Type> valueType, GenericDecl* genericDecl)
+ {
+ auto typeDecl = genericDecl->inner;
+
+ auto substitutions = new GenericSubstitution();
+ substitutions->genericDecl = genericDecl;
+ substitutions->args.add(valueType);
+
+ auto declRef = DeclRef<Decl>(typeDecl.Ptr(), substitutions);
+ auto rsType = DeclRefType::Create(
+ this,
+ declRef);
+ return as<PtrTypeBase>( rsType);
+ }
+
+ RefPtr<ArrayExpressionType> Session::getArrayType(
+ Type* elementType,
+ IntVal* elementCount)
+ {
+ RefPtr<ArrayExpressionType> arrayType = new ArrayExpressionType();
+ arrayType->setSession(this);
+ arrayType->baseType = elementType;
+ arrayType->ArrayLength = elementCount;
+ return arrayType;
+ }
+
+ SyntaxClass<RefObject> Session::findSyntaxClass(Name* name)
+ {
+ SyntaxClass<RefObject> syntaxClass;
+ if (mapNameToSyntaxClass.TryGetValue(name, syntaxClass))
+ return syntaxClass;
+
+ return SyntaxClass<RefObject>();
+ }
+
+
+
+ bool ArrayExpressionType::EqualsImpl(Type* type)
+ {
+ auto arrType = as<ArrayExpressionType>(type);
+ if (!arrType)
+ return false;
+ return (areValsEqual(ArrayLength, arrType->ArrayLength) && baseType->Equals(arrType->baseType.Ptr()));
+ }
+
+ RefPtr<Val> ArrayExpressionType::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ int diff = 0;
+ auto elementType = baseType->SubstituteImpl(subst, &diff).as<Type>();
+ auto arrlen = ArrayLength->SubstituteImpl(subst, &diff).as<IntVal>();
+ SLANG_ASSERT(arrlen);
+ if (diff)
+ {
+ *ioDiff = 1;
+ auto rsType = getArrayType(
+ elementType,
+ arrlen);
+ return rsType;
+ }
+ return this;
+ }
+
+ RefPtr<Type> ArrayExpressionType::CreateCanonicalType()
+ {
+ auto canonicalElementType = baseType->GetCanonicalType();
+ auto canonicalArrayType = getArrayType(
+ canonicalElementType,
+ ArrayLength);
+ return canonicalArrayType;
+ }
+ int ArrayExpressionType::GetHashCode()
+ {
+ if (ArrayLength)
+ return (baseType->GetHashCode() * 16777619) ^ ArrayLength->GetHashCode();
+ else
+ return baseType->GetHashCode();
+ }
+ Slang::String ArrayExpressionType::ToString()
+ {
+ if (ArrayLength)
+ return baseType->ToString() + "[" + ArrayLength->ToString() + "]";
+ else
+ return baseType->ToString() + "[]";
+ }
+
+ // DeclRefType
+
+ String DeclRefType::ToString()
+ {
+ return declRef.toString();
+ }
+
+ int DeclRefType::GetHashCode()
+ {
+ return (declRef.GetHashCode() * 16777619) ^ (int)(typeid(this).hash_code());
+ }
+
+ bool DeclRefType::EqualsImpl(Type * type)
+ {
+ if (auto declRefType = as<DeclRefType>(type))
+ {
+ return declRef.Equals(declRefType->declRef);
+ }
+ return false;
+ }
+
+ RefPtr<Type> DeclRefType::CreateCanonicalType()
+ {
+ // A declaration reference is already canonical
+ return this;
+ }
+
+ //
+ // RequirementWitness
+ //
+
+ RequirementWitness::RequirementWitness(RefPtr<Val> val)
+ : m_flavor(Flavor::val)
+ , m_obj(val)
+ {}
+
+
+ RequirementWitness::RequirementWitness(RefPtr<WitnessTable> witnessTable)
+ : m_flavor(Flavor::witnessTable)
+ , m_obj(witnessTable)
+ {}
+
+ RefPtr<WitnessTable> RequirementWitness::getWitnessTable()
+ {
+ SLANG_ASSERT(getFlavor() == Flavor::witnessTable);
+ return m_obj.as<WitnessTable>();
+ }
+
+
+ RequirementWitness RequirementWitness::specialize(SubstitutionSet const& subst)
+ {
+ switch(getFlavor())
+ {
+ default:
+ SLANG_UNEXPECTED("unknown requirement witness flavor");
+ case RequirementWitness::Flavor::none:
+ return RequirementWitness();
+
+ case RequirementWitness::Flavor::declRef:
+ {
+ int diff = 0;
+ return RequirementWitness(
+ getDeclRef().SubstituteImpl(subst, &diff));
+ }
+
+ case RequirementWitness::Flavor::val:
+ {
+ auto val = getVal();
+ SLANG_ASSERT(val);
+
+ return RequirementWitness(
+ val->Substitute(subst));
+ }
+ }
+ }
+
+ RequirementWitness tryLookUpRequirementWitness(
+ SubtypeWitness* subtypeWitness,
+ Decl* requirementKey)
+ {
+ if(auto declaredSubtypeWitness = as<DeclaredSubtypeWitness>(subtypeWitness))
+ {
+ if(auto inheritanceDeclRef = declaredSubtypeWitness->declRef.as<InheritanceDecl>())
+ {
+ // A conformance that was declared as part of an inheritance clause
+ // will have built up a dictionary of the satisfying declarations
+ // for each of its requirements.
+ RequirementWitness requirementWitness;
+ auto witnessTable = inheritanceDeclRef.getDecl()->witnessTable;
+ if(witnessTable && witnessTable->requirementDictionary.TryGetValue(requirementKey, requirementWitness))
+ {
+ // The `inheritanceDeclRef` has substitutions applied to it that
+ // *aren't* present in the `requirementWitness`, because it was
+ // derived by the front-end when looking at the `InheritanceDecl` alone.
+ //
+ // We need to apply these substitutions here for the result to make sense.
+ //
+ // E.g., if we have a case like:
+ //
+ // interface ISidekick { associatedtype Hero; void follow(Hero hero); }
+ // struct Sidekick<H> : ISidekick { typedef H Hero; void follow(H hero) {} };
+ //
+ // void followHero<S : ISidekick>(S s, S.Hero h)
+ // {
+ // s.follow(h);
+ // }
+ //
+ // Batman batman;
+ // Sidekick<Batman> robin;
+ // followHero<Sidekick<Batman>>(robin, batman);
+ //
+ // The second argument to `followHero` is `batman`, which has type `Batman`.
+ // The parameter declaration lists the type `S.Hero`, which is a reference
+ // to an associated type. The front end will expand this into something
+ // like `S.{S:ISidekick}.Hero` - that is, we'll end up with a declaration
+ // reference to `ISidekick.Hero` with a this-type substitution that references
+ // the `{S:ISidekick}` declaration as a witness.
+ //
+ // The front-end will expand the generic application `followHero<Sidekick<Batman>>`
+ // to `followHero<Sidekick<Batman>, {Sidekick<H>:ISidekick}[H->Batman]>`
+ // (that is, the hidden second parameter will reference the inheritance
+ // clause on `Sidekick<H>`, with a substitution to map `H` to `Batman`.
+ //
+ // This step should map the `{S:ISidekick}` declaration over to the
+ // concrete `{Sidekick<H>:ISidekick}[H->Batman]` inheritance declaration.
+ // At that point `tryLookupRequirementWitness` might be called, because
+ // we want to look up the witness for the key `ISidekick.Hero` in the
+ // inheritance decl-ref that is `{Sidekick<H>:ISidekick}[H->Batman]`.
+ //
+ // That lookup will yield us a reference to the typedef `Sidekick<H>.Hero`,
+ // *without* any substitution for `H` (or rather, with a default one that
+ // maps `H` to `H`.
+ //
+ // So, in order to get the *right* end result, we need to apply
+ // the substitutions from the inheritance decl-ref to the witness.
+ //
+ requirementWitness = requirementWitness.specialize(inheritanceDeclRef.substitutions);
+
+ return requirementWitness;
+ }
+ }
+ }
+
+ // TODO: should handle the transitive case here too
+
+ return RequirementWitness();
+ }
+
+ RefPtr<Val> DeclRefType::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ if (!subst) return this;
+
+ // the case we especially care about is when this type references a declaration
+ // of a generic parameter, since that is what we might be substituting...
+ if (auto genericTypeParamDecl = as<GenericTypeParamDecl>(declRef.getDecl()))
+ {
+ // search for a substitution that might apply to us
+ for(auto s = subst.substitutions; s; s = s->outer)
+ {
+ auto genericSubst = s.as<GenericSubstitution>();
+ if(!genericSubst)
+ continue;
+
+ // the generic decl associated with the substitution list must be
+ // the generic decl that declared this parameter
+ auto genericDecl = genericSubst->genericDecl;
+ if (genericDecl != genericTypeParamDecl->ParentDecl)
+ continue;
+
+ int index = 0;
+ for (auto m : genericDecl->Members)
+ {
+ if (m.Ptr() == genericTypeParamDecl)
+ {
+ // We've found it, so return the corresponding specialization argument
+ (*ioDiff)++;
+ return genericSubst->args[index];
+ }
+ else if (auto typeParam = as<GenericTypeParamDecl>(m))
+ {
+ index++;
+ }
+ else if (auto valParam = as<GenericValueParamDecl>(m))
+ {
+ index++;
+ }
+ else
+ {
+ }
+ }
+ }
+ }
+ else if (auto globalGenParam = as<GlobalGenericParamDecl>(declRef.getDecl()))
+ {
+ // search for a substitution that might apply to us
+ for(auto s = subst.substitutions; s; s = s->outer)
+ {
+ auto genericSubst = as<GlobalGenericParamSubstitution>(s);
+ if(!genericSubst)
+ continue;
+
+ if (genericSubst->paramDecl == globalGenParam)
+ {
+ (*ioDiff)++;
+ return genericSubst->actualType;
+ }
+ }
+ }
+ int diff = 0;
+ DeclRef<Decl> substDeclRef = declRef.SubstituteImpl(subst, &diff);
+
+ if (!diff)
+ return this;
+
+ // Make sure to record the difference!
+ *ioDiff += diff;
+
+ // If this type is a reference to an associated type declaration,
+ // and the substitutions provide a "this type" substitution for
+ // the outer interface, then try to replace the type with the
+ // actual value of the associated type for the given implementation.
+ //
+ if(auto substAssocTypeDecl = as<AssocTypeDecl>(substDeclRef.decl))
+ {
+ for(auto s = substDeclRef.substitutions.substitutions; s; s = s->outer)
+ {
+ auto thisSubst = s.as<ThisTypeSubstitution>();
+ if(!thisSubst)
+ continue;
+
+ if(auto interfaceDecl = as<InterfaceDecl>(substAssocTypeDecl->ParentDecl))
+ {
+ if(thisSubst->interfaceDecl == interfaceDecl)
+ {
+ // We need to look up the declaration that satisfies
+ // the requirement named by the associated type.
+ Decl* requirementKey = substAssocTypeDecl;
+ RequirementWitness requirementWitness = tryLookUpRequirementWitness(thisSubst->witness, requirementKey);
+ switch(requirementWitness.getFlavor())
+ {
+ default:
+ // No usable value was found, so there is nothing we can do.
+ break;
+
+ case RequirementWitness::Flavor::val:
+ {
+ auto satisfyingVal = requirementWitness.getVal();
+ return satisfyingVal;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Re-construct the type in case we are using a specialized sub-class
+ return DeclRefType::Create(getSession(), substDeclRef);
+ }
+
+ static RefPtr<Type> ExtractGenericArgType(RefPtr<Val> val)
+ {
+ auto type = val.as<Type>();
+ SLANG_RELEASE_ASSERT(type.Ptr());
+ return type;
+ }
+
+ static RefPtr<IntVal> ExtractGenericArgInteger(RefPtr<Val> val)
+ {
+ auto intVal = val.as<IntVal>();
+ SLANG_RELEASE_ASSERT(intVal.Ptr());
+ return intVal;
+ }
+
+ DeclRef<Decl> createDefaultSubstitutionsIfNeeded(
+ Session* session,
+ DeclRef<Decl> declRef)
+ {
+ // It is possible that `declRef` refers to a generic type,
+ // but does not specify arguments for its generic parameters.
+ // (E.g., this happens when referring to a generic type from
+ // within its own member functions). To handle this case,
+ // we will construct a default specialization at the use
+ // site if needed.
+ //
+ // This same logic should also apply to declarations nested
+ // more than one level inside of a generic (e.g., a `typdef`
+ // inside of a generic `struct`).
+ //
+ // Similarly, it needs to work for multiple levels of
+ // nested generics.
+ //
+
+ // We are going to build up a list of substitutions that need
+ // to be applied to the decl-ref to make it specialized.
+ RefPtr<Substitutions> substsToApply;
+ RefPtr<Substitutions>* link = &substsToApply;
+
+ RefPtr<Decl> dd = declRef.getDecl();
+ for(;;)
+ {
+ RefPtr<Decl> childDecl = dd;
+ RefPtr<Decl> parentDecl = dd->ParentDecl;
+ if(!parentDecl)
+ break;
+
+ dd = parentDecl;
+
+ if(auto genericParentDecl = parentDecl.as<GenericDecl>())
+ {
+ // Don't specialize any parameters of a generic.
+ if(childDecl != genericParentDecl->inner)
+ break;
+
+ // We have a generic ancestor, but do we have an substitutions for it?
+ RefPtr<GenericSubstitution> foundSubst;
+ for(auto s = declRef.substitutions.substitutions; s; s = s->outer)
+ {
+ auto genSubst = s.as<GenericSubstitution>();
+ if(!genSubst)
+ continue;
+
+ if(genSubst->genericDecl != genericParentDecl)
+ continue;
+
+ // Okay, we found a matching substitution,
+ // so there is nothing to be done.
+ foundSubst = genSubst;
+ break;
+ }
+
+ if(!foundSubst)
+ {
+ RefPtr<Substitutions> newSubst = createDefaultSubsitutionsForGeneric(
+ session,
+ genericParentDecl,
+ nullptr);
+
+ *link = newSubst;
+ link = &newSubst->outer;
+ }
+ }
+ }
+
+ if(!substsToApply)
+ return declRef;
+
+ int diff = 0;
+ return declRef.SubstituteImpl(substsToApply, &diff);
+ }
+
+ // TODO: need to figure out how to unify this with the logic
+ // in the generic case...
+ RefPtr<DeclRefType> DeclRefType::Create(
+ Session* session,
+ DeclRef<Decl> declRef)
+ {
+ declRef = createDefaultSubstitutionsIfNeeded(session, declRef);
+
+ if (auto builtinMod = declRef.getDecl()->FindModifier<BuiltinTypeModifier>())
+ {
+ auto type = new BasicExpressionType(builtinMod->tag);
+ type->setSession(session);
+ type->declRef = declRef;
+ return type;
+ }
+ else if (auto magicMod = declRef.getDecl()->FindModifier<MagicTypeModifier>())
+ {
+ GenericSubstitution* subst = nullptr;
+ for(auto s = declRef.substitutions.substitutions; s; s = s->outer)
+ {
+ if(auto genericSubst = s.as<GenericSubstitution>())
+ {
+ subst = genericSubst;
+ break;
+ }
+ }
+
+ if (magicMod->name == "SamplerState")
+ {
+ auto type = new SamplerStateType();
+ type->setSession(session);
+ type->declRef = declRef;
+ type->flavor = SamplerStateFlavor(magicMod->tag);
+ return type;
+ }
+ else if (magicMod->name == "Vector")
+ {
+ SLANG_ASSERT(subst && subst->args.getCount() == 2);
+ auto vecType = new VectorExpressionType();
+ vecType->setSession(session);
+ vecType->declRef = declRef;
+ vecType->elementType = ExtractGenericArgType(subst->args[0]);
+ vecType->elementCount = ExtractGenericArgInteger(subst->args[1]);
+ return vecType;
+ }
+ else if (magicMod->name == "Matrix")
+ {
+ SLANG_ASSERT(subst && subst->args.getCount() == 3);
+ auto matType = new MatrixExpressionType();
+ matType->setSession(session);
+ matType->declRef = declRef;
+ return matType;
+ }
+ else if (magicMod->name == "Texture")
+ {
+ SLANG_ASSERT(subst && subst->args.getCount() >= 1);
+ auto textureType = new TextureType(
+ TextureFlavor(magicMod->tag),
+ ExtractGenericArgType(subst->args[0]));
+ textureType->setSession(session);
+ textureType->declRef = declRef;
+ return textureType;
+ }
+ else if (magicMod->name == "TextureSampler")
+ {
+ SLANG_ASSERT(subst && subst->args.getCount() >= 1);
+ auto textureType = new TextureSamplerType(
+ TextureFlavor(magicMod->tag),
+ ExtractGenericArgType(subst->args[0]));
+ textureType->setSession(session);
+ textureType->declRef = declRef;
+ return textureType;
+ }
+ else if (magicMod->name == "GLSLImageType")
+ {
+ SLANG_ASSERT(subst && subst->args.getCount() >= 1);
+ auto textureType = new GLSLImageType(
+ TextureFlavor(magicMod->tag),
+ ExtractGenericArgType(subst->args[0]));
+ textureType->setSession(session);
+ textureType->declRef = declRef;
+ return textureType;
+ }
+
+ // TODO: eventually everything should follow this pattern,
+ // and we can drive the dispatch with a table instead
+ // of this ridiculously slow `if` cascade.
+
+ #define CASE(n,T) \
+ else if(magicMod->name == #n) { \
+ auto type = new T(); \
+ type->setSession(session); \
+ type->declRef = declRef; \
+ return type; \
+ }
+
+ CASE(HLSLInputPatchType, HLSLInputPatchType)
+ CASE(HLSLOutputPatchType, HLSLOutputPatchType)
+
+ #undef CASE
+
+ #define CASE(n,T) \
+ else if(magicMod->name == #n) { \
+ SLANG_ASSERT(subst && subst->args.getCount() == 1); \
+ auto type = new T(); \
+ type->setSession(session); \
+ type->elementType = ExtractGenericArgType(subst->args[0]); \
+ type->declRef = declRef; \
+ return type; \
+ }
+
+ CASE(ConstantBuffer, ConstantBufferType)
+ CASE(TextureBuffer, TextureBufferType)
+ CASE(ParameterBlockType, ParameterBlockType)
+ CASE(GLSLInputParameterGroupType, GLSLInputParameterGroupType)
+ CASE(GLSLOutputParameterGroupType, GLSLOutputParameterGroupType)
+ CASE(GLSLShaderStorageBufferType, GLSLShaderStorageBufferType)
+
+ CASE(HLSLStructuredBufferType, HLSLStructuredBufferType)
+ CASE(HLSLRWStructuredBufferType, HLSLRWStructuredBufferType)
+ CASE(HLSLRasterizerOrderedStructuredBufferType, HLSLRasterizerOrderedStructuredBufferType)
+ CASE(HLSLAppendStructuredBufferType, HLSLAppendStructuredBufferType)
+ CASE(HLSLConsumeStructuredBufferType, HLSLConsumeStructuredBufferType)
+
+ CASE(HLSLPointStreamType, HLSLPointStreamType)
+ CASE(HLSLLineStreamType, HLSLLineStreamType)
+ CASE(HLSLTriangleStreamType, HLSLTriangleStreamType)
+
+ #undef CASE
+
+ // "magic" builtin types which have no generic parameters
+ #define CASE(n,T) \
+ else if(magicMod->name == #n) { \
+ auto type = new T(); \
+ type->setSession(session); \
+ type->declRef = declRef; \
+ return type; \
+ }
+
+ CASE(HLSLByteAddressBufferType, HLSLByteAddressBufferType)
+ CASE(HLSLRWByteAddressBufferType, HLSLRWByteAddressBufferType)
+ CASE(HLSLRasterizerOrderedByteAddressBufferType, HLSLRasterizerOrderedByteAddressBufferType)
+ CASE(UntypedBufferResourceType, UntypedBufferResourceType)
+
+ CASE(GLSLInputAttachmentType, GLSLInputAttachmentType)
+
+ #undef CASE
+
+ else
+ {
+ auto classInfo = session->findSyntaxClass(
+ session->getNamePool()->getName(magicMod->name));
+ if (!classInfo.classInfo)
+ {
+ SLANG_UNEXPECTED("unhandled type");
+ }
+
+ RefPtr<RefObject> type = classInfo.createInstance();
+ if (!type)
+ {
+ SLANG_UNEXPECTED("constructor failure");
+ }
+
+ auto declRefType = dynamicCast<DeclRefType>(type);
+ if (!declRefType)
+ {
+ SLANG_UNEXPECTED("expected a declaration reference type");
+ }
+ declRefType->session = session;
+ declRefType->declRef = declRef;
+ return declRefType;
+ }
+ }
+ else
+ {
+ auto type = new DeclRefType(declRef);
+ type->setSession(session);
+ return type;
+ }
+ }
+
+ // OverloadGroupType
+
+ String OverloadGroupType::ToString()
+ {
+ return "overload group";
+ }
+
+ bool OverloadGroupType::EqualsImpl(Type * /*type*/)
+ {
+ return false;
+ }
+
+ RefPtr<Type> OverloadGroupType::CreateCanonicalType()
+ {
+ return this;
+ }
+
+ int OverloadGroupType::GetHashCode()
+ {
+ return (int)(int64_t)(void*)this;
+ }
+
+ // InitializerListType
+
+ String InitializerListType::ToString()
+ {
+ return "initializer list";
+ }
+
+ bool InitializerListType::EqualsImpl(Type * /*type*/)
+ {
+ return false;
+ }
+
+ RefPtr<Type> InitializerListType::CreateCanonicalType()
+ {
+ return this;
+ }
+
+ int InitializerListType::GetHashCode()
+ {
+ return (int)(int64_t)(void*)this;
+ }
+
+ // ErrorType
+
+ String ErrorType::ToString()
+ {
+ return "error";
+ }
+
+ bool ErrorType::EqualsImpl(Type* type)
+ {
+ if (auto errorType = as<ErrorType>(type))
+ return true;
+ return false;
+ }
+
+ RefPtr<Type> ErrorType::CreateCanonicalType()
+ {
+ return this;
+ }
+
+ RefPtr<Val> ErrorType::SubstituteImpl(SubstitutionSet /*subst*/, int* /*ioDiff*/)
+ {
+ return this;
+ }
+
+ int ErrorType::GetHashCode()
+ {
+ return (int)(int64_t)(void*)this;
+ }
+
+
+ // NamedExpressionType
+
+ String NamedExpressionType::ToString()
+ {
+ return getText(declRef.GetName());
+ }
+
+ bool NamedExpressionType::EqualsImpl(Type * /*type*/)
+ {
+ SLANG_UNEXPECTED("unreachable");
+ UNREACHABLE_RETURN(false);
+ }
+
+ RefPtr<Type> NamedExpressionType::CreateCanonicalType()
+ {
+ if (!innerType)
+ innerType = GetType(declRef);
+ return innerType->GetCanonicalType();
+ }
+
+ int NamedExpressionType::GetHashCode()
+ {
+ // Type equality is based on comparing canonical types,
+ // so the hash code for a type needs to come from the
+ // canonical version of the type. This really means
+ // that `Type::GetHashCode()` should dispatch out to
+ // something like `Type::GetHashCodeImpl()` on the
+ // canonical version of a type, but it is less invasive
+ // for now (and hopefully equivalent) to just have any
+ // named types automaticlaly route hash-code requests
+ // to their canonical type.
+ return GetCanonicalType()->GetHashCode();
+ }
+
+ // FuncType
+
+ String FuncType::ToString()
+ {
+ StringBuilder sb;
+ sb << "(";
+ UInt paramCount = getParamCount();
+ for (UInt pp = 0; pp < paramCount; ++pp)
+ {
+ if (pp != 0) sb << ", ";
+ sb << getParamType(pp)->ToString();
+ }
+ sb << ") -> ";
+ sb << getResultType()->ToString();
+ return sb.ProduceString();
+ }
+
+ bool FuncType::EqualsImpl(Type * type)
+ {
+ if (auto funcType = as<FuncType>(type))
+ {
+ auto paramCount = getParamCount();
+ auto otherParamCount = funcType->getParamCount();
+ if (paramCount != otherParamCount)
+ return false;
+
+ for (UInt pp = 0; pp < paramCount; ++pp)
+ {
+ auto paramType = getParamType(pp);
+ auto otherParamType = funcType->getParamType(pp);
+ if (!paramType->Equals(otherParamType))
+ return false;
+ }
+
+ if(!resultType->Equals(funcType->resultType))
+ return false;
+
+ // TODO: if we ever introduce other kinds
+ // of qualification on function types, we'd
+ // want to consider it here.
+ return true;
+ }
+ return false;
+ }
+
+ RefPtr<Val> FuncType::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ int diff = 0;
+
+ // result type
+ RefPtr<Type> substResultType = resultType->SubstituteImpl(subst, &diff).as<Type>();
+
+ // parameter types
+ List<RefPtr<Type>> substParamTypes;
+ for( auto pp : paramTypes )
+ {
+ substParamTypes.add(pp->SubstituteImpl(subst, &diff).as<Type>());
+ }
+
+ // early exit for no change...
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+ RefPtr<FuncType> substType = new FuncType();
+ substType->session = session;
+ substType->resultType = substResultType;
+ substType->paramTypes = substParamTypes;
+ return substType;
+ }
+
+ RefPtr<Type> FuncType::CreateCanonicalType()
+ {
+ // result type
+ RefPtr<Type> canResultType = resultType->GetCanonicalType();
+
+ // parameter types
+ List<RefPtr<Type>> canParamTypes;
+ for( auto pp : paramTypes )
+ {
+ canParamTypes.add(pp->GetCanonicalType());
+ }
+
+ RefPtr<FuncType> canType = new FuncType();
+ canType->session = session;
+ canType->resultType = resultType;
+ canType->paramTypes = canParamTypes;
+
+ return canType;
+ }
+
+ int FuncType::GetHashCode()
+ {
+ int hashCode = getResultType()->GetHashCode();
+ UInt paramCount = getParamCount();
+ hashCode = combineHash(hashCode, Slang::GetHashCode(paramCount));
+ for (UInt pp = 0; pp < paramCount; ++pp)
+ {
+ hashCode = combineHash(
+ hashCode,
+ getParamType(pp)->GetHashCode());
+ }
+ return hashCode;
+ }
+
+ // TypeType
+
+ String TypeType::ToString()
+ {
+ StringBuilder sb;
+ sb << "typeof(" << type->ToString() << ")";
+ return sb.ProduceString();
+ }
+
+ bool TypeType::EqualsImpl(Type * t)
+ {
+ if (auto typeType = as<TypeType>(t))
+ {
+ return t->Equals(typeType->type);
+ }
+ return false;
+ }
+
+ RefPtr<Type> TypeType::CreateCanonicalType()
+ {
+ auto canType = getTypeType(type->GetCanonicalType());
+ return canType;
+ }
+
+ int TypeType::GetHashCode()
+ {
+ SLANG_UNEXPECTED("unreachable");
+ UNREACHABLE_RETURN(0);
+ }
+
+ // GenericDeclRefType
+
+ String GenericDeclRefType::ToString()
+ {
+ // TODO: what is appropriate here?
+ return "<DeclRef<GenericDecl>>";
+ }
+
+ bool GenericDeclRefType::EqualsImpl(Type * type)
+ {
+ if (auto genericDeclRefType = as<GenericDeclRefType>(type))
+ {
+ return declRef.Equals(genericDeclRefType->declRef);
+ }
+ return false;
+ }
+
+ int GenericDeclRefType::GetHashCode()
+ {
+ return declRef.GetHashCode();
+ }
+
+ RefPtr<Type> GenericDeclRefType::CreateCanonicalType()
+ {
+ return this;
+ }
+
+ // ArithmeticExpressionType
+
+ // VectorExpressionType
+
+ String VectorExpressionType::ToString()
+ {
+ StringBuilder sb;
+ sb << "vector<" << elementType->ToString() << "," << elementCount->ToString() << ">";
+ return sb.ProduceString();
+ }
+
+ BasicExpressionType* VectorExpressionType::GetScalarType()
+ {
+ return as<BasicExpressionType>(elementType);
+ }
+
+ //
+
+ RefPtr<GenericSubstitution> findInnerMostGenericSubstitution(Substitutions* subst)
+ {
+ for(RefPtr<Substitutions> s = subst; s; s = s->outer)
+ {
+ if(auto genericSubst = as<GenericSubstitution>(s))
+ return genericSubst;
+ }
+ return nullptr;
+ }
+
+ // MatrixExpressionType
+
+ String MatrixExpressionType::ToString()
+ {
+ StringBuilder sb;
+ sb << "matrix<" << getElementType()->ToString() << "," << getRowCount()->ToString() << "," << getColumnCount()->ToString() << ">";
+ return sb.ProduceString();
+ }
+
+ BasicExpressionType* MatrixExpressionType::GetScalarType()
+ {
+ return as<BasicExpressionType>(getElementType());
+ }
+
+ Type* MatrixExpressionType::getElementType()
+ {
+ return as<Type>(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]);
+ }
+
+ IntVal* MatrixExpressionType::getRowCount()
+ {
+ return as<IntVal>(findInnerMostGenericSubstitution(declRef.substitutions)->args[1]);
+ }
+
+ IntVal* MatrixExpressionType::getColumnCount()
+ {
+ return as<IntVal>(findInnerMostGenericSubstitution(declRef.substitutions)->args[2]);
+ }
+
+ RefPtr<Type> MatrixExpressionType::getRowType()
+ {
+ if( !mRowType )
+ {
+ mRowType = getSession()->getVectorType(getElementType(), getColumnCount());
+ }
+ return mRowType;
+ }
+
+ RefPtr<VectorExpressionType> Session::getVectorType(
+ RefPtr<Type> elementType,
+ RefPtr<IntVal> elementCount)
+ {
+ auto vectorGenericDecl = findMagicDecl(
+ this, "Vector").as<GenericDecl>();
+ auto vectorTypeDecl = vectorGenericDecl->inner;
+
+ auto substitutions = new GenericSubstitution();
+ substitutions->genericDecl = vectorGenericDecl.Ptr();
+ substitutions->args.add(elementType);
+ substitutions->args.add(elementCount);
+
+ auto declRef = DeclRef<Decl>(vectorTypeDecl.Ptr(), substitutions);
+
+ return DeclRefType::Create(
+ this,
+ declRef).as<VectorExpressionType>();
+ }
+
+
+ // PtrTypeBase
+
+ Type* PtrTypeBase::getValueType()
+ {
+ return as<Type>(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]);
+ }
+
+ // GenericParamIntVal
+
+ bool GenericParamIntVal::EqualsVal(Val* val)
+ {
+ if (auto genericParamVal = as<GenericParamIntVal>(val))
+ {
+ return declRef.Equals(genericParamVal->declRef);
+ }
+ return false;
+ }
+
+ String GenericParamIntVal::ToString()
+ {
+ return getText(declRef.GetName());
+ }
+
+ int GenericParamIntVal::GetHashCode()
+ {
+ return declRef.GetHashCode() ^ 0xFFFF;
+ }
+
+ RefPtr<Val> GenericParamIntVal::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ // search for a substitution that might apply to us
+ for(auto s = subst.substitutions; s; s = s->outer)
+ {
+ auto genSubst = s.as<GenericSubstitution>();
+ if(!genSubst)
+ continue;
+
+ // the generic decl associated with the substitution list must be
+ // the generic decl that declared this parameter
+ auto genericDecl = genSubst->genericDecl;
+ if (genericDecl != declRef.getDecl()->ParentDecl)
+ continue;
+
+ int index = 0;
+ for (auto m : genericDecl->Members)
+ {
+ if (m.Ptr() == declRef.getDecl())
+ {
+ // We've found it, so return the corresponding specialization argument
+ (*ioDiff)++;
+ return genSubst->args[index];
+ }
+ else if (auto typeParam = as<GenericTypeParamDecl>(m))
+ {
+ index++;
+ }
+ else if (auto valParam = as<GenericValueParamDecl>(m))
+ {
+ index++;
+ }
+ else
+ {
+ }
+ }
+ }
+
+ // Nothing found: don't substitute.
+ return this;
+ }
+
+ // Substitutions
+
+ RefPtr<Substitutions> GenericSubstitution::applySubstitutionsShallow(SubstitutionSet substSet, RefPtr<Substitutions> substOuter, int* ioDiff)
+ {
+ int diff = 0;
+
+ if(substOuter != outer) diff++;
+
+ List<RefPtr<Val>> substArgs;
+ for (auto a : args)
+ {
+ substArgs.add(a->SubstituteImpl(substSet, &diff));
+ }
+
+ if (!diff) return this;
+
+ (*ioDiff)++;
+ auto substSubst = new GenericSubstitution();
+ substSubst->genericDecl = genericDecl;
+ substSubst->args = substArgs;
+ substSubst->outer = substOuter;
+ return substSubst;
+ }
+
+ bool GenericSubstitution::Equals(Substitutions* subst)
+ {
+ // both must be NULL, or non-NULL
+ if (subst == nullptr)
+ return false;
+ if (this == subst)
+ return true;
+
+ auto genericSubst = as<GenericSubstitution>(subst);
+ if (!genericSubst)
+ return false;
+ if (genericDecl != genericSubst->genericDecl)
+ return false;
+
+ Index argCount = args.getCount();
+ SLANG_RELEASE_ASSERT(args.getCount() == genericSubst->args.getCount());
+ for (Index aa = 0; aa < argCount; ++aa)
+ {
+ if (!args[aa]->EqualsVal(genericSubst->args[aa].Ptr()))
+ return false;
+ }
+
+ if (!outer)
+ return !genericSubst->outer;
+
+ if (!outer->Equals(genericSubst->outer.Ptr()))
+ return false;
+
+ return true;
+ }
+
+ RefPtr<Substitutions> ThisTypeSubstitution::applySubstitutionsShallow(SubstitutionSet substSet, RefPtr<Substitutions> substOuter, int* ioDiff)
+ {
+ int diff = 0;
+
+ if(substOuter != outer) diff++;
+
+ // NOTE: Must use .as because we must have a smart pointer here to keep in scope.
+ auto substWitness = witness->SubstituteImpl(substSet, &diff).as<SubtypeWitness>();
+
+ if (!diff) return this;
+
+ (*ioDiff)++;
+ auto substSubst = new ThisTypeSubstitution();
+ substSubst->interfaceDecl = interfaceDecl;
+ substSubst->witness = substWitness;
+ substSubst->outer = substOuter;
+ return substSubst;
+ }
+
+ bool ThisTypeSubstitution::Equals(Substitutions* subst)
+ {
+ if (!subst)
+ return false;
+ if (subst == this)
+ return true;
+
+ if (auto thisTypeSubst = as<ThisTypeSubstitution>(subst))
+ {
+ return witness->EqualsVal(thisTypeSubst->witness);
+ }
+ return false;
+ }
+
+ int ThisTypeSubstitution::GetHashCode() const
+ {
+ return witness->GetHashCode();
+ }
+
+ RefPtr<Substitutions> GlobalGenericParamSubstitution::applySubstitutionsShallow(SubstitutionSet substSet, RefPtr<Substitutions> substOuter, int* ioDiff)
+ {
+ // if we find a GlobalGenericParamSubstitution in subst that references the same type_param decl
+ // return a copy of that GlobalGenericParamSubstitution
+ int diff = 0;
+
+ if(substOuter != outer) diff++;
+
+ auto substActualType = actualType->SubstituteImpl(substSet, &diff).as<Type>();
+
+ List<ConstraintArg> substConstraintArgs;
+ for(auto constraintArg : constraintArgs)
+ {
+ ConstraintArg substConstraintArg;
+ substConstraintArg.decl = constraintArg.decl;
+ substConstraintArg.val = constraintArg.val->SubstituteImpl(substSet, &diff);
+
+ substConstraintArgs.add(substConstraintArg);
+ }
+
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ RefPtr<GlobalGenericParamSubstitution> substSubst = new GlobalGenericParamSubstitution();
+ substSubst->paramDecl = paramDecl;
+ substSubst->actualType = substActualType;
+ substSubst->constraintArgs = substConstraintArgs;
+ substSubst->outer = substOuter;
+ return substSubst;
+ }
+
+ bool GlobalGenericParamSubstitution::Equals(Substitutions* subst)
+ {
+ if (!subst)
+ return false;
+ if (subst == this)
+ return true;
+
+ if (auto genSubst = as<GlobalGenericParamSubstitution>(subst))
+ {
+ if (paramDecl != genSubst->paramDecl)
+ return false;
+ if (!actualType->EqualsVal(genSubst->actualType))
+ return false;
+ if (constraintArgs.getCount() != genSubst->constraintArgs.getCount())
+ return false;
+ for (Index i = 0; i < constraintArgs.getCount(); i++)
+ {
+ if (!constraintArgs[i].val->EqualsVal(genSubst->constraintArgs[i].val))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ // DeclRefBase
+
+ RefPtr<Type> DeclRefBase::Substitute(RefPtr<Type> type) const
+ {
+ // Note that type can be nullptr, and so this function can return nullptr (although only correctly when no substitutions)
+
+ // No substitutions? Easy.
+ if (!substitutions)
+ return type;
+
+ SLANG_ASSERT(type);
+
+ // Otherwise we need to recurse on the type structure
+ // and apply substitutions where it makes sense
+ return type->Substitute(substitutions).as<Type>();
+ }
+
+ DeclRefBase DeclRefBase::Substitute(DeclRefBase declRef) const
+ {
+ if(!substitutions)
+ return declRef;
+
+ int diff = 0;
+ return declRef.SubstituteImpl(substitutions, &diff);
+ }
+
+ RefPtr<Expr> DeclRefBase::Substitute(RefPtr<Expr> expr) const
+ {
+ // No substitutions? Easy.
+ if (!substitutions)
+ return expr;
+
+ SLANG_UNIMPLEMENTED_X("generic substitution into expressions");
+
+ UNREACHABLE_RETURN(expr);
+ }
+
+ void buildMemberDictionary(ContainerDecl* decl);
+
+ InterfaceDecl* findOuterInterfaceDecl(Decl* decl)
+ {
+ Decl* dd = decl;
+ while(dd)
+ {
+ if(auto interfaceDecl = as<InterfaceDecl>(dd))
+ return interfaceDecl;
+
+ dd = dd->ParentDecl;
+ }
+ return nullptr;
+ }
+
+ RefPtr<GlobalGenericParamSubstitution> findGlobalGenericSubst(
+ RefPtr<Substitutions> substs,
+ GlobalGenericParamDecl* paramDecl)
+ {
+ for(auto s = substs; s; s = s->outer)
+ {
+ auto gSubst = s.as<GlobalGenericParamSubstitution>();
+ if(!gSubst)
+ continue;
+
+ if(gSubst->paramDecl != paramDecl)
+ continue;
+
+ return gSubst;
+ }
+
+ return nullptr;
+ }
+
+ RefPtr<Substitutions> specializeSubstitutionsShallow(
+ RefPtr<Substitutions> substToSpecialize,
+ RefPtr<Substitutions> substsToApply,
+ RefPtr<Substitutions> restSubst,
+ int* ioDiff)
+ {
+ SLANG_ASSERT(substToSpecialize);
+ return substToSpecialize->applySubstitutionsShallow(substsToApply, restSubst, ioDiff);
+ }
+
+ RefPtr<Substitutions> specializeGlobalGenericSubstitutions(
+ Decl* declToSpecialize,
+ RefPtr<Substitutions> substsToSpecialize,
+ RefPtr<Substitutions> substsToApply,
+ int* ioDiff,
+ HashSet<GlobalGenericParamDecl*>& ioParametersFound)
+ {
+ // Any existing global-generic substitutions will trigger
+ // a recursive case that skips the rest of the function.
+ for(auto specSubst = substsToSpecialize; specSubst; specSubst = specSubst->outer)
+ {
+ auto specGlobalGenericSubst = specSubst.as<GlobalGenericParamSubstitution>();
+ if(!specGlobalGenericSubst)
+ continue;
+
+ ioParametersFound.Add(specGlobalGenericSubst->paramDecl);
+
+ int diff = 0;
+ auto restSubst = specializeGlobalGenericSubstitutions(
+ declToSpecialize,
+ specSubst->outer,
+ substsToApply,
+ &diff,
+ ioParametersFound);
+
+ auto firstSubst = specializeSubstitutionsShallow(
+ specGlobalGenericSubst,
+ substsToApply,
+ restSubst,
+ &diff);
+
+ *ioDiff += diff;
+ return firstSubst;
+ }
+
+ // No more existing substitutions, so we know we can apply
+ // our global generic substitutions without any special work.
+
+ // We expect global generic substitutions to come at
+ // the end of the list in all cases, so lets advance
+ // until we see them.
+ RefPtr<Substitutions> appGlobalGenericSubsts = substsToApply;
+ while(appGlobalGenericSubsts && !appGlobalGenericSubsts.as<GlobalGenericParamSubstitution>())
+ appGlobalGenericSubsts = appGlobalGenericSubsts->outer;
+
+
+ // If there is nothing to apply, then we are done
+ if(!appGlobalGenericSubsts)
+ return nullptr;
+
+ // Otherwise, it seems like something has to change.
+ (*ioDiff)++;
+
+ // If there were no parameters bound by the existing substitution,
+ // then we can safely use the global generics from the to-apply set.
+ if(ioParametersFound.Count() == 0)
+ return appGlobalGenericSubsts;
+
+ RefPtr<Substitutions> resultSubst;
+ RefPtr<Substitutions>* link = &resultSubst;
+ for(auto appSubst = appGlobalGenericSubsts; appSubst; appSubst = appSubst->outer)
+ {
+ auto appGlobalGenericSubst = appSubst.as<GlobalGenericParamSubstitution>();
+ if(!appSubst)
+ continue;
+
+ // Don't include substitutions for parameters already handled.
+ if(ioParametersFound.Contains(appGlobalGenericSubst->paramDecl))
+ continue;
+
+ RefPtr<GlobalGenericParamSubstitution> newSubst = new GlobalGenericParamSubstitution();
+ newSubst->paramDecl = appGlobalGenericSubst->paramDecl;
+ newSubst->actualType = appGlobalGenericSubst->actualType;
+ newSubst->constraintArgs = appGlobalGenericSubst->constraintArgs;
+
+ *link = newSubst;
+ link = &newSubst->outer;
+ }
+
+ return resultSubst;
+ }
+
+ RefPtr<Substitutions> specializeGlobalGenericSubstitutions(
+ Decl* declToSpecialize,
+ RefPtr<Substitutions> substsToSpecialize,
+ RefPtr<Substitutions> substsToApply,
+ int* ioDiff)
+ {
+ // Keep track of any parameters already present in the
+ // existing substitution.
+ HashSet<GlobalGenericParamDecl*> parametersFound;
+ return specializeGlobalGenericSubstitutions(declToSpecialize, substsToSpecialize, substsToApply, ioDiff, parametersFound);
+ }
+
+
+ // Construct new substitutions to apply to a declaration,
+ // based on a provided substitution set to be applied
+ RefPtr<Substitutions> specializeSubstitutions(
+ Decl* declToSpecialize,
+ RefPtr<Substitutions> substsToSpecialize,
+ RefPtr<Substitutions> substsToApply,
+ int* ioDiff)
+ {
+ // No declaration? Then nothing to specialize.
+ if(!declToSpecialize)
+ return nullptr;
+
+ // No (remaining) substitutions to apply? Then we are done.
+ if(!substsToApply)
+ return substsToSpecialize;
+
+ // Walk the hierarchy of the declaration to determine what specializations might apply.
+ // We assume that the `substsToSpecialize` must be aligned with the ancestor
+ // hierarchy of `declToSpecialize` such that if, e.g., the `declToSpecialize` is
+ // nested directly in a generic, then `substToSpecialize` will either start with
+ // the corresponding `GenericSubstitution` or there will be *no* generic substitutions
+ // corresponding to that decl.
+ for(Decl* ancestorDecl = declToSpecialize; ancestorDecl; ancestorDecl = ancestorDecl->ParentDecl)
+ {
+ if(auto ancestorGenericDecl = as<GenericDecl>(ancestorDecl))
+ {
+ // The declaration is nested inside a generic.
+ // Does it already have a specialization for that generic?
+ if(auto specGenericSubst = as<GenericSubstitution>(substsToSpecialize))
+ {
+ if(specGenericSubst->genericDecl == ancestorGenericDecl)
+ {
+ // Yes. We have an existing specialization, so we will
+ // keep one matching it in place.
+ int diff = 0;
+ auto restSubst = specializeSubstitutions(
+ ancestorGenericDecl->ParentDecl,
+ specGenericSubst->outer,
+ substsToApply,
+ &diff);
+
+ auto firstSubst = specializeSubstitutionsShallow(
+ specGenericSubst,
+ substsToApply,
+ restSubst,
+ &diff);
+
+ *ioDiff += diff;
+ return firstSubst;
+ }
+ }
+
+ // If the declaration is not already specialized
+ // for the given generic, then see if we are trying
+ // to *apply* such specializations to it.
+ //
+ // TODO: The way we handle things right now with
+ // "default" specializations, this case shouldn't
+ // actually come up.
+ //
+ for(auto s = substsToApply; s; s = s->outer)
+ {
+ auto appGenericSubst = as<GenericSubstitution>(s);
+ if(!appGenericSubst)
+ continue;
+
+ if(appGenericSubst->genericDecl != ancestorGenericDecl)
+ continue;
+
+ // The substitutions we are applying are trying
+ // to specialize this generic, but we don't already
+ // have a generic substitution in place.
+ // We will need to create one.
+
+ int diff = 0;
+ auto restSubst = specializeSubstitutions(
+ ancestorGenericDecl->ParentDecl,
+ substsToSpecialize,
+ substsToApply,
+ &diff);
+
+ RefPtr<GenericSubstitution> firstSubst = new GenericSubstitution();
+ firstSubst->genericDecl = ancestorGenericDecl;
+ firstSubst->args = appGenericSubst->args;
+ firstSubst->outer = restSubst;
+
+ (*ioDiff)++;
+ return firstSubst;
+ }
+ }
+ else if(auto ancestorInterfaceDecl = as<InterfaceDecl>(ancestorDecl))
+ {
+ // The task is basically the same as for the generic case:
+ // We want to see if there is any existing substitution that
+ // applies to this declaration, and use that if possible.
+
+ // The declaration is nested inside a generic.
+ // Does it already have a specialization for that generic?
+ if(auto specThisTypeSubst = as<ThisTypeSubstitution>(substsToSpecialize))
+ {
+ if(specThisTypeSubst->interfaceDecl == ancestorInterfaceDecl)
+ {
+ // Yes. We have an existing specialization, so we will
+ // keep one matching it in place.
+ int diff = 0;
+ auto restSubst = specializeSubstitutions(
+ ancestorInterfaceDecl->ParentDecl,
+ specThisTypeSubst->outer,
+ substsToApply,
+ &diff);
+
+ auto firstSubst = specializeSubstitutionsShallow(
+ specThisTypeSubst,
+ substsToApply,
+ restSubst,
+ &diff);
+
+ *ioDiff += diff;
+ return firstSubst;
+ }
+ }
+
+ // Otherwise, check if we are trying to apply
+ // a this-type substitution to the given interface
+ //
+ for(auto s = substsToApply; s; s = s->outer)
+ {
+ auto appThisTypeSubst = s.as<ThisTypeSubstitution>();
+ if(!appThisTypeSubst)
+ continue;
+
+ if(appThisTypeSubst->interfaceDecl != ancestorInterfaceDecl)
+ continue;
+
+ int diff = 0;
+ auto restSubst = specializeSubstitutions(
+ ancestorInterfaceDecl->ParentDecl,
+ substsToSpecialize,
+ substsToApply,
+ &diff);
+
+ RefPtr<ThisTypeSubstitution> firstSubst = new ThisTypeSubstitution();
+ firstSubst->interfaceDecl = ancestorInterfaceDecl;
+ firstSubst->witness = appThisTypeSubst->witness;
+ firstSubst->outer = restSubst;
+
+ (*ioDiff)++;
+ return firstSubst;
+ }
+ }
+ }
+
+ // If we reach here then we've walked the full hierarchy up from
+ // `declToSpecialize` and either didn't run into an generic/interface
+ // declarations, or we didn't find any attempt to specialize them
+ // in either substitution.
+ //
+ // As an invariant, there should *not* be any generic or this-type
+ // substitutions in `substToSpecialize`, because otherwise they
+ // would be specializations that don't actually apply to the given
+ // declaration.
+ //
+ // The remaining substitutions to apply, if any, should thus be
+ // global-generic substitutions. And similarly, those are the
+ // only remaining substitutions we really care about in
+ // `substsToApply`.
+ //
+ // Note: this does *not* mean that `substsToApply` doesn't have
+ // any generic or this-type substitutions; it just means that none
+ // of them were applicable.
+ //
+ return specializeGlobalGenericSubstitutions(
+ declToSpecialize,
+ substsToSpecialize,
+ substsToApply,
+ ioDiff);
+ }
+
+ DeclRefBase DeclRefBase::SubstituteImpl(SubstitutionSet substSet, int* ioDiff)
+ {
+ // Nothing to do when we have no declaration.
+ if(!decl)
+ return *this;
+
+ // Apply the given substitutions to any specializations
+ // that have already been applied to this declaration.
+ int diff = 0;
+
+ auto substSubst = specializeSubstitutions(
+ decl,
+ substitutions.substitutions,
+ substSet.substitutions,
+ &diff);
+
+ if (!diff)
+ return *this;
+
+ *ioDiff += diff;
+
+ DeclRefBase substDeclRef;
+ substDeclRef.decl = decl;
+ substDeclRef.substitutions = substSubst;
+
+ // TODO: The old code here used to try to translate a decl-ref
+ // to an associated type in a decl-ref for the concrete type
+ // in a particular implementation.
+ //
+ // I have only kept that logic in `DeclRefType::SubstituteImpl`,
+ // but it may turn out it is needed here too.
+
+ return substDeclRef;
+ }
+
+
+ // Check if this is an equivalent declaration reference to another
+ bool DeclRefBase::Equals(DeclRefBase const& declRef) const
+ {
+ if (decl != declRef.decl)
+ return false;
+ if (!substitutions.Equals(declRef.substitutions))
+ return false;
+
+ return true;
+ }
+
+ // Convenience accessors for common properties of declarations
+ Name* DeclRefBase::GetName() const
+ {
+ return decl->nameAndLoc.name;
+ }
+
+ SourceLoc DeclRefBase::getLoc() const
+ {
+ return decl->loc;
+ }
+
+ DeclRefBase DeclRefBase::GetParent() const
+ {
+ // Want access to the free function (the 'as' method by default gets priority)
+ // Can access as method with this->as because it removes any ambiguity.
+ using Slang::as;
+
+ auto parentDecl = decl->ParentDecl;
+ if (!parentDecl)
+ return DeclRefBase();
+
+ // Default is to apply the same set of substitutions/specializations
+ // to the parent declaration as were applied to the child.
+ RefPtr<Substitutions> substToApply = substitutions.substitutions;
+
+ if(auto interfaceDecl = as<InterfaceDecl>(decl))
+ {
+ // The declaration being referenced is an `interface` declaration,
+ // and there might be a this-type substitution in place.
+ // A reference to the parent of the interface declaration
+ // should not include that substitution.
+ if(auto thisTypeSubst = as<ThisTypeSubstitution>(substToApply))
+ {
+ if(thisTypeSubst->interfaceDecl == interfaceDecl)
+ {
+ // Strip away that specializations that apply to the interface.
+ substToApply = thisTypeSubst->outer;
+ }
+ }
+ }
+
+ if (auto parentGenericDecl = as<GenericDecl>(parentDecl))
+ {
+ // The parent of this declaration is a generic, which means
+ // that the decl-ref to the current declaration might include
+ // substitutions that specialize the generic parameters.
+ // A decl-ref to the parent generic should *not* include
+ // those substitutions.
+ //
+ if(auto genericSubst = as<GenericSubstitution>(substToApply))
+ {
+ if(genericSubst->genericDecl == parentGenericDecl)
+ {
+ // Strip away the specializations that were applied to the parent.
+ substToApply = genericSubst->outer;
+ }
+ }
+ }
+
+ return DeclRefBase(parentDecl, substToApply);
+ }
+
+ int DeclRefBase::GetHashCode() const
+ {
+ return combineHash(PointerHash<1>::GetHashCode(decl), substitutions.GetHashCode());
+ }
+
+ // Val
+
+ RefPtr<Val> Val::Substitute(SubstitutionSet subst)
+ {
+ if (!subst) return this;
+ int diff = 0;
+ return SubstituteImpl(subst, &diff);
+ }
+
+ RefPtr<Val> Val::SubstituteImpl(SubstitutionSet /*subst*/, int* /*ioDiff*/)
+ {
+ // Default behavior is to not substitute at all
+ return this;
+ }
+
+ // IntVal
+
+ IntegerLiteralValue GetIntVal(RefPtr<IntVal> val)
+ {
+ if (auto constantVal = as<ConstantIntVal>(val))
+ {
+ return constantVal->value;
+ }
+ SLANG_UNEXPECTED("needed a known integer value");
+ return 0;
+ }
+
+ // ConstantIntVal
+
+ bool ConstantIntVal::EqualsVal(Val* val)
+ {
+ if (auto intVal = as<ConstantIntVal>(val))
+ return value == intVal->value;
+ return false;
+ }
+
+ String ConstantIntVal::ToString()
+ {
+ return String(value);
+ }
+
+ int ConstantIntVal::GetHashCode()
+ {
+ return (int) value;
+ }
+
+ //
+
+ void registerBuiltinDecl(
+ Session* session,
+ RefPtr<Decl> decl,
+ RefPtr<BuiltinTypeModifier> modifier)
+ {
+ auto type = DeclRefType::Create(
+ session,
+ DeclRef<Decl>(decl.Ptr(), nullptr));
+ session->builtinTypes[(int)modifier->tag] = type;
+ }
+
+ void registerMagicDecl(
+ Session* session,
+ RefPtr<Decl> decl,
+ RefPtr<MagicTypeModifier> modifier)
+ {
+ session->magicDecls[modifier->name] = decl.Ptr();
+ }
+
+ RefPtr<Decl> findMagicDecl(
+ Session* session,
+ String const& name)
+ {
+ return session->magicDecls[name].GetValue();
+ }
+
+ //
+
+ SyntaxNodeBase* createInstanceOfSyntaxClassByName(
+ String const& name)
+ {
+ if(0) {}
+ #define CASE(NAME) \
+ else if(name == #NAME) return new NAME()
+
+ CASE(GLSLBufferModifier);
+ CASE(GLSLWriteOnlyModifier);
+ CASE(GLSLReadOnlyModifier);
+ CASE(GLSLPatchModifier);
+ CASE(SimpleModifier);
+
+ #undef CASE
+ else
+ {
+ SLANG_UNEXPECTED("unhandled syntax class name");
+ UNREACHABLE_RETURN(nullptr);
+ }
+ }
+
+ //
+
+ // HLSLPatchType
+
+ Type* HLSLPatchType::getElementType()
+ {
+ return as<Type>(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]);
+ }
+
+ IntVal* HLSLPatchType::getElementCount()
+ {
+ return as<IntVal>(findInnerMostGenericSubstitution(declRef.substitutions)->args[1]);
+ }
+
+ // Constructors for types
+
+ RefPtr<ArrayExpressionType> getArrayType(
+ Type* elementType,
+ IntVal* elementCount)
+ {
+ auto session = elementType->getSession();
+ auto arrayType = new ArrayExpressionType();
+ arrayType->setSession(session);
+ arrayType->baseType = elementType;
+ arrayType->ArrayLength = elementCount;
+ return arrayType;
+ }
+
+ RefPtr<ArrayExpressionType> getArrayType(
+ Type* elementType)
+ {
+ auto session = elementType->getSession();
+ auto arrayType = new ArrayExpressionType();
+ arrayType->setSession(session);
+ arrayType->baseType = elementType;
+ return arrayType;
+ }
+
+ RefPtr<NamedExpressionType> getNamedType(
+ Session* session,
+ DeclRef<TypeDefDecl> const& declRef)
+ {
+ DeclRef<TypeDefDecl> specializedDeclRef = createDefaultSubstitutionsIfNeeded(session, declRef).as<TypeDefDecl>();
+
+ auto namedType = new NamedExpressionType(specializedDeclRef);
+ namedType->setSession(session);
+ return namedType;
+ }
+
+ RefPtr<TypeType> getTypeType(
+ Type* type)
+ {
+ auto session = type->getSession();
+ auto typeType = new TypeType(type);
+ typeType->setSession(session);
+ return typeType;
+ }
+
+ RefPtr<FuncType> getFuncType(
+ Session* session,
+ DeclRef<CallableDecl> const& declRef)
+ {
+ RefPtr<FuncType> funcType = new FuncType();
+ funcType->setSession(session);
+
+ funcType->resultType = GetResultType(declRef);
+ for (auto paramDeclRef : GetParameters(declRef))
+ {
+ auto paramDecl = paramDeclRef.getDecl();
+ auto paramType = GetType(paramDeclRef);
+ if( paramDecl->FindModifier<RefModifier>() )
+ {
+ paramType = session->getRefType(paramType);
+ }
+ else if( paramDecl->FindModifier<OutModifier>() )
+ {
+ if(paramDecl->FindModifier<InOutModifier>() || paramDecl->FindModifier<InModifier>())
+ {
+ paramType = session->getInOutType(paramType);
+ }
+ else
+ {
+ paramType = session->getOutType(paramType);
+ }
+ }
+ funcType->paramTypes.add(paramType);
+ }
+
+ return funcType;
+ }
+
+ RefPtr<GenericDeclRefType> getGenericDeclRefType(
+ Session* session,
+ DeclRef<GenericDecl> const& declRef)
+ {
+ auto genericDeclRefType = new GenericDeclRefType(declRef);
+ genericDeclRefType->setSession(session);
+ return genericDeclRefType;
+ }
+
+ RefPtr<SamplerStateType> getSamplerStateType(
+ Session* session)
+ {
+ auto samplerStateType = new SamplerStateType();
+ samplerStateType->setSession(session);
+ return samplerStateType;
+ }
+
+ // TODO: should really have a `type.cpp` and a `witness.cpp`
+
+ bool TypeEqualityWitness::EqualsVal(Val* val)
+ {
+ auto otherWitness = as<TypeEqualityWitness>(val);
+ if (!otherWitness)
+ return false;
+ return sub->Equals(otherWitness->sub);
+ }
+
+ RefPtr<Val> TypeEqualityWitness::SubstituteImpl(SubstitutionSet subst, int * ioDiff)
+ {
+ RefPtr<TypeEqualityWitness> rs = new TypeEqualityWitness();
+ rs->sub = sub->SubstituteImpl(subst, ioDiff).as<Type>();
+ rs->sup = sup->SubstituteImpl(subst, ioDiff).as<Type>();
+ return rs;
+ }
+
+ String TypeEqualityWitness::ToString()
+ {
+ return "TypeEqualityWitness(" + sub->ToString() + ")";
+ }
+
+ int TypeEqualityWitness::GetHashCode()
+ {
+ return sub->GetHashCode();
+ }
+
+ bool DeclaredSubtypeWitness::EqualsVal(Val* val)
+ {
+ auto otherWitness = as<DeclaredSubtypeWitness>(val);
+ if(!otherWitness)
+ return false;
+
+ return sub->Equals(otherWitness->sub)
+ && sup->Equals(otherWitness->sup)
+ && declRef.Equals(otherWitness->declRef);
+ }
+
+ RefPtr<ThisTypeSubstitution> findThisTypeSubstitution(
+ Substitutions* substs,
+ InterfaceDecl* interfaceDecl)
+ {
+ for(RefPtr<Substitutions> s = substs; s; s = s->outer)
+ {
+ auto thisTypeSubst = as<ThisTypeSubstitution>(s);
+ if(!thisTypeSubst)
+ continue;
+
+ if(thisTypeSubst->interfaceDecl != interfaceDecl)
+ continue;
+
+ return thisTypeSubst;
+ }
+
+ return nullptr;
+ }
+
+ RefPtr<Val> DeclaredSubtypeWitness::SubstituteImpl(SubstitutionSet subst, int * ioDiff)
+ {
+ if (auto genConstraintDeclRef = declRef.as<GenericTypeConstraintDecl>())
+ {
+ auto genConstraintDecl = genConstraintDeclRef.getDecl();
+
+ // search for a substitution that might apply to us
+ for(auto s = subst.substitutions; s; s = s->outer)
+ {
+ if(auto genericSubst = as<GenericSubstitution>(s))
+ {
+ // the generic decl associated with the substitution list must be
+ // the generic decl that declared this parameter
+ auto genericDecl = genericSubst->genericDecl;
+ if (genericDecl != genConstraintDecl->ParentDecl)
+ continue;
+
+ bool found = false;
+ Index index = 0;
+ for (auto m : genericDecl->Members)
+ {
+ if (auto constraintParam = as<GenericTypeConstraintDecl>(m))
+ {
+ if (constraintParam == declRef.getDecl())
+ {
+ found = true;
+ break;
+ }
+ index++;
+ }
+ }
+ if (found)
+ {
+ (*ioDiff)++;
+ auto ordinaryParamCount = genericDecl->getMembersOfType<GenericTypeParamDecl>().getCount() +
+ genericDecl->getMembersOfType<GenericValueParamDecl>().getCount();
+ SLANG_ASSERT(index + ordinaryParamCount < genericSubst->args.getCount());
+ return genericSubst->args[index + ordinaryParamCount];
+ }
+ }
+ else if(auto globalGenericSubst = s.as<GlobalGenericParamSubstitution>())
+ {
+ // check if the substitution is really about this global generic type parameter
+ if (globalGenericSubst->paramDecl != genConstraintDecl->ParentDecl)
+ continue;
+
+ for(auto constraintArg : globalGenericSubst->constraintArgs)
+ {
+ if(constraintArg.decl.Ptr() != genConstraintDecl)
+ continue;
+
+ (*ioDiff)++;
+ return constraintArg.val;
+ }
+ }
+ }
+ }
+
+ // Perform substitution on the constituent elements.
+ int diff = 0;
+ auto substSub = sub->SubstituteImpl(subst, &diff).as<Type>();
+ auto substSup = sup->SubstituteImpl(subst, &diff).as<Type>();
+ auto substDeclRef = declRef.SubstituteImpl(subst, &diff);
+ if (!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ // If we have a reference to a type constraint for an
+ // associated type declaration, then we can replace it
+ // with the concrete conformance witness for a concrete
+ // type implementing the outer interface.
+ //
+ // TODO: It is a bit gross that we use `GenericTypeConstraintDecl` for
+ // associated types, when they aren't really generic type *parameters*,
+ // so we'll need to change this location in the code if we ever clean
+ // up the hierarchy.
+ //
+ if (auto substTypeConstraintDecl = as<GenericTypeConstraintDecl>(substDeclRef.decl))
+ {
+ if (auto substAssocTypeDecl = as<AssocTypeDecl>(substTypeConstraintDecl->ParentDecl))
+ {
+ if (auto interfaceDecl = as<InterfaceDecl>(substAssocTypeDecl->ParentDecl))
+ {
+ // At this point we have a constraint decl for an associated type,
+ // and we nee to see if we are dealing with a concrete substitution
+ // for the interface around that associated type.
+ if(auto thisTypeSubst = findThisTypeSubstitution(substDeclRef.substitutions, interfaceDecl))
+ {
+ // We need to look up the declaration that satisfies
+ // the requirement named by the associated type.
+ Decl* requirementKey = substTypeConstraintDecl;
+ RequirementWitness requirementWitness = tryLookUpRequirementWitness(thisTypeSubst->witness, requirementKey);
+ switch(requirementWitness.getFlavor())
+ {
+ default:
+ break;
+
+ case RequirementWitness::Flavor::val:
+ {
+ auto satisfyingVal = requirementWitness.getVal();
+ return satisfyingVal;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+ RefPtr<DeclaredSubtypeWitness> rs = new DeclaredSubtypeWitness();
+ rs->sub = substSub;
+ rs->sup = substSup;
+ rs->declRef = substDeclRef;
+ return rs;
+ }
+
+ String DeclaredSubtypeWitness::ToString()
+ {
+ StringBuilder sb;
+ sb << "DeclaredSubtypeWitness(";
+ sb << this->sub->ToString();
+ sb << ", ";
+ sb << this->sup->ToString();
+ sb << ", ";
+ sb << this->declRef.toString();
+ sb << ")";
+ return sb.ProduceString();
+ }
+
+ int DeclaredSubtypeWitness::GetHashCode()
+ {
+ return declRef.GetHashCode();
+ }
+
+ // TransitiveSubtypeWitness
+
+ bool TransitiveSubtypeWitness::EqualsVal(Val* val)
+ {
+ auto otherWitness = as<TransitiveSubtypeWitness>(val);
+ if(!otherWitness)
+ return false;
+
+ return sub->Equals(otherWitness->sub)
+ && sup->Equals(otherWitness->sup)
+ && subToMid->EqualsVal(otherWitness->subToMid)
+ && midToSup.Equals(otherWitness->midToSup);
+ }
+
+ RefPtr<Val> TransitiveSubtypeWitness::SubstituteImpl(SubstitutionSet subst, int * ioDiff)
+ {
+ int diff = 0;
+
+ RefPtr<Type> substSub = sub->SubstituteImpl(subst, &diff).as<Type>();
+ RefPtr<Type> substSup = sup->SubstituteImpl(subst, &diff).as<Type>();
+ RefPtr<SubtypeWitness> substSubToMid = subToMid->SubstituteImpl(subst, &diff).as<SubtypeWitness>();
+ DeclRef<Decl> substMidToSup = midToSup.SubstituteImpl(subst, &diff);
+
+ // If nothing changed, then we can bail out early.
+ if (!diff)
+ return this;
+
+ // Something changes, so let the caller know.
+ (*ioDiff)++;
+
+ // TODO: are there cases where we can simplify?
+ //
+ // In principle, if either `subToMid` or `midToSub` turns into
+ // a reflexive subtype witness, then we could drop that side,
+ // and just return the other one (this would imply that `sub == mid`
+ // or `mid == sup` after substitutions).
+ //
+ // In the long run, is it also possible that if `sub` gets resolved
+ // to a concrete type *and* we decide to flatten out the inheritance
+ // graph into a linearized "class precedence list" stored in any
+ // aggregate type, then we could potentially just redirect to point
+ // to the appropriate inheritance decl in the original type.
+ //
+ // For now I'm going to ignore those possibilities and hope for the best.
+
+ // In the simple case, we just construct a new transitive subtype
+ // witness, and we move on with life.
+ RefPtr<TransitiveSubtypeWitness> result = new TransitiveSubtypeWitness();
+ result->sub = substSub;
+ result->sup = substSup;
+ result->subToMid = substSubToMid;
+ result->midToSup = substMidToSup;
+ return result;
+ }
+
+ String TransitiveSubtypeWitness::ToString()
+ {
+ // Note: we only print the constituent
+ // witnesses, and rely on them to print
+ // the starting and ending types.
+ StringBuilder sb;
+ sb << "TransitiveSubtypeWitness(";
+ sb << this->subToMid->ToString();
+ sb << ", ";
+ sb << this->midToSup.toString();
+ sb << ")";
+ return sb.ProduceString();
+ }
+
+ int TransitiveSubtypeWitness::GetHashCode()
+ {
+ auto hash = sub->GetHashCode();
+ hash = combineHash(hash, sup->GetHashCode());
+ hash = combineHash(hash, subToMid->GetHashCode());
+ hash = combineHash(hash, midToSup.GetHashCode());
+ return hash;
+ }
+
+ //
+
+ String DeclRefBase::toString() const
+ {
+ if (!decl) return "";
+
+ auto name = decl->getName();
+ if (!name) return "";
+
+ // TODO: need to print out substitutions too!
+ return name->text;
+ }
+
+ bool SubstitutionSet::Equals(const SubstitutionSet& substSet) const
+ {
+ if (substitutions == substSet.substitutions)
+ {
+ return true;
+ }
+ if (substitutions == nullptr || substSet.substitutions == nullptr)
+ {
+ return false;
+ }
+ return substitutions->Equals(substSet.substitutions);
+ }
+
+ int SubstitutionSet::GetHashCode() const
+ {
+ int rs = 0;
+ if (substitutions)
+ rs = combineHash(rs, substitutions->GetHashCode());
+ return rs;
+ }
+
+ // ExtractExistentialType
+
+ String ExtractExistentialType::ToString()
+ {
+ String result;
+ result.append(declRef.toString());
+ result.append(".This");
+ return result;
+ }
+
+ bool ExtractExistentialType::EqualsImpl(Type* type)
+ {
+ if( auto extractExistential = as<ExtractExistentialType>(type) )
+ {
+ return declRef.Equals(extractExistential->declRef);
+ }
+ return false;
+ }
+
+ int ExtractExistentialType::GetHashCode()
+ {
+ return declRef.GetHashCode();
+ }
+
+ RefPtr<Type> ExtractExistentialType::CreateCanonicalType()
+ {
+ return this;
+ }
+
+ RefPtr<Val> ExtractExistentialType::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ int diff = 0;
+ auto substDeclRef = declRef.SubstituteImpl(subst, &diff);
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ RefPtr<ExtractExistentialType> substValue = new ExtractExistentialType();
+ substValue->declRef = declRef;
+ return substValue;
+ }
+
+ // ExtractExistentialSubtypeWitness
+
+ bool ExtractExistentialSubtypeWitness::EqualsVal(Val* val)
+ {
+ if( auto extractWitness = as<ExtractExistentialSubtypeWitness>(val) )
+ {
+ return declRef.Equals(extractWitness->declRef);
+ }
+ return false;
+ }
+
+ String ExtractExistentialSubtypeWitness::ToString()
+ {
+ String result;
+ result.append("extractExistentialValue(");
+ result.append(declRef.toString());
+ result.append(")");
+ return result;
+ }
+
+ int ExtractExistentialSubtypeWitness::GetHashCode()
+ {
+ return declRef.GetHashCode();
+ }
+
+ RefPtr<Val> ExtractExistentialSubtypeWitness::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ int diff = 0;
+
+ auto substDeclRef = declRef.SubstituteImpl(subst, &diff);
+ auto substSub = sub->SubstituteImpl(subst, &diff).as<Type>();
+ auto substSup = sup->SubstituteImpl(subst, &diff).as<Type>();
+
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ RefPtr<ExtractExistentialSubtypeWitness> substValue = new ExtractExistentialSubtypeWitness();
+ substValue->declRef = declRef;
+ substValue->sub = substSub;
+ substValue->sup = substSup;
+ return substValue;
+ }
+
+ //
+ // TaggedUnionType
+ //
+
+ String TaggedUnionType::ToString()
+ {
+ String result;
+ result.append("__TaggedUnion(");
+ bool first = true;
+ for( auto caseType : caseTypes )
+ {
+ if(!first) result.append(", ");
+ first = false;
+
+ result.append(caseType->ToString());
+ }
+ result.append(")");
+ return result;
+ }
+
+ bool TaggedUnionType::EqualsImpl(Type* type)
+ {
+ auto taggedUnion = as<TaggedUnionType>(type);
+ if(!taggedUnion)
+ return false;
+
+ auto caseCount = caseTypes.getCount();
+ if(caseCount != taggedUnion->caseTypes.getCount())
+ return false;
+
+ for( Index ii = 0; ii < caseCount; ++ii )
+ {
+ if(!caseTypes[ii]->Equals(taggedUnion->caseTypes[ii]))
+ return false;
+ }
+ return true;
+ }
+
+ int TaggedUnionType::GetHashCode()
+ {
+ int hashCode = 0;
+ for( auto caseType : caseTypes )
+ {
+ hashCode = combineHash(hashCode, caseType->GetHashCode());
+ }
+ return hashCode;
+ }
+
+ RefPtr<Type> TaggedUnionType::CreateCanonicalType()
+ {
+ RefPtr<TaggedUnionType> canType = new TaggedUnionType();
+ canType->setSession(getSession());
+
+ for( auto caseType : caseTypes )
+ {
+ auto canCaseType = caseType->GetCanonicalType();
+ canType->caseTypes.add(canCaseType);
+ }
+
+ return canType;
+ }
+
+ RefPtr<Val> TaggedUnionType::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+ {
+ int diff = 0;
+
+ List<RefPtr<Type>> substCaseTypes;
+ for( auto caseType : caseTypes )
+ {
+ substCaseTypes.add(caseType->SubstituteImpl(subst, &diff).as<Type>());
+ }
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ RefPtr<TaggedUnionType> substType = new TaggedUnionType();
+ substType->setSession(getSession());
+ substType->caseTypes.swapWith(substCaseTypes);
+ return substType;
+ }
+
+//
+// TaggedUnionSubtypeWitness
+//
+
+
+bool TaggedUnionSubtypeWitness::EqualsVal(Val* val)
+{
+ auto taggedUnionWitness = as<TaggedUnionSubtypeWitness>(val);
+ if(!taggedUnionWitness)
+ return false;
+
+ auto caseCount = caseWitnesses.getCount();
+ if(caseCount != taggedUnionWitness->caseWitnesses.getCount())
+ return false;
+
+ for(Index ii = 0; ii < caseCount; ++ii)
+ {
+ if(!caseWitnesses[ii]->EqualsVal(taggedUnionWitness->caseWitnesses[ii]))
+ return false;
+ }
+
+ return true;
+}
+
+String TaggedUnionSubtypeWitness::ToString()
+{
+ String result;
+ result.append("TaggedUnionSubtypeWitness(");
+ bool first = true;
+ for( auto caseWitness : caseWitnesses )
+ {
+ if(!first) result.append(", ");
+ first = false;
+
+ result.append(caseWitness->ToString());
+ }
+ return result;
+}
+
+int TaggedUnionSubtypeWitness::GetHashCode()
+{
+ int hash = 0;
+ for( auto caseWitness : caseWitnesses )
+ {
+ hash = combineHash(hash, caseWitness->GetHashCode());
+ }
+ return hash;
+}
+
+RefPtr<Val> TaggedUnionSubtypeWitness::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+{
+ int diff = 0;
+
+ auto substSub = sub->SubstituteImpl(subst, &diff).as<Type>();
+ auto substSup = sup->SubstituteImpl(subst, &diff).as<Type>();
+
+ List<RefPtr<Val>> substCaseWitnesses;
+ for( auto caseWitness : caseWitnesses )
+ {
+ substCaseWitnesses.add(caseWitness->SubstituteImpl(subst, &diff));
+ }
+
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ RefPtr<TaggedUnionSubtypeWitness> substWitness = new TaggedUnionSubtypeWitness();
+ substWitness->sub = substSub;
+ substWitness->sup = substSup;
+ substWitness->caseWitnesses.swapWith(substCaseWitnesses);
+ return substWitness;
+}
+
+Module* getModule(Decl* decl)
+{
+ for( auto dd = decl; dd; dd = dd->ParentDecl )
+ {
+ if(auto moduleDecl = as<ModuleDecl>(dd))
+ return moduleDecl->module;
+ }
+ return nullptr;
+}
+
+bool findImageFormatByName(char const* name, ImageFormat* outFormat)
+{
+ static const struct
+ {
+ char const* name;
+ ImageFormat format;
+ } kFormats[] =
+ {
+#define FORMAT(NAME) { #NAME, ImageFormat::NAME },
+#include "slang-image-format-defs.h"
+ };
+
+ for( auto item : kFormats )
+ {
+ if( strcmp(item.name, name) == 0 )
+ {
+ *outFormat = item.format;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+char const* getGLSLNameForImageFormat(ImageFormat format)
+{
+ switch( format )
+ {
+ default: return "unhandled";
+#define FORMAT(NAME) case ImageFormat::NAME: return #NAME;
+#include "slang-image-format-defs.h"
+ }
+}
+
+//
+// ExistentialSpecializedType
+//
+
+String ExistentialSpecializedType::ToString()
+{
+ String result;
+ result.append("__ExistentialSpecializedType(");
+ result.append(baseType->ToString());
+ for( auto arg : slots.args )
+ {
+ result.append(", ");
+ result.append(arg.type->ToString());
+ }
+ result.append(")");
+ return result;
+}
+
+bool ExistentialSpecializedType::EqualsImpl(Type * type)
+{
+ auto other = as<ExistentialSpecializedType>(type);
+ if(!other)
+ return false;
+
+ if(!baseType->Equals(other->baseType))
+ return false;
+
+ auto argCount = slots.args.getCount();
+ if(argCount != other->slots.args.getCount())
+ return false;
+
+ for( Index ii = 0; ii < argCount; ++ii )
+ {
+ if(!slots.args[ii].type->Equals(other->slots.args[ii].type))
+ return false;
+
+ if(!slots.args[ii].witness->EqualsVal(other->slots.args[ii].witness))
+ return false;
+ }
+ return true;
+}
+
+int ExistentialSpecializedType::GetHashCode()
+{
+ Hasher hasher;
+ hasher.hashObject(baseType);
+ for(auto arg : slots.args)
+ {
+ hasher.hashObject(arg.type);
+ hasher.hashObject(arg.witness);
+ }
+ return hasher.getResult();
+}
+
+RefPtr<Type> ExistentialSpecializedType::CreateCanonicalType()
+{
+ RefPtr<ExistentialSpecializedType> canType = new ExistentialSpecializedType();
+ canType->setSession(getSession());
+
+ canType->baseType = baseType->GetCanonicalType();
+ for( auto paramType : slots.paramTypes )
+ {
+ canType->slots.paramTypes.add( paramType->GetCanonicalType() );
+ }
+ for( auto arg : slots.args )
+ {
+ ExistentialTypeSlots::Arg canArg;
+ canArg.type = arg.type->GetCanonicalType();
+ canArg.witness = arg.witness;
+ canType->slots.args.add(canArg);
+ }
+ return canType;
+}
+
+RefPtr<Val> ExistentialSpecializedType::SubstituteImpl(SubstitutionSet subst, int* ioDiff)
+{
+ int diff = 0;
+
+ auto substBaseType = baseType->SubstituteImpl(subst, &diff).as<Type>();
+
+ ExistentialTypeSlots substSlots;
+ for( auto paramType : slots.paramTypes )
+ {
+ substSlots.paramTypes.add( paramType->SubstituteImpl(subst, &diff).as<Type>() );
+ }
+ for( auto arg : slots.args )
+ {
+ ExistentialTypeSlots::Arg substArg;
+ substArg.type = arg.type->SubstituteImpl(subst, &diff).as<Type>();
+ substArg.witness = arg.witness->SubstituteImpl(subst, &diff);
+ substSlots.args.add(substArg);
+ }
+
+ if(!diff)
+ return this;
+
+ (*ioDiff)++;
+
+ RefPtr<ExistentialSpecializedType> substType = new ExistentialSpecializedType();
+ substType->setSession(getSession());
+ substType->baseType = substBaseType;
+ substType->slots = substSlots;
+ return substType;
+}
+
+} // namespace Slang