summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/hlsl.meta.slang1
-rw-r--r--source/slang/slang-check-decl.cpp6
-rw-r--r--source/slang/slang-check-inheritance.cpp13
-rw-r--r--source/slang/slang-check-overload.cpp32
-rw-r--r--tests/language-feature/extensions/extension-override-2.slang41
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