Skip to content

Commit 2425b02

Browse files
committed
review comments
1 parent 92247ff commit 2425b02

File tree

4 files changed

+22
-11
lines changed

4 files changed

+22
-11
lines changed

crates/red_knot_python_semantic/src/types.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ pub enum Type<'db> {
492492
/// Construct this variant using the `Type::instance` constructor function.
493493
NominalInstance(NominalInstanceType<'db>),
494494
/// The set of Python objects that conform to the interface described by a given protocol.
495+
/// Construct this variant using the `Type::instance` constructor function.
495496
ProtocolInstance(ProtocolInstanceType<'db>),
496497
/// A single Python object that requires special treatment in the type system
497498
KnownInstance(KnownInstanceType<'db>),
@@ -1180,7 +1181,6 @@ impl<'db> Type<'db> {
11801181
left.is_subtype_of(db, right)
11811182
}
11821183
// A protocol instance can never be a subtype of a nominal type, with the *sole* exception of `object`.
1183-
// TODO: `Callable` types are also structural types.
11841184
(Type::ProtocolInstance(_), _) => false,
11851185
(_, Type::ProtocolInstance(protocol)) => self.satisfies_protocol(db, protocol),
11861186

@@ -1510,7 +1510,6 @@ impl<'db> Type<'db> {
15101510
// Other than the dynamic types such as `Any`/`Unknown`/`Todo` handled above,
15111511
// a protocol instance can never be assignable to a nominal type,
15121512
// with the *sole* exception of `object`.
1513-
// TODO: `Callable` types are also structural types.
15141513
(Type::ProtocolInstance(_), _) => false,
15151514
(_, Type::ProtocolInstance(protocol)) => self.satisfies_protocol(db, protocol),
15161515

@@ -1537,8 +1536,8 @@ impl<'db> Type<'db> {
15371536
(Type::NominalInstance(left), Type::NominalInstance(right)) => {
15381537
left.is_equivalent_to(db, right)
15391538
}
1540-
(Type::ProtocolInstance(first), Type::ProtocolInstance(right)) => {
1541-
first.is_equivalent_to(db, right)
1539+
(Type::ProtocolInstance(left), Type::ProtocolInstance(right)) => {
1540+
left.is_equivalent_to(db, right)
15421541
}
15431542
(Type::ProtocolInstance(protocol), nominal @ Type::NominalInstance(n))
15441543
| (nominal @ Type::NominalInstance(n), Type::ProtocolInstance(protocol)) => {
@@ -1594,8 +1593,8 @@ impl<'db> Type<'db> {
15941593
first.is_gradual_equivalent_to(db, second)
15951594
}
15961595

1597-
(Type::ProtocolInstance(first), Type::ProtocolInstance(right)) => {
1598-
first.is_gradual_equivalent_to(db, right)
1596+
(Type::ProtocolInstance(first), Type::ProtocolInstance(second)) => {
1597+
first.is_gradual_equivalent_to(db, second)
15991598
}
16001599
(Type::ProtocolInstance(protocol), nominal @ Type::NominalInstance(n))
16011600
| (nominal @ Type::NominalInstance(n), Type::ProtocolInstance(protocol)) => {

crates/red_knot_python_semantic/src/types/class.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,13 +534,24 @@ impl<'db> ClassLiteral<'db> {
534534

535535
/// Determine if this class is a protocol.
536536
///
537-
/// See the docs on [`KnownClass::is_protocol`] for why we hardcode knowledge
538-
/// about certain special-cased classes, rather than treating all classes
539-
/// the same way here.
537+
/// This method relies on the accuracy of the [`KnownClass::is_protocol`] method,
538+
/// which hardcodes knowledge about certain special-cased classes. See the docs on
539+
/// that method for why we do this rather than relying on generalised logic for all
540+
/// classes, including the special-cased ones that are included in the [`KnownClass`]
541+
/// enum.
540542
pub(super) fn is_protocol(self, db: &'db dyn Db) -> bool {
541543
self.known(db)
542544
.map(KnownClass::is_protocol)
543545
.unwrap_or_else(|| {
546+
// Iterate through the last three bases of the class
547+
// searching for `Protocol` or `Protocol[]` in the bases list.
548+
//
549+
// If `Protocol` is present in the bases list of a valid protocol class, it must either:
550+
//
551+
// - be the last base
552+
// - OR be the last-but-one base (with the final base being `Generic[]` or `object`)
553+
// - OR be the last-but-two base (with the penultimate base being `Generic[]`
554+
// and the final base being `object`)
544555
self.explicit_bases(db).iter().rev().take(3).any(|base| {
545556
matches!(
546557
base,

crates/red_knot_python_semantic/src/types/instance.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ impl<'db> Type<'db> {
2222
}
2323

2424
/// Return `true` if `self` conforms to the interface described by `protocol`.
25+
///
26+
/// TODO: we may need to split this into two methods in the future, once we start
27+
/// differentiating between fully-static and non-fully-static protocols.
2528
pub(super) fn satisfies_protocol(
2629
self,
2730
db: &'db dyn Db,

crates/red_knot_python_semantic/src/types/type_ordering.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,6 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
137137
(_, Type::NominalInstance(_)) => Ordering::Greater,
138138

139139
(Type::ProtocolInstance(left_proto), Type::ProtocolInstance(right_proto)) => {
140-
debug_assert_eq!(*left, left_proto.normalized(db));
141-
debug_assert_eq!(*right, right_proto.normalized(db));
142140
left_proto.cmp(right_proto)
143141
}
144142
(Type::ProtocolInstance(_), _) => Ordering::Less,

0 commit comments

Comments
 (0)