diff options
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 198 |
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, |
