Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/instance.rs (Rust)

Code before:
            // `Q`'s members in a Liskov-incompatible way.
            let type_to_test = self
                .as_protocol_instance()
                .and_then(ProtocolInstanceType::to_nominal_instance)
                .map(Type::NominalInstance)
                .unwrap_or(self);
            let nominally_satisfied = type_to_test.has_relation_to_impl(
                db,
                Type::NominalInstance(nominal_instance),
                inferable,
                relation,
                relation_visitor,
                disjointness_visitor,
            );
            if result
                .union(db, nominally_satisfied)
                .is_always_satisfied(db)
            {
                return result;
            }
        }

        let structurally_satisfied = if let Type::ProtocolInstance(self_protocol) = self {
            self_protocol.interface(db).has_relation_to_impl(
                db,
                protocol.interface(db),
                inferable,
                relation,
                relation_visitor,
                disjointness_visitor,
            )
        } else {
            protocol
                .inner
                .interface(db)
                .members(db)
                .when_all(db, |member| {
                    member.is_satisfied_by(
                        db,
                        self,
                        inferable,
                        relation,
                        relation_visitor,
                        disjointness_visitor,
                    )
                })
        };
        result.or(db, || structurally_satisfied)
    }
}


Review comment (suggestion):
Similarly here -- I feel like "which gets normalized to `Any`" suggests that it's just an implementation limitation (because `Any` normalization of recursive types is not always correct, and _is_ a current implementation limitation), but in this case even if we didn't normalize to `Any` we would still correctly consider the types equivalent

Code after:
            // from a protocol `Q` to be a subtype of `Q` to be a subtype of `Q` if it overrides
            // `Q`'s members in a Liskov-incompatible way.
            let type_to_test = self
                .as_protocol_instance()
                .and_then(ProtocolInstanceType::to_nominal_instance)
                .map(Type::NominalInstance)
                .unwrap_or(self);
            let nominally_satisfied = type_to_test.has_relation_to_impl(
                db,
                Type::NominalInstance(nominal_instance),
                inferable,
                relation,
                relation_visitor,
                disjointness_visitor,
            );
            if result
                .union(db, nominally_satisfied)
                .is_always_satisfied(db)
            {
                return result;
            }
        }

        // `Generator` special case: Prior to 3.13, the `_ReturnT_co` type didn't appear in any
        // methods (except `__iter__`, but that returns the self type recursively, which gets
        // normalized to `Any`). We don't want generators with different return types to be
        // assignable to each other. In this case we use the result of the nominal check above.
        if let Some(self_protocol) = self.as_protocol_instance()
            && let Protocol::FromClass(self_class) = self_protocol.inner
            && let Protocol::FromClass(proto_class) = protocol.inner
            && self_class.known(db) == Some(KnownClass::Generator)
            && proto_class.known(db) == Some(KnownClass::Generator)
            && Program::get(db).python_version(db) < PythonVersion::PY313
        {
            return result;
        }

        let structurally_satisfied = if let Type::ProtocolInstance(self_protocol) = self {
            self_protocol.interface(db).has_relation_to_impl(
                db,
                protocol.interface(db),
                inferable,
                relation,
                relation_visitor,
                disjointness_visitor,
            )
        } else {
            protocol
                .inner
                .interface(db)
                .members(db)