summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-decl.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-06-16 20:37:27 -0700
committerGitHub <noreply@github.com>2025-06-16 20:37:27 -0700
commita4345725a083651c16795d27fedd769f2d7e55ae (patch)
tree763c27f687e25e081a87cd266ca1442f5f6624ad /source/slang/slang-check-decl.cpp
parent07f79b943c3041dd18137d72893af260b75ddcf9 (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.cpp64
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);
+ }
+ }
}
}