diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/slang-hash.h | 8 | ||||
| -rw-r--r-- | source/slang/slang-ast-type.cpp | 43 | ||||
| -rw-r--r-- | source/slang/slang-ast-type.h | 37 | ||||
| -rw-r--r-- | source/slang/slang-check-conformance.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 16 | ||||
| -rw-r--r-- | source/slang/slang-lookup.cpp | 8 |
6 files changed, 97 insertions, 27 deletions
diff --git a/source/core/slang-hash.h b/source/core/slang-hash.h index b2a583744..248d11303 100644 --- a/source/core/slang-hash.h +++ b/source/core/slang-hash.h @@ -169,6 +169,14 @@ namespace Slang return (left * 16777619) ^ right; } + inline HashCode combineHash(HashCode hash0, HashCode hash1, HashCode hash2) + { + auto h = hash0; + h = combineHash(h, hash1); + h = combineHash(h, hash2); + return h; + } + struct Hasher { public: diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp index 64b8c7515..45a736f23 100644 --- a/source/slang/slang-ast-type.cpp +++ b/source/slang/slang-ast-type.cpp @@ -655,7 +655,7 @@ bool ExtractExistentialType::_equalsImplOverride(Type* type) HashCode ExtractExistentialType::_getHashCodeOverride() { - return combineHash(declRef.getHashCode(), interfaceDeclRef.getHashCode()); + return combineHash(declRef.getHashCode(), originalInterfaceType->getHashCode(), originalInterfaceDeclRef.getHashCode()); } Type* ExtractExistentialType::_createCanonicalTypeOverride() @@ -667,7 +667,8 @@ Val* ExtractExistentialType::_substituteImplOverride(ASTBuilder* astBuilder, Sub { int diff = 0; auto substDeclRef = declRef.substituteImpl(astBuilder, subst, &diff); - auto interfaceSubstDeclRef = interfaceDeclRef.substituteImpl(astBuilder, subst, &diff); + auto substOriginalInterfaceType = originalInterfaceType->substituteImpl(astBuilder, subst, &diff); + auto substOriginalInterfaceDeclRef = originalInterfaceDeclRef.substituteImpl(astBuilder, subst, &diff); if (!diff) return this; @@ -675,10 +676,46 @@ Val* ExtractExistentialType::_substituteImplOverride(ASTBuilder* astBuilder, Sub ExtractExistentialType* substValue = astBuilder->create<ExtractExistentialType>(); substValue->declRef = substDeclRef; - substValue->interfaceDeclRef = interfaceSubstDeclRef; + substValue->originalInterfaceType = as<Type>(substOriginalInterfaceType); + substValue->originalInterfaceDeclRef = substOriginalInterfaceDeclRef; return substValue; } +SubtypeWitness* ExtractExistentialType::getSubtypeWitness() +{ + if (auto cachedValue = this->cachedSubtypeWitness) + return cachedValue; + + ExtractExistentialSubtypeWitness* openedWitness = m_astBuilder->create<ExtractExistentialSubtypeWitness>(); + openedWitness->sub = this; + openedWitness->sup = originalInterfaceType; + openedWitness->declRef = this->declRef; + + this->cachedSubtypeWitness = openedWitness; + return openedWitness; +} + +DeclRef<InterfaceDecl> ExtractExistentialType::getSpecializedInterfaceDeclRef() +{ + if (auto cachedValue = this->cachedSpecializedInterfaceDeclRef) + return cachedValue; + + auto interfaceDecl = originalInterfaceDeclRef.getDecl(); + + SubtypeWitness* openedWitness = getSubtypeWitness(); + + ThisTypeSubstitution* openedThisType = m_astBuilder->create<ThisTypeSubstitution>(); + openedThisType->outer = originalInterfaceDeclRef.substitutions.substitutions; + openedThisType->interfaceDecl = interfaceDecl; + openedThisType->witness = openedWitness; + + DeclRef<InterfaceDecl> specialiedInterfaceDeclRef = DeclRef<InterfaceDecl>(interfaceDecl, openedThisType); + + this->cachedSpecializedInterfaceDeclRef = specialiedInterfaceDeclRef; + return specialiedInterfaceDeclRef; +} + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TaggedUnionType !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void TaggedUnionType::_toTextOverride(StringBuilder& out) diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index f4aca515c..5b44a5087 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -616,7 +616,29 @@ class ExtractExistentialType : public Type SLANG_AST_CLASS(ExtractExistentialType) DeclRef<VarDeclBase> declRef; - DeclRef<InterfaceDecl> interfaceDeclRef; + + // A reference to the original interface this type is known + // to be a subtype of. + // + Type* originalInterfaceType; + DeclRef<InterfaceDecl> originalInterfaceDeclRef; + +// Following fields will not be reflected (and thus won't be serialized, etc.) +SLANG_UNREFLECTED + + // A cached decl-ref to the original interface above, with + // a this-type substitution that refers to the type extracted here. + // + // This field is optional and can be filled in on-demand. It does *not* + // represent part of the logical value of this `Type`, and should not + // be serialized, included in hashes, etc. + // + DeclRef<InterfaceDecl> cachedSpecializedInterfaceDeclRef; + + // A cached pointer to a witness that shows how this type is a subtype + // of `originalInterfaceType`. + // + SubtypeWitness* cachedSubtypeWitness = nullptr; // Overrides should be public so base classes can access void _toTextOverride(StringBuilder& out); @@ -624,6 +646,19 @@ class ExtractExistentialType : public Type HashCode _getHashCodeOverride(); Type* _createCanonicalTypeOverride(); Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); + + /// Get a witness that shows how this type is a subtype of `originalInterfaceType`. + /// + /// This operation may create the witness on demand and cache it. + /// + SubtypeWitness* getSubtypeWitness(); + + /// Get a interface decl-ref for the original interface specialized to this type + /// (using a type-type substitution). + /// + /// This operation may create the decl-ref on demand and cache it. + /// + DeclRef<InterfaceDecl> getSpecializedInterfaceDeclRef(); }; /// A tagged union of zero or more other types. diff --git a/source/slang/slang-check-conformance.cpp b/source/slang/slang-check-conformance.cpp index b95df520d..e77ea4981 100644 --- a/source/slang/slang-check-conformance.cpp +++ b/source/slang/slang-check-conformance.cpp @@ -301,19 +301,13 @@ namespace Slang // is a subtype of I. // We need to check and make sure the interface type of the `ExtractExistentialType` // is equal to `superType`. - auto interfaceDeclRef = extractExistentialType->interfaceDeclRef; - auto thisTypeSubst = findThisTypeSubstitution(interfaceDeclRef.substitutions.substitutions, interfaceDeclRef.getDecl()); - SLANG_ASSERT(thisTypeSubst && thisTypeSubst == interfaceDeclRef.substitutions.substitutions); - // The interfaceDeclRef in `extractExistentialType` contains a `ThisTypeSubstitution` - // to allow member lookup to return correct substituted types. Here we just need - // to know if that interface is the same as the superType, so we need to exclude - // the `ThisTypeSubstitution` from comparison. - interfaceDeclRef.substitutions.substitutions = thisTypeSubst->outer; + // + auto interfaceDeclRef = extractExistentialType->originalInterfaceDeclRef; if (interfaceDeclRef.equals(superTypeDeclRef)) { if (outWitness) { - *outWitness = thisTypeSubst->witness; + *outWitness = extractExistentialType->getSubtypeWitness(); } return true; } diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index fbbfcd473..6b1ab13cc 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -101,24 +101,14 @@ namespace Slang // immutable temporary so that we can use // it directly. // - auto interfaceDecl = interfaceDeclRef.getDecl(); return maybeMoveTemp(expr, [&](DeclRef<VarDeclBase> varDeclRef) { ExtractExistentialType* openedType = m_astBuilder->create<ExtractExistentialType>(); openedType->declRef = varDeclRef; + openedType->originalInterfaceType = expr->type.type; + openedType->originalInterfaceDeclRef = interfaceDeclRef; - ExtractExistentialSubtypeWitness* openedWitness = m_astBuilder->create<ExtractExistentialSubtypeWitness>(); - openedWitness->sub = openedType; - openedWitness->sup = expr->type.type; - openedWitness->declRef = varDeclRef; - - ThisTypeSubstitution* openedThisType = m_astBuilder->create<ThisTypeSubstitution>(); - openedThisType->outer = interfaceDeclRef.substitutions.substitutions; - openedThisType->interfaceDecl = interfaceDecl; - openedThisType->witness = openedWitness; - - DeclRef<InterfaceDecl> substDeclRef = DeclRef<InterfaceDecl>(interfaceDecl, openedThisType); - openedType->interfaceDeclRef = substDeclRef; + DeclRef<InterfaceDecl> substDeclRef = openedType->getSpecializedInterfaceDeclRef(); ExtractExistentialValueExpr* openedValue = m_astBuilder->create<ExtractExistentialValueExpr>(); openedValue->declRef = varDeclRef; diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index 20670e7b3..e3093a3db 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -613,7 +613,13 @@ static void _lookUpMembersInSuperTypeImpl( } else if (auto extractExistentialType = as<ExtractExistentialType>(superType)) { - _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, extractExistentialType->interfaceDeclRef, request, ioResult, inBreadcrumbs); + // We want lookup to be performed on the underlying interface type of the existential, + // but we need to have a this-type substitution applied to ensure that the result of + // lookup will have a comparable substitution applied (allowing things like associated + // types, etc. used in the signature of a method to resolve correctly). + // + auto interfaceDeclRef = extractExistentialType->getSpecializedInterfaceDeclRef(); + _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, interfaceDeclRef, request, ioResult, inBreadcrumbs); } else if( auto thisType = as<ThisType>(superType) ) { |
