已合并
Require override for multiple inherited explicit overloads #10640
Require override for multiple inherited explicit overloads #10640
已合并
zhelyapovaleksey创建于 5月7日
共 8 个文件变更+229-7
@@ -653,6 +653,7 @@ public:
653 void CheckFunctionOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const;653 void CheckFunctionOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const;
654 void CheckClassMethodOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const;654 void CheckClassMethodOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const;
655 void CheckInterfaceMethodOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const;655 void CheckInterfaceMethodOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const;
656+ void CheckInheritedExplicitOverloadRedeclarationRequirement(ETSObjectType *objectType);
656 657 
657 ETSObjectType *GetRelevantArgumentedTypeFromChild(ETSObjectType *child, ETSObjectType *target);658 ETSObjectType *GetRelevantArgumentedTypeFromChild(ETSObjectType *child, ETSObjectType *target);
658 util::StringView GetHashFromTypeArguments(const ArenaVector<Type *> &typeArgTypes);659 util::StringView GetHashFromTypeArguments(const ArenaVector<Type *> &typeArgTypes);
@@ -959,6 +959,7 @@ Type *ETSChecker::BuildBasicInterfaceProperties(ir::TSInterfaceDeclaration *inte
959 // and it is possible that the FunctionType interface is not yet created.959 // and it is possible that the FunctionType interface is not yet created.
960 if (builtinsInitialized) { // NOTE(vpukhov): #31391960 if (builtinsInitialized) { // NOTE(vpukhov): #31391
961 CheckInterfaceFunctions(interfaceType);961 CheckInterfaceFunctions(interfaceType);
962+ CheckInheritedExplicitOverloadRedeclarationRequirement(interfaceType);
962 }963 }
963 CheckInterfaceAnnotations(interfaceDecl);964 CheckInterfaceAnnotations(interfaceDecl);
964 965 
@@ -3433,6 +3434,7 @@ void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefini
3433 3434 
3434 const auto &allProps = classType->GetAllProperties();3435 const auto &allProps = classType->GetAllProperties();
3435 auto const interfaceList = GetInterfaces(classType);3436 auto const interfaceList = GetInterfaces(classType);
3437+ CheckInheritedExplicitOverloadRedeclarationRequirement(classType);
3436 auto const instancePropNamesTransitive = CollectInstancePropsTransitive(classType);3438 auto const instancePropNamesTransitive = CollectInstancePropsTransitive(classType);
3437 3439 
3438 for (auto *it : allProps) {3440 for (auto *it : allProps) {
@@ -1834,6 +1834,50 @@ static std::unordered_set<util::StringView> CollectInstanceOverloadDeclsTransiti
1834 return transitivePropNames;1834 return transitivePropNames;
1835}1835}
1836 1836 
1837+void ETSChecker::CheckInheritedExplicitOverloadRedeclarationRequirement(ETSObjectType *objectType)
1838+{
1839+ auto isOverloadDecl = [](const auto prop) {
1840+ auto *decl = prop ? prop->Declaration() : nullptr;
1841+ return decl && decl->Node() && decl->Node()->IsOverloadDeclaration();
1842+ };
1843+ 
1844+ std::unordered_map<util::StringView, std::vector<ETSObjectType *>> inheritedOverloads;
1845+ 
1846+ objectType->EnsureTransitiveSupertypesInitialized();
1847+ for (auto *superType : objectType->TransitiveSupertypes()) {
1848+ for (auto const [propName, prop] : superType->InstanceDecls()) {
1849+ if (isOverloadDecl(prop)) {
1850+ inheritedOverloads[propName].push_back(superType);
1851+ }
1852+ }
1853+ }
1854+ 
1855+ auto const loc = objectType->GetDeclNode() ? objectType->GetDeclNode()->Start() : lexer::SourcePosition {};
1856+ auto const &localDecls = objectType->InstanceDecls();
1857+ 
1858+ for (auto const &entry : inheritedOverloads) {
1859+ auto const &name = entry.first;
1860+ auto const &types = entry.second;
1861+ 
1862+ if (types.size() <= 1) {
1863+ continue;
1864+ }
1865+ 
1866+ if (auto it = localDecls.find(name); it != localDecls.end() && isOverloadDecl(it->second)) {
1867+ continue;
1868+ }
1869+ 
1870+ auto independentCount = std::count_if(types.begin(), types.end(), [&](ETSObjectType *typeA) {
1871+ return !std::any_of(types.begin(), types.end(), [&](ETSObjectType *typeB) {
1872+ return typeA != typeB && Relation()->IsSupertypeOf(typeA, typeB);
1873+ });
1874+ });
1875+ if (independentCount > 1) {
1876+ LogError(diagnostic::NO_EXPLICIT_OVERLOAD_OVERRIDING, {name, objectType->Name()}, loc);
1877+ }
1878+ }
1879+}
1880+ 
1837static void CheckOverloadDeclInheritance(ETSChecker *checker, ir::OverloadDeclaration *currOverloadDecl,1881static void CheckOverloadDeclInheritance(ETSChecker *checker, ir::OverloadDeclaration *currOverloadDecl,
1838 const std::unordered_set<util::StringView> &currOverloadDeclNames)1882 const std::unordered_set<util::StringView> &currOverloadDeclNames)
1839{1883{
@@ -435,6 +435,13 @@ public:
435 return propertiesInstantiated_;435 return propertiesInstantiated_;
436 }436 }
437 437 
438+ void EnsureTransitiveSupertypesInitialized() const
xingshunxiang

why move it to public?

likedislike
439+ {
440+ if (transitiveSupertypes_ == nullptr) {
441+ transitiveSupertypes_ = allocator_->New<ArenaSet<ETSObjectType *>>(allocator_->Adapter());
442+ }
443+ }
444+ 
438protected:445protected:
439 virtual ETSFunctionType *CreateMethodTypeForProp(util::StringView name) const;446 virtual ETSFunctionType *CreateMethodTypeForProp(util::StringView name) const;
440 447 
@@ -502,13 +509,6 @@ private:
502 }509 }
503 }510 }
504 511 
505- void EnsureTransitiveSupertypesInitialized() const
506- {
507- if (transitiveSupertypes_ == nullptr) {
508- transitiveSupertypes_ = allocator_->New<ArenaSet<ETSObjectType *>>(allocator_->Adapter());
509- }
510- }
511- 
512 bool CastWidening(TypeRelation *relation, Type *target, TypeFlag unboxFlags, TypeFlag wideningFlags);512 bool CastWidening(TypeRelation *relation, Type *target, TypeFlag unboxFlags, TypeFlag wideningFlags);
513 void IdenticalUptoTypeArguments(TypeRelation *relation, Type *other);513 void IdenticalUptoTypeArguments(TypeRelation *relation, Type *other);
514 void SubstitutePartialTypes(TypeRelation *relation, Type *other);514 void SubstitutePartialTypes(TypeRelation *relation, Type *other);
@@ -0,0 +1,61 @@
1+/*
fanglou
fangloufanglou5月12日

Negative test cases can be added.

likedislike
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+/*---
17+desc: >-
18+ A class that implements interfaces with explicit overloads of the same name
19+ remains valid when it declares a new explicit overload containing all
20+ inherited target methods.
21+---*/
22+ 
23+interface I1 {
24+ f1(x: int): string
25+ f2(x: boolean): string
26+ overload foo { f1, f2 }
27+}
28+ 
29+interface I2 {
30+ f3(x: number): string
31+ f4(x: string): string
32+ overload foo { f3, f4 }
33+}
34+ 
35+class A implements I1, I2 {
36+ f1(x: int): string {
37+ return "f1"
38+ }
39+ 
40+ f2(x: boolean): string {
41+ return "f2"
42+ }
43+ 
44+ f3(x: number): string {
45+ return "f3"
46+ }
47+ 
48+ f4(x: string): string {
49+ return "f4"
50+ }
51+ 
52+ overload foo { f2, f4, f1, f3 }
53+}
54+ 
55+function main(): void {
56+ let a: A = new A()
57+ arktest.assertEQ("f1", a.foo(1))
58+ arktest.assertEQ("f2", a.foo(false))
59+ arktest.assertEQ("f3", a.foo(1.5))
60+ arktest.assertEQ("f4", a.foo("ets"))
61+}
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+/*---
17+desc: >-
18+ One inherited explicit interface overload does not require redeclaration in a
19+ subinterface. The inherited overload remains usable through the subinterface.
20+---*/
21+ 
22+interface I1 {
23+ fooInt(x: int): string
24+ fooString(x: string): string
25+ overload foo { fooInt, fooString }
26+}
27+ 
28+interface I2 extends I1 {
29+}
30+ 
31+class A implements I2 {
32+ fooInt(x: int): string {
33+ return "int"
34+ }
35+ 
36+ fooString(x: string): string {
37+ return "string"
38+ }
39+}
40+ 
41+function main(): void {
42+ let a: I2 = new A()
43+ arktest.assertEQ("int", a.foo(1))
44+ arktest.assertEQ("string", a.foo("ets"))
45+}
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+/*---
17+desc: >-
18+ A subinterface that inherits several explicit overload declarations of the
19+ same name may remain valid when it declares a new explicit overload that
20+ includes all inherited target methods, even when the inherited member sets
21+ are disjoint and the new order differs.
22+---*/
23+ 
24+interface I1 {
25+ f1(x: int): string
26+ f2(x: boolean): string
27+ overload foo { f1, f2 }
28+}
29+ 
30+interface I2 {
31+ f3(x: number): string
32+ f4(x: string): string
33+ overload foo { f3, f4 }
34+}
35+ 
36+interface I3 extends I1, I2 {
37+ overload foo { f4, f1, f3, f2 }
38+}
39+ 
40+class A implements I3 {
41+ f1(x: int): string {
42+ return "f1"
43+ }
44+ 
45+ f2(x: boolean): string {
46+ return "f2"
47+ }
48+ 
49+ f3(x: number): string {
50+ return "f3"
51+ }
52+ 
53+ f4(x: string): string {
54+ return "f4"
55+ }
56+}
57+ 
58+function main(): void {
59+ let a: I3 = new A()
60+ arktest.assertEQ("f1", a.foo(1))
61+ arktest.assertEQ("f2", a.foo(true))
62+ arktest.assertEQ("f3", a.foo(1.5))
63+ arktest.assertEQ("f4", a.foo("ets"))
64+}
@@ -1096,6 +1096,11 @@ semantic:
1096 message: "Type '{}' has no call signatures."1096 message: "Type '{}' has no call signatures."
1097 code_fix_ids: [FixAddMissingNewOperator, RemoveAccidentalCallParentheses]1097 code_fix_ids: [FixAddMissingNewOperator, RemoveAccidentalCallParentheses]
1098 1098 
1099+- name: NO_EXPLICIT_OVERLOAD_OVERRIDING
1100+ id: 464
1101+ message: "When multiple explicit overloads with the same name '{}' are inherited, the new explicit overload must be declared
1102+ instead in '{}'."
1103+ 
1099- name: NO_INDEX_ACCESS_METHOD1104- name: NO_INDEX_ACCESS_METHOD
1100 id: 2501105 id: 250
1101 message: "Object type doesn't have proper index access method."1106 message: "Object type doesn't have proper index access method."