From 1b8731c809761c4e2dbec81dcee207f8a4621903 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Wed, 3 Jun 2020 17:22:48 -0400 Subject: Devirtualize AST types (#1368) * Make getSup work with more general non-virtual 'virtual' mechanism. * WIP: Non virtual AST types. * Project change. * Type doesn't implement equalsImpl * Fix macro invocation Make Overridden functions public to make simply accessible by base types. * Use SLANG_UNEXPECTED. * GetScalarType -> getScalarType Use SLANG_UNEXPECTED instead on ASSERT in NamedExpressionType and TypeType --- source/slang/slang-ast-base.h | 91 +- source/slang/slang-ast-decl.cpp | 21 + source/slang/slang-ast-decl.h | 27 +- source/slang/slang-ast-reflect.h | 24 +- source/slang/slang-ast-substitutions.cpp | 237 +++ source/slang/slang-ast-type.cpp | 972 ++++++++++++ source/slang/slang-ast-type.h | 194 +-- source/slang/slang-ast-val.cpp | 552 +++++++ source/slang/slang-ast-val.h | 74 +- source/slang/slang-syntax.cpp | 2556 ++++++------------------------ source/slang/slang-syntax.h | 11 + source/slang/slang.vcxproj | 4 + source/slang/slang.vcxproj.filters | 12 + 13 files changed, 2505 insertions(+), 2270 deletions(-) create mode 100644 source/slang/slang-ast-decl.cpp create mode 100644 source/slang/slang-ast-substitutions.cpp create mode 100644 source/slang/slang-ast-type.cpp create mode 100644 source/slang/slang-ast-val.cpp (limited to 'source') diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h index 5f40cba49..05d2ded69 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -98,15 +98,21 @@ class Val : public NodeBase // integer parameter that should be incremented when // returning a modified value (this can help the caller // decide whether they need to do anything). - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); - virtual bool equalsVal(Val* val) = 0; - virtual String toString() = 0; - virtual HashCode getHashCode() = 0; + bool equalsVal(Val* val); + String toString(); + HashCode getHashCode(); bool operator == (const Val & v) { return equalsVal(const_cast(&v)); } + + // Overrides should be public so base classes can access + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); }; class Type; @@ -144,22 +150,22 @@ class Type: public Val /// Get the ASTBuilder that was used to construct this Type SLANG_FORCE_INLINE ASTBuilder* getASTBuilder() const { return m_astBuilder; } - //Session* getSession() { return this->session; } - bool equals(Type* type); Type* getCanonicalType(); - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; - - virtual bool equalsVal(Val* val) override; - ~Type(); + // Overrides should be public so base classes can access + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + bool _equalsValOverride(Val* val); + bool _equalsImplOverride(Type* type); + RefPtr _createCanonicalTypeOverride(); + protected: - virtual bool equalsImpl(Type* type) = 0; + bool equalsImpl(Type* type); + RefPtr createCanonicalType(); - virtual RefPtr createCanonicalType() = 0; Type* canonicalType = nullptr; SLANG_UNREFLECTED @@ -181,11 +187,16 @@ class Substitutions: public NodeBase RefPtr outer; // Apply a set of substitutions to the bindings in this substitution - virtual RefPtr applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) = 0; + RefPtr applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff); // Check if these are equivalent substitutions to another set - virtual bool equals(Substitutions* subst) = 0; - virtual HashCode getHashCode() const = 0; + bool equals(Substitutions* subst); + HashCode getHashCode() const; + + // Overrides should be public so base classes can access + RefPtr _applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff); + bool _equalsOverride(Substitutions* subst); + HashCode _getHashCodeOverride() const; }; class GenericSubstitution : public Substitutions @@ -199,22 +210,10 @@ class GenericSubstitution : public Substitutions // The actual values of the arguments List > args; - // Apply a set of substitutions to the bindings in this substitution - virtual RefPtr applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) override; - - // Check if these are equivalent substitutions to another set - virtual bool equals(Substitutions* subst) override; - - virtual HashCode getHashCode() const override - { - HashCode rs = 0; - for (auto && v : args) - { - rs ^= v->getHashCode(); - rs *= 16777619; - } - return rs; - } + // Overrides should be public so base classes can access + RefPtr _applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff); + bool _equalsOverride(Substitutions* subst); + HashCode _getHashCodeOverride() const; }; class ThisTypeSubstitution : public Substitutions @@ -228,14 +227,11 @@ class ThisTypeSubstitution : public Substitutions // specialize the interface conforms to the interface. RefPtr witness; + // Overrides should be public so base classes can access // The actual type that provides the lookup scope for an associated type - // Apply a set of substitutions to the bindings in this substitution - virtual RefPtr applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) override; - - // Check if these are equivalent substitutions to another set - virtual bool equals(Substitutions* subst) override; - - virtual HashCode getHashCode() const override; + RefPtr _applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff); + bool _equalsOverride(Substitutions* subst); + HashCode _getHashCodeOverride() const; }; class GlobalGenericParamSubstitution : public Substitutions @@ -256,21 +252,10 @@ class GlobalGenericParamSubstitution : public Substitutions // the values that satisfy any constraints on the type parameter List constraintArgs; - // Apply a set of substitutions to the bindings in this substitution - virtual RefPtr applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) override; - - // Check if these are equivalent substitutions to another set - virtual bool equals(Substitutions* subst) override; - - virtual HashCode getHashCode() const override - { - HashCode rs = actualType->getHashCode(); - for (auto && a : constraintArgs) - { - rs = combineHash(rs, a.val->getHashCode()); - } - return rs; - } + // Overrides should be public so base classes can access + RefPtr _applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff); + bool _equalsOverride(Substitutions* subst); + HashCode _getHashCodeOverride() const; }; class SyntaxNode : public SyntaxNodeBase diff --git a/source/slang/slang-ast-decl.cpp b/source/slang/slang-ast-decl.cpp new file mode 100644 index 000000000..a10411ebb --- /dev/null +++ b/source/slang/slang-ast-decl.cpp @@ -0,0 +1,21 @@ +// slang-ast-decl.cpp +#include "slang-ast-builder.h" +#include + +#include "slang-ast-generated-macro.h" + +namespace Slang { + +const TypeExp& TypeConstraintDecl::getSup() const +{ + SLANG_AST_NODE_CONST_VIRTUAL_CALL(TypeConstraintDecl, getSup, ()) +} + +const TypeExp& TypeConstraintDecl::_getSupOverride() const +{ + SLANG_UNEXPECTED("TypeConstraintDecl::_getSupOverride not overridden"); + //return TypeExp::empty; +} + + +} // namespace Slang diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index 54e8ac18b..bdb9b8ad8 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -171,8 +171,11 @@ class InterfaceDecl : public AggTypeDecl class TypeConstraintDecl : public Decl { SLANG_ABSTRACT_CLASS(TypeConstraintDecl) - - SLANG_INLINE const TypeExp& getSup() const; + + 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; }; // A kind of pseudo-member that represents an explicit @@ -190,6 +193,9 @@ class InheritanceDecl : public TypeConstraintDecl // implementations in the type that contains // this inheritance declaration. RefPtr witnessTable; + + // 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 @@ -403,6 +409,9 @@ class GenericTypeConstraintDecl : public TypeConstraintDecl // think of these fields as the sub-type and super-type, respectively. TypeExp sub; TypeExp sup; + + // Overrides should be public so base classes can access + const TypeExp& _getSupOverride() const { return sup; } }; class GenericValueParamDecl : public VarDeclBase @@ -450,18 +459,4 @@ class AttributeDecl : public ContainerDecl SyntaxClass syntaxClass; }; -// ------------------------------------------------------------------------ - -const TypeExp& TypeConstraintDecl::getSup() const -{ - ASTNodeType type = ASTNodeType(getClassInfo().m_classId); - switch (type) - { - case ASTNodeType::InheritanceDecl: return static_cast(this)->base; - case ASTNodeType::GenericTypeConstraintDecl: return static_cast(this)->sup; - default: SLANG_ASSERT(!"getSup not implemented for this type!"); return TypeExp::empty; - } -} - - } // namespace Slang diff --git a/source/slang/slang-ast-reflect.h b/source/slang/slang-ast-reflect.h index 2c629e839..82fb80b22 100644 --- a/source/slang/slang-ast-reflect.h +++ b/source/slang/slang-ast-reflect.h @@ -16,7 +16,7 @@ static const ReflectClassInfo kReflectClassInfo; \ SLANG_FORCE_INLINE static bool isDerivedFrom(ASTNodeType type) { return int(type) >= int(kType) && int(type) <= int(ASTNodeType::LAST); } \ friend class ASTBuilder; \ - friend struct ASTConstructAccess; + friend struct ASTConstructAccess; // Macro definitions - use the SLANG_ASTNode_ definitions to invoke the IMPL to produce the code // injected into AST classes @@ -28,4 +28,26 @@ #define SLANG_REFLECTED #define SLANG_UNREFLECTED +// Macros for simulating virtual methods without virtual methods + +#define SLANG_AST_NODE_INVOKE(method, methodParams) _##method##Override methodParams + +#define SLANG_AST_NODE_CASE(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) case ASTNodeType::NAME: return static_cast(this)-> SLANG_AST_NODE_INVOKE param; + +#define SLANG_AST_NODE_VIRTUAL_CALL(base, methodName, methodParams) \ + switch (astNodeType) \ + { \ + SLANG_ALL_ASTNode_##base(SLANG_AST_NODE_CASE, (methodName, methodParams)) \ + default: return SLANG_AST_NODE_INVOKE (methodName, methodParams); \ + } + +// Same but for a method that's const +#define SLANG_AST_NODE_CONST_CASE(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) case ASTNodeType::NAME: return static_cast(this)-> SLANG_AST_NODE_INVOKE param; +#define SLANG_AST_NODE_CONST_VIRTUAL_CALL(base, methodName, methodParams) \ + switch (astNodeType) \ + { \ + SLANG_ALL_ASTNode_##base(SLANG_AST_NODE_CONST_CASE, (methodName, methodParams)) \ + default: return SLANG_AST_NODE_INVOKE (methodName, methodParams); \ + } + #endif // SLANG_AST_REFLECT_H diff --git a/source/slang/slang-ast-substitutions.cpp b/source/slang/slang-ast-substitutions.cpp new file mode 100644 index 000000000..05865fe8f --- /dev/null +++ b/source/slang/slang-ast-substitutions.cpp @@ -0,0 +1,237 @@ +// slang-ast-substitutions.cpp +#include "slang-ast-builder.h" +#include + +#include "slang-ast-generated-macro.h" + +namespace Slang { + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Substitutions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +RefPtr Substitutions::applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) +{ + SLANG_AST_NODE_VIRTUAL_CALL(Substitutions, applySubstitutionsShallow, (astBuilder, substSet, substOuter, ioDiff)) +} + +bool Substitutions::equals(Substitutions* subst) +{ + SLANG_AST_NODE_VIRTUAL_CALL(Substitutions, equals, (subst)) +} + +HashCode Substitutions::getHashCode() const +{ + SLANG_AST_NODE_CONST_VIRTUAL_CALL(Substitutions, getHashCode, ()) +} + +RefPtr Substitutions::_applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) +{ + SLANG_UNUSED(astBuilder); + SLANG_UNUSED(substSet); + SLANG_UNUSED(substOuter); + SLANG_UNUSED(ioDiff); + SLANG_UNEXPECTED("Substitutions::_applySubstitutionsShallowOverride not overridden"); + //return RefPtr(); +} + +bool Substitutions::_equalsOverride(Substitutions* subst) +{ + SLANG_UNUSED(subst); + SLANG_UNEXPECTED("Substitutions::_equalsOverride not overridden"); + //return false; +} + +HashCode Substitutions::_getHashCodeOverride() const +{ + SLANG_UNEXPECTED("Substitutions::_getHashCodeOverride not overridden"); + //return HashCode(0); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericSubstitution !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +RefPtr GenericSubstitution::_applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) +{ + int diff = 0; + + if (substOuter != outer) diff++; + + List> substArgs; + for (auto a : args) + { + substArgs.add(a->substituteImpl(astBuilder, substSet, &diff)); + } + + if (!diff) return this; + + (*ioDiff)++; + auto substSubst = astBuilder->create(); + substSubst->genericDecl = genericDecl; + substSubst->args = substArgs; + substSubst->outer = substOuter; + return substSubst; +} + +bool GenericSubstitution::_equalsOverride(Substitutions* subst) +{ + // both must be NULL, or non-NULL + if (subst == nullptr) + return false; + if (this == subst) + return true; + + auto genericSubst = as(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; +} + +HashCode GenericSubstitution::_getHashCodeOverride() const +{ + HashCode rs = 0; + for (auto && v : args) + { + rs ^= v->getHashCode(); + rs *= 16777619; + } + return rs; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ThisTypeSubstitution !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +RefPtr ThisTypeSubstitution::_applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr 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(astBuilder, substSet, &diff).as(); + + if (!diff) return this; + + (*ioDiff)++; + auto substSubst = astBuilder->create(); + substSubst->interfaceDecl = interfaceDecl; + substSubst->witness = substWitness; + substSubst->outer = substOuter; + return substSubst; +} + +bool ThisTypeSubstitution::_equalsOverride(Substitutions* subst) +{ + if (!subst) + return false; + if (subst == this) + return true; + + if (auto thisTypeSubst = as(subst)) + { + // For our purposes, two this-type substitutions are + // equivalent if they have the same type as `This`, + // even if the specific witness values they use + // might differ. + // + if (this->interfaceDecl != thisTypeSubst->interfaceDecl) + return false; + + if (!this->witness->sub->equals(thisTypeSubst->witness->sub)) + return false; + + return true; + } + return false; +} + +HashCode ThisTypeSubstitution::_getHashCodeOverride() const +{ + return witness->getHashCode(); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GlobalGenericParamSubstitution !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +RefPtr GlobalGenericParamSubstitution::_applySubstitutionsShallowOverride(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr 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(astBuilder, substSet, &diff).as(); + + List substConstraintArgs; + for (auto constraintArg : constraintArgs) + { + ConstraintArg substConstraintArg; + substConstraintArg.decl = constraintArg.decl; + substConstraintArg.val = constraintArg.val->substituteImpl(astBuilder, substSet, &diff); + + substConstraintArgs.add(substConstraintArg); + } + + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substSubst = astBuilder->create(); + substSubst->paramDecl = paramDecl; + substSubst->actualType = substActualType; + substSubst->constraintArgs = substConstraintArgs; + substSubst->outer = substOuter; + return substSubst; +} + +bool GlobalGenericParamSubstitution::_equalsOverride(Substitutions* subst) +{ + if (!subst) + return false; + if (subst == this) + return true; + + if (auto genSubst = as(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; +} + +HashCode GlobalGenericParamSubstitution::_getHashCodeOverride() const +{ + HashCode rs = actualType->getHashCode(); + for (auto && a : constraintArgs) + { + rs = combineHash(rs, a.val->getHashCode()); + } + return rs; +} + + +} // namespace Slang diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp new file mode 100644 index 000000000..48e95562e --- /dev/null +++ b/source/slang/slang-ast-type.cpp @@ -0,0 +1,972 @@ +// slang-ast-type.cpp +#include "slang-ast-builder.h" +#include +#include + +#include "slang-syntax.h" + +#include "slang-ast-generated-macro.h" + +namespace Slang { + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Type !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +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(); + } +} + +RefPtr Type::createCanonicalType() +{ + SLANG_AST_NODE_VIRTUAL_CALL(Type, createCanonicalType, ()) +} + +bool Type::equals(Type* type) +{ + return getCanonicalType()->equalsImpl(type->getCanonicalType()); +} + +bool Type::equalsImpl(Type* type) +{ + SLANG_AST_NODE_VIRTUAL_CALL(Type, equalsImpl, (type)) +} + +bool Type::_equalsImplOverride(Type* type) +{ + SLANG_UNUSED(type) + SLANG_UNEXPECTED("Type::_equalsImplOverride not overridden"); + //return false; +} + +RefPtr Type::_createCanonicalTypeOverride() +{ + SLANG_UNEXPECTED("Type::_createCanonicalTypeOverride not overridden"); + //return RefPtr(); +} + +bool Type::_equalsValOverride(Val* val) +{ + if (auto type = dynamicCast(val)) + return const_cast(this)->equals(type); + return false; +} + +RefPtr Type::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + auto canSubst = getCanonicalType()->substituteImpl(astBuilder, 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(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; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OverloadGroupType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String OverloadGroupType::_toStringOverride() +{ + return "overload group"; +} + +bool OverloadGroupType::_equalsImplOverride(Type * /*type*/) +{ + return false; +} + +RefPtr OverloadGroupType::_createCanonicalTypeOverride() +{ + return this; +} + +HashCode OverloadGroupType::_getHashCodeOverride() +{ + return (HashCode)(size_t(this)); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! InitializerListType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String InitializerListType::_toStringOverride() +{ + return "initializer list"; +} + +bool InitializerListType::_equalsImplOverride(Type * /*type*/) +{ + return false; +} + +RefPtr InitializerListType::_createCanonicalTypeOverride() +{ + return this; +} + +HashCode InitializerListType::_getHashCodeOverride() +{ + return (HashCode)(size_t(this)); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ErrorType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String ErrorType::_toStringOverride() +{ + return "error"; +} + +bool ErrorType::_equalsImplOverride(Type* type) +{ + if (auto errorType = as(type)) + return true; + return false; +} + +RefPtr ErrorType::_createCanonicalTypeOverride() +{ + return this; +} + +RefPtr ErrorType::_substituteImplOverride(ASTBuilder* /* astBuilder */, SubstitutionSet /*subst*/, int* /*ioDiff*/) +{ + return this; +} + +HashCode ErrorType::_getHashCodeOverride() +{ + return HashCode(size_t(this)); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DeclRefType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String DeclRefType::_toStringOverride() +{ + return declRef.toString(); +} + +HashCode DeclRefType::_getHashCodeOverride() +{ + return (declRef.getHashCode() * 16777619) ^ (HashCode)(typeid(this).hash_code()); +} + +bool DeclRefType::_equalsImplOverride(Type * type) +{ + if (auto declRefType = as(type)) + { + return declRef.equals(declRefType->declRef); + } + return false; +} + +RefPtr DeclRefType::_createCanonicalTypeOverride() +{ + // A declaration reference is already canonical + return this; +} + +RefPtr DeclRefType::_substituteImplOverride(ASTBuilder* astBuilder, 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(declRef.getDecl())) + { + // search for a substitution that might apply to us + for (auto s = subst.substitutions; s; s = s->outer) + { + auto genericSubst = s.as(); + 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(m)) + { + index++; + } + else if (auto valParam = as(m)) + { + index++; + } + else + { + } + } + } + } + else if (auto globalGenParam = as(declRef.getDecl())) + { + // search for a substitution that might apply to us + for (auto s = subst.substitutions; s; s = s->outer) + { + auto genericSubst = as(s); + if (!genericSubst) + continue; + + if (genericSubst->paramDecl == globalGenParam) + { + (*ioDiff)++; + return genericSubst->actualType; + } + } + } + int diff = 0; + DeclRef substDeclRef = declRef.substituteImpl(astBuilder, 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(substDeclRef.decl)) + { + for (auto s = substDeclRef.substitutions.substitutions; s; s = s->outer) + { + auto thisSubst = s.as(); + if (!thisSubst) + continue; + + if (auto interfaceDecl = as(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(astBuilder, 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(astBuilder, substDeclRef); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArithmeticExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +BasicExpressionType* ArithmeticExpressionType::getScalarType() +{ + SLANG_AST_NODE_VIRTUAL_CALL(ArithmeticExpressionType, getScalarType, ()) +} + +BasicExpressionType* ArithmeticExpressionType::_getScalarTypeOverride() +{ + SLANG_UNEXPECTED("ArithmeticExpressionType::_getScalarTypeOverride not overridden"); + //return nullptr; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BasicExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool BasicExpressionType::_equalsImplOverride(Type * type) +{ + auto basicType = as(type); + return basicType && basicType->baseType == this->baseType; +} + +RefPtr BasicExpressionType::_createCanonicalTypeOverride() +{ + // A basic type is already canonical, in our setup + return this; +} + +BasicExpressionType* BasicExpressionType::_getScalarTypeOverride() +{ + return this; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VectorExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String VectorExpressionType::_toStringOverride() +{ + StringBuilder sb; + sb << "vector<" << elementType->toString() << "," << elementCount->toString() << ">"; + return sb.ProduceString(); +} + +BasicExpressionType* VectorExpressionType::_getScalarTypeOverride() +{ + return as(elementType); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MatrixExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String MatrixExpressionType::_toStringOverride() +{ + StringBuilder sb; + sb << "matrix<" << getElementType()->toString() << "," << getRowCount()->toString() << "," << getColumnCount()->toString() << ">"; + return sb.ProduceString(); +} + +BasicExpressionType* MatrixExpressionType::_getScalarTypeOverride() +{ + return as(getElementType()); +} + +Type* MatrixExpressionType::getElementType() +{ + return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]); +} + +IntVal* MatrixExpressionType::getRowCount() +{ + return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[1]); +} + +IntVal* MatrixExpressionType::getColumnCount() +{ + return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[2]); +} + +RefPtr MatrixExpressionType::getRowType() +{ + if (!rowType) + { + rowType = m_astBuilder->getVectorType(getElementType(), getColumnCount()); + } + return rowType; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool ArrayExpressionType::_equalsImplOverride(Type* type) +{ + auto arrType = as(type); + if (!arrType) + return false; + return (areValsEqual(arrayLength, arrType->arrayLength) && baseType->equals(arrType->baseType.Ptr())); +} + +RefPtr ArrayExpressionType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + auto elementType = baseType->substituteImpl(astBuilder, subst, &diff).as(); + auto arrlen = arrayLength->substituteImpl(astBuilder, subst, &diff).as(); + SLANG_ASSERT(arrlen); + if (diff) + { + *ioDiff = 1; + auto rsType = getArrayType( + astBuilder, + elementType, + arrlen); + return rsType; + } + return this; +} + +RefPtr ArrayExpressionType::_createCanonicalTypeOverride() +{ + auto canonicalElementType = baseType->getCanonicalType(); + auto canonicalArrayType = getASTBuilder()->getArrayType( + canonicalElementType, + arrayLength); + return canonicalArrayType; +} + +HashCode ArrayExpressionType::_getHashCodeOverride() +{ + if (arrayLength) + return (baseType->getHashCode() * 16777619) ^ arrayLength->getHashCode(); + else + return baseType->getHashCode(); +} + +Slang::String ArrayExpressionType::_toStringOverride() +{ + if (arrayLength) + return baseType->toString() + "[" + arrayLength->toString() + "]"; + else + return baseType->toString() + "[]"; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TypeType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String TypeType::_toStringOverride() +{ + StringBuilder sb; + sb << "typeof(" << type->toString() << ")"; + return sb.ProduceString(); +} + +bool TypeType::_equalsImplOverride(Type * t) +{ + if (auto typeType = as(t)) + { + return t->equals(typeType->type); + } + return false; +} + +RefPtr TypeType::_createCanonicalTypeOverride() +{ + return getASTBuilder()->getTypeType(type->getCanonicalType()); +} + +HashCode TypeType::_getHashCodeOverride() +{ + SLANG_UNEXPECTED("TypeType::_getHashCodeOverride should be unreachable"); + //return HashCode(0); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericDeclRefType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String GenericDeclRefType::_toStringOverride() +{ + // TODO: what is appropriate here? + return ">"; +} + +bool GenericDeclRefType::_equalsImplOverride(Type * type) +{ + if (auto genericDeclRefType = as(type)) + { + return declRef.equals(genericDeclRefType->declRef); + } + return false; +} + +HashCode GenericDeclRefType::_getHashCodeOverride() +{ + return declRef.getHashCode(); +} + +RefPtr GenericDeclRefType::_createCanonicalTypeOverride() +{ + return this; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NamespaceType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String NamespaceType::_toStringOverride() +{ + String result; + result.append("namespace "); + result.append(declRef.toString()); + return result; +} + +bool NamespaceType::_equalsImplOverride(Type * type) +{ + if (auto namespaceType = as(type)) + { + return declRef.equals(namespaceType->declRef); + } + return false; +} + +HashCode NamespaceType::_getHashCodeOverride() +{ + return declRef.getHashCode(); +} + +RefPtr NamespaceType::_createCanonicalTypeOverride() +{ + return this; +} + + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PtrTypeBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Type* PtrTypeBase::getValueType() +{ + return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NamedExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String NamedExpressionType::_toStringOverride() +{ + return getText(declRef.getName()); +} + +bool NamedExpressionType::_equalsImplOverride(Type * /*type*/) +{ + SLANG_UNEXPECTED("NamedExpressionType::_equalsImplOverride should be unreachable"); + //return false; +} + +RefPtr NamedExpressionType::_createCanonicalTypeOverride() +{ + if (!innerType) + innerType = getType(m_astBuilder, declRef); + return innerType->getCanonicalType(); +} + +HashCode NamedExpressionType::_getHashCodeOverride() +{ + // 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::_toStringOverride() +{ + 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::_equalsImplOverride(Type * type) +{ + if (auto funcType = as(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 FuncType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + // result type + RefPtr substResultType = resultType->substituteImpl(astBuilder, subst, &diff).as(); + + // parameter types + List> substParamTypes; + for (auto pp : paramTypes) + { + substParamTypes.add(pp->substituteImpl(astBuilder, subst, &diff).as()); + } + + // early exit for no change... + if (!diff) + return this; + + (*ioDiff)++; + RefPtr substType = astBuilder->create(); + substType->resultType = substResultType; + substType->paramTypes = substParamTypes; + return substType; +} + +RefPtr FuncType::_createCanonicalTypeOverride() +{ + // result type + RefPtr canResultType = resultType->getCanonicalType(); + + // parameter types + List> canParamTypes; + for (auto pp : paramTypes) + { + canParamTypes.add(pp->getCanonicalType()); + } + + RefPtr canType = getASTBuilder()->create(); + canType->resultType = resultType; + canType->paramTypes = canParamTypes; + + return canType; +} + +HashCode FuncType::_getHashCodeOverride() +{ + HashCode 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; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExtractExistentialType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String ExtractExistentialType::_toStringOverride() +{ + String result; + result.append(declRef.toString()); + result.append(".This"); + return result; +} + +bool ExtractExistentialType::_equalsImplOverride(Type* type) +{ + if (auto extractExistential = as(type)) + { + return declRef.equals(extractExistential->declRef); + } + return false; +} + +HashCode ExtractExistentialType::_getHashCodeOverride() +{ + return declRef.getHashCode(); +} + +RefPtr ExtractExistentialType::_createCanonicalTypeOverride() +{ + return this; +} + +RefPtr ExtractExistentialType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substValue = astBuilder->create(); + substValue->declRef = declRef; + return substValue; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TaggedUnionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String TaggedUnionType::_toStringOverride() +{ + 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::_equalsImplOverride(Type* type) +{ + auto taggedUnion = as(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; +} + +HashCode TaggedUnionType::_getHashCodeOverride() +{ + HashCode hashCode = 0; + for (auto caseType : caseTypes) + { + hashCode = combineHash(hashCode, caseType->getHashCode()); + } + return hashCode; +} + +RefPtr TaggedUnionType::_createCanonicalTypeOverride() +{ + RefPtr canType = m_astBuilder->create(); + + for (auto caseType : caseTypes) + { + auto canCaseType = caseType->getCanonicalType(); + canType->caseTypes.add(canCaseType); + } + + return canType; +} + +RefPtr TaggedUnionType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + List> substCaseTypes; + for (auto caseType : caseTypes) + { + substCaseTypes.add(caseType->substituteImpl(astBuilder, subst, &diff).as()); + } + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substType = astBuilder->create(); + substType->caseTypes.swapWith(substCaseTypes); + return substType; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExistentialSpecializedType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String ExistentialSpecializedType::_toStringOverride() +{ + String result; + result.append("__ExistentialSpecializedType("); + result.append(baseType->toString()); + for (auto arg : args) + { + result.append(", "); + result.append(arg.val->toString()); + } + result.append(")"); + return result; +} + +bool ExistentialSpecializedType::_equalsImplOverride(Type * type) +{ + auto other = as(type); + if (!other) + return false; + + if (!baseType->equals(other->baseType)) + return false; + + auto argCount = args.getCount(); + if (argCount != other->args.getCount()) + return false; + + for (Index ii = 0; ii < argCount; ++ii) + { + auto arg = args[ii]; + auto otherArg = other->args[ii]; + + if (!arg.val->equalsVal(otherArg.val)) + return false; + + if (!areValsEqual(arg.witness, otherArg.witness)) + return false; + } + return true; +} + +HashCode ExistentialSpecializedType::_getHashCodeOverride() +{ + Hasher hasher; + hasher.hashObject(baseType); + for (auto arg : args) + { + hasher.hashObject(arg.val); + if (auto witness = arg.witness) + hasher.hashObject(witness); + } + return hasher.getResult(); +} + +static RefPtr _getCanonicalValue(Val* val) +{ + if (!val) + return nullptr; + if (auto type = as(val)) + { + return type->getCanonicalType(); + } + // TODO: We may eventually need/want some sort of canonicalization + // for non-type values, but for now there is nothing to do. + return val; +} + +RefPtr ExistentialSpecializedType::_createCanonicalTypeOverride() +{ + RefPtr canType = m_astBuilder->create(); + + canType->baseType = baseType->getCanonicalType(); + for (auto arg : args) + { + ExpandedSpecializationArg canArg; + canArg.val = _getCanonicalValue(arg.val); + canArg.witness = _getCanonicalValue(arg.witness); + canType->args.add(canArg); + } + return canType; +} + +static RefPtr _substituteImpl(ASTBuilder* astBuilder, Val* val, SubstitutionSet subst, int* ioDiff) +{ + if (!val) return nullptr; + return val->substituteImpl(astBuilder, subst, ioDiff); +} + +RefPtr ExistentialSpecializedType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + auto substBaseType = baseType->substituteImpl(astBuilder, subst, &diff).as(); + + ExpandedSpecializationArgs substArgs; + for (auto arg : args) + { + ExpandedSpecializationArg substArg; + substArg.val = _substituteImpl(astBuilder, arg.val, subst, &diff); + substArg.witness = _substituteImpl(astBuilder, arg.witness, subst, &diff); + substArgs.add(substArg); + } + + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substType = astBuilder->create(); + substType->baseType = substBaseType; + substType->args = substArgs; + return substType; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ThisType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +String ThisType::_toStringOverride() +{ + String result; + result.append(interfaceDeclRef.toString()); + result.append(".This"); + return result; +} + +bool ThisType::_equalsImplOverride(Type * type) +{ + auto other = as(type); + if (!other) + return false; + + if (!interfaceDeclRef.equals(other->interfaceDeclRef)) + return false; + + return true; +} + +HashCode ThisType::_getHashCodeOverride() +{ + return combineHash( + HashCode(typeid(*this).hash_code()), + interfaceDeclRef.getHashCode()); +} + +RefPtr ThisType::_createCanonicalTypeOverride() +{ + RefPtr canType = m_astBuilder->create(); + + // TODO: need to canonicalize the decl-ref + canType->interfaceDeclRef = interfaceDeclRef; + return canType; +} + +RefPtr ThisType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + auto substInterfaceDeclRef = interfaceDeclRef.substituteImpl(astBuilder, subst, &diff); + + auto thisTypeSubst = findThisTypeSubstitution(subst.substitutions, substInterfaceDeclRef.getDecl()); + if (thisTypeSubst) + { + return thisTypeSubst->witness->sub; + } + + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substType = m_astBuilder->create(); + substType->interfaceDeclRef = substInterfaceDeclRef; + return substType; +} + + +} // namespace Slang diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index 68935108c..14028eff6 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -13,12 +13,11 @@ class OverloadGroupType : public Type { SLANG_CLASS(OverloadGroupType) - virtual String toString() override; - -protected: - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); }; // The type of an initializer-list expression (before it has @@ -27,12 +26,12 @@ class InitializerListType : public Type { SLANG_CLASS(InitializerListType) - virtual String toString() override; - -protected: - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; + + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); }; // The type of an expression that was erroneous @@ -40,13 +39,12 @@ class ErrorType : public Type { SLANG_CLASS(ErrorType) - virtual String toString() override; - -protected: - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; - virtual HashCode getHashCode() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; // A type that takes the form of a reference to some declaration @@ -56,19 +54,20 @@ class DeclRefType : public Type DeclRef declRef; - virtual String toString() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; - + static RefPtr create(ASTBuilder* astBuilder, DeclRef declRef); + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + protected: DeclRefType( DeclRef declRef) : declRef(declRef) {} - - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; }; // Base class for types that can be used in arithmetic expressions @@ -76,8 +75,10 @@ class ArithmeticExpressionType : public DeclRefType { SLANG_ABSTRACT_CLASS(ArithmeticExpressionType) -public: - virtual BasicExpressionType* GetScalarType() = 0; + BasicExpressionType* getScalarType(); + + // Overrides should be public so base classes can access + BasicExpressionType* _getScalarTypeOverride(); }; class BasicExpressionType : public ArithmeticExpressionType @@ -86,16 +87,16 @@ class BasicExpressionType : public ArithmeticExpressionType BaseType baseType; + // Overrides should be public so base classes can access + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + BasicExpressionType* _getScalarTypeOverride(); + protected: BasicExpressionType( Slang::BaseType baseType) : baseType(baseType) {} - - virtual BasicExpressionType* GetScalarType() override; - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - }; // Base type for things that are built in to the compiler, @@ -375,13 +376,12 @@ class ArrayExpressionType : public Type RefPtr baseType; RefPtr arrayLength; - virtual String toString() override; - -protected: - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; - virtual HashCode getHashCode() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + HashCode _getHashCodeOverride(); }; // The "type" of an expression that resolves to a type. @@ -394,16 +394,18 @@ class TypeType : public Type // The type that this is the type of... RefPtr type; - virtual String toString() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); protected: TypeType(RefPtr type) : type(type) {} - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; + }; // A vector type, e.g., `vector` @@ -418,10 +420,9 @@ class VectorExpressionType : public ArithmeticExpressionType // The number of elements RefPtr elementCount; - virtual String toString() override; - -protected: - virtual BasicExpressionType* GetScalarType() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + BasicExpressionType* _getScalarTypeOverride(); }; // A matrix type, e.g., `matrix` @@ -435,10 +436,9 @@ class MatrixExpressionType : public ArithmeticExpressionType RefPtr getRowType(); - virtual String toString() override; - -protected: - virtual BasicExpressionType* GetScalarType() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + BasicExpressionType* _getScalarTypeOverride(); private: RefPtr rowType; @@ -465,7 +465,7 @@ class PtrTypeBase : public BuiltinType SLANG_CLASS(PtrTypeBase) // Get the type of the pointed-to value. - Type* getValueType(); + Type* getValueType(); }; // A true (user-visible) pointer type, e.g., `T*` @@ -508,7 +508,11 @@ class NamedExpressionType : public Type DeclRef declRef; RefPtr innerType; - virtual String toString() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); protected: NamedExpressionType( @@ -516,9 +520,7 @@ protected: : declRef(declRef) {} - virtual RefPtr createCanonicalType() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; + }; // A function type is defined by its parameter types @@ -540,13 +542,12 @@ class FuncType : public Type Type* getParamType(UInt index) { return paramTypes[index]; } Type* getResultType() { return resultType; } - virtual String toString() override; - -protected: - virtual RefPtr createCanonicalType() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + RefPtr _createCanonicalTypeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); }; // The "type" of an expression that names a generic declaration. @@ -558,17 +559,17 @@ class GenericDeclRefType : public Type DeclRef const& getDeclRef() const { return declRef; } - virtual String toString() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _createCanonicalTypeOverride(); protected: GenericDeclRefType( DeclRef declRef) : declRef(declRef) {} - - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; }; // The "type" of a reference to a module or namespace @@ -580,12 +581,11 @@ class NamespaceType : public Type DeclRef const& getDeclRef() const { return declRef; } - virtual String toString() override; - -protected: - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; + // Overrides should be public so base classes can access + String _toStringOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _createCanonicalTypeOverride(); }; // The concrete type for a value wrapped in an existential, accessible @@ -596,11 +596,12 @@ class ExtractExistentialType : public Type DeclRef declRef; - virtual String toString() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + String _toStringOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _createCanonicalTypeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; /// A tagged union of zero or more other types. @@ -615,11 +616,12 @@ class TaggedUnionType : public Type /// List> caseTypes; - virtual String toString() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + String _toStringOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _createCanonicalTypeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; class ExistentialSpecializedType : public Type @@ -629,11 +631,12 @@ class ExistentialSpecializedType : public Type RefPtr baseType; ExpandedSpecializationArgs args; - virtual String toString() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + String _toStringOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _createCanonicalTypeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; /// The type of `this` within a polymorphic declaration @@ -643,11 +646,12 @@ class ThisType : public Type DeclRef interfaceDeclRef; - virtual String toString() override; - virtual bool equalsImpl(Type* type) override; - virtual HashCode getHashCode() override; - virtual RefPtr createCanonicalType() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + String _toStringOverride(); + bool _equalsImplOverride(Type* type); + HashCode _getHashCodeOverride(); + RefPtr _createCanonicalTypeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; } // namespace Slang diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp new file mode 100644 index 000000000..cb711a653 --- /dev/null +++ b/source/slang/slang-ast-val.cpp @@ -0,0 +1,552 @@ +// slang-ast-type.cpp +#include "slang-ast-builder.h" +#include +#include + +#include "slang-ast-generated-macro.h" + +#include "slang-syntax.h" + +namespace Slang { + +RefPtr Val::substitute(ASTBuilder* astBuilder, SubstitutionSet subst) +{ + if (!subst) return this; + int diff = 0; + return substituteImpl(astBuilder, subst, &diff); +} + +RefPtr Val::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + SLANG_AST_NODE_VIRTUAL_CALL(Val, substituteImpl, (astBuilder, subst, ioDiff)) +} + +bool Val::equalsVal(Val* val) +{ + SLANG_AST_NODE_VIRTUAL_CALL(Val, equalsVal, (val)) +} + +String Val::toString() +{ + SLANG_AST_NODE_VIRTUAL_CALL(Val, toString, ()) +} + +HashCode Val::getHashCode() +{ + SLANG_AST_NODE_VIRTUAL_CALL(Val, getHashCode, ()) +} + +RefPtr Val::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + SLANG_UNUSED(astBuilder); + SLANG_UNUSED(subst); + SLANG_UNUSED(ioDiff); + // Default behavior is to not substitute at all + return this; +} + +bool Val::_equalsValOverride(Val* val) +{ + SLANG_UNUSED(val); + SLANG_UNEXPECTED("Val::_equalsValOverride not overridden"); + //return false; +} + +String Val::_toStringOverride() +{ + SLANG_UNEXPECTED("Val::_toStringOverride not overridden"); + //return String(); +} + +HashCode Val::_getHashCodeOverride() +{ + SLANG_UNEXPECTED("Val::_getHashCodeOverride not overridden"); + //return HashCode(0); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ConstantIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool ConstantIntVal::_equalsValOverride(Val* val) +{ + if (auto intVal = as(val)) + return value == intVal->value; + return false; +} + +String ConstantIntVal::_toStringOverride() +{ + return String(value); +} + +HashCode ConstantIntVal::_getHashCodeOverride() +{ + return (HashCode)value; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericParamIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool GenericParamIntVal::_equalsValOverride(Val* val) +{ + if (auto genericParamVal = as(val)) + { + return declRef.equals(genericParamVal->declRef); + } + return false; +} + +String GenericParamIntVal::_toStringOverride() +{ + return getText(declRef.getName()); +} + +HashCode GenericParamIntVal::_getHashCodeOverride() +{ + return declRef.getHashCode() ^ HashCode(0xFFFF); +} + +RefPtr GenericParamIntVal::_substituteImplOverride(ASTBuilder* /* astBuilder */, 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(); + 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(m)) + { + index++; + } + else if (auto valParam = as(m)) + { + index++; + } + else + { + } + } + } + + // Nothing found: don't substitute. + return this; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ErrorIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool ErrorIntVal::_equalsValOverride(Val* val) +{ + if (auto errorIntVal = as(val)) + { + return true; + } + return false; +} + +String ErrorIntVal::_toStringOverride() +{ + return ""; +} + +HashCode ErrorIntVal::_getHashCodeOverride() +{ + return HashCode(typeid(this).hash_code()); +} + +RefPtr ErrorIntVal::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + SLANG_UNUSED(astBuilder); + SLANG_UNUSED(subst); + SLANG_UNUSED(ioDiff); + return this; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ErrorIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// TODO: should really have a `type.cpp` and a `witness.cpp` + +bool TypeEqualityWitness::_equalsValOverride(Val* val) +{ + auto otherWitness = as(val); + if (!otherWitness) + return false; + return sub->equals(otherWitness->sub); +} + +RefPtr TypeEqualityWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) +{ + RefPtr rs = astBuilder->create(); + rs->sub = sub->substituteImpl(astBuilder, subst, ioDiff).as(); + rs->sup = sup->substituteImpl(astBuilder, subst, ioDiff).as(); + return rs; +} + +String TypeEqualityWitness::_toStringOverride() +{ + return "TypeEqualityWitness(" + sub->toString() + ")"; +} + +HashCode TypeEqualityWitness::_getHashCodeOverride() +{ + return sub->getHashCode(); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DeclaredSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool DeclaredSubtypeWitness::_equalsValOverride(Val* val) +{ + auto otherWitness = as(val); + if (!otherWitness) + return false; + + return sub->equals(otherWitness->sub) + && sup->equals(otherWitness->sup) + && declRef.equals(otherWitness->declRef); +} + +RefPtr DeclaredSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) +{ + if (auto genConstraintDeclRef = declRef.as()) + { + 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(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(m)) + { + if (constraintParam == declRef.getDecl()) + { + found = true; + break; + } + index++; + } + } + if (found) + { + (*ioDiff)++; + auto ordinaryParamCount = genericDecl->getMembersOfType().getCount() + + genericDecl->getMembersOfType().getCount(); + SLANG_ASSERT(index + ordinaryParamCount < genericSubst->args.getCount()); + return genericSubst->args[index + ordinaryParamCount]; + } + } + else if (auto globalGenericSubst = s.as()) + { + // 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(astBuilder, subst, &diff).as(); + auto substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); + auto substDeclRef = declRef.substituteImpl(astBuilder, 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(substDeclRef.decl)) + { + if (auto substAssocTypeDecl = as(substTypeConstraintDecl->parentDecl)) + { + if (auto interfaceDecl = as(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(astBuilder, thisTypeSubst->witness, requirementKey); + switch (requirementWitness.getFlavor()) + { + default: + break; + + case RequirementWitness::Flavor::val: + { + auto satisfyingVal = requirementWitness.getVal(); + return satisfyingVal; + } + } + } + } + } + } + + RefPtr rs = astBuilder->create(); + rs->sub = substSub; + rs->sup = substSup; + rs->declRef = substDeclRef; + return rs; +} + +String DeclaredSubtypeWitness::_toStringOverride() +{ + StringBuilder sb; + sb << "DeclaredSubtypeWitness("; + sb << this->sub->toString(); + sb << ", "; + sb << this->sup->toString(); + sb << ", "; + sb << this->declRef.toString(); + sb << ")"; + return sb.ProduceString(); +} + +HashCode DeclaredSubtypeWitness::_getHashCodeOverride() +{ + return declRef.getHashCode(); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TransitiveSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool TransitiveSubtypeWitness::_equalsValOverride(Val* val) +{ + auto otherWitness = as(val); + if (!otherWitness) + return false; + + return sub->equals(otherWitness->sub) + && sup->equals(otherWitness->sup) + && subToMid->equalsVal(otherWitness->subToMid) + && midToSup.equals(otherWitness->midToSup); +} + +RefPtr TransitiveSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) +{ + int diff = 0; + + RefPtr substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); + RefPtr substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); + RefPtr substSubToMid = subToMid->substituteImpl(astBuilder, subst, &diff).as(); + DeclRef substMidToSup = midToSup.substituteImpl(astBuilder, 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 result = astBuilder->create(); + result->sub = substSub; + result->sup = substSup; + result->subToMid = substSubToMid; + result->midToSup = substMidToSup; + return result; +} + +String TransitiveSubtypeWitness::_toStringOverride() +{ + // 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(); +} + +HashCode TransitiveSubtypeWitness::_getHashCodeOverride() +{ + auto hash = sub->getHashCode(); + hash = combineHash(hash, sup->getHashCode()); + hash = combineHash(hash, subToMid->getHashCode()); + hash = combineHash(hash, midToSup.getHashCode()); + return hash; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExtractExistentialSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool ExtractExistentialSubtypeWitness::_equalsValOverride(Val* val) +{ + if (auto extractWitness = as(val)) + { + return declRef.equals(extractWitness->declRef); + } + return false; +} + +String ExtractExistentialSubtypeWitness::_toStringOverride() +{ + String result; + result.append("extractExistentialValue("); + result.append(declRef.toString()); + result.append(")"); + return result; +} + +HashCode ExtractExistentialSubtypeWitness::_getHashCodeOverride() +{ + return declRef.getHashCode(); +} + +RefPtr ExtractExistentialSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); + auto substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); + auto substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); + + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substValue = astBuilder->create(); + substValue->declRef = declRef; + substValue->sub = substSub; + substValue->sup = substSup; + return substValue; +} + + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TaggedUnionSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +bool TaggedUnionSubtypeWitness::_equalsValOverride(Val* val) +{ + auto taggedUnionWitness = as(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::_toStringOverride() +{ + String result; + result.append("TaggedUnionSubtypeWitness("); + bool first = true; + for (auto caseWitness : caseWitnesses) + { + if (!first) result.append(", "); + first = false; + + result.append(caseWitness->toString()); + } + return result; +} + +HashCode TaggedUnionSubtypeWitness::_getHashCodeOverride() +{ + HashCode hash = 0; + for (auto caseWitness : caseWitnesses) + { + hash = combineHash(hash, caseWitness->getHashCode()); + } + return hash; +} + +RefPtr TaggedUnionSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) +{ + int diff = 0; + + auto substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); + auto substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); + + List> substCaseWitnesses; + for (auto caseWitness : caseWitnesses) + { + substCaseWitnesses.add(caseWitness->substituteImpl(astBuilder, subst, &diff)); + } + + if (!diff) + return this; + + (*ioDiff)++; + + RefPtr substWitness = astBuilder->create(); + substWitness->sub = substSub; + substWitness->sup = substSup; + substWitness->caseWitnesses.swapWith(substCaseWitnesses); + return substWitness; +} + + + +} // namespace Slang diff --git a/source/slang/slang-ast-val.h b/source/slang/slang-ast-val.h index 5345a389f..91c20e3b2 100644 --- a/source/slang/slang-ast-val.h +++ b/source/slang/slang-ast-val.h @@ -21,14 +21,16 @@ class ConstantIntVal : public IntVal IntegerLiteralValue value; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + protected: ConstantIntVal(IntegerLiteralValue inValue) : value(inValue) {} - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; }; // The logical "value" of a reference to a generic value parameter @@ -38,15 +40,16 @@ class GenericParamIntVal : public IntVal DeclRef declRef; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + protected: GenericParamIntVal(DeclRef inDeclRef) : declRef(inDeclRef) {} - - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; }; /// An unknown integer value indicating an erroneous sub-expression @@ -58,10 +61,11 @@ class ErrorIntVal : public IntVal // and have all `Val`s that represent ordinary values hold their // `Type` so that we can have an `ErrorVal` of any type. - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; // A witness to the fact that some proposition is true, encoded @@ -119,10 +123,11 @@ class TypeEqualityWitness : public SubtypeWitness { SLANG_CLASS(TypeEqualityWitness) - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; // A witness that one type is a subtype of another @@ -133,10 +138,11 @@ class DeclaredSubtypeWitness : public SubtypeWitness DeclRef declRef; - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; // A witness that `sub : sup` because `sub : mid` and `mid : sup` @@ -150,10 +156,11 @@ class TransitiveSubtypeWitness : public SubtypeWitness // Witness that `mid : sup` DeclRef midToSup; - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; // A witness taht `sub : sup` because `sub` was wrapped into @@ -165,10 +172,11 @@ class ExtractExistentialSubtypeWitness : public SubtypeWitness // The declaration of the existential value that has been opened DeclRef declRef; - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; // A witness that `sub : sup`, because `sub` is a tagged union @@ -184,10 +192,12 @@ class TaggedUnionSubtypeWitness : public SubtypeWitness // List> caseWitnesses; - virtual bool equalsVal(Val* val) override; - virtual String toString() override; - virtual HashCode getHashCode() override; - virtual RefPtr substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) override; + + // Overrides should be public so base classes can access + bool _equalsValOverride(Val* val); + String _toStringOverride(); + HashCode _getHashCodeOverride(); + RefPtr _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; } // namespace Slang diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp index 1b96aec98..c78de91a5 100644 --- a/source/slang/slang-syntax.cpp +++ b/source/slang/slang-syntax.cpp @@ -51,19 +51,6 @@ SourceLoc const& getDiagnosticPos(TypeExp const& typeExp) return typeExp.exp->loc; } -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! BasicExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -bool BasicExpressionType::equalsImpl(Type * type) -{ - auto basicType = as(type); - return basicType && basicType->baseType == this->baseType; -} - -RefPtr BasicExpressionType::createCanonicalType() -{ - // A basic type is already canonical, in our setup - return this; -} // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! Free functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -213,149 +200,6 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt return type->equals(other); } - // 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(val)) - return const_cast(this)->equals(type); - return false; - } - - RefPtr Type::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) - { - int diff = 0; - auto canSubst = getCanonicalType()->substituteImpl(astBuilder, 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(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; - } - - bool ArrayExpressionType::equalsImpl(Type* type) - { - auto arrType = as(type); - if (!arrType) - return false; - return (areValsEqual(arrayLength, arrType->arrayLength) && baseType->equals(arrType->baseType.Ptr())); - } - - RefPtr ArrayExpressionType::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) - { - int diff = 0; - auto elementType = baseType->substituteImpl(astBuilder, subst, &diff).as(); - auto arrlen = arrayLength->substituteImpl(astBuilder, subst, &diff).as(); - SLANG_ASSERT(arrlen); - if (diff) - { - *ioDiff = 1; - auto rsType = getArrayType( - astBuilder, - elementType, - arrlen); - return rsType; - } - return this; - } - - RefPtr ArrayExpressionType::createCanonicalType() - { - auto canonicalElementType = baseType->getCanonicalType(); - auto canonicalArrayType = getASTBuilder()->getArrayType( - canonicalElementType, - arrayLength); - return canonicalArrayType; - } - - HashCode 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(); - } - - HashCode DeclRefType::getHashCode() - { - return (declRef.getHashCode() * 16777619) ^ (HashCode)(typeid(this).hash_code()); - } - - bool DeclRefType::equalsImpl(Type * type) - { - if (auto declRefType = as(type)) - { - return declRef.equals(declRefType->declRef); - } - return false; - } - - RefPtr DeclRefType::createCanonicalType() - { - // A declaration reference is already canonical - return this; - } - // // RequirementWitness // @@ -478,117 +322,7 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt return RequirementWitness(); } - RefPtr DeclRefType::substituteImpl(ASTBuilder* astBuilder, 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(declRef.getDecl())) - { - // search for a substitution that might apply to us - for(auto s = subst.substitutions; s; s = s->outer) - { - auto genericSubst = s.as(); - 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(m)) - { - index++; - } - else if (auto valParam = as(m)) - { - index++; - } - else - { - } - } - } - } - else if (auto globalGenParam = as(declRef.getDecl())) - { - // search for a substitution that might apply to us - for(auto s = subst.substitutions; s; s = s->outer) - { - auto genericSubst = as(s); - if(!genericSubst) - continue; - - if (genericSubst->paramDecl == globalGenParam) - { - (*ioDiff)++; - return genericSubst->actualType; - } - } - } - int diff = 0; - DeclRef substDeclRef = declRef.substituteImpl(astBuilder, 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(substDeclRef.decl)) - { - for(auto s = substDeclRef.substitutions.substitutions; s; s = s->outer) - { - auto thisSubst = s.as(); - if(!thisSubst) - continue; - - if(auto interfaceDecl = as(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(astBuilder, 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(astBuilder, substDeclRef); - } + static RefPtr ExtractGenericArgType(RefPtr val) { @@ -848,1812 +582,668 @@ Index getFilterCountImpl(const ReflectClassInfo& clsInfo, MemberFilterStyle filt } } - // OverloadGroupType + // - String OverloadGroupType::toString() + RefPtr findInnerMostGenericSubstitution(Substitutions* subst) { - return "overload group"; + for(RefPtr s = subst; s; s = s->outer) + { + if(auto genericSubst = as(s)) + return genericSubst; + } + return nullptr; } - bool OverloadGroupType::equalsImpl(Type * /*type*/) - { - return false; - } + + // DeclRefBase - RefPtr OverloadGroupType::createCanonicalType() + RefPtr DeclRefBase::substitute(ASTBuilder* astBuilder, RefPtr type) const { - return this; - } + // Note that type can be nullptr, and so this function can return nullptr (although only correctly when no substitutions) - HashCode OverloadGroupType::getHashCode() - { - return (HashCode)(size_t(this)); - } + // No substitutions? Easy. + if (!substitutions) + return type; - // InitializerListType + SLANG_ASSERT(type); - String InitializerListType::toString() - { - return "initializer list"; + // Otherwise we need to recurse on the type structure + // and apply substitutions where it makes sense + return type->substitute(astBuilder, substitutions).as(); } - bool InitializerListType::equalsImpl(Type * /*type*/) + DeclRefBase DeclRefBase::substitute(ASTBuilder* astBuilder, DeclRefBase declRef) const { - return false; - } + if(!substitutions) + return declRef; - RefPtr InitializerListType::createCanonicalType() - { - return this; + int diff = 0; + return declRef.substituteImpl(astBuilder, substitutions, &diff); } - HashCode InitializerListType::getHashCode() + RefPtr DeclRefBase::substitute(ASTBuilder* /* astBuilder*/, RefPtr expr) const { - return (HashCode)(size_t(this)); - } + // No substitutions? Easy. + if (!substitutions) + return expr; - // ErrorType + SLANG_UNIMPLEMENTED_X("generic substitution into expressions"); - String ErrorType::toString() - { - return "error"; + UNREACHABLE_RETURN(expr); } - bool ErrorType::equalsImpl(Type* type) - { - if (auto errorType = as(type)) - return true; - return false; - } + void buildMemberDictionary(ContainerDecl* decl); - RefPtr ErrorType::createCanonicalType() + InterfaceDecl* findOuterInterfaceDecl(Decl* decl) { - return this; - } + Decl* dd = decl; + while(dd) + { + if(auto interfaceDecl = as(dd)) + return interfaceDecl; - RefPtr ErrorType::substituteImpl(ASTBuilder* /* astBuilder */, SubstitutionSet /*subst*/, int* /*ioDiff*/) - { - return this; + dd = dd->parentDecl; + } + return nullptr; } - HashCode ErrorType::getHashCode() + RefPtr findGlobalGenericSubst( + RefPtr substs, + GlobalGenericParamDecl* paramDecl) { - return HashCode(size_t(this)); - } - - - // NamedExpressionType + for(auto s = substs; s; s = s->outer) + { + auto gSubst = s.as(); + if(!gSubst) + continue; - String NamedExpressionType::toString() - { - return getText(declRef.getName()); - } + if(gSubst->paramDecl != paramDecl) + continue; - bool NamedExpressionType::equalsImpl(Type * /*type*/) - { - SLANG_UNEXPECTED("unreachable"); - UNREACHABLE_RETURN(false); - } + return gSubst; + } - RefPtr NamedExpressionType::createCanonicalType() - { - if (!innerType) - innerType = getType(m_astBuilder, declRef); - return innerType->getCanonicalType(); + return nullptr; } - HashCode NamedExpressionType::getHashCode() + RefPtr specializeSubstitutionsShallow( + ASTBuilder* astBuilder, + RefPtr substToSpecialize, + RefPtr substsToApply, + RefPtr restSubst, + int* ioDiff) { - // 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(); + SLANG_ASSERT(substToSpecialize); + return substToSpecialize->applySubstitutionsShallow(astBuilder, substsToApply, restSubst, ioDiff); } - // FuncType - - String FuncType::toString() + RefPtr specializeGlobalGenericSubstitutions( + ASTBuilder* astBuilder, + Decl* declToSpecialize, + RefPtr substsToSpecialize, + RefPtr substsToApply, + int* ioDiff, + HashSet& ioParametersFound) { - StringBuilder sb; - sb << "("; - UInt paramCount = getParamCount(); - for (UInt pp = 0; pp < paramCount; ++pp) + // 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) { - if (pp != 0) sb << ", "; - sb << getParamType(pp)->toString(); - } - sb << ") -> "; - sb << getResultType()->toString(); - return sb.ProduceString(); - } + auto specGlobalGenericSubst = specSubst.as(); + if(!specGlobalGenericSubst) + continue; - bool FuncType::equalsImpl(Type * type) - { - if (auto funcType = as(type)) - { - auto paramCount = getParamCount(); - auto otherParamCount = funcType->getParamCount(); - if (paramCount != otherParamCount) - return false; + ioParametersFound.Add(specGlobalGenericSubst->paramDecl); - for (UInt pp = 0; pp < paramCount; ++pp) - { - auto paramType = getParamType(pp); - auto otherParamType = funcType->getParamType(pp); - if (!paramType->equals(otherParamType)) - return false; - } + int diff = 0; + auto restSubst = specializeGlobalGenericSubstitutions( + astBuilder, + declToSpecialize, + specSubst->outer, + substsToApply, + &diff, + ioParametersFound); - if(!resultType->equals(funcType->resultType)) - return false; + auto firstSubst = specializeSubstitutionsShallow( + astBuilder, + specGlobalGenericSubst, + substsToApply, + restSubst, + &diff); - // TODO: if we ever introduce other kinds - // of qualification on function types, we'd - // want to consider it here. - return true; + *ioDiff += diff; + return firstSubst; } - return false; - } - RefPtr FuncType::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) - { - int diff = 0; + // No more existing substitutions, so we know we can apply + // our global generic substitutions without any special work. - // result type - RefPtr substResultType = resultType->substituteImpl(astBuilder, subst, &diff).as(); + // We expect global generic substitutions to come at + // the end of the list in all cases, so lets advance + // until we see them. + RefPtr appGlobalGenericSubsts = substsToApply; + while(appGlobalGenericSubsts && !appGlobalGenericSubsts.as()) + appGlobalGenericSubsts = appGlobalGenericSubsts->outer; - // parameter types - List> substParamTypes; - for( auto pp : paramTypes ) - { - substParamTypes.add(pp->substituteImpl(astBuilder, subst, &diff).as()); - } - // early exit for no change... - if(!diff) - return this; + // If there is nothing to apply, then we are done + if(!appGlobalGenericSubsts) + return nullptr; + // Otherwise, it seems like something has to change. (*ioDiff)++; - RefPtr substType = astBuilder->create(); - substType->resultType = substResultType; - substType->paramTypes = substParamTypes; - return substType; - } - RefPtr FuncType::createCanonicalType() - { - // result type - RefPtr canResultType = resultType->getCanonicalType(); - - // parameter types - List> canParamTypes; - for( auto pp : paramTypes ) - { - canParamTypes.add(pp->getCanonicalType()); - } - - RefPtr canType = getASTBuilder()->create(); - canType->resultType = resultType; - canType->paramTypes = canParamTypes; - - return canType; - } - - HashCode FuncType::getHashCode() - { - HashCode 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(t)) - { - return t->equals(typeType->type); - } - return false; - } - - RefPtr TypeType::createCanonicalType() - { - return getASTBuilder()->getTypeType(type->getCanonicalType()); - } - - HashCode TypeType::getHashCode() - { - SLANG_UNEXPECTED("unreachable"); - UNREACHABLE_RETURN(0); - } - - // GenericDeclRefType - - String GenericDeclRefType::toString() - { - // TODO: what is appropriate here? - return ">"; - } - - bool GenericDeclRefType::equalsImpl(Type * type) - { - if (auto genericDeclRefType = as(type)) - { - return declRef.equals(genericDeclRefType->declRef); - } - return false; - } - - HashCode GenericDeclRefType::getHashCode() - { - return declRef.getHashCode(); - } - - RefPtr GenericDeclRefType::createCanonicalType() - { - return this; - } - - // NamespaceType - - String NamespaceType::toString() - { - String result; - result.append("namespace "); - result.append(declRef.toString()); - return result; - } - - bool NamespaceType::equalsImpl(Type * type) - { - if (auto namespaceType = as(type)) - { - return declRef.equals(namespaceType->declRef); - } - return false; - } - - HashCode NamespaceType::getHashCode() - { - return declRef.getHashCode(); - } - - RefPtr NamespaceType::createCanonicalType() - { - return this; - } - - // ArithmeticExpressionType - - // VectorExpressionType - - String VectorExpressionType::toString() - { - StringBuilder sb; - sb << "vector<" << elementType->toString() << "," << elementCount->toString() << ">"; - return sb.ProduceString(); - } - - BasicExpressionType* VectorExpressionType::GetScalarType() - { - return as(elementType); - } - - // - - RefPtr findInnerMostGenericSubstitution(Substitutions* subst) - { - for(RefPtr s = subst; s; s = s->outer) - { - if(auto genericSubst = as(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(getElementType()); - } - - Type* MatrixExpressionType::getElementType() - { - return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]); - } - - IntVal* MatrixExpressionType::getRowCount() - { - return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[1]); - } - - IntVal* MatrixExpressionType::getColumnCount() - { - return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[2]); - } - - RefPtr MatrixExpressionType::getRowType() - { - if( !rowType ) - { - rowType = m_astBuilder->getVectorType(getElementType(), getColumnCount()); - } - return rowType; - } - - - - - // PtrTypeBase - - Type* PtrTypeBase::getValueType() - { - return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]); - } - - // GenericParamIntVal - - bool GenericParamIntVal::equalsVal(Val* val) - { - if (auto genericParamVal = as(val)) - { - return declRef.equals(genericParamVal->declRef); - } - return false; - } - - String GenericParamIntVal::toString() - { - return getText(declRef.getName()); - } - - HashCode GenericParamIntVal::getHashCode() - { - return declRef.getHashCode() ^ HashCode(0xFFFF); - } + // 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 GenericParamIntVal::substituteImpl(ASTBuilder* /* astBuilder */, SubstitutionSet subst, int* ioDiff) - { - // search for a substitution that might apply to us - for(auto s = subst.substitutions; s; s = s->outer) + RefPtr resultSubst; + RefPtr* link = &resultSubst; + for(auto appSubst = appGlobalGenericSubsts; appSubst; appSubst = appSubst->outer) { - auto genSubst = s.as(); - if(!genSubst) + auto appGlobalGenericSubst = appSubst.as(); + if(!appSubst) 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) + // Don't include substitutions for parameters already handled. + if(ioParametersFound.Contains(appGlobalGenericSubst->paramDecl)) 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(m)) - { - index++; - } - else if (auto valParam = as(m)) - { - index++; - } - else - { - } - } - } - - // Nothing found: don't substitute. - return this; - } - - // ErrorIntVal - - bool ErrorIntVal::equalsVal(Val* val) - { - if( auto errorIntVal = as(val) ) - { - return true; - } - return false; - } - - String ErrorIntVal::toString() - { - return ""; - } - - HashCode ErrorIntVal::getHashCode() - { - return HashCode(typeid(this).hash_code()); - } - - RefPtr ErrorIntVal::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) - { - SLANG_UNUSED(astBuilder); - SLANG_UNUSED(subst); - SLANG_UNUSED(ioDiff); - return this; - } - - // Substitutions - - RefPtr GenericSubstitution::applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) - { - int diff = 0; - - if(substOuter != outer) diff++; - - List> substArgs; - for (auto a : args) - { - substArgs.add(a->substituteImpl(astBuilder, substSet, &diff)); - } - - if (!diff) return this; - - (*ioDiff)++; - auto substSubst = astBuilder->create(); - 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(subst); - if (!genericSubst) - return false; - if (genericDecl != genericSubst->genericDecl) - return false; + RefPtr newSubst = astBuilder->create(); + newSubst->paramDecl = appGlobalGenericSubst->paramDecl; + newSubst->actualType = appGlobalGenericSubst->actualType; + newSubst->constraintArgs = appGlobalGenericSubst->constraintArgs; - 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; + *link = newSubst; + link = &newSubst->outer; } - if (!outer) - return !genericSubst->outer; - - if (!outer->equals(genericSubst->outer.Ptr())) - return false; - - return true; - } - - RefPtr ThisTypeSubstitution::applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr 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(astBuilder, substSet, &diff).as(); - - if (!diff) return this; - - (*ioDiff)++; - auto substSubst = astBuilder->create(); - substSubst->interfaceDecl = interfaceDecl; - substSubst->witness = substWitness; - substSubst->outer = substOuter; - return substSubst; + return resultSubst; } - bool ThisTypeSubstitution::equals(Substitutions* subst) + RefPtr specializeGlobalGenericSubstitutions( + ASTBuilder* astBuilder, + Decl* declToSpecialize, + RefPtr substsToSpecialize, + RefPtr substsToApply, + int* ioDiff) { - if (!subst) - return false; - if (subst == this) - return true; - - if (auto thisTypeSubst = as(subst)) - { - // For our purposes, two this-type substitutions are - // equivalent if they have the same type as `This`, - // even if the specific witness values they use - // might differ. - // - if(this->interfaceDecl != thisTypeSubst->interfaceDecl) - return false; - - if(!this->witness->sub->equals(thisTypeSubst->witness->sub)) - return false; - - return true; - } - return false; + // Keep track of any parameters already present in the + // existing substitution. + HashSet parametersFound; + return specializeGlobalGenericSubstitutions(astBuilder, declToSpecialize, substsToSpecialize, substsToApply, ioDiff, parametersFound); } - HashCode ThisTypeSubstitution::getHashCode() const - { - return witness->getHashCode(); - } - RefPtr GlobalGenericParamSubstitution::applySubstitutionsShallow(ASTBuilder* astBuilder, SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) + // Construct new substitutions to apply to a declaration, + // based on a provided substitution set to be applied + RefPtr specializeSubstitutions( + ASTBuilder* astBuilder, + Decl* declToSpecialize, + RefPtr substsToSpecialize, + RefPtr substsToApply, + 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(astBuilder, substSet, &diff).as(); - - List substConstraintArgs; - for(auto constraintArg : constraintArgs) - { - ConstraintArg substConstraintArg; - substConstraintArg.decl = constraintArg.decl; - substConstraintArg.val = constraintArg.val->substituteImpl(astBuilder, substSet, &diff); - - substConstraintArgs.add(substConstraintArg); - } - - if(!diff) - return this; - - (*ioDiff)++; - - RefPtr substSubst = astBuilder->create(); - substSubst->paramDecl = paramDecl; - substSubst->actualType = substActualType; - substSubst->constraintArgs = substConstraintArgs; - substSubst->outer = substOuter; - return substSubst; - } + // No declaration? Then nothing to specialize. + if(!declToSpecialize) + return nullptr; - bool GlobalGenericParamSubstitution::equals(Substitutions* subst) - { - if (!subst) - return false; - if (subst == this) - return true; + // No (remaining) substitutions to apply? Then we are done. + if(!substsToApply) + return substsToSpecialize; - if (auto genSubst = as(subst)) + // 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 (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 DeclRefBase::substitute(ASTBuilder* astBuilder, RefPtr 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(astBuilder, substitutions).as(); - } - - DeclRefBase DeclRefBase::substitute(ASTBuilder* astBuilder, DeclRefBase declRef) const - { - if(!substitutions) - return declRef; - - int diff = 0; - return declRef.substituteImpl(astBuilder, substitutions, &diff); - } - - RefPtr DeclRefBase::substitute(ASTBuilder* /* astBuilder*/, RefPtr 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(dd)) - return interfaceDecl; - - dd = dd->parentDecl; - } - return nullptr; - } - - RefPtr findGlobalGenericSubst( - RefPtr substs, - GlobalGenericParamDecl* paramDecl) - { - for(auto s = substs; s; s = s->outer) - { - auto gSubst = s.as(); - if(!gSubst) - continue; - - if(gSubst->paramDecl != paramDecl) - continue; - - return gSubst; - } - - return nullptr; - } - - RefPtr specializeSubstitutionsShallow( - ASTBuilder* astBuilder, - RefPtr substToSpecialize, - RefPtr substsToApply, - RefPtr restSubst, - int* ioDiff) - { - SLANG_ASSERT(substToSpecialize); - return substToSpecialize->applySubstitutionsShallow(astBuilder, substsToApply, restSubst, ioDiff); - } - - RefPtr specializeGlobalGenericSubstitutions( - ASTBuilder* astBuilder, - Decl* declToSpecialize, - RefPtr substsToSpecialize, - RefPtr substsToApply, - int* ioDiff, - HashSet& 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(); - if(!specGlobalGenericSubst) - continue; - - ioParametersFound.Add(specGlobalGenericSubst->paramDecl); - - int diff = 0; - auto restSubst = specializeGlobalGenericSubstitutions( - astBuilder, - declToSpecialize, - specSubst->outer, - substsToApply, - &diff, - ioParametersFound); - - auto firstSubst = specializeSubstitutionsShallow( - astBuilder, - 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 appGlobalGenericSubsts = substsToApply; - while(appGlobalGenericSubsts && !appGlobalGenericSubsts.as()) - 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 resultSubst; - RefPtr* link = &resultSubst; - for(auto appSubst = appGlobalGenericSubsts; appSubst; appSubst = appSubst->outer) - { - auto appGlobalGenericSubst = appSubst.as(); - if(!appSubst) - continue; - - // Don't include substitutions for parameters already handled. - if(ioParametersFound.Contains(appGlobalGenericSubst->paramDecl)) - continue; - - RefPtr newSubst = astBuilder->create(); - newSubst->paramDecl = appGlobalGenericSubst->paramDecl; - newSubst->actualType = appGlobalGenericSubst->actualType; - newSubst->constraintArgs = appGlobalGenericSubst->constraintArgs; - - *link = newSubst; - link = &newSubst->outer; - } - - return resultSubst; - } - - RefPtr specializeGlobalGenericSubstitutions( - ASTBuilder* astBuilder, - Decl* declToSpecialize, - RefPtr substsToSpecialize, - RefPtr substsToApply, - int* ioDiff) - { - // Keep track of any parameters already present in the - // existing substitution. - HashSet parametersFound; - return specializeGlobalGenericSubstitutions(astBuilder, declToSpecialize, substsToSpecialize, substsToApply, ioDiff, parametersFound); - } - - - // Construct new substitutions to apply to a declaration, - // based on a provided substitution set to be applied - RefPtr specializeSubstitutions( - ASTBuilder* astBuilder, - Decl* declToSpecialize, - RefPtr substsToSpecialize, - RefPtr 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(ancestorDecl)) - { - // The declaration is nested inside a generic. - // Does it already have a specialization for that generic? - if(auto specGenericSubst = as(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( - astBuilder, - ancestorGenericDecl->parentDecl, - specGenericSubst->outer, - substsToApply, - &diff); - - auto firstSubst = specializeSubstitutionsShallow( - astBuilder, - 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(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( - astBuilder, - ancestorGenericDecl->parentDecl, - substsToSpecialize, - substsToApply, - &diff); - - RefPtr firstSubst = astBuilder->create(); - firstSubst->genericDecl = ancestorGenericDecl; - firstSubst->args = appGenericSubst->args; - firstSubst->outer = restSubst; - - (*ioDiff)++; - return firstSubst; - } - } - else if(auto ancestorInterfaceDecl = as(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(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( - astBuilder, - ancestorInterfaceDecl->parentDecl, - specThisTypeSubst->outer, - substsToApply, - &diff); - - auto firstSubst = specializeSubstitutionsShallow( - astBuilder, - 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(); - if(!appThisTypeSubst) - continue; - - if(appThisTypeSubst->interfaceDecl != ancestorInterfaceDecl) - continue; - - int diff = 0; - auto restSubst = specializeSubstitutions( - astBuilder, - ancestorInterfaceDecl->parentDecl, - substsToSpecialize, - substsToApply, - &diff); - - RefPtr firstSubst = astBuilder->create(); - 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( - astBuilder, - declToSpecialize, - substsToSpecialize, - substsToApply, - ioDiff); - } - - DeclRefBase DeclRefBase::substituteImpl(ASTBuilder* astBuilder, 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( - astBuilder, - 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 substToApply = substitutions.substitutions; - - if(auto interfaceDecl = as(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(substToApply)) - { - if(thisTypeSubst->interfaceDecl == interfaceDecl) - { - // Strip away that specializations that apply to the interface. - substToApply = thisTypeSubst->outer; - } - } - } - - if (auto parentGenericDecl = as(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(substToApply)) - { - if(genericSubst->genericDecl == parentGenericDecl) - { - // Strip away the specializations that were applied to the parent. - substToApply = genericSubst->outer; - } - } - } - - return DeclRefBase(parentDecl, substToApply); - } - - HashCode DeclRefBase::getHashCode() const - { - return combineHash(PointerHash<1>::getHashCode(decl), substitutions.getHashCode()); - } - - // Val - - RefPtr Val::substitute(ASTBuilder* astBuilder, SubstitutionSet subst) - { - if (!subst) return this; - int diff = 0; - return substituteImpl(astBuilder, subst, &diff); - } - - RefPtr Val::substituteImpl(ASTBuilder* /* astBuilder */, SubstitutionSet /*subst*/, int* /*ioDiff*/) - { - // Default behavior is to not substitute at all - return this; - } - - // IntVal - - IntegerLiteralValue getIntVal(RefPtr val) - { - if (auto constantVal = as(val)) - { - return constantVal->value; - } - SLANG_UNEXPECTED("needed a known integer value"); - return 0; - } - - // ConstantIntVal - - bool ConstantIntVal::equalsVal(Val* val) - { - if (auto intVal = as(val)) - return value == intVal->value; - return false; - } - - String ConstantIntVal::toString() - { - return String(value); - } - - HashCode ConstantIntVal::getHashCode() - { - return (HashCode) value; - } - - - - // - - // HLSLPatchType - - Type* HLSLPatchType::getElementType() - { - return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]); - } - - IntVal* HLSLPatchType::getElementCount() - { - return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[1]); - } - - // Constructors for types - - RefPtr getArrayType( - ASTBuilder* astBuilder, - Type* elementType, - IntVal* elementCount) - { - auto arrayType = astBuilder->create(); - arrayType->baseType = elementType; - arrayType->arrayLength = elementCount; - return arrayType; - } - - RefPtr getArrayType( - ASTBuilder* astBuilder, - Type* elementType) - { - auto arrayType = astBuilder->create(); - arrayType->baseType = elementType; - return arrayType; - } - - RefPtr getNamedType( - ASTBuilder* astBuilder, - DeclRef const& declRef) - { - DeclRef specializedDeclRef = createDefaultSubstitutionsIfNeeded(astBuilder, declRef).as(); - - return astBuilder->create(specializedDeclRef); - } - - - RefPtr getFuncType( - ASTBuilder* astBuilder, - DeclRef const& declRef) - { - RefPtr funcType = astBuilder->create(); - - funcType->resultType = getResultType(astBuilder, declRef); - for (auto paramDeclRef : getParameters(declRef)) - { - auto paramDecl = paramDeclRef.getDecl(); - auto paramType = getType(astBuilder, paramDeclRef); - if( paramDecl->findModifier() ) - { - paramType = astBuilder->getRefType(paramType); - } - else if( paramDecl->findModifier() ) - { - if(paramDecl->findModifier() || paramDecl->findModifier()) - { - paramType = astBuilder->getInOutType(paramType); - } - else - { - paramType = astBuilder->getOutType(paramType); - } - } - funcType->paramTypes.add(paramType); - } - - return funcType; - } - - RefPtr getGenericDeclRefType( - ASTBuilder* astBuilder, - DeclRef const& declRef) - { - return astBuilder->create(declRef); - } - - RefPtr getNamespaceType( - ASTBuilder* astBuilder, - DeclRef const& declRef) - { - auto type = astBuilder->create(); - type->declRef = declRef; - return type; - } - - RefPtr getSamplerStateType( - ASTBuilder* astBuilder) - { - return astBuilder->create(); - } - - // TODO: should really have a `type.cpp` and a `witness.cpp` - - bool TypeEqualityWitness::equalsVal(Val* val) - { - auto otherWitness = as(val); - if (!otherWitness) - return false; - return sub->equals(otherWitness->sub); - } - - RefPtr TypeEqualityWitness::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) - { - RefPtr rs = astBuilder->create(); - rs->sub = sub->substituteImpl(astBuilder, subst, ioDiff).as(); - rs->sup = sup->substituteImpl(astBuilder, subst, ioDiff).as(); - return rs; - } - - String TypeEqualityWitness::toString() - { - return "TypeEqualityWitness(" + sub->toString() + ")"; - } - - HashCode TypeEqualityWitness::getHashCode() - { - return sub->getHashCode(); - } - - bool DeclaredSubtypeWitness::equalsVal(Val* val) - { - auto otherWitness = as(val); - if(!otherWitness) - return false; - - return sub->equals(otherWitness->sub) - && sup->equals(otherWitness->sup) - && declRef.equals(otherWitness->declRef); - } - - RefPtr findThisTypeSubstitution( - Substitutions* substs, - InterfaceDecl* interfaceDecl) - { - for(RefPtr s = substs; s; s = s->outer) - { - auto thisTypeSubst = as(s); - if(!thisTypeSubst) - continue; - - if(thisTypeSubst->interfaceDecl != interfaceDecl) - continue; - - return thisTypeSubst; - } - - return nullptr; - } - - RefPtr DeclaredSubtypeWitness::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) - { - if (auto genConstraintDeclRef = declRef.as()) - { - auto genConstraintDecl = genConstraintDeclRef.getDecl(); - - // search for a substitution that might apply to us - for(auto s = subst.substitutions; s; s = s->outer) + if(auto ancestorGenericDecl = as(ancestorDecl)) { - if(auto genericSubst = as(s)) + // The declaration is nested inside a generic. + // Does it already have a specialization for that generic? + if(auto specGenericSubst = as(substsToSpecialize)) { - // 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(m)) - { - if (constraintParam == declRef.getDecl()) - { - found = true; - break; - } - index++; - } - } - if (found) + if(specGenericSubst->genericDecl == ancestorGenericDecl) { - (*ioDiff)++; - auto ordinaryParamCount = genericDecl->getMembersOfType().getCount() + - genericDecl->getMembersOfType().getCount(); - SLANG_ASSERT(index + ordinaryParamCount < genericSubst->args.getCount()); - return genericSubst->args[index + ordinaryParamCount]; + // Yes. We have an existing specialization, so we will + // keep one matching it in place. + int diff = 0; + auto restSubst = specializeSubstitutions( + astBuilder, + ancestorGenericDecl->parentDecl, + specGenericSubst->outer, + substsToApply, + &diff); + + auto firstSubst = specializeSubstitutionsShallow( + astBuilder, + specGenericSubst, + substsToApply, + restSubst, + &diff); + + *ioDiff += diff; + return firstSubst; } } - else if(auto globalGenericSubst = s.as()) + + // 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) { - // check if the substitution is really about this global generic type parameter - if (globalGenericSubst->paramDecl != genConstraintDecl->parentDecl) + auto appGenericSubst = as(s); + if(!appGenericSubst) continue; - for(auto constraintArg : globalGenericSubst->constraintArgs) - { - if(constraintArg.decl.Ptr() != genConstraintDecl) - continue; + if(appGenericSubst->genericDecl != ancestorGenericDecl) + continue; - (*ioDiff)++; - return constraintArg.val; - } - } - } - } + // 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. - // Perform substitution on the constituent elements. - int diff = 0; - auto substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); - auto substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); - auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); - if (!diff) - return this; + int diff = 0; + auto restSubst = specializeSubstitutions( + astBuilder, + ancestorGenericDecl->parentDecl, + substsToSpecialize, + substsToApply, + &diff); - (*ioDiff)++; + RefPtr firstSubst = astBuilder->create(); + firstSubst->genericDecl = ancestorGenericDecl; + firstSubst->args = appGenericSubst->args; + firstSubst->outer = restSubst; - // 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(substDeclRef.decl)) - { - if (auto substAssocTypeDecl = as(substTypeConstraintDecl->parentDecl)) + (*ioDiff)++; + return firstSubst; + } + } + else if(auto ancestorInterfaceDecl = as(ancestorDecl)) { - if (auto interfaceDecl = as(substAssocTypeDecl->parentDecl)) + // 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(substsToSpecialize)) { - // 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)) + if(specThisTypeSubst->interfaceDecl == ancestorInterfaceDecl) { - // We need to look up the declaration that satisfies - // the requirement named by the associated type. - Decl* requirementKey = substTypeConstraintDecl; - RequirementWitness requirementWitness = tryLookUpRequirementWitness(astBuilder, thisTypeSubst->witness, requirementKey); - switch(requirementWitness.getFlavor()) - { - default: - break; - - case RequirementWitness::Flavor::val: - { - auto satisfyingVal = requirementWitness.getVal(); - return satisfyingVal; - } - } + // Yes. We have an existing specialization, so we will + // keep one matching it in place. + int diff = 0; + auto restSubst = specializeSubstitutions( + astBuilder, + ancestorInterfaceDecl->parentDecl, + specThisTypeSubst->outer, + substsToApply, + &diff); + + auto firstSubst = specializeSubstitutionsShallow( + astBuilder, + 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(); + if(!appThisTypeSubst) + continue; + if(appThisTypeSubst->interfaceDecl != ancestorInterfaceDecl) + continue; + int diff = 0; + auto restSubst = specializeSubstitutions( + astBuilder, + ancestorInterfaceDecl->parentDecl, + substsToSpecialize, + substsToApply, + &diff); - RefPtr rs = astBuilder->create(); - rs->sub = substSub; - rs->sup = substSup; - rs->declRef = substDeclRef; - return rs; - } + RefPtr firstSubst = astBuilder->create(); + firstSubst->interfaceDecl = ancestorInterfaceDecl; + firstSubst->witness = appThisTypeSubst->witness; + firstSubst->outer = restSubst; - 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(); - } + (*ioDiff)++; + return firstSubst; + } + } + } - HashCode DeclaredSubtypeWitness::getHashCode() - { - return declRef.getHashCode(); + // 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( + astBuilder, + declToSpecialize, + substsToSpecialize, + substsToApply, + ioDiff); } - // TransitiveSubtypeWitness - - bool TransitiveSubtypeWitness::equalsVal(Val* val) + DeclRefBase DeclRefBase::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet substSet, int* ioDiff) { - auto otherWitness = as(val); - if(!otherWitness) - return false; - - return sub->equals(otherWitness->sub) - && sup->equals(otherWitness->sup) - && subToMid->equalsVal(otherWitness->subToMid) - && midToSup.equals(otherWitness->midToSup); - } + // Nothing to do when we have no declaration. + if(!decl) + return *this; - RefPtr TransitiveSubtypeWitness::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) - { + // Apply the given substitutions to any specializations + // that have already been applied to this declaration. int diff = 0; - RefPtr substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); - RefPtr substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); - RefPtr substSubToMid = subToMid->substituteImpl(astBuilder, subst, &diff).as(); - DeclRef substMidToSup = midToSup.substituteImpl(astBuilder, subst, &diff); + auto substSubst = specializeSubstitutions( + astBuilder, + decl, + substitutions.substitutions, + substSet.substitutions, + &diff); - // If nothing changed, then we can bail out early. if (!diff) - return this; + return *this; - // Something changes, so let the caller know. - (*ioDiff)++; + *ioDiff += diff; - // 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. + 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. // - // 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 result = astBuilder->create(); - result->sub = substSub; - result->sup = substSup; - result->subToMid = substSubToMid; - result->midToSup = substMidToSup; - return result; + // I have only kept that logic in `DeclRefType::SubstituteImpl`, + // but it may turn out it is needed here too. + + return substDeclRef; } - String TransitiveSubtypeWitness::toString() + + // Check if this is an equivalent declaration reference to another + bool DeclRefBase::equals(DeclRefBase const& declRef) const { - // 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(); + if (decl != declRef.decl) + return false; + if (!substitutions.equals(declRef.substitutions)) + return false; + + return true; } - HashCode TransitiveSubtypeWitness::getHashCode() + // Convenience accessors for common properties of declarations + Name* DeclRefBase::getName() const { - auto hash = sub->getHashCode(); - hash = combineHash(hash, sup->getHashCode()); - hash = combineHash(hash, subToMid->getHashCode()); - hash = combineHash(hash, midToSup.getHashCode()); - return hash; + return decl->nameAndLoc.name; } - // + SourceLoc DeclRefBase::getLoc() const + { + return decl->loc; + } - String DeclRefBase::toString() const + DeclRefBase DeclRefBase::getParent() const { - if (!decl) return ""; + // 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 name = decl->getName(); - if (!name) return ""; + auto parentDecl = decl->parentDecl; + if (!parentDecl) + return DeclRefBase(); - // TODO: need to print out substitutions too! - return name->text; - } + // Default is to apply the same set of substitutions/specializations + // to the parent declaration as were applied to the child. + RefPtr substToApply = substitutions.substitutions; - bool SubstitutionSet::equals(const SubstitutionSet& substSet) const - { - if (substitutions == substSet.substitutions) + if(auto interfaceDecl = as(decl)) { - return true; + // 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(substToApply)) + { + if(thisTypeSubst->interfaceDecl == interfaceDecl) + { + // Strip away that specializations that apply to the interface. + substToApply = thisTypeSubst->outer; + } + } } - if (substitutions == nullptr || substSet.substitutions == nullptr) + + if (auto parentGenericDecl = as(parentDecl)) { - return false; + // 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(substToApply)) + { + if(genericSubst->genericDecl == parentGenericDecl) + { + // Strip away the specializations that were applied to the parent. + substToApply = genericSubst->outer; + } + } } - return substitutions->equals(substSet.substitutions); - } - HashCode SubstitutionSet::getHashCode() const - { - HashCode rs = 0; - if (substitutions) - rs = combineHash(rs, substitutions->getHashCode()); - return rs; + return DeclRefBase(parentDecl, substToApply); } - // ExtractExistentialType - - String ExtractExistentialType::toString() + HashCode DeclRefBase::getHashCode() const { - String result; - result.append(declRef.toString()); - result.append(".This"); - return result; + return combineHash(PointerHash<1>::getHashCode(decl), substitutions.getHashCode()); } - bool ExtractExistentialType::equalsImpl(Type* type) + // IntVal + + IntegerLiteralValue getIntVal(RefPtr val) { - if( auto extractExistential = as(type) ) + if (auto constantVal = as(val)) { - return declRef.equals(extractExistential->declRef); + return constantVal->value; } - return false; + SLANG_UNEXPECTED("needed a known integer value"); + return 0; } - HashCode ExtractExistentialType::getHashCode() - { - return declRef.getHashCode(); - } + // + + // HLSLPatchType - RefPtr ExtractExistentialType::createCanonicalType() + Type* HLSLPatchType::getElementType() { - return this; + return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[0]); } - RefPtr ExtractExistentialType::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) + IntVal* HLSLPatchType::getElementCount() { - int diff = 0; - auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); - if(!diff) - return this; - - (*ioDiff)++; - - RefPtr substValue = astBuilder->create(); - substValue->declRef = declRef; - return substValue; + return as(findInnerMostGenericSubstitution(declRef.substitutions)->args[1]); } - // ExtractExistentialSubtypeWitness + // Constructors for types - bool ExtractExistentialSubtypeWitness::equalsVal(Val* val) + RefPtr getArrayType( + ASTBuilder* astBuilder, + Type* elementType, + IntVal* elementCount) { - if( auto extractWitness = as(val) ) - { - return declRef.equals(extractWitness->declRef); - } - return false; + auto arrayType = astBuilder->create(); + arrayType->baseType = elementType; + arrayType->arrayLength = elementCount; + return arrayType; } - String ExtractExistentialSubtypeWitness::toString() + RefPtr getArrayType( + ASTBuilder* astBuilder, + Type* elementType) { - String result; - result.append("extractExistentialValue("); - result.append(declRef.toString()); - result.append(")"); - return result; + auto arrayType = astBuilder->create(); + arrayType->baseType = elementType; + return arrayType; } - HashCode ExtractExistentialSubtypeWitness::getHashCode() + RefPtr getNamedType( + ASTBuilder* astBuilder, + DeclRef const& declRef) { - return declRef.getHashCode(); + DeclRef specializedDeclRef = createDefaultSubstitutionsIfNeeded(astBuilder, declRef).as(); + + return astBuilder->create(specializedDeclRef); } - RefPtr ExtractExistentialSubtypeWitness::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) + + RefPtr getFuncType( + ASTBuilder* astBuilder, + DeclRef const& declRef) { - int diff = 0; - - auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); - auto substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); - auto substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); - - if(!diff) - return this; + RefPtr funcType = astBuilder->create(); - (*ioDiff)++; + funcType->resultType = getResultType(astBuilder, declRef); + for (auto paramDeclRef : getParameters(declRef)) + { + auto paramDecl = paramDeclRef.getDecl(); + auto paramType = getType(astBuilder, paramDeclRef); + if( paramDecl->findModifier() ) + { + paramType = astBuilder->getRefType(paramType); + } + else if( paramDecl->findModifier() ) + { + if(paramDecl->findModifier() || paramDecl->findModifier()) + { + paramType = astBuilder->getInOutType(paramType); + } + else + { + paramType = astBuilder->getOutType(paramType); + } + } + funcType->paramTypes.add(paramType); + } - RefPtr substValue = astBuilder->create(); - substValue->declRef = declRef; - substValue->sub = substSub; - substValue->sup = substSup; - return substValue; + return funcType; } - // - // TaggedUnionType - // - - String TaggedUnionType::toString() + RefPtr getGenericDeclRefType( + ASTBuilder* astBuilder, + DeclRef const& declRef) { - 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; + return astBuilder->create(declRef); } - bool TaggedUnionType::equalsImpl(Type* type) + RefPtr getNamespaceType( + ASTBuilder* astBuilder, + DeclRef const& declRef) { - auto taggedUnion = as(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; + auto type = astBuilder->create(); + type->declRef = declRef; + return type; } - HashCode TaggedUnionType::getHashCode() + RefPtr getSamplerStateType( + ASTBuilder* astBuilder) { - HashCode hashCode = 0; - for( auto caseType : caseTypes ) - { - hashCode = combineHash(hashCode, caseType->getHashCode()); - } - return hashCode; + return astBuilder->create(); } - RefPtr TaggedUnionType::createCanonicalType() + RefPtr findThisTypeSubstitution( + Substitutions* substs, + InterfaceDecl* interfaceDecl) { - RefPtr canType = m_astBuilder->create(); - - for( auto caseType : caseTypes ) + for(RefPtr s = substs; s; s = s->outer) { - auto canCaseType = caseType->getCanonicalType(); - canType->caseTypes.add(canCaseType); - } - - return canType; - } + auto thisTypeSubst = as(s); + if(!thisTypeSubst) + continue; - RefPtr TaggedUnionType::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) - { - int diff = 0; + if(thisTypeSubst->interfaceDecl != interfaceDecl) + continue; - List> substCaseTypes; - for( auto caseType : caseTypes ) - { - substCaseTypes.add(caseType->substituteImpl(astBuilder, subst, &diff).as()); + return thisTypeSubst; } - if(!diff) - return this; - - (*ioDiff)++; - RefPtr substType = astBuilder->create(); - substType->caseTypes.swapWith(substCaseTypes); - return substType; + return nullptr; } -// -// TaggedUnionSubtypeWitness -// - - -bool TaggedUnionSubtypeWitness::equalsVal(Val* val) -{ - auto taggedUnionWitness = as(val); - if(!taggedUnionWitness) - return false; - - auto caseCount = caseWitnesses.getCount(); - if(caseCount != taggedUnionWitness->caseWitnesses.getCount()) - return false; + // - for(Index ii = 0; ii < caseCount; ++ii) + String DeclRefBase::toString() const { - if(!caseWitnesses[ii]->equalsVal(taggedUnionWitness->caseWitnesses[ii])) - return false; - } - - return true; -} + if (!decl) return ""; -String TaggedUnionSubtypeWitness::toString() -{ - String result; - result.append("TaggedUnionSubtypeWitness("); - bool first = true; - for( auto caseWitness : caseWitnesses ) - { - if(!first) result.append(", "); - first = false; + auto name = decl->getName(); + if (!name) return ""; - result.append(caseWitness->toString()); + // TODO: need to print out substitutions too! + return name->text; } - return result; -} -HashCode TaggedUnionSubtypeWitness::getHashCode() -{ - HashCode hash = 0; - for( auto caseWitness : caseWitnesses ) + bool SubstitutionSet::equals(const SubstitutionSet& substSet) const { - hash = combineHash(hash, caseWitness->getHashCode()); + if (substitutions == substSet.substitutions) + { + return true; + } + if (substitutions == nullptr || substSet.substitutions == nullptr) + { + return false; + } + return substitutions->equals(substSet.substitutions); } - return hash; -} -RefPtr TaggedUnionSubtypeWitness::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) -{ - int diff = 0; - - auto substSub = sub->substituteImpl(astBuilder, subst, &diff).as(); - auto substSup = sup->substituteImpl(astBuilder, subst, &diff).as(); - - List> substCaseWitnesses; - for( auto caseWitness : caseWitnesses ) + HashCode SubstitutionSet::getHashCode() const { - substCaseWitnesses.add(caseWitness->substituteImpl(astBuilder, subst, &diff)); + HashCode rs = 0; + if (substitutions) + rs = combineHash(rs, substitutions->getHashCode()); + return rs; } - if(!diff) - return this; - - (*ioDiff)++; - - RefPtr substWitness = astBuilder->create(); - substWitness->sub = substSub; - substWitness->sup = substSup; - substWitness->caseWitnesses.swapWith(substCaseWitnesses); - return substWitness; -} - + + Module* getModule(Decl* decl) { for( auto dd = decl; dd; dd = dd->parentDecl ) @@ -2698,184 +1288,4 @@ char const* getGLSLNameForImageFormat(ImageFormat format) } } -// -// ExistentialSpecializedType -// - -String ExistentialSpecializedType::toString() -{ - String result; - result.append("__ExistentialSpecializedType("); - result.append(baseType->toString()); - for( auto arg : args ) - { - result.append(", "); - result.append(arg.val->toString()); - } - result.append(")"); - return result; -} - -bool ExistentialSpecializedType::equalsImpl(Type * type) -{ - auto other = as(type); - if(!other) - return false; - - if(!baseType->equals(other->baseType)) - return false; - - auto argCount = args.getCount(); - if(argCount != other->args.getCount()) - return false; - - for( Index ii = 0; ii < argCount; ++ii ) - { - auto arg = args[ii]; - auto otherArg = other->args[ii]; - - if(!arg.val->equalsVal(otherArg.val)) - return false; - - if(!areValsEqual(arg.witness, otherArg.witness)) - return false; - } - return true; -} - -HashCode ExistentialSpecializedType::getHashCode() -{ - Hasher hasher; - hasher.hashObject(baseType); - for(auto arg : args) - { - hasher.hashObject(arg.val); - if(auto witness = arg.witness) - hasher.hashObject(witness); - } - return hasher.getResult(); -} - -RefPtr getCanonicalValue(Val* val) -{ - if(!val) - return nullptr; - if(auto type = as(val)) - { - return type->getCanonicalType(); - } - // TODO: We may eventually need/want some sort of canonicalization - // for non-type values, but for now there is nothing to do. - return val; -} - -RefPtr ExistentialSpecializedType::createCanonicalType() -{ - RefPtr canType = m_astBuilder->create(); - - canType->baseType = baseType->getCanonicalType(); - for( auto arg : args ) - { - ExpandedSpecializationArg canArg; - canArg.val = getCanonicalValue(arg.val); - canArg.witness = getCanonicalValue(arg.witness); - canType->args.add(canArg); - } - return canType; -} - -RefPtr substituteImpl(ASTBuilder* astBuilder, Val* val, SubstitutionSet subst, int* ioDiff) -{ - if(!val) return nullptr; - return val->substituteImpl(astBuilder, subst, ioDiff); -} - -RefPtr ExistentialSpecializedType::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) -{ - int diff = 0; - - auto substBaseType = baseType->substituteImpl(astBuilder, subst, &diff).as(); - - ExpandedSpecializationArgs substArgs; - for( auto arg : args ) - { - ExpandedSpecializationArg substArg; - substArg.val = Slang::substituteImpl(astBuilder, arg.val, subst, &diff); - substArg.witness = Slang::substituteImpl(astBuilder, arg.witness, subst, &diff); - substArgs.add(substArg); - } - - if(!diff) - return this; - - (*ioDiff)++; - - RefPtr substType = astBuilder->create(); - substType->baseType = substBaseType; - substType->args = substArgs; - return substType; -} - -// -// ThisType -// - -String ThisType::toString() -{ - String result; - result.append(interfaceDeclRef.toString()); - result.append(".This"); - return result; -} - -bool ThisType::equalsImpl(Type * type) -{ - auto other = as(type); - if(!other) - return false; - - if(!interfaceDeclRef.equals(other->interfaceDeclRef)) - return false; - - return true; -} - -HashCode ThisType::getHashCode() -{ - return combineHash( - HashCode(typeid(*this).hash_code()), - interfaceDeclRef.getHashCode()); -} - -RefPtr ThisType::createCanonicalType() -{ - RefPtr canType = m_astBuilder->create(); - - // TODO: need to canonicalize the decl-ref - canType->interfaceDeclRef = interfaceDeclRef; - return canType; -} - -RefPtr ThisType::substituteImpl(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) -{ - int diff = 0; - - auto substInterfaceDeclRef = interfaceDeclRef.substituteImpl(astBuilder, subst, &diff); - - auto thisTypeSubst = findThisTypeSubstitution(subst.substitutions, substInterfaceDeclRef.getDecl()); - if( thisTypeSubst ) - { - return thisTypeSubst->witness->sub; - } - - if(!diff) - return this; - - (*ioDiff)++; - - RefPtr substType = m_astBuilder->create(); - substType->interfaceDeclRef = substInterfaceDeclRef; - return substType; -} - } // namespace Slang diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h index dff24435d..53ec57daa 100644 --- a/source/slang/slang-syntax.h +++ b/source/slang/slang-syntax.h @@ -210,6 +210,17 @@ namespace Slang } } + // + + RefPtr findThisTypeSubstitution( + Substitutions* substs, + InterfaceDecl* interfaceDecl); + + RequirementWitness tryLookUpRequirementWitness( + ASTBuilder* astBuilder, + SubtypeWitness* subtypeWitness, + Decl* requirementKey); + // TODO: where should this live? SubstitutionSet createDefaultSubstitutions( ASTBuilder* astBuilder, diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index c3e936f8a..353da833d 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -275,8 +275,12 @@ + + + + diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index bec8547e1..589bd374c 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -272,12 +272,24 @@ Source Files + + Source Files + Source Files Source Files + + Source Files + + + Source Files + + + Source Files + Source Files -- cgit v1.2.3