summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-decl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
-rw-r--r--source/slang/slang-check-decl.cpp198
1 files changed, 188 insertions, 10 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index daa761d3d..c03d8e985 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -23,6 +23,176 @@
namespace Slang
{
+
+static bool isAssociatedTypeDecl(Decl* decl)
+{
+ auto d = decl;
+ while (auto genericDecl = as<GenericDecl>(d))
+ d = genericDecl->inner;
+ if (as<AssocTypeDecl>(d))
+ return true;
+ return false;
+}
+
+static bool isSlang2026(CompilerOptionSet& optionSet)
+{
+ if (!optionSet.hasOption(CompilerOptionName::Language))
+ return false;
+ return SLANG_SOURCE_LANGUAGE_SLANG ==
+ SlangSourceLanguage(
+ optionSet.getEnumOption<SlangSourceLanguage>(CompilerOptionName::Language)) &&
+ SLANG_STD_REVISION_2026 ==
+ optionSet.getEnumOption<SlangStdRevision>(CompilerOptionName::StdRevision);
+}
+
+static bool allowExperimentalDynamicDispatch(CompilerOptionSet& optionSet)
+{
+ return optionSet.getBoolOption(CompilerOptionName::EnableExperimentalDynamicDispatch) ||
+ !isSlang2026(optionSet);
+}
+
+static void validateDynInterfaceUsage(
+ SemanticsDeclVisitorBase* visitor,
+ DiagnosticSink* sink,
+ CompilerOptionSet& optionSet,
+ InterfaceDecl* decl)
+{
+ if (allowExperimentalDynamicDispatch(optionSet))
+ return;
+
+ if (!decl->hasModifier<DynModifier>())
+ return;
+
+ // validate members inside `dyn interface`
+ for (auto m : decl->members)
+ {
+ if (isAssociatedTypeDecl(m))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveAssociatedTypeInDynInterface);
+ continue;
+ }
+ else if (auto genericDecl = as<GenericDecl>(m))
+ {
+ if (as<FuncDecl>(genericDecl->inner))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveGenericMethodInDynInterface);
+ }
+ continue;
+ }
+ else if (auto funcDecl = as<FuncDecl>(m))
+ {
+ visitor->ensureDecl(m, DeclCheckState::ModifiersChecked);
+ for (auto modifier : funcDecl->modifiers)
+ {
+ if (as<MutatingAttribute>(modifier))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveMutatingMethodInDynInterface);
+ }
+ else if (as<DifferentiableAttribute>(modifier))
+ {
+ sink->diagnose(m, Diagnostics::cannotHaveDifferentiableMethodInDynInterface);
+ }
+ }
+ continue;
+ }
+ else if (auto inheritanceDecl = as<InheritanceDecl>(m))
+ {
+ visitor->ensureDecl(m, DeclCheckState::ReadyForLookup);
+ auto inheritedInterfaceDeclRefType =
+ isDeclRefTypeOf<InterfaceDecl>(inheritanceDecl->base.type);
+ if (!inheritedInterfaceDeclRefType)
+ continue;
+
+ auto inheritedInterfaceDecl = inheritedInterfaceDeclRefType.getDecl();
+ if (!inheritedInterfaceDecl->hasModifier<DynModifier>())
+ sink->diagnose(
+ m,
+ Diagnostics::DynInterfaceCannotInheritNonDynInterface,
+ decl,
+ inheritedInterfaceDecl);
+ }
+ }
+
+ // dyn interface cannot be generic
+ if (visitor->GetOuterGeneric(decl))
+ {
+ sink->diagnose(decl, Diagnostics::cannotHaveGenericDynInterface, decl);
+ }
+}
+
+static void validateDynInterfaceUseWithInheritanceDecl(
+ SemanticsDeclVisitorBase* visitor,
+ DiagnosticSink* sink,
+ CompilerOptionSet& optionSet,
+ InheritanceDecl* decl)
+{
+ auto interfaceDeclRef = isDeclRefTypeOf<InterfaceDecl>(decl->base.type);
+ if (!interfaceDeclRef)
+ return;
+ auto interfaceDecl = interfaceDeclRef.getDecl();
+ bool interfaceDeclIsDyn = interfaceDecl->hasModifier<DynModifier>();
+ if (!interfaceDeclIsDyn)
+ return;
+
+ if (!allowExperimentalDynamicDispatch(optionSet))
+ {
+ if (auto extensionDeclParent = as<ExtensionDecl>(decl->parentDecl))
+ {
+ // not allowed to extend to conform to a 'dyn interface'
+ sink->diagnose(
+ extensionDeclParent,
+ Diagnostics::cannotUseExtensionToMakeTypeConformToDynInterface,
+ interfaceDecl);
+ }
+ else if (visitor->GetOuterGeneric(decl->parentDecl))
+ {
+ sink->diagnose(
+ decl,
+ Diagnostics::cannotConformGenericToDynInterface,
+ decl->parentDecl,
+ interfaceDecl);
+ }
+ }
+ if (auto aggTypeDeclParent = as<AggTypeDecl>(decl->parentDecl))
+ {
+ // Ensure if we inherit from a `dyn interface` that the parent does not have: opaque
+ // types, unsized types, non-copyable types
+ for (auto m : aggTypeDeclParent->members)
+ {
+ auto varDecl = as<VarDecl>(m);
+ if (!varDecl)
+ continue;
+
+ visitor->ensureDecl(varDecl, DeclCheckState::ReadyForLookup);
+
+ if (isNonCopyableType(varDecl->getType()))
+ {
+ sink->diagnose(
+ m,
+ Diagnostics::cannotHaveNonCopyableMemberWhenInheritingDynInterface,
+ m,
+ interfaceDecl);
+ }
+
+ int varTypeTags = (int)visitor->getTypeTags(varDecl->getType());
+ bool isUnsized = varTypeTags & (int)TypeTag::Unsized;
+ bool isOpaque = varTypeTags & (int)TypeTag::Opaque;
+ if (isUnsized)
+ sink->diagnose(
+ m,
+ Diagnostics::cannotHaveUnsizedMemberWhenInheritingDynInterface,
+ m,
+ interfaceDecl);
+ if (isOpaque)
+ sink->diagnose(
+ m,
+ Diagnostics::cannotHaveOpaqueMemberWhenInheritingDynInterface,
+ m,
+ interfaceDecl);
+ }
+ }
+}
+
static ConstructorDecl* _getDefaultCtor(StructDecl* structDecl);
static List<ConstructorDecl*> _getCtorList(
ASTBuilder* m_astBuilder,
@@ -70,6 +240,8 @@ struct SemanticsDeclModifiersVisitor : public SemanticsDeclVisitorBase,
void visitDecl(Decl* decl) { checkModifiers(decl); }
void visitStructDecl(StructDecl* structDecl);
+
+ void visitInterfaceDecl(InterfaceDecl* interfaceDecl);
};
struct SemanticsDeclScopeWiringVisitor : public SemanticsDeclVisitorBase,
@@ -1485,6 +1657,16 @@ IntVal* SemanticsVisitor::_validateCircularVarDefinition(VarDeclBase* varDecl)
nullptr);
}
+void SemanticsDeclModifiersVisitor::visitInterfaceDecl(InterfaceDecl* interfaceDecl)
+{
+ visitDecl(interfaceDecl);
+
+ if (interfaceDecl->hasModifier<AnyValueSizeAttribute>())
+ addModifier(interfaceDecl, m_astBuilder->create<DynModifier>());
+
+ validateDynInterfaceUsage(this, getSink(), getOptionSet(), interfaceDecl);
+}
+
void SemanticsDeclModifiersVisitor::visitStructDecl(StructDecl* structDecl)
{
checkModifiers(structDecl);
@@ -3114,6 +3296,12 @@ struct SemanticsDeclDifferentialConformanceVisitor
void visitInheritanceDecl(InheritanceDecl* inheritanceDecl)
{
+ validateDynInterfaceUseWithInheritanceDecl(
+ this,
+ getSink(),
+ getOptionSet(),
+ inheritanceDecl);
+
if (as<InterfaceDecl>(inheritanceDecl->parentDecl))
return;
@@ -6964,16 +7152,6 @@ RefPtr<WitnessTable> SemanticsVisitor::checkInterfaceConformance(
return witnessTable;
}
-static bool isAssociatedTypeDecl(Decl* decl)
-{
- auto d = decl;
- while (auto genericDecl = as<GenericDecl>(d))
- d = genericDecl->inner;
- if (as<AssocTypeDecl>(d))
- return true;
- return false;
-}
-
bool SemanticsVisitor::checkInterfaceConformance(
ConformanceCheckingContext* context,
Type* subType,