diff options
| -rw-r--r-- | source/slang/hlsl.meta.slang | 1 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-inheritance.cpp | 13 | ||||
| -rw-r--r-- | source/slang/slang-check-overload.cpp | 32 | ||||
| -rw-r--r-- | tests/language-feature/extensions/extension-override-2.slang | 41 |
5 files changed, 81 insertions, 12 deletions
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 8b0bade6e..3cfa9410b 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -533,6 +533,7 @@ interface ITexelElement { associatedtype Element : __BuiltinArithmeticType; static const int elementCount; + [OverloadRank(-1)] __init(Element x); } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index b56c3cb07..2865188b4 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -7545,7 +7545,9 @@ void SemanticsVisitor::checkExtensionConformance(ExtensionDecl* decl) .as<ExtensionDecl>(); auto targetType = getTargetType(m_astBuilder, declRef); - for (auto inheritanceDecl : decl->getMembersOfType<InheritanceDecl>()) + // Make a copy of inhertanceDecls first since `checkConformance` may modify decl->members. + auto inheritanceDecls = decl->getMembersOfType<InheritanceDecl>().toList(); + for (auto inheritanceDecl : inheritanceDecls) { checkConformance(targetType, inheritanceDecl, decl); } @@ -7596,7 +7598,7 @@ void SemanticsVisitor::checkAggTypeConformance(AggTypeDecl* decl) // just with `abstract` methods that replicate things? // (That's what C# does). - // Make a copy of inhertanceDecls firstsince `checkConformance` may modify decl->members. + // Make a copy of inhertanceDecls first since `checkConformance` may modify decl->members. auto inheritanceDecls = decl->getMembersOfType<InheritanceDecl>().toList(); for (auto inheritanceDecl : inheritanceDecls) { diff --git a/source/slang/slang-check-inheritance.cpp b/source/slang/slang-check-inheritance.cpp index 37b4d3158..2554553de 100644 --- a/source/slang/slang-check-inheritance.cpp +++ b/source/slang/slang-check-inheritance.cpp @@ -450,14 +450,15 @@ InheritanceInfo SharedSemanticsContext::_calcInheritanceInfo( // then we need to add the extension itself as a facet. // auto extDeclRef = - createDefaultSubstitutionsIfNeeded(astBuilder, &visitor, extensionDecl); - auto selfExtFacet = new (arena) Facet::Impl( + createDefaultSubstitutionsIfNeeded(astBuilder, &visitor, extensionDecl) + .as<ExtensionDecl>(); + auto extInheritanceInfo = getInheritanceInfo(extDeclRef, circularityInfo); + addDirectBaseFacet( Facet::Kind::Extension, - Facet::Directness::Direct, - extDeclRef, selfType, - astBuilder->getTypeEqualityWitness(selfType)); - allFacets.add(selfExtFacet); + selfIsSelf, + extDeclRef, + extInheritanceInfo); } } diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 8fbdceabb..8d76d2554 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1321,6 +1321,34 @@ int SemanticsVisitor::CompareLookupResultItems( LookupResultItem const& left, LookupResultItem const& right) { + auto leftDeclRefParent = getParentDeclRef(left.declRef); + auto rightDeclRefParent = getParentDeclRef(right.declRef); + + bool leftIsExtension = false; + bool rightIsExtension = false; + bool leftIsFreeFormExtension = false; + bool rightIsFreeFormExtension = false; + + // Prefer declarations that are not in free-form generic extensions, i.e. + // `extension<T:IFoo> T { /* declaration here should have lower precedence. */ } + if (auto leftExt = as<ExtensionDecl>(leftDeclRefParent.getDecl())) + { + leftIsExtension = true; + if (isDeclRefTypeOf<GenericTypeParamDeclBase>(leftExt->targetType)) + leftIsFreeFormExtension = true; + } + if (auto rightExt = as<ExtensionDecl>(rightDeclRefParent.getDecl())) + { + rightIsExtension = true; + if (isDeclRefTypeOf<GenericTypeParamDeclBase>(rightExt->targetType)) + rightIsFreeFormExtension = true; + } + + // If one of the candidates is a free-form extension, it is always worse than + // a non-free-form extension. + if (leftIsFreeFormExtension != rightIsFreeFormExtension) + return int(leftIsFreeFormExtension) - int(rightIsFreeFormExtension); + // It is possible for lookup to return both an interface requirement // and the concrete function that satisfies that requirement. // We always want to favor a concrete method over an interface @@ -1334,16 +1362,12 @@ int SemanticsVisitor::CompareLookupResultItems( // directly (it is only visible through the requirement witness // information for inheritance declarations). // - auto leftDeclRefParent = getParentDeclRef(left.declRef); - auto rightDeclRefParent = getParentDeclRef(right.declRef); bool leftIsInterfaceRequirement = isInterfaceRequirement(left.declRef.getDecl()); bool rightIsInterfaceRequirement = isInterfaceRequirement(right.declRef.getDecl()); if (leftIsInterfaceRequirement != rightIsInterfaceRequirement) return int(leftIsInterfaceRequirement) - int(rightIsInterfaceRequirement); // Prefer non-extension declarations over extension declarations. - bool leftIsExtension = as<ExtensionDecl>(leftDeclRefParent.getDecl()) != nullptr; - bool rightIsExtension = as<ExtensionDecl>(rightDeclRefParent.getDecl()) != nullptr; if (leftIsExtension != rightIsExtension) { // Add a special case for constructors, where we prefer the one that is not synthesized, diff --git a/tests/language-feature/extensions/extension-override-2.slang b/tests/language-feature/extensions/extension-override-2.slang new file mode 100644 index 000000000..bd40e8ba9 --- /dev/null +++ b/tests/language-feature/extensions/extension-override-2.slang @@ -0,0 +1,41 @@ +//TEST:INTERPRET(filecheck=CHECK): +interface IBar +{} + +interface IFoo : IBar +{ + void execute(); +} + +struct Impl : IFoo +{ + void execute() + { + printf("Impl::execute();\n"); + } +} + +extension<T:IBar> T : IFoo +{ + void execute() + { + printf("Extension::execute();\n"); + } +} + +struct Base : IBar{} + +void test<T:IFoo>(T t) +{ + t.execute(); +} + +void main() +{ + // CHECK: Impl::execute(); + Impl f; + test(f); + // CHECK: Extension::execute(); + Base b; + test(b); +}
\ No newline at end of file |
