diff options
| author | Yong He <yonghe@outlook.com> | 2025-06-16 20:37:27 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-16 20:37:27 -0700 |
| commit | a4345725a083651c16795d27fedd769f2d7e55ae (patch) | |
| tree | 763c27f687e25e081a87cd266ca1442f5f6624ad /source/slang/slang-check-decl.cpp | |
| parent | 07f79b943c3041dd18137d72893af260b75ddcf9 (diff) | |
Require `override` keyword for overriding default interface methods. (#7458)
* Require `override` keyword for overriding default interface methods.
* Update doc.
* Fix test.
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 8471acb0a..23458c94a 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -5055,6 +5055,40 @@ HasInterfaceDefaultImplModifier* hasDefaultImpl(DeclRef<Decl> declRef) return nullptr; } +void SemanticsVisitor::markOverridingDecl( + ConformanceCheckingContext* context, + Decl* memberDecl, + DeclRef<Decl> requiredMemberDeclRef) +{ + if (!memberDecl->isChildOf(context->parentDecl)) + { + // If the member being checked isn't the child of the container decl containing + // the inheritance decl that triggers the conformance check, don't modify/diagnose + // anything since it should have already been diagnosed when checking its parent. + // This can happen when we check for things like: + // extension float : IComparable{} + // where the method used to satisfy IComparable comes from outside the extension decl. + // we don't want to diagnose or check anything about the found memberDecl that doesn't + // belong to this extension decl (context->parentDecl). + // + return; + } + + if (hasDefaultImpl(requiredMemberDeclRef)) + { + memberDecl = maybeGetInner(memberDecl); + // If the required member has a default implementation, + // we need to make sure the member we found is marked as 'override'. + if (!memberDecl->hasModifier<OverrideModifier>()) + { + getSink()->diagnose(memberDecl, Diagnostics::missingOverride); + } + } + auto overridingModifier = m_astBuilder->create<IsOverridingModifier>(); + overridingModifier->overridedDecl = requiredMemberDeclRef.getDecl(); + addModifier(memberDecl, overridingModifier); +} + bool SemanticsVisitor::trySynthesizeMethodRequirementWitness( ConformanceCheckingContext* context, LookupResult const& lookupResult, @@ -5345,6 +5379,8 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness( return false; } } + + markOverridingDecl(context, callee.getDecl(), requiredMemberDeclRef); } } } @@ -7232,6 +7268,7 @@ bool SemanticsVisitor::findWitnessForInterfaceRequirement( QualifiedDeclPath(requiredMemberDeclRef)); return false; } + markOverridingDecl(context, member.declRef.getDecl(), requiredMemberDeclRef); return true; } } @@ -7738,6 +7775,33 @@ void SemanticsVisitor::checkAggTypeConformance(AggTypeDecl* decl) // only the types that are affected by these interface decls. // astBuilder->incrementEpoch(); + + // For all members marked as `override`, we need to ensure they are actually + // overriding something. + for (auto member : decl->getMembers()) + { + auto innerMember = maybeGetInner(member); + bool hasOverride = false; + bool isOverriding = false; + for (auto modifier : innerMember->modifiers) + { + if (as<OverrideModifier>(modifier)) + { + hasOverride = true; + } + else if (as<IsOverridingModifier>(modifier)) + { + isOverriding = true; + } + } + if (hasOverride && !isOverriding) + { + getSink()->diagnose( + innerMember, + Diagnostics::overrideModifierNotOverridingBaseDecl, + innerMember); + } + } } } |
