Skip to content

Commit 899fce0

Browse files
regression
1 parent d20b3fe commit 899fce0

3 files changed

Lines changed: 82 additions & 3 deletions

File tree

pyrefly/lib/alt/class/class_field.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,11 +626,55 @@ impl ClassField {
626626

627627
fn instantiate_for(&self, heap: &TypeHeap, instance: &Instance) -> Self {
628628
self.instantiate_helper(&mut |ty| {
629-
ty.subst_self_type_mut(&instance.to_type(heap));
629+
if let Some(self_type) = instance.self_return_type_override() {
630+
Self::subst_callable_return_self_type_mut(ty, self_type, &instance.to_type(heap));
631+
} else {
632+
ty.subst_self_type_mut(&instance.to_type(heap));
633+
}
630634
instance.instantiate_member(ty)
631635
})
632636
}
633637

638+
fn subst_callable_return_self_type_mut(
639+
ty: &mut Type,
640+
self_type: &Type,
641+
fallback_self_type: &Type,
642+
) {
643+
let subst_callable = |callable: &mut Callable| {
644+
callable.ret.subst_self_type_mut(self_type);
645+
callable
646+
.params
647+
.visit_mut(&mut |ty| ty.subst_self_type_mut(fallback_self_type));
648+
};
649+
match ty {
650+
Type::Callable(callable) => subst_callable(callable),
651+
Type::Function(func) => subst_callable(&mut func.signature),
652+
Type::Forall(forall) => match &mut forall.body {
653+
Forallable::Callable(callable) => subst_callable(callable),
654+
Forallable::Function(func) => subst_callable(&mut func.signature),
655+
_ => ty.subst_self_type_mut(fallback_self_type),
656+
},
657+
Type::Overload(overload) => {
658+
for sig in overload.signatures.iter_mut() {
659+
match sig {
660+
OverloadType::Function(func) => subst_callable(&mut func.signature),
661+
OverloadType::Forall(forall) => subst_callable(&mut forall.body.signature),
662+
}
663+
}
664+
}
665+
Type::Union(union) => {
666+
for member in union.members.iter_mut() {
667+
Self::subst_callable_return_self_type_mut(
668+
member,
669+
self_type,
670+
fallback_self_type,
671+
);
672+
}
673+
}
674+
_ => ty.subst_self_type_mut(fallback_self_type),
675+
}
676+
}
677+
634678
fn instantiate_for_class_targs(
635679
&self,
636680
targs: &TArgs,
@@ -3822,7 +3866,11 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
38223866
) -> Option<ClassAttribute> {
38233867
self.get_class_member(cls.class_object(), name)
38243868
.map(|field| {
3825-
self.as_instance_attribute(name, &field, &Instance::of_protocol(cls, self_type))
3869+
self.as_instance_attribute(
3870+
name,
3871+
&field,
3872+
&Instance::of_class_with_self_type(cls, self_type),
3873+
)
38263874
})
38273875
}
38283876

pyrefly/lib/alt/types/instance.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub enum InstanceKind {
2727
TypedDict,
2828
TypeVar(Quantified),
2929
SelfType,
30+
ClassWithSelfType(Type),
3031
Protocol(Type),
3132
Metaclass(ClassBase),
3233
LiteralString,
@@ -83,6 +84,14 @@ impl<'a> Instance<'a> {
8384
}
8485
}
8586

87+
pub fn of_class_with_self_type(cls: &'a ClassType, self_type: Type) -> Self {
88+
Self {
89+
kind: InstanceKind::ClassWithSelfType(self_type),
90+
class: cls.class_object(),
91+
targs: cls.targs(),
92+
}
93+
}
94+
8695
pub fn of_protocol(cls: &'a ClassType, self_type: Type) -> Self {
8796
Self {
8897
kind: InstanceKind::Protocol(self_type),
@@ -113,9 +122,16 @@ impl<'a> Instance<'a> {
113122
self.targs.substitute_into_mut(raw_member)
114123
}
115124

125+
pub fn self_return_type_override(&self) -> Option<&Type> {
126+
match &self.kind {
127+
InstanceKind::ClassWithSelfType(self_type) => Some(self_type),
128+
_ => None,
129+
}
130+
}
131+
116132
pub fn to_type(&self, heap: &TypeHeap) -> Type {
117133
match &self.kind {
118-
InstanceKind::ClassType => {
134+
InstanceKind::ClassType | InstanceKind::ClassWithSelfType(_) => {
119135
heap.mk_class_type(ClassType::new(self.class.dupe(), self.targs.clone()))
120136
}
121137
InstanceKind::TypedDict => {
@@ -161,6 +177,7 @@ impl<'a> Instance<'a> {
161177
self.targs.clone(),
162178
))),
163179
InstanceKind::ClassType
180+
| InstanceKind::ClassWithSelfType(_)
164181
| InstanceKind::Protocol(..)
165182
| InstanceKind::Metaclass(..)
166183
| InstanceKind::TypeVar(..)

pyrefly/lib/test/narrow.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,20 @@ def test[T: ParentModel](value: T) -> T:
15481548
"#,
15491549
);
15501550

1551+
testcase!(
1552+
test_non_self_method_on_generic_typevar_intersection,
1553+
r#"
1554+
class Mixin[T]:
1555+
def remove_all_commands(self) -> None: ...
1556+
1557+
class Command[T]: ...
1558+
1559+
def test[CogT](command: Command[CogT]) -> None:
1560+
if isinstance(command, Mixin):
1561+
command.remove_all_commands()
1562+
"#,
1563+
);
1564+
15511565
testcase!(
15521566
test_issubclass_typevar_nondisjoint_classes,
15531567
r#"

0 commit comments

Comments
 (0)