diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 8b0bade6e6c..3cfa9410b26 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 b56c3cb0790..2865188b4db 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(); auto targetType = getTargetType(m_astBuilder, declRef); - for (auto inheritanceDecl : decl->getMembersOfType()) + // Make a copy of inhertanceDecls first since `checkConformance` may modify decl->members. + auto inheritanceDecls = decl->getMembersOfType().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().toList(); for (auto inheritanceDecl : inheritanceDecls) { diff --git a/source/slang/slang-check-inheritance.cpp b/source/slang/slang-check-inheritance.cpp index 37b4d315827..2554553de2c 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(); + 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 8fbdceabb6d..8d76d25548c 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 { /* declaration here should have lower precedence. */ } + if (auto leftExt = as(leftDeclRefParent.getDecl())) + { + leftIsExtension = true; + if (isDeclRefTypeOf(leftExt->targetType)) + leftIsFreeFormExtension = true; + } + if (auto rightExt = as(rightDeclRefParent.getDecl())) + { + rightIsExtension = true; + if (isDeclRefTypeOf(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(leftDeclRefParent.getDecl()) != nullptr; - bool rightIsExtension = as(rightDeclRefParent.getDecl()) != nullptr; if (leftIsExtension != rightIsExtension) { // Add a special case for constructors, where we prefer the one that is not synthesized, diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 5400ab16630..596a091d44a 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -3094,9 +3094,10 @@ struct StmtLoweringVisitor; void maybeEmitDebugLine( IRGenContext* context, - StmtLoweringVisitor& visitor, + StmtLoweringVisitor* visitor, Stmt* stmt, - SourceLoc loc = SourceLoc()); + SourceLoc loc = SourceLoc(), + bool allowNullStmt = false); // When lowering something callable (most commonly a function declaration), // we need to construct an appropriate parameter list for the IR function @@ -5221,6 +5222,8 @@ struct ExprLoweringVisitorBase : public ExprVisitor auto afterBlock = builder->createBlock(); auto irCond = getSimpleVal(context, lowerRValueExpr(context, expr->arguments[0])); + maybeEmitDebugLine(context, nullptr, nullptr, irCond->sourceLoc, true); + // ifElse(, %true-block, %false-block, %after-block) builder->emitIfElse(irCond, thenBlock, elseBlock, afterBlock); @@ -6211,6 +6214,8 @@ struct StmtLoweringVisitor : StmtVisitor auto irCond = getSimpleVal(context, lowerRValueExpr(context, condExpr)); + maybeEmitDebugLine(context, this, stmt, condExpr->loc); + IRInst* ifInst = nullptr; if (elseStmt) @@ -6323,7 +6328,7 @@ struct StmtLoweringVisitor : StmtVisitor // want to emit the expression for the loop condition: if (const auto condExpr = stmt->predicateExpression) { - maybeEmitDebugLine(context, *this, stmt, condExpr->loc); + maybeEmitDebugLine(context, this, stmt, condExpr->loc); auto irCondition = getSimpleVal(context, lowerRValueExpr(context, stmt->predicateExpression)); @@ -6383,7 +6388,7 @@ struct StmtLoweringVisitor : StmtVisitor insertBlock(continueLabel); if (auto incrExpr = stmt->sideEffectExpression) { - maybeEmitDebugLine(context, *this, stmt, incrExpr->loc); + maybeEmitDebugLine(context, this, stmt, incrExpr->loc); lowerRValueExpr(context, incrExpr); } @@ -6432,7 +6437,7 @@ struct StmtLoweringVisitor : StmtVisitor // want to emit the expression for the loop condition: if (auto condExpr = stmt->predicate) { - maybeEmitDebugLine(context, *this, stmt, condExpr->loc); + maybeEmitDebugLine(context, this, stmt, condExpr->loc); auto irCondition = getSimpleVal(context, lowerRValueExpr(context, condExpr)); @@ -6498,7 +6503,7 @@ struct StmtLoweringVisitor : StmtVisitor // want to emit the expression for the loop condition: if (auto condExpr = stmt->predicate) { - maybeEmitDebugLine(context, *this, stmt, stmt->predicate->loc); + maybeEmitDebugLine(context, this, stmt, stmt->predicate->loc); auto irCondition = getSimpleVal(context, lowerRValueExpr(context, condExpr)); @@ -7398,24 +7403,29 @@ IRInst* getOrEmitDebugSource(IRGenContext* context, PathInfo path) void maybeEmitDebugLine( IRGenContext* context, - StmtLoweringVisitor& visitor, + StmtLoweringVisitor* visitor, Stmt* stmt, - SourceLoc loc) + SourceLoc loc, + bool allowNullStmt) { if (!context->includeDebugInfo) return; - if (as(stmt)) - return; - if (!loc.isValid()) - loc = stmt->loc; + + if (!allowNullStmt) + { + if (as(stmt)) + return; + if (!loc.isValid()) + loc = stmt->loc; + } + auto sourceManager = context->getLinkage()->getSourceManager(); - auto sourceView = context->getLinkage()->getSourceManager()->findSourceView(loc); + auto sourceView = sourceManager->findSourceView(loc); if (!sourceView) return; IRInst* debugSourceInst = nullptr; - auto humaneLoc = - context->getLinkage()->getSourceManager()->getHumaneLoc(loc, SourceLocType::Emit); + auto humaneLoc = sourceManager->getHumaneLoc(loc, SourceLocType::Emit); // Do a best-effort attempt to retrieve the nominal source file. auto pathInfo = sourceView->getPathInfo(loc, SourceLocType::Emit); @@ -7434,7 +7444,8 @@ void maybeEmitDebugLine( { debugSourceInst = getOrEmitDebugSource(context, pathInfo); } - visitor.startBlockIfNeeded(stmt); + if (visitor) + visitor->startBlockIfNeeded(stmt); context->irBuilder->emitDebugLine( debugSourceInst, humaneLoc.line, @@ -7471,7 +7482,7 @@ void lowerStmt(IRGenContext* context, Stmt* stmt) try { - maybeEmitDebugLine(context, visitor, stmt, stmt->loc); + maybeEmitDebugLine(context, &visitor, stmt, stmt->loc); visitor.dispatch(stmt); } // Don't emit any context message for an explicit `AbortCompilationException` 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 00000000000..bd40e8ba925 --- /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 : IFoo +{ + void execute() + { + printf("Extension::execute();\n"); + } +} + +struct Base : IBar{} + +void test(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