Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd86b1e5

Browse files
Fix attribute type resolution with multiple inheritance (#18415)
Fixes#18268.Fixes#9319.Fixes#14279.Fixes#9031.Supersedes#18270 as requested by@ilevkivskyi.This PR introduces two changes:* Add missing `map_type_from_supertype` when checking generic attributes* Only compare the first base defining a name to all following in MRO -others are not necessarily pairwise compatible.---------Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
1 parent106f714 commitd86b1e5

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

‎mypy/checker.py‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2733,19 +2733,20 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None:
27332733
return
27342734
# Verify that inherited attributes are compatible.
27352735
mro=typ.mro[1:]
2736-
fori,baseinenumerate(mro):
2736+
all_names= {nameforbaseinmrofornameinbase.names}
2737+
fornameinsorted(all_names-typ.names.keys()):
2738+
# Sort for reproducible message order.
27372739
# Attributes defined in both the type and base are skipped.
27382740
# Normal checks for attribute compatibility should catch any problems elsewhere.
2739-
non_overridden_attrs=base.names.keys()-typ.names.keys()
2740-
fornameinnon_overridden_attrs:
2741-
ifis_private(name):
2742-
continue
2743-
forbase2inmro[i+1 :]:
2744-
# We only need to check compatibility of attributes from classes not
2745-
# in a subclass relationship. For subclasses, normal (single inheritance)
2746-
# checks suffice (these are implemented elsewhere).
2747-
ifnameinbase2.namesandbase2notinbase.mro:
2748-
self.check_compatibility(name,base,base2,typ)
2741+
ifis_private(name):
2742+
continue
2743+
# Compare the first base defining a name with the rest.
2744+
# Remaining bases may not be pairwise compatible as the first base provides
2745+
# the used definition.
2746+
i,base=next((i,base)fori,baseinenumerate(mro)ifnameinbase.names)
2747+
forbase2inmro[i+1 :]:
2748+
ifnameinbase2.namesandbase2notinbase.mro:
2749+
self.check_compatibility(name,base,base2,typ)
27492750

27502751
defdetermine_type_of_member(self,sym:SymbolTableNode)->Type|None:
27512752
ifsym.typeisnotNone:
@@ -2826,8 +2827,10 @@ class C(B, A[int]): ... # this is unsafe because...
28262827
ok=is_subtype(first_sig,second_sig,ignore_pos_arg_names=True)
28272828
eliffirst_typeandsecond_type:
28282829
ifisinstance(first.node,Var):
2830+
first_type=get_proper_type(map_type_from_supertype(first_type,ctx,base1))
28292831
first_type=expand_self_type(first.node,first_type,fill_typevars(ctx))
28302832
ifisinstance(second.node,Var):
2833+
second_type=get_proper_type(map_type_from_supertype(second_type,ctx,base2))
28312834
second_type=expand_self_type(second.node,second_type,fill_typevars(ctx))
28322835
ok=is_equivalent(first_type,second_type)
28332836
ifnotok:

‎test-data/unit/check-generic-subtyping.test‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,3 +1065,38 @@ class F(E[T_co], Generic[T_co]): ... # E: Variance of TypeVar "T_co" incompatib
10651065

10661066
class G(Generic[T]): ...
10671067
class H(G[T_contra], Generic[T_contra]): ... # E: Variance of TypeVar "T_contra" incompatible with variance in parent type
1068+
1069+
[case testMultipleInheritanceCompatibleTypeVar]
1070+
from typing import Generic, TypeVar
1071+
1072+
T = TypeVar("T")
1073+
U = TypeVar("U")
1074+
1075+
class A(Generic[T]):
1076+
x: T
1077+
def fn(self, t: T) -> None: ...
1078+
1079+
class A2(A[T]):
1080+
y: str
1081+
z: str
1082+
1083+
class B(Generic[T]):
1084+
x: T
1085+
def fn(self, t: T) -> None: ...
1086+
1087+
class C1(A2[str], B[str]): pass
1088+
class C2(A2[str], B[int]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \
1089+
# E: Definition of "x" in base class "A" is incompatible with definition in base class "B"
1090+
class C3(A2[T], B[T]): pass
1091+
class C4(A2[U], B[U]): pass
1092+
class C5(A2[U], B[T]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \
1093+
# E: Definition of "x" in base class "A" is incompatible with definition in base class "B"
1094+
1095+
class D1(A[str], B[str]): pass
1096+
class D2(A[str], B[int]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \
1097+
# E: Definition of "x" in base class "A" is incompatible with definition in base class "B"
1098+
class D3(A[T], B[T]): pass
1099+
class D4(A[U], B[U]): pass
1100+
class D5(A[U], B[T]): pass # E: Definition of "fn" in base class "A" is incompatible with definition in base class "B" \
1101+
# E: Definition of "x" in base class "A" is incompatible with definition in base class "B"
1102+
[builtins fixtures/tuple.pyi]

‎test-data/unit/check-multiple-inheritance.test‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,3 +706,29 @@ class C34(B3, B4): ...
706706
class C41(B4, B1): ...
707707
class C42(B4, B2): ...
708708
class C43(B4, B3): ...
709+
710+
[case testMultipleInheritanceExplicitDiamondResolution]
711+
# Adapted from #14279
712+
class A:
713+
class M:
714+
pass
715+
716+
class B0(A):
717+
class M(A.M):
718+
pass
719+
720+
class B1(A):
721+
class M(A.M):
722+
pass
723+
724+
class C(B0,B1):
725+
class M(B0.M, B1.M):
726+
pass
727+
728+
class D0(B0):
729+
pass
730+
class D1(B1):
731+
pass
732+
733+
class D(D0,D1,C):
734+
pass

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp