// slang-ast-type.cpp #include "slang-ast-builder.h" #include #include #include "slang-syntax.h" #include "slang-generated-ast-macro.h" namespace Slang { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Type !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Type* 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; } Type* Type::_createCanonicalTypeOverride() { SLANG_UNEXPECTED("Type::_createCanonicalTypeOverride not overridden"); //return Type*(); } bool Type::_equalsValOverride(Val* val) { if (auto type = dynamicCast(val)) return const_cast(this)->equals(type); return false; } Val* 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; if (!et->canonicalType) return getASTBuilder()->getErrorType(); } return et->canonicalType; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OverloadGroupType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void OverloadGroupType::_toTextOverride(StringBuilder& out) { out << toSlice("overload group"); } bool OverloadGroupType::_equalsImplOverride(Type * /*type*/) { return false; } Type* OverloadGroupType::_createCanonicalTypeOverride() { return this; } HashCode OverloadGroupType::_getHashCodeOverride() { return (HashCode)(size_t(this)); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! InitializerListType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void InitializerListType::_toTextOverride(StringBuilder& out) { out << toSlice("initializer list"); } bool InitializerListType::_equalsImplOverride(Type * /*type*/) { return false; } Type* InitializerListType::_createCanonicalTypeOverride() { return this; } HashCode InitializerListType::_getHashCodeOverride() { return (HashCode)(size_t(this)); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ErrorType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void ErrorType::_toTextOverride(StringBuilder& out) { out << toSlice("error"); } bool ErrorType::_equalsImplOverride(Type* type) { if (auto errorType = as(type)) return true; return false; } Type* ErrorType::_createCanonicalTypeOverride() { return this; } Val* ErrorType::_substituteImplOverride(ASTBuilder* /* astBuilder */, SubstitutionSet /*subst*/, int* /*ioDiff*/) { return this; } HashCode ErrorType::_getHashCodeOverride() { return HashCode(size_t(this)); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BottomType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void BottomType::_toTextOverride(StringBuilder& out) { out << toSlice("never"); } bool BottomType::_equalsImplOverride(Type* type) { if (auto bottomType = as(type)) return true; return false; } Type* BottomType::_createCanonicalTypeOverride() { return this; } Val* BottomType::_substituteImplOverride( ASTBuilder* /* astBuilder */, SubstitutionSet /*subst*/, int* /*ioDiff*/) { return this; } HashCode BottomType::_getHashCodeOverride() { return HashCode(size_t(this)); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DeclRefType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void DeclRefType::_toTextOverride(StringBuilder& out) { out << declRef; } 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; } Type* DeclRefType::_createCanonicalTypeOverride() { // A declaration reference is already canonical declRef.substitute(this->getASTBuilder(), this); return this; } Val* maybeSubstituteGenericParam(Val* paramVal, Decl* paramDecl, SubstitutionSet subst, int* ioDiff); Val* 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())) { if (auto result = maybeSubstituteGenericParam(this, genericTypeParamDecl, subst, ioDiff)) { if (auto substDeclRefType = as(result)) { // After generic substitution, we may be able to further simplify // by looking up the actual type of an associated type. if (auto satisfyingVal = _tryLookupConcreteAssociatedTypeFromThisTypeSubst( astBuilder, substDeclRefType->declRef)) return satisfyingVal; } return result; } } 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 satisfyingVal = _tryLookupConcreteAssociatedTypeFromThisTypeSubst(astBuilder, substDeclRef)) return satisfyingVal; // 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; } Type* BasicExpressionType::_createCanonicalTypeOverride() { // A basic type is already canonical, in our setup return this; } BasicExpressionType* BasicExpressionType::_getScalarTypeOverride() { return this; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TensorViewType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Type* TensorViewType::getElementType() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[0]); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VectorExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void VectorExpressionType::_toTextOverride(StringBuilder& out) { out << toSlice("vector<") << elementType << toSlice(",") << elementCount << toSlice(">"); } BasicExpressionType* VectorExpressionType::_getScalarTypeOverride() { return as(elementType); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MatrixExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void MatrixExpressionType::_toTextOverride(StringBuilder& out) { out << toSlice("matrix<") << getElementType() << toSlice(",") << getRowCount() << toSlice(",") << getColumnCount() << toSlice(">"); } BasicExpressionType* MatrixExpressionType::_getScalarTypeOverride() { return as(getElementType()); } Type* MatrixExpressionType::getElementType() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[0]); } IntVal* MatrixExpressionType::getRowCount() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[1]); } IntVal* MatrixExpressionType::getColumnCount() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[2]); } Type* MatrixExpressionType::getRowType() { if (!rowType) { rowType = m_astBuilder->getVectorType(getElementType(), getColumnCount()); } return rowType; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Type* ArrayExpressionType::getElementType() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[0]); } IntVal* ArrayExpressionType::getElementCount() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[1]); } void ArrayExpressionType::_toTextOverride(StringBuilder& out) { out << getElementType(); out.appendChar('['); if (!isUnsized()) { out << getElementCount(); } out.appendChar(']'); } bool ArrayExpressionType::isUnsized() { if (auto constSize = as(getElementCount())) { if (constSize->value == kUnsizedArrayMagicLength) return true; } return false; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TypeType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void TypeType::_toTextOverride(StringBuilder& out) { out << toSlice("typeof(") << type << toSlice(")"); } bool TypeType::_equalsImplOverride(Type * t) { if (auto typeType = as(t)) { return t->equals(typeType->type); } return false; } Type* TypeType::_createCanonicalTypeOverride() { return getASTBuilder()->getTypeType(type->getCanonicalType()); } HashCode TypeType::_getHashCodeOverride() { SLANG_UNEXPECTED("TypeType::_getHashCodeOverride should be unreachable"); //return HashCode(0); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericDeclRefType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void GenericDeclRefType::_toTextOverride(StringBuilder& out) { // TODO: what is appropriate here? out << toSlice(">"); } bool GenericDeclRefType::_equalsImplOverride(Type * type) { if (auto genericDeclRefType = as(type)) { return declRef.equals(genericDeclRefType->declRef); } return false; } HashCode GenericDeclRefType::_getHashCodeOverride() { return declRef.getHashCode(); } Type* GenericDeclRefType::_createCanonicalTypeOverride() { return this; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NamespaceType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void NamespaceType::_toTextOverride(StringBuilder& out) { out << toSlice("namespace ") << declRef; } bool NamespaceType::_equalsImplOverride(Type * type) { if (auto namespaceType = as(type)) { return declRef.equals(namespaceType->declRef); } return false; } HashCode NamespaceType::_getHashCodeOverride() { return declRef.getHashCode(); } Type* NamespaceType::_createCanonicalTypeOverride() { return this; } Type* DifferentialPairType::getPrimalType() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[0]); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PtrTypeBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Type* PtrTypeBase::getValueType() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[0]); } Type* OptionalType::getValueType() { return as(findInnerMostGenericSubstitution(declRef.substitutions)->getArgs()[0]); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NamedExpressionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void NamedExpressionType::_toTextOverride(StringBuilder& out) { if (declRef.getDecl()) { _printNestedDecl(declRef.substitutions, declRef.getDecl(), out); } } bool NamedExpressionType::_equalsImplOverride(Type * /*type*/) { SLANG_UNEXPECTED("NamedExpressionType::_equalsImplOverride should be unreachable"); //return false; } Type* NamedExpressionType::_createCanonicalTypeOverride() { if (!innerType) innerType = getType(m_astBuilder, declRef); if (innerType) return innerType->getCanonicalType(); return nullptr; } 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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ParameterDirection FuncType::getParamDirection(Index index) { auto paramType = getParamType(index); if (as(paramType)) { return kParameterDirection_Ref; } else if (as(paramType)) { return kParameterDirection_InOut; } else if (as(paramType)) { return kParameterDirection_Out; } else { return kParameterDirection_In; } } void FuncType::_toTextOverride(StringBuilder& out) { out << toSlice("("); Index paramCount = getParamCount(); for (Index pp = 0; pp < paramCount; ++pp) { if (pp != 0) { out << toSlice(", "); } out << getParamType(pp); } out << toSlice(") -> ") << getResultType(); if (!getErrorType()->equals(getASTBuilder()->getBottomType())) { out << " throws " << getErrorType(); } } 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; if (!errorType->equals(funcType->errorType)) 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; } Val* FuncType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; // result type Type* substResultType = as(resultType->substituteImpl(astBuilder, subst, &diff)); // error type Type* substErrorType = as(errorType->substituteImpl(astBuilder, subst, &diff)); // parameter types List substParamTypes; for (auto pp : paramTypes) { substParamTypes.add(as(pp->substituteImpl(astBuilder, subst, &diff))); } // early exit for no change... if (!diff) return this; (*ioDiff)++; FuncType* substType = astBuilder->create(); substType->resultType = substResultType; substType->paramTypes = substParamTypes; substType->errorType = substErrorType; return substType; } Type* FuncType::_createCanonicalTypeOverride() { // result type Type* canResultType = resultType->getCanonicalType(); Type* canErrorType = errorType->getCanonicalType(); // parameter types List canParamTypes; for (auto pp : paramTypes) { canParamTypes.add(pp->getCanonicalType()); } FuncType* canType = getASTBuilder()->create(); canType->resultType = canResultType; canType->paramTypes = canParamTypes; canType->errorType = canErrorType; 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()); } combineHash(hashCode, getErrorType()->getHashCode()); return hashCode; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExtractExistentialType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void ExtractExistentialType::_toTextOverride(StringBuilder& out) { out << declRef << toSlice(".This"); } bool ExtractExistentialType::_equalsImplOverride(Type* type) { if (auto extractExistential = as(type)) { return declRef.equals(extractExistential->declRef); } return false; } HashCode ExtractExistentialType::_getHashCodeOverride() { return combineHash(declRef.getHashCode(), originalInterfaceType->getHashCode(), originalInterfaceDeclRef.getHashCode()); } Type* ExtractExistentialType::_createCanonicalTypeOverride() { return this; } Val* ExtractExistentialType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); auto substOriginalInterfaceType = originalInterfaceType->substituteImpl(astBuilder, subst, &diff); auto substOriginalInterfaceDeclRef = originalInterfaceDeclRef.substituteImpl(astBuilder, subst, &diff); if (!diff) return this; (*ioDiff)++; ExtractExistentialType* substValue = astBuilder->create(); substValue->declRef = substDeclRef; substValue->originalInterfaceType = as(substOriginalInterfaceType); substValue->originalInterfaceDeclRef = substOriginalInterfaceDeclRef; return substValue; } SubtypeWitness* ExtractExistentialType::getSubtypeWitness() { if (auto cachedValue = this->cachedSubtypeWitness) return cachedValue; ExtractExistentialSubtypeWitness* openedWitness = m_astBuilder->create(); openedWitness->sub = this; openedWitness->sup = originalInterfaceType; openedWitness->declRef = this->declRef; this->cachedSubtypeWitness = openedWitness; return openedWitness; } DeclRef ExtractExistentialType::getSpecializedInterfaceDeclRef() { if (auto cachedValue = this->cachedSpecializedInterfaceDeclRef) return cachedValue; auto interfaceDecl = originalInterfaceDeclRef.getDecl(); SubtypeWitness* openedWitness = getSubtypeWitness(); ThisTypeSubstitution* openedThisType = m_astBuilder->create(); openedThisType->outer = originalInterfaceDeclRef.substitutions.substitutions; openedThisType->interfaceDecl = interfaceDecl; openedThisType->witness = openedWitness; DeclRef specialiedInterfaceDeclRef = DeclRef(interfaceDecl, openedThisType); this->cachedSpecializedInterfaceDeclRef = specialiedInterfaceDeclRef; return specialiedInterfaceDeclRef; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TaggedUnionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void TaggedUnionType::_toTextOverride(StringBuilder& out) { out << toSlice("__TaggedUnion("); bool first = true; for (auto caseType : caseTypes) { if (!first) { out << toSlice(", "); } first = false; out << caseType; } out << toSlice(")"); } 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; } Type* TaggedUnionType::_createCanonicalTypeOverride() { TaggedUnionType* canType = m_astBuilder->create(); for (auto caseType : caseTypes) { auto canCaseType = caseType->getCanonicalType(); canType->caseTypes.add(canCaseType); } return canType; } Val* TaggedUnionType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; List substCaseTypes; for (auto caseType : caseTypes) { substCaseTypes.add(as(caseType->substituteImpl(astBuilder, subst, &diff))); } if (!diff) return this; (*ioDiff)++; TaggedUnionType* substType = astBuilder->create(); substType->caseTypes.swapWith(substCaseTypes); return substType; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExistentialSpecializedType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void ExistentialSpecializedType::_toTextOverride(StringBuilder& out) { out << toSlice("__ExistentialSpecializedType(") << baseType; for (auto arg : args) { out << toSlice(", ") << arg.val; } out << toSlice(")"); } 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 Val* _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; } Type* ExistentialSpecializedType::_createCanonicalTypeOverride() { ExistentialSpecializedType* 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 Val* _substituteImpl(ASTBuilder* astBuilder, Val* val, SubstitutionSet subst, int* ioDiff) { if (!val) return nullptr; return val->substituteImpl(astBuilder, subst, ioDiff); } Val* ExistentialSpecializedType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; auto substBaseType = as(baseType->substituteImpl(astBuilder, subst, &diff)); 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)++; ExistentialSpecializedType* substType = astBuilder->create(); substType->baseType = substBaseType; substType->args = substArgs; return substType; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ThisType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void ThisType::_toTextOverride(StringBuilder& out) { out << interfaceDeclRef << toSlice(".This"); } 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()); } Type* ThisType::_createCanonicalTypeOverride() { ThisType* canType = m_astBuilder->create(); // TODO: need to canonicalize the decl-ref canType->interfaceDeclRef = interfaceDeclRef; return canType; } Val* 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)++; ThisType* substType = m_astBuilder->create(); substType->interfaceDeclRef = substInterfaceDeclRef; return substType; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AndType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void AndType::_toTextOverride(StringBuilder& out) { out << left << toSlice(" & ") << right; } bool AndType::_equalsImplOverride(Type * type) { auto other = as(type); if (!other) return false; if(!left->equals(other->left)) return false; if(!right->equals(other->right)) return false; return true; } HashCode AndType::_getHashCodeOverride() { Hasher hasher; hasher.hashObject(left); hasher.hashObject(right); return hasher.getResult(); } Type* AndType::_createCanonicalTypeOverride() { AndType* canType = m_astBuilder->create(); // TODO: proper canonicalization of an `&` type relies on // several different things: // // * We need to re-associate types that might involve // nesting of `&`, such as `(A & B) & (C & D)`, into // a canonical form where the nesting is consistent // (i.e., always left- or right-associative). // // * We need to commute types so that they are in a // consistent order, so that `A & B` and `B & A` both // result in the same canonicalization. This requirement // implies that we must invent a total order on types. // // * We need to canonicalize `&` types where one of the // elements might be implied by another. E.g., if we // have `interface IDerived : IBase`, then a type like // `IDerived & IBase` is equivalent to just `IDerived` // because the presence of an `IBase` conformance is // implied. A special case of the above is the possibility // of duplicates in the list of types (e.g., `A & B & A`). // // * The previous requirement raises the problem that // the relationships between `interface`s might either // evolve over time, or be subject to `extension` // declarations in other modules. The canonicalization // algorithm must be clear about what information it // is allowed to make use of, as this can/will affect // binary interfaces (via mangled names). // // We are going to completely ignore these issues for // right now, in the name of getting something up and running. // canType->left = left->getCanonicalType(); canType->right = right->getCanonicalType(); return canType; } Val* AndType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; auto substLeft = as(left ->substituteImpl(astBuilder, subst, &diff)); auto substRight = as(right->substituteImpl(astBuilder, subst, &diff)); if(!diff) return this; (*ioDiff)++; AndType* substType = m_astBuilder->create(); substType->left = substLeft; substType->right = substRight; return substType; } // ModifiedType void ModifiedType::_toTextOverride(StringBuilder& out) { for( auto modifier : modifiers ) { modifier->toText(out); out.appendChar(' '); } base->toText(out); } bool ModifiedType::_equalsImplOverride(Type* type) { auto other = as(type); if(!other) return false; if(!base->equals(other->base)) return false; // TODO: Eventually we need to put the `modifiers` into // a canonical ordering as part of creation of a `ModifiedType`, // so that two instances that apply the same modifiers to // the same type will have those modifiers in a matching order. // // The simplest way to achieve that ordering *for now* would // be to sort the array by the integer AST node type tag. // That approach would of course not scale to modifiers that // have any operands of their own. // // Note that we would *also* need the logic that creates a // `ModifiedType` to detect when the base type is itself a // `ModifiedType` and produce a single `ModifiedType` with // a combined list of modifiers and a non-`ModifiedType` as // its base type. // auto modifierCount = modifiers.getCount(); if(modifierCount != other->modifiers.getCount()) return false; for( Index i = 0; i < modifierCount; ++i ) { auto thisModifier = this->modifiers[i]; auto otherModifier = other->modifiers[i]; if(!thisModifier->equalsVal(otherModifier)) return false; } return true; } HashCode ModifiedType::_getHashCodeOverride() { Hasher hasher; hasher.hashObject(base); for( auto modifier : modifiers ) { hasher.hashObject(modifier); } return hasher.getResult(); } Type* ModifiedType::_createCanonicalTypeOverride() { ModifiedType* canonical = m_astBuilder->create(); canonical->base = base->getCanonicalType(); for( auto modifier : modifiers ) { canonical->modifiers.add(modifier); } return canonical; } Val* ModifiedType::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff) { int diff = 0; Type* substBase = as(base->substituteImpl(astBuilder, subst, &diff)); List substModifiers; for( auto modifier : modifiers ) { auto substModifier = modifier->substituteImpl(astBuilder, subst, &diff); substModifiers.add(substModifier); } if(!diff) return this; *ioDiff = 1; ModifiedType* substType = m_astBuilder->create(); substType->base = substBase; substType->modifiers = _Move(substModifiers); return substType; } Type* removeParamDirType(Type* type) { for (auto paramDirType = as(type); paramDirType;) { type = paramDirType->getValueType(); paramDirType = as(type); } return type; } } // namespace Slang