https://github.com/shader-slang/slang
Raw File
Tip revision: e59516fa8c3a16eb7b99a928c5b85b97bf44fd72 authored by Yong He on 01 February 2022, 00:26:03 UTC
Revise entrypoint renaming interface. (#2113)
Tip revision: e59516f
slang-ast-val.cpp
// slang-ast-type.cpp
#include "slang-ast-builder.h"
#include <assert.h>
#include <typeinfo>

#include "slang-generated-ast-macro.h"

#include "slang-syntax.h"

namespace Slang {

Val* Val::substitute(ASTBuilder* astBuilder, SubstitutionSet subst)
{
    if (!subst) return this;
    int diff = 0;
    return substituteImpl(astBuilder, subst, &diff);
}

Val* 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))
}

void Val::toText(StringBuilder& out)
{
    SLANG_AST_NODE_VIRTUAL_CALL(Val, toText, (out))
}

String Val::toString()
{
    StringBuilder builder;
    toText(builder);
    return builder;
}

HashCode Val::getHashCode()
{
    SLANG_AST_NODE_VIRTUAL_CALL(Val, getHashCode, ())
}

Val* 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;
}

void Val::_toTextOverride(StringBuilder& out)
{
    SLANG_UNUSED(out);
    SLANG_UNEXPECTED("Val::_toStringOverride not overridden");
}

HashCode Val::_getHashCodeOverride()
{
    SLANG_UNEXPECTED("Val::_getHashCodeOverride not overridden");
    //return HashCode(0);
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ConstantIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

bool ConstantIntVal::_equalsValOverride(Val* val)
{
    if (auto intVal = as<ConstantIntVal>(val))
        return value == intVal->value;
    return false;
}

void ConstantIntVal::_toTextOverride(StringBuilder& out)
{
    out << value;
}

HashCode ConstantIntVal::_getHashCodeOverride()
{
    return (HashCode)value;
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericParamIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

bool GenericParamIntVal::_equalsValOverride(Val* val)
{
    if (auto genericParamVal = as<GenericParamIntVal>(val))
    {
        return declRef.equals(genericParamVal->declRef);
    }
    return false;
}

void GenericParamIntVal::_toTextOverride(StringBuilder& out)
{
    Name* name = declRef.getName();
    if (name)
    {
        out << name->text;
    }
}

HashCode GenericParamIntVal::_getHashCodeOverride()
{
    return declRef.getHashCode() ^ HashCode(0xFFFF);
}

Val* 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 = as<GenericSubstitution>(s);
        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 == declRef.getDecl())
            {
                // We've found it, so return the corresponding specialization argument
                (*ioDiff)++;
                return genSubst->args[index];
            }
            else if (auto typeParam = as<GenericTypeParamDecl>(m))
            {
                index++;
            }
            else if (auto valParam = as<GenericValueParamDecl>(m))
            {
                index++;
            }
            else
            {
            }
        }
    }

    // Nothing found: don't substitute.
    return this;
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ErrorIntVal !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

bool ErrorIntVal::_equalsValOverride(Val* val)
{
    if (auto errorIntVal = as<ErrorIntVal>(val))
    {
        return true;
    }
    return false;
}

void ErrorIntVal::_toTextOverride(StringBuilder& out)
{
    out << toSlice("<error>");
}

HashCode ErrorIntVal::_getHashCodeOverride()
{
    return HashCode(typeid(this).hash_code());
}

Val* 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<TypeEqualityWitness>(val);
    if (!otherWitness)
        return false;
    return sub->equals(otherWitness->sub);
}

Val* TypeEqualityWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff)
{
    TypeEqualityWitness* rs = astBuilder->create<TypeEqualityWitness>();
    rs->sub = as<Type>(sub->substituteImpl(astBuilder, subst, ioDiff));
    rs->sup = as<Type>(sup->substituteImpl(astBuilder, subst, ioDiff));
    return rs;
}

void TypeEqualityWitness::_toTextOverride(StringBuilder& out)
{
    out << toSlice("TypeEqualityWitness(") << sub << toSlice(")");
}

HashCode TypeEqualityWitness::_getHashCodeOverride()
{
    return sub->getHashCode();
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DeclaredSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

bool DeclaredSubtypeWitness::_equalsValOverride(Val* val)
{
    auto otherWitness = as<DeclaredSubtypeWitness>(val);
    if (!otherWitness)
        return false;

    return sub->equals(otherWitness->sub)
        && sup->equals(otherWitness->sup)
        && declRef.equals(otherWitness->declRef);
}

Val* DeclaredSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff)
{
    if (auto genConstraintDeclRef = declRef.as<GenericTypeConstraintDecl>())
    {
        auto genConstraintDecl = genConstraintDeclRef.getDecl();

        // search for a substitution that might apply to us
        for (auto s = subst.substitutions; s; s = s->outer)
        {
            if (auto genericSubst = as<GenericSubstitution>(s))
            {
                // the generic decl associated with the substitution list must be
                // the generic decl that declared this parameter
                auto genericDecl = genericSubst->genericDecl;
                if (genericDecl != genConstraintDecl->parentDecl)
                    continue;

                bool found = false;
                Index index = 0;
                for (auto m : genericDecl->members)
                {
                    if (auto constraintParam = as<GenericTypeConstraintDecl>(m))
                    {
                        if (constraintParam == declRef.getDecl())
                        {
                            found = true;
                            break;
                        }
                        index++;
                    }
                }
                if (found)
                {
                    (*ioDiff)++;
                    auto ordinaryParamCount = genericDecl->getMembersOfType<GenericTypeParamDecl>().getCount() +
                        genericDecl->getMembersOfType<GenericValueParamDecl>().getCount();
                    SLANG_ASSERT(index + ordinaryParamCount < genericSubst->args.getCount());
                    return genericSubst->args[index + ordinaryParamCount];
                }
            }
        }
    }

    // Perform substitution on the constituent elements.
    int diff = 0;
    auto substSub = as<Type>(sub->substituteImpl(astBuilder, subst, &diff));
    auto substSup = as<Type>(sup->substituteImpl(astBuilder, subst, &diff));
    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<GenericTypeConstraintDecl>(substDeclRef.decl))
    {
        if (auto substAssocTypeDecl = as<AssocTypeDecl>(substTypeConstraintDecl->parentDecl))
        {
            if (auto interfaceDecl = as<InterfaceDecl>(substAssocTypeDecl->parentDecl))
            {
                // At this point we have a constraint decl for an associated type,
                // and we nee to see if we are dealing with a concrete substitution
                // for the interface around that associated type.
                if (auto thisTypeSubst = findThisTypeSubstitution(substDeclRef.substitutions, interfaceDecl))
                {
                    // We need to look up the declaration that satisfies
                    // the requirement named by the associated type.
                    Decl* requirementKey = substTypeConstraintDecl;
                    RequirementWitness requirementWitness = tryLookUpRequirementWitness(astBuilder, thisTypeSubst->witness, requirementKey);
                    switch (requirementWitness.getFlavor())
                    {
                        default:
                            break;

                        case RequirementWitness::Flavor::val:
                        {
                            auto satisfyingVal = requirementWitness.getVal();
                            return satisfyingVal;
                        }
                    }
                }
            }
        }
    }

    DeclaredSubtypeWitness* rs = astBuilder->create<DeclaredSubtypeWitness>();
    rs->sub = substSub;
    rs->sup = substSup;
    rs->declRef = substDeclRef;
    return rs;
}

void DeclaredSubtypeWitness::_toTextOverride(StringBuilder& out)
{
    out << toSlice("DeclaredSubtypeWitness(") << sub << toSlice(", ") << sup << toSlice(", ") << declRef << toSlice(")");
}

HashCode DeclaredSubtypeWitness::_getHashCodeOverride()
{
    return declRef.getHashCode();
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TransitiveSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

bool TransitiveSubtypeWitness::_equalsValOverride(Val* val)
{
    auto otherWitness = as<TransitiveSubtypeWitness>(val);
    if (!otherWitness)
        return false;

    return sub->equals(otherWitness->sub)
        && sup->equals(otherWitness->sup)
        && subToMid->equalsVal(otherWitness->subToMid)
        && midToSup->equalsVal(otherWitness->midToSup);
}

Val* TransitiveSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff)
{
    int diff = 0;

    Type* substSub = as<Type>(sub->substituteImpl(astBuilder, subst, &diff));
    Type* substSup = as<Type>(sup->substituteImpl(astBuilder, subst, &diff));
    SubtypeWitness* substSubToMid = as<SubtypeWitness>(subToMid->substituteImpl(astBuilder, subst, &diff));
    SubtypeWitness* substMidToSup = as<SubtypeWitness>(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.
    TransitiveSubtypeWitness* result = astBuilder->create<TransitiveSubtypeWitness>();
    result->sub = substSub;
    result->sup = substSup;
    result->subToMid = substSubToMid;
    result->midToSup = substMidToSup;
    return result;
}

void TransitiveSubtypeWitness::_toTextOverride(StringBuilder& out)
{
    // Note: we only print the constituent
    // witnesses, and rely on them to print
    // the starting and ending types.
    
    out << toSlice("TransitiveSubtypeWitness(") << subToMid << toSlice(", ") << midToSup << toSlice(")");
}

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<ExtractExistentialSubtypeWitness>(val))
    {
        return declRef.equals(extractWitness->declRef);
    }
    return false;
}

void ExtractExistentialSubtypeWitness::_toTextOverride(StringBuilder& out)
{
    out << toSlice("extractExistentialValue(") << declRef << toSlice(")");
}

HashCode ExtractExistentialSubtypeWitness::_getHashCodeOverride()
{
    return declRef.getHashCode();
}

Val* ExtractExistentialSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff)
{
    int diff = 0;

    auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff);
    auto substSub = as<Type>(sub->substituteImpl(astBuilder, subst, &diff));
    auto substSup = as<Type>(sup->substituteImpl(astBuilder, subst, &diff));

    if (!diff)
        return this;

    (*ioDiff)++;

    ExtractExistentialSubtypeWitness* substValue = astBuilder->create<ExtractExistentialSubtypeWitness>();
    substValue->declRef = declRef;
    substValue->sub = substSub;
    substValue->sup = substSup;
    return substValue;
}


// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TaggedUnionSubtypeWitness !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

bool TaggedUnionSubtypeWitness::_equalsValOverride(Val* val)
{
    auto taggedUnionWitness = as<TaggedUnionSubtypeWitness>(val);
    if (!taggedUnionWitness)
        return false;

    auto caseCount = caseWitnesses.getCount();
    if (caseCount != taggedUnionWitness->caseWitnesses.getCount())
        return false;

    for (Index ii = 0; ii < caseCount; ++ii)
    {
        if (!caseWitnesses[ii]->equalsVal(taggedUnionWitness->caseWitnesses[ii]))
            return false;
    }

    return true;
}

void TaggedUnionSubtypeWitness::_toTextOverride(StringBuilder& out)
{
    out << toSlice("TaggedUnionSubtypeWitness(");
    bool first = true;
    for (auto caseWitness : caseWitnesses)
    {
        if (!first)
        {
            out << toSlice(", ");
        }
        first = false;

        out << caseWitness;
    }
    out << toSlice(")");
}

HashCode TaggedUnionSubtypeWitness::_getHashCodeOverride()
{
    HashCode hash = 0;
    for (auto caseWitness : caseWitnesses)
    {
        hash = combineHash(hash, caseWitness->getHashCode());
    }
    return hash;
}

Val* TaggedUnionSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff)
{
    int diff = 0;

    auto substSub = as<Type>(sub->substituteImpl(astBuilder, subst, &diff));
    auto substSup = as<Type>(sup->substituteImpl(astBuilder, subst, &diff));

    List<Val*> substCaseWitnesses;
    for (auto caseWitness : caseWitnesses)
    {
        substCaseWitnesses.add(caseWitness->substituteImpl(astBuilder, subst, &diff));
    }

    if (!diff)
        return this;

    (*ioDiff)++;

    TaggedUnionSubtypeWitness* substWitness = astBuilder->create<TaggedUnionSubtypeWitness>();
    substWitness->sub = substSub;
    substWitness->sup = substSup;
    substWitness->caseWitnesses.swapWith(substCaseWitnesses);
    return substWitness;
}

// ModifierVal

bool ModifierVal::_equalsValOverride(Val* val)
{
    // TODO: This is assuming we can fully deduplicate the values that represent
    // modifiers, which may not actually be the case if there are multiple modules
    // being combined that use different `ASTBuilder`s.
    //
    return this == val;
}

HashCode ModifierVal::_getHashCodeOverride()
{
    Hasher hasher;
    hasher.hashValue((void*) this);
    return hasher.getResult();
}

// UNormModifierVal

void UNormModifierVal::_toTextOverride(StringBuilder& out)
{
    out.append("unorm");
}

Val* UNormModifierVal::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff)
{
    SLANG_UNUSED(astBuilder);
    SLANG_UNUSED(subst);
    SLANG_UNUSED(ioDiff);
    return this;
}

// SNormModifierVal

void SNormModifierVal::_toTextOverride(StringBuilder& out)
{
    out.append("snorm");
}

Val* SNormModifierVal::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff)
{
    SLANG_UNUSED(astBuilder);
    SLANG_UNUSED(subst);
    SLANG_UNUSED(ioDiff);
    return this;
}

} // namespace Slang
back to top