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

Code before:
                    .to_specialized_instance(db, [KnownClass::Str.to_instance(db), Type::object()])
                    .has_relation_to_impl(
                        db,
                        target,
                        inferable,
                        relation,
                        relation_visitor,
                        disjointness_visitor,
                    )
            }),

            // A non-`TypedDict` cannot subtype a `TypedDict`
            (_, Type::TypedDict(_)) => ConstraintSet::from(false),

            // All `StringLiteral` types are a subtype of `LiteralString`.
            (Type::StringLiteral(_), Type::LiteralString) => ConstraintSet::from(true),

            (Type::StringLiteral(_), Type::NominalInstance(instance))
                if instance.has_known_class(db, KnownClass::Str) =>
            {
                ConstraintSet::from(true)
            }

            // A string literal `Literal["abc"]` is a subtype of `str` *and* of
            // `Sequence[Literal["a", "b", "c"]]` because strings are sequences of their characters.
            (Type::StringLiteral(value), _) => {
                let chars: FxHashSet<char> = value.value(db).chars().collect();

                let spec = match chars.len() {
                    0 => Type::Never,
                    1 => Type::StringLiteral(StringLiteralType::new(
                        db,
                        chars.iter().next().unwrap().to_compact_string(),
                    )),
                    _ => {
                        // Optimisation: since we know this union will only include string-literal types,
                        // avoid eagerly creating string-literal types when unnecessary, and avoid going
                        // via the union-builder.
                        let union_elements: Box<[Type<'db>]> = chars
                            .iter()
                            .map(|c| {
                                Type::StringLiteral(StringLiteralType::new(
                                    db,
                                    c.to_compact_string(),
                                ))
                            })
                            .collect();
                        Type::Union(UnionType::new(db, union_elements, RecursivelyDefined::No))
                    }
                };


Review comment (refactor):
I suspect that by far the most effective optimization for this PR would be if we could find ways to narrow down the `_` in this match. Right now we are doing all this work to construct a new sequence-of-characters type anytime we compare a string literal type with anything other than `LiteralString` or `NominalInstance(str)` -- and this could happen quite often e.g. with construction of unions, not necessarily with explicit assignment attempts.

Using `_` here is nice and simple and tempting because it should always be correct to try this delegation -- but can we narrow it down further without losing any correct results? Like for instance, is the new sequence type ever going to be a subtype of anything that isn't a nominal instance type or a protocol?

Or another approach: what if we want this subtype relationship for assignability, but we actually don't care about simplifying a union of `Literal["abba"] | Sequence["a", "b"]`? We could skip this branch if `relation` is redundant-with, and I suspect that would eliminate most of the regression.

Ultimately I think understanding this subtype relationship is pretty low priority (no other type checker does it), so if we can't do it without regression, we should consider not doing it at all.

Code after:
                | Type::ModuleLiteral(_)
                | Type::EnumLiteral(_),
            ) => ConstraintSet::from(false),

            (Type::Callable(self_callable), Type::Callable(other_callable)) => relation_visitor
                .visit((self, target, relation), || {
                    self_callable.has_relation_to_impl(
                        db,
                        other_callable,
                        inferable,
                        relation,
                        relation_visitor,
                        disjointness_visitor,
                    )
                }),

            (_, Type::Callable(other_callable)) => {
                relation_visitor.visit((self, target, relation), || {
                    self.try_upcast_to_callable(db).when_some_and(|callables| {
                        callables.has_relation_to_impl(
                            db,
                            other_callable,
                            inferable,
                            relation,
                            relation_visitor,
                            disjointness_visitor,
                        )
                    })
                })
            }

            // `type[Any]` is assignable to arbitrary protocols as it has arbitrary attributes
            // (this is handled by a lower-down branch), but it is only a subtype of a given
            // protocol if `type` is a subtype of that protocol. Similarly, `type[T]` will
            // always be assignable to any protocol if `type[<upper bound of T>]` is assignable
            // to that protocol (handled lower down), but it is only a subtype of that protocol
            // if `type` is a subtype of that protocol.
            (Type::SubclassOf(self_subclass_ty), Type::ProtocolInstance(_))
                if (self_subclass_ty.is_dynamic() || self_subclass_ty.is_type_var())
                    && !relation.is_assignability() =>
            {
                KnownClass::Type.to_instance(db).has_relation_to_impl(
                    db,
                    target,
                    inferable,
                    relation,
                    relation_visitor,
                    disjointness_visitor,
                )
            }