Skip to content

[ty] Correctly compare generic function subtyping/assignability regardless of TypeVar identity#18634

Closed
LaBatata101 wants to merge 14 commits intoastral-sh:mainfrom
LaBatata101:fix-typevar-identity
Closed

[ty] Correctly compare generic function subtyping/assignability regardless of TypeVar identity#18634
LaBatata101 wants to merge 14 commits intoastral-sh:mainfrom
LaBatata101:fix-typevar-identity

Conversation

@LaBatata101
Copy link
Contributor

Summary

Attempt to fix #95.

For this fix, I've tried to follow the suggestion made in this comment. I've added a new function with_specialized_generic_context -- the name here could probably be better -- that is used to create a new specialized Signature using the SpecializationBuilder, this function is called before the subtyping/assignability/equivalency comparisons. Then we use this new Signature to do the actual comparison. Not sure if this was what @dcreager had in mind.

There's a bit of code duplication because I had to create a carbon copy of is_assignable_to_impl function to call the SpecializationBuilder::infer on the signature types.

This PR also creates a generic context for the Callable type. And finally, I didn't fix the issue in the implementation of SpecializationBuilder::infer that was mentioned on Discord.

Let me know if this is heading in the right direction or if you'd prefer a different approach.
No hard feelings if this gets rejected.

Test Plan

Add more mdtest.

@github-actions
Copy link
Contributor

github-actions bot commented Jun 11, 2025

mypy_primer results

Changes were detected when running on open source projects
python-chess (https://github.com/niklasf/python-chess)
- chess/pgn.py:1857:35: error[invalid-argument-type] Argument to function `read_game` is incorrect: Expected `() -> BaseVisitor[Unknown]`, found `<class 'SkipVisitor'>`
- Found 16 diagnostics
+ Found 15 diagnostics

Expression (https://github.com/cognitedata/Expression)
- expression/collections/seq.py:637:41: error[invalid-argument-type] Argument to function `init_infinite` is incorrect: Expected `(int, /) -> Unknown`, found `def identity(value: _A) -> _A`
- expression/extra/result/traversable.py:50:21: error[invalid-argument-type] Argument to function `traverse` is incorrect: Expected `(Result[_TSource, _TError], /) -> Result[Unknown, Unknown]`, found `def identity(value: _A) -> _A`
- tests/test_map.py:49:19: error[invalid-argument-type] Argument to function `pipe` is incorrect: Expected `(Map[str, int], /) -> Unknown`, found `def to_seq(table: Map[_Key, _Value]) -> Iterable[tuple[_Key, _Value]]`
- tests/test_parser.py:232:9: error[invalid-argument-type] Argument to function `pipe` is incorrect: Expected `(Parser[str], /) -> Unknown`, found `def many(parser: Parser[_A]) -> Parser[Block[_A]]`
- tests/test_result.py:487:24: error[invalid-argument-type] Argument to bound method `pipe` is incorrect: Expected `(Result[Literal[42], Any], /) -> Unknown`, found `def swap(result: Result[_TSource, _TError]) -> Result[_TError, _TSource]`
- tests/test_result.py:573:24: error[invalid-argument-type] Argument to bound method `pipe` is incorrect: Expected `(Result[Literal[42], Any], /) -> Unknown`, found `def merge(result: Result[_TSource, _TSource]) -> _TSource`
- tests/test_seq.py:308:20: error[invalid-argument-type] Argument to bound method `choose` is incorrect: Expected `(None | Literal[42], /) -> Option[Unknown]`, found `def of_optional(value: _TSource | None) -> Option[_TSource]`
- Found 227 diagnostics
+ Found 220 diagnostics

werkzeug (https://github.com/pallets/werkzeug)
- src/werkzeug/datastructures/mixins.py:238:28: error[invalid-argument-type] Argument is incorrect: Expected `Self`, found `UpdateDictMixin[Any, Any]`
- src/werkzeug/local.py:526:24: error[invalid-return-type] Return type does not match returned value: expected `T`, found `Unknown | LocalProxy[Any] | T`
+ src/werkzeug/local.py:526:24: error[invalid-return-type] Return type does not match returned value: expected `T`, found `Unknown | LocalProxy[Any]`
- Found 370 diagnostics
+ Found 369 diagnostics

pydantic (https://github.com/pydantic/pydantic)
- pydantic/functional_serializers.py:298:12: error[invalid-return-type] Return type does not match returned value: expected `((_FieldWrapSerializerT, /) -> _FieldWrapSerializerT) | ((_FieldPlainSerializerT, /) -> _FieldPlainSerializerT)`, found `def dec(f: @Todo(Support for `typing.TypeAlias`)) -> PydanticDescriptorProxy[Any]`
+ pydantic/functional_serializers.py:298:12: error[invalid-return-type] Return type does not match returned value: expected `(_FieldWrapSerializerT, /) -> _FieldWrapSerializerT`, found `def dec(f: @Todo(Support for `typing.TypeAlias`)) -> PydanticDescriptorProxy[Any]`
- pydantic/functional_serializers.py:416:16: error[invalid-return-type] Return type does not match returned value: expected `_ModelPlainSerializerT | ((_ModelWrapSerializerT, /) -> _ModelWrapSerializerT) | ((_ModelPlainSerializerT, /) -> _ModelPlainSerializerT)`, found `def dec(f: @Todo(Support for `typing.TypeAlias`)) -> PydanticDescriptorProxy[Any]`
+ pydantic/functional_serializers.py:416:16: error[invalid-return-type] Return type does not match returned value: expected `_ModelPlainSerializerT | ((_ModelWrapSerializerT, /) -> _ModelWrapSerializerT)`, found `def dec(f: @Todo(Support for `typing.TypeAlias`)) -> PydanticDescriptorProxy[Any]`
- pydantic/functional_serializers.py:418:16: error[invalid-return-type] Return type does not match returned value: expected `_ModelPlainSerializerT | ((_ModelWrapSerializerT, /) -> _ModelWrapSerializerT) | ((_ModelPlainSerializerT, /) -> _ModelPlainSerializerT)`, found `PydanticDescriptorProxy[Any]`
+ pydantic/functional_serializers.py:418:16: error[invalid-return-type] Return type does not match returned value: expected `_ModelPlainSerializerT | ((_ModelWrapSerializerT, /) -> _ModelWrapSerializerT)`, found `PydanticDescriptorProxy[Any]`

discord.py (https://github.com/Rapptz/discord.py)
- discord/ext/commands/core.py:2103:12: error[invalid-return-type] Return type does not match returned value: expected `(T, /) -> T`, found `Check[Unknown]`
- discord/ext/commands/core.py:2136:12: error[invalid-return-type] Return type does not match returned value: expected `(T, /) -> T`, found `Check[Unknown]`
- discord/ext/commands/core.py:2165:12: error[invalid-return-type] Return type does not match returned value: expected `(T, /) -> T`, found `Check[Unknown]`
- Found 527 diagnostics
+ Found 524 diagnostics

urllib3 (https://github.com/urllib3/urllib3)
- test/__init__.py:119:12: error[invalid-return-type] Return type does not match returned value: expected `(_TestFuncT, /) -> _TestFuncT`, found `Unknown | MarkDecorator`
- test/__init__.py:126:12: error[invalid-return-type] Return type does not match returned value: expected `(_TestFuncT, /) -> _TestFuncT`, found `Unknown | MarkDecorator`
- test/__init__.py:132:12: error[invalid-return-type] Return type does not match returned value: expected `(_TestFuncT, /) -> _TestFuncT`, found `Unknown | MarkDecorator`
- test/__init__.py:138:12: error[invalid-return-type] Return type does not match returned value: expected `(_TestFuncT, /) -> _TestFuncT`, found `Unknown | MarkDecorator`
- test/__init__.py:145:12: error[invalid-return-type] Return type does not match returned value: expected `(_TestFuncT, /) -> _TestFuncT`, found `Unknown | MarkDecorator`
- test/__init__.py:205:12: error[invalid-return-type] Return type does not match returned value: expected `(_TestFuncT, /) -> _TestFuncT`, found `Unknown | MarkDecorator`
- Found 397 diagnostics
+ Found 391 diagnostics

pwndbg (https://github.com/pwndbg/pwndbg)
- pwndbg/dbg/gdb/__init__.py:1663:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def exit(func: () -> T, **kwargs: Any) -> () -> T`
- pwndbg/dbg/gdb/__init__.py:1665:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def cont(func: () -> T, **kwargs: Any) -> () -> T`
- pwndbg/dbg/gdb/__init__.py:1667:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def start(func: () -> T, **kwargs: Any) -> () -> T`
- pwndbg/dbg/gdb/__init__.py:1669:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def stop(func: () -> T, **kwargs: Any) -> () -> T`
- pwndbg/dbg/gdb/__init__.py:1671:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def new_objfile(func: () -> T, **kwargs: Any) -> () -> T`
- pwndbg/dbg/gdb/__init__.py:1673:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def mem_changed(func: () -> T, **kwargs: Any) -> () -> T`
- pwndbg/dbg/gdb/__init__.py:1675:20: error[invalid-return-type] Return type does not match returned value: expected `((...) -> T, /) -> (...) -> T`, found `def reg_changed(func: () -> T, **kwargs: Any) -> () -> T`
- Found 2260 diagnostics
+ Found 2253 diagnostics

meson (https://github.com/mesonbuild/meson)
- unittests/helpers.py:228:16: error[invalid-return-type] Return type does not match returned value: expected `((...) -> R, /) -> (...) -> R`, found `def expectedFailure(test_item: _FT) -> _FT`
- Found 757 diagnostics
+ Found 756 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/utilities/collections.py:395:36: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, VT]`, found `dict[str, VT] | None`
+ src/prefect/utilities/collections.py:395:36: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Unknown]`, found `dict[str, Unknown] | None`

zulip (https://github.com/zulip/zulip)
- zerver/lib/rest.py:189:40: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `(...) -> HttpResponse`
- zerver/lib/rest.py:205:40: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `(...) -> HttpResponse`
- zerver/views/auth.py:1178:1: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `def api_get_server_settings(request: HttpRequest) -> HttpResponse`
- zerver/views/development/email_log.py:52:1: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `def generate_all_emails(request: HttpRequest) -> HttpResponse`
- zerver/views/realm.py:572:1: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `def check_subdomain_available(request: HttpRequest, subdomain: str) -> HttpResponse`
- zerver/views/report.py:14:1: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `(...) -> Unknown`
- zerver/views/video_calls.py:298:1: error[invalid-argument-type] Argument is incorrect: Expected `_F`, found `(...) -> Unknown`
- Found 7322 diagnostics
+ Found 7315 diagnostics
No memory usage changes detected ✅

@LaBatata101 LaBatata101 force-pushed the fix-typevar-identity branch from 2609c74 to 4a4802b Compare June 11, 2025 20:24
@LaBatata101
Copy link
Contributor Author

The implementation is probably wrong, given the mypy_primer results

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Jun 11, 2025
@dcreager
Copy link
Member

I'm just about to sign off for the night, but I can take a look at this first thing tomorrow!

Copy link
Member

@dcreager dcreager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some initial comments. I think it would be good to get @dhruvmanila's thoughts on this, too, since he was the original author of the is_assignable_to_impl method that you're basing this on

Comment on lines 546 to 494
if default_type.is_none() {
return Ok(());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment for this arm in is_assignable_to_impl says this:

// For `self <: other` to be valid, if there are no more parameters in
// `other`, then the non-variadic parameters in `self` must have a default
// value.

We're not doing a subtype/assignability check here, so I think the default_type check isn't needed. Any parameters that don't "line up" should just be skipped, since there aren't respective typevars that we want to infer to be the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I remove that check and this one too?

for (_, self_parameter) in self_keywords {
if self_parameter.default_type().is_none() {
return Ok(());
}
}

Copy link
Member

@dhruvmanila dhruvmanila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit unfortunate that we need to copy the entire parameter loop over as it's quite complicated and will get even more so when adding support for TypedDict and Unpack.

I'm not exactly sure if there's an easy way to avoid duplicating the logic. We could accept a closure which is called for each pair of the parameter but then it will need to retain information that's required for both assignability/subtyping and specialization. There are also subtle differences between the two like the handling of default values.

I don't think it's worth spending time to de-duplicate right now but might be useful to do a time-blocked exploration in the future.

Comment on lines 706 to 507
for (_, self_parameter) in self_keywords {
if self_parameter.default_type().is_none() {
return Ok(());
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment that Doug made above regarding the default value -- will it apply here as well?

@LaBatata101 LaBatata101 marked this pull request as ready for review June 24, 2025 22:39
@LaBatata101 LaBatata101 requested a review from dcreager June 24, 2025 22:40
@MichaReiser
Copy link
Member

It's a bit unfortunate that we need to copy the entire parameter loop over as it's quite complicated and will get even more so when adding support for TypedDict and Unpack.

Given the size of it (and that the divergences are very subtle), I do think it would make sense to invest some time into avoiding this duplication now

Cow::Borrowed(self)
}

/// This is a carbon copy of [`Self::is_assignable_to_impl`], but instead of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find is_assignable_to_impl

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's down below on line 849

Copy link
Member

@MichaReiser MichaReiser Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I think it got renamed on main (we should also double check if there are no behavior changes to it that need to be accounted for here)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, it's now has_relation_to as detected by the merge conflict

@AlexWaygood AlexWaygood removed their request for review June 25, 2025 08:04
@LaBatata101 LaBatata101 force-pushed the fix-typevar-identity branch from cc24464 to 8880063 Compare June 25, 2025 19:29
c: Callable[[int], C[int]] = C[int]
```

### Generic callables and TypeVar identity
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test looks great. I think ideally we'd have a version of it using PEP 695 typevars also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reminder, I will add them later. Now I have to figure it out how to apply my changes to the new changes made in signatures.rs, a lot has changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about all the conflicts!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries

@carljm carljm marked this pull request as draft June 26, 2025 16:03
@carljm
Copy link
Contributor

carljm commented Jun 26, 2025

Marking as draft since there have been some reviews and some updates (and conflict resolutions) are needed. Please mark ready for review when you would like us to take another look!

@LaBatata101 LaBatata101 force-pushed the fix-typevar-identity branch from 8880063 to 902dfdc Compare June 26, 2025 21:13
@LaBatata101 LaBatata101 force-pushed the fix-typevar-identity branch from 1a26a63 to 256f31c Compare June 30, 2025 22:52
Copy link
Member

@dhruvmanila dhruvmanila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for combining the implementation of the parameter check loop!

Comment on lines 561 to 566
fn compare_with<'a>(
&self,
db: &'db dyn Db,
other: &Signature<'db>,
mode: &mut SignatureCheckMode<'a, 'db>,
) -> Result<bool, SpecializationError<'db>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, the Ok variant of the return type corresponds to the SignatureCheckMode::Relation variant while the Err variant corresponds to the SignatureCheckMode::InferSpecialization variant, is that correct?

If so, it's a bit unfortunate that we cannot encode this in the type system and the fact that the Err variant is only for a specific mode. I don't have a good solution to this apart from the fact that we use .unwrap in has_relation_to because it should always return Ok(bool) and if that is Err then I think it would be a logic error.

Maybe we should instead use a custom enum to reflect the return type which is according to the mode parameter:

enum SignatureCheckResult {
	Relation(bool),
	InferSpecialization(Result<(), SpecializationError>)
}

impl SignatureCheckResult {
	fn expect_relation(&self) -> bool {
		match self {
			Self::Relation(result) => result,
			Self::InferSpecialization(_) => panic!(...),
		}
	}

	fn expect_infer_specialization(&self) -> bool {
		match self {
			Self::Relation(_) => panic!(...),
			Self::InferSpecialization(result) => result,
		}
	}
}

But, I'm not too sold on this idea either, it just makes it explicit on what the relation is between the return type and the mode parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, the Ok variant of the return type corresponds to the SignatureCheckMode::Relation variant while the Err variant corresponds to the SignatureCheckMode::InferSpecialization variant, is that correct?

yes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also put the return value into the SignatureCheckMode enum:

enum SignatureCheckMode<'a, 'db> {
    Relation {
        relation: TypeRelation,
        result: bool,
    },
    InferSpecialization {
        builder: &'a mut SpecializationBuilder<'db>,
        result: Result<(), SpecializationError<'db>>,
    },
}

Then the signature of this method would become

    fn compare_with<'a>(
        &self,
        db: &'db dyn Db,
        other: &Signature<'db>,
        mode: &mut SignatureCheckMode<'a, 'db>,
    ) {

Comment on lines -147 to +150
self_signature.has_relation_to(db, other_signature, relation)
self_signature
.with_specialized_generic_context(db, other_signature)
.has_relation_to(db, other_signature, relation)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that we're potentially looping over all the parameters twice - first two infer the specialization and second to perform the type relation check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, unfortunately.

@dhruvmanila
Copy link
Member

And, I've also added new tests, but there are two cases that are failing that I don't if they are supposed to be failing or not.

This is a bit hand wavy but could this be because the actual parameter loop of subtyping/assignability is different than the one for equivalence check but the parameter loop of constructing the specialization is the same for both?

@LaBatata101
Copy link
Contributor Author

And, I've also added new tests, but there are two cases that are failing that I don't if they are supposed to be failing or not.

This is a bit hand wavy but could this be because the actual parameter loop of subtyping/assignability is different than the one for equivalence check but the parameter loop of constructing the specialization is the same for both?

Hmm, I don't know. It only happens when comparing the legacy typevar with the PEP695 typevar, the other equivalence cases are okay. But I'll take a look at that.

@LaBatata101
Copy link
Contributor Author

Sorry for the delay on this. I've done some debugging and for this failing test case:

from ty_extensions import (CallableTypeOf, is_equivalent_to,  static_assert)

T = TypeVar("T")


def f[T](x: T) -> T:
    return x


static_assert(is_equivalent_to(CallableTypeOf[f], Callable[[T], T]))

In the is_equivalent_to function the code execute this branch

_ => return false,
}

with these parameters

[crates/ty_python_semantic/src/types/signatures.rs:523:21] a = PositionalOrKeyword {
    name: Name("x"),
    default_type: None,
}
[crates/ty_python_semantic/src/types/signatures.rs:523:21] b = PositionalOnly {
    name: None,
    default_type: None,
}

how should they be handled?

@carljm
Copy link
Contributor

carljm commented Jul 22, 2025

I think that test is simply incorrect? One of those callable types is a subtype of the other, but they are not equivalent, because one of them can accept the call f(x=1) and the other cannot (since it has a positional-only argument that can't be named as a keyword in a call).

I think modifying the test to assert that the one specified with CallableTypeOf is a subtype of the one specified with Callable would be a useful test (it would show that we apply this understanding of typevar equivalence not only in type equivalence but also in subtyping), and would be correct.

@LaBatata101
Copy link
Contributor Author

I think modifying the test to assert that the one specified with CallableTypeOf is a subtype of the one specified with Callable would be a useful test (it would show that we apply this understanding of typevar equivalence not only in type equivalence but also in subtyping), and would be correct.

I think I've put one like that in crates/ty_python_semantic/resources/mdtest/type_properties/is_subtype_of.md

Copy link
Member

@dcreager dcreager left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of comments that should help clean up compare_with and friends some more. Otherwise this is getting very close!

db: &'db dyn Db,
other: &'a Signature<'db>,
) -> Cow<'a, Signature<'db>> {
if let (Some(self_gc), Some(other_gc)) = (self.generic_context, other.generic_context) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit to remove indentation:

Suggested change
if let (Some(self_gc), Some(other_gc)) = (self.generic_context, other.generic_context) {
let (Some(self_gc), Some(other_gc)) = (self.generic_context, other.generic_context) else {
return Cow::Borrowed(self);
};

then all of the work to infer the specialization is unindented and looks like the "main" bit of work that the method does

Comment on lines 561 to 566
fn compare_with<'a>(
&self,
db: &'db dyn Db,
other: &Signature<'db>,
mode: &mut SignatureCheckMode<'a, 'db>,
) -> Result<bool, SpecializationError<'db>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also put the return value into the SignatureCheckMode enum:

enum SignatureCheckMode<'a, 'db> {
    Relation {
        relation: TypeRelation,
        result: bool,
    },
    InferSpecialization {
        builder: &'a mut SpecializationBuilder<'db>,
        result: Result<(), SpecializationError<'db>>,
    },
}

Then the signature of this method would become

    fn compare_with<'a>(
        &self,
        db: &'db dyn Db,
        other: &Signature<'db>,
        mode: &mut SignatureCheckMode<'a, 'db>,
    ) {

Comment on lines 607 to 619
match mode {
SignatureCheckMode::Relation(relation) => {
// Return types are covariant.
if !check_types(self.return_ty, other.return_ty, *relation) {
return Ok(false);
}
}
SignatureCheckMode::InferSpecialization(builder) => {
// Return types are covariant. For inference, `self` is formal, `other` is actual.
if let (Some(self_type), Some(other_type)) = (self.return_ty, other.return_ty) {
builder.infer(self_type, other_type)?;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is repeated a lot; I think it should become a method on SignatureCheckMode. Ideally you could get this down to where there are no match mode or equivalent checks inside of here, and all of that moves into logic on SignatureCheckMode itself

// A gradual parameter list is a supertype of the "bottom" parameter list (*args: object,
// **kwargs: object).
if other.parameters.is_gradual()
if mode.is_relation()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This check, for instance, is morally equivalent to a match mode and so should ideally move into SignatureMatchMode as well)

@LaBatata101
Copy link
Contributor Author

I'll be working on the feedbacks in the weekend

@LaBatata101
Copy link
Contributor Author

@dcreager I've applied your suggestions, but I think the code hasn't improved that much honestly. The code is currently failing to build because I don't know how to get the function definition to pass it to GenericContext::from_function_params, here:

let callable_type = if let (Some(parameters), Some(return_type), true) =
(parameters, return_type, correct_argument_number)
{
CallableType::single(
db,
Signature::new_generic(
GenericContext::from_function_params(
db,
&parameters,
Some(return_type),
),
parameters,
Some(return_type),
),
)
} else {

@carljm
Copy link
Contributor

carljm commented Aug 5, 2025

Will leave review here to @dcreager, unless it seems like another pair of eyes would be useful.

@carljm carljm requested review from dcreager and removed request for carljm August 5, 2025 03:28
@dcreager
Copy link
Member

dcreager commented Aug 6, 2025

The code is currently failing to build because I don't know how to get the function definition to pass it to GenericContext::from_function_params, here:

To resolve this part, I think we should update from_function_params to take in containing_scope: FileScopeId instead of definition: Definition. In your new code in infer.rs, you'd get that FileScopeId via self.scope().file_scope_id(self.db()).

@github-actions
Copy link
Contributor

github-actions bot commented Aug 6, 2025

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-08-06 19:40:29.595655223 +0000
+++ new-output.txt	2025-08-06 19:40:29.653655585 +0000
@@ -1,174 +1,58 @@
 WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
-_directives_deprecated_library.py:15:31: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-_directives_deprecated_library.py:30:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
-_directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Spam`
-_directives_deprecated_library.py:41:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int | float`
-_directives_deprecated_library.py:45:24: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
-aliases_explicit.py:41:24: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[str, str]`?
-aliases_explicit.py:45:10: error[invalid-type-form] Variable of type `Literal["int | str"]` is not allowed in a type expression
-aliases_explicit.py:49:5: error[type-assertion-failure] Argument does not have asserted type `int | str`
-aliases_explicit.py:50:5: error[type-assertion-failure] Argument does not have asserted type `int | None`
-aliases_explicit.py:51:5: error[type-assertion-failure] Argument does not have asserted type `list[int | None]`
-aliases_explicit.py:52:5: error[type-assertion-failure] Argument does not have asserted type `list[int]`
-aliases_explicit.py:53:5: error[type-assertion-failure] Argument does not have asserted type `tuple[str, ...] | list[str]`
-aliases_explicit.py:54:5: error[type-assertion-failure] Argument does not have asserted type `tuple[int, int, int, str]`
-aliases_explicit.py:55:5: error[type-assertion-failure] Argument does not have asserted type `(...) -> int`
-aliases_explicit.py:56:5: error[type-assertion-failure] Argument does not have asserted type `(int, str, /) -> str`
-aliases_explicit.py:57:5: error[type-assertion-failure] Argument does not have asserted type `(int, str, str, /) -> None`
-aliases_explicit.py:59:5: error[type-assertion-failure] Argument does not have asserted type `int | str | None | list[list[int]]`
-aliases_explicit.py:60:5: error[type-assertion-failure] Argument does not have asserted type `(...) -> None`
-aliases_explicit.py:61:5: error[type-assertion-failure] Argument does not have asserted type `int | str`
-aliases_explicit.py:63:5: error[type-assertion-failure] Argument does not have asserted type `Literal[3, 4, 5] | None`
-aliases_explicit.py:98:1: error[type-assertion-failure] Argument does not have asserted type `list[str]`
-aliases_explicit.py:101:6: error[call-non-callable] Object of type `UnionType` is not callable
-aliases_implicit.py:54:24: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[str, str]`?
-aliases_implicit.py:60:5: error[type-assertion-failure] Argument does not have asserted type `int | str`
-aliases_implicit.py:61:5: error[type-assertion-failure] Argument does not have asserted type `int | None`
-aliases_implicit.py:62:5: error[type-assertion-failure] Argument does not have asserted type `list[int | None]`
-aliases_implicit.py:63:5: error[type-assertion-failure] Argument does not have asserted type `list[int]`
-aliases_implicit.py:64:5: error[type-assertion-failure] Argument does not have asserted type `tuple[str, ...] | list[str]`
-aliases_implicit.py:65:5: error[type-assertion-failure] Argument does not have asserted type `tuple[int, int, int, str]`
-aliases_implicit.py:66:5: error[type-assertion-failure] Argument does not have asserted type `(...) -> int`
-aliases_implicit.py:67:5: error[type-assertion-failure] Argument does not have asserted type `(int, str, /) -> str`
-aliases_implicit.py:68:5: error[type-assertion-failure] Argument does not have asserted type `(int, str, str, /) -> None`
-aliases_implicit.py:70:5: error[type-assertion-failure] Argument does not have asserted type `int | str | None | list[list[int]]`
-aliases_implicit.py:71:5: error[type-assertion-failure] Argument does not have asserted type `list[bool]`
-aliases_implicit.py:72:5: error[type-assertion-failure] Argument does not have asserted type `(...) -> None`
-aliases_implicit.py:107:9: error[invalid-type-form] Variable of type `list[Unknown]` is not allowed in a type expression
-aliases_implicit.py:108:9: error[invalid-type-form] Variable of type `tuple[tuple[<class 'int'>, <class 'str'>]]` is not allowed in a type expression
-aliases_implicit.py:110:9: error[invalid-type-form] Variable of type `dict[Unknown, Unknown]` is not allowed in a type expression
-aliases_implicit.py:114:9: error[invalid-type-form] Variable of type `Literal[3]` is not allowed in a type expression
-aliases_implicit.py:115:10: error[invalid-type-form] Variable of type `Literal[True]` is not allowed in a type expression
-aliases_implicit.py:116:10: error[invalid-type-form] Variable of type `Literal[1]` is not allowed in a type expression
-aliases_implicit.py:118:10: error[invalid-type-form] Variable of type `Literal["int"]` is not allowed in a type expression
-aliases_implicit.py:119:10: error[invalid-type-form] Variable of type `Literal["int | str"]` is not allowed in a type expression
-aliases_implicit.py:128:1: error[type-assertion-failure] Argument does not have asserted type `list[str]`
-aliases_implicit.py:133:6: error[call-non-callable] Object of type `UnionType` is not callable
-aliases_newtype.py:15:1: error[type-assertion-failure] Argument does not have asserted type `int`
-aliases_newtype.py:18:1: error[invalid-assignment] Object of type `NewType` is not assignable to `type`
-aliases_newtype.py:26:21: error[invalid-base] Invalid class base with type `NewType`
-aliases_newtype.py:63:43: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 3, got 4
-aliases_type_statement.py:17:1: error[unresolved-attribute] Type `typing.TypeAliasType` has no attribute `bit_count`
-aliases_type_statement.py:19:1: error[call-non-callable] Object of type `TypeAliasType` is not callable
-aliases_type_statement.py:23:7: error[unresolved-attribute] Type `typing.TypeAliasType` has no attribute `other_attrib`
-aliases_type_statement.py:26:18: error[invalid-base] Invalid class base with type `typing.TypeAliasType`
-aliases_type_statement.py:37:22: error[invalid-type-form] Function calls are not allowed in type expressions
-aliases_type_statement.py:38:22: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_type_statement.py:39:22: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression
-aliases_type_statement.py:39:23: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_type_statement.py:40:22: error[invalid-type-form] List comprehensions are not allowed in type expressions
-aliases_type_statement.py:41:22: error[invalid-type-form] Dict literals are not allowed in type expressions
-aliases_type_statement.py:42:22: error[invalid-type-form] Function calls are not allowed in type expressions
-aliases_type_statement.py:43:28: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-aliases_type_statement.py:44:22: error[invalid-type-form] `if` expressions are not allowed in type expressions
-aliases_type_statement.py:45:22: error[invalid-type-form] Variable of type `Literal[1]` is not allowed in a type expression
-aliases_type_statement.py:46:23: error[invalid-type-form] Boolean literals are not allowed in this context in a type expression
-aliases_type_statement.py:47:23: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-aliases_type_statement.py:48:23: error[invalid-type-form] Boolean operations are not allowed in type expressions
-aliases_type_statement.py:49:23: error[fstring-type-annotation] Type expressions cannot use f-strings
-aliases_type_statement.py:80:37: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_typealiastype.py:32:7: error[unresolved-attribute] Type `typing.TypeAliasType` has no attribute `other_attrib`
-aliases_typealiastype.py:39:26: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_typealiastype.py:52:40: error[invalid-type-form] Function calls are not allowed in type expressions
-aliases_typealiastype.py:53:40: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_typealiastype.py:54:42: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression
-aliases_typealiastype.py:54:43: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-aliases_typealiastype.py:55:42: error[invalid-type-form] List comprehensions are not allowed in type expressions
-aliases_typealiastype.py:56:42: error[invalid-type-form] Dict literals are not allowed in type expressions
-aliases_typealiastype.py:57:42: error[invalid-type-form] Function calls are not allowed in type expressions
-aliases_typealiastype.py:58:48: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-aliases_typealiastype.py:59:42: error[invalid-type-form] `if` expressions are not allowed in type expressions
-aliases_typealiastype.py:60:42: error[invalid-type-form] Variable of type `Literal[3]` is not allowed in a type expression
-aliases_typealiastype.py:61:42: error[invalid-type-form] Boolean literals are not allowed in this context in a type expression
-aliases_typealiastype.py:62:42: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-aliases_typealiastype.py:63:42: error[invalid-type-form] Boolean operations are not allowed in type expressions
-aliases_typealiastype.py:64:42: error[invalid-type-form] F-strings are not allowed in type expressions
-aliases_typealiastype.py:66:47: error[unresolved-reference] Name `BadAlias21` used when not defined
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_scoping.py`: `FunctionType < 'db >::signature_(Id(60800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/dataclasses_transform_converter.py`: `FunctionType < 'db >::signature_(Id(69c00)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/constructors_callable.py`: `FunctionType < 'db >::signature_(Id(4f401)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_self_advanced.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/directives_cast.py`: `FunctionType < 'db >::signature_(Id(34006)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_upper_bound.py`: `FunctionType < 'db >::signature_(Id(34007)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/callables_annotation.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_implicit.py`: `FunctionType < 'db >::signature_(Id(3cc10)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/enums_members.py`: `FunctionType < 'db >::signature_(Id(32818)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/specialtypes_type.py`: `FunctionType < 'db >::signature_(Id(3400a)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/narrowing_typeis.py`: `FunctionType < 'db >::signature_(Id(66800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/protocols_generic.py`: `FunctionType < 'db >::signature_(Id(4f409)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_type_statement.py`: `FunctionType < 'db >::signature_(Id(3cc10)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/constructors_call_init.py`: `FunctionType < 'db >::signature_(Id(72415)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_paramspec_semantics.py`: `FunctionType < 'db >::signature_(Id(53413)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_paramspec_components.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/directives_assert_type.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/constructors_call_type.py`: `FunctionType < 'db >::signature_(Id(49c18)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/directives_reveal_type.py`: `FunctionType < 'db >::signature_(Id(4f400)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `FunctionType < 'db >::signature_(Id(3cc10)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/enums_expansion.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/protocols_recursive.py`: `FunctionType < 'db >::signature_(Id(6081a)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/_directives_deprecated_library.py`: `FunctionType < 'db >::signature_(Id(49c1b)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/annotations_methods.py`: `FunctionType < 'db >::signature_(Id(87801)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_defaults_specialization.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/annotations_typeexpr.py`: `FunctionType < 'db >::signature_(Id(3cc10)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/literals_literalstring.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_explicit.py`: `FunctionType < 'db >::signature_(Id(3cc10)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/dataclasses_usage.py`: `FunctionType < 'db >::signature_(Id(4980e)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_basic.py`: `FunctionType < 'db >::signature_(Id(35c03)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/callables_protocol.py`: `FunctionType < 'db >::signature_(Id(72431)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/narrowing_typeguard.py`: `FunctionType < 'db >::signature_(Id(55020)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_newtype.py`: `FunctionType < 'db >::signature_(Id(69c18)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_base_class.py`: `FunctionType < 'db >::signature_(Id(3cc25)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_defaults.py`: `FunctionType < 'db >::signature_(Id(5e83a)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/classes_classvar.py`: `FunctionType < 'db >::signature_(Id(2ec1b)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/protocols_self.py`: `FunctionType < 'db >::signature_(Id(35c0f)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/annotations_coroutines.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_typevartuple_concat.py`: `FunctionType < 'db >::signature_(Id(5341d)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/enums_behaviors.py`: `FunctionType < 'db >::signature_(Id(8082c)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/tuples_unpacked.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_typevartuple_basic.py`: `FunctionType < 'db >::signature_(Id(69c18)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/dataclasses_transform_func.py`: `FunctionType < 'db >::signature_(Id(3402e)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/directives_deprecated.py`: `FunctionType < 'db >::signature_(Id(49c1b)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/dataclasses_kwonly.py`: `FunctionType < 'db >::signature_(Id(4980e)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/generics_variance.py`: `FunctionType < 'db >::signature_(Id(87814)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/qualifiers_annotated.py`: `FunctionType < 'db >::signature_(Id(69c22)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/overloads_evaluation.py`: `FunctionType < 'db >::signature_(Id(49800)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/b121ee4/src/function/execute.rs:202:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/annotations_generators.py`: `FunctionType < 'db >::signature_(Id(a703a)): execute: too many cycle iterations`
 aliases_variance.py:18:24: error[non-subscriptable] Cannot subscript object of type `<class 'ClassA[T_co]'>` with no `__class_getitem__` method
 aliases_variance.py:28:16: error[non-subscriptable] Cannot subscript object of type `<class 'ClassA[T_co]'>` with no `__class_getitem__` method
 aliases_variance.py:44:16: error[non-subscriptable] Cannot subscript object of type `<class 'ClassB[T_co, T_contra]'>` with no `__class_getitem__` method
-annotations_forward_refs.py:22:7: error[unresolved-reference] Name `ClassA` used when not defined
-annotations_forward_refs.py:23:12: error[unresolved-reference] Name `ClassA` used when not defined
-annotations_forward_refs.py:49:10: error[invalid-type-form] Variable of type `Literal[1]` is not allowed in a type expression
-annotations_forward_refs.py:54:11: error[fstring-type-annotation] Type expressions cannot use f-strings
-annotations_forward_refs.py:55:11: error[invalid-type-form] Variable of type `<module 'types'>` is not allowed in a type expression
-annotations_forward_refs.py:66:26: error[unresolved-reference] Name `ClassB` used when not defined
-annotations_forward_refs.py:80:14: error[unresolved-reference] Name `ClassF` used when not defined
-annotations_forward_refs.py:82:11: error[invalid-type-form] Variable of type `Literal[""]` is not allowed in a type expression
-annotations_forward_refs.py:87:9: error[invalid-type-form] Variable of type `def int(self) -> None` is not allowed in a type expression
-annotations_forward_refs.py:89:8: error[invalid-type-form] Variable of type `def int(self) -> None` is not allowed in a type expression
-annotations_forward_refs.py:95:1: error[type-assertion-failure] Argument does not have asserted type `str`
-annotations_forward_refs.py:96:1: error[type-assertion-failure] Argument does not have asserted type `int`
-annotations_generators.py:86:21: error[invalid-return-type] Return type does not match returned value: expected `int`, found `types.GeneratorType`
-annotations_generators.py:91:27: error[invalid-return-type] Return type does not match returned value: expected `int`, found `types.AsyncGeneratorType`
-annotations_generators.py:193:1: error[type-assertion-failure] Argument does not have asserted type `() -> AsyncIterator[int]`
-annotations_methods.py:31:1: error[type-assertion-failure] Argument does not have asserted type `A`
-annotations_methods.py:36:1: error[type-assertion-failure] Argument does not have asserted type `B`
-annotations_methods.py:42:1: error[type-assertion-failure] Argument does not have asserted type `A`
-annotations_methods.py:48:1: error[type-assertion-failure] Argument does not have asserted type `A`
-annotations_methods.py:49:1: error[type-assertion-failure] Argument does not have asserted type `B`
-annotations_methods.py:50:1: error[type-assertion-failure] Argument does not have asserted type `B`
-annotations_methods.py:51:1: error[type-assertion-failure] Argument does not have asserted type `A`
-annotations_typeexpr.py:88:9: error[invalid-type-form] Function calls are not allowed in type expressions
-annotations_typeexpr.py:89:9: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-annotations_typeexpr.py:90:9: error[invalid-type-form] Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?
-annotations_typeexpr.py:91:9: error[invalid-type-form] List comprehensions are not allowed in type expressions
-annotations_typeexpr.py:92:9: error[invalid-type-form] Dict literals are not allowed in type expressions
-annotations_typeexpr.py:93:9: error[invalid-type-form] Function calls are not allowed in type expressions
-annotations_typeexpr.py:94:15: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-annotations_typeexpr.py:95:9: error[invalid-type-form] `if` expressions are not allowed in type expressions
-annotations_typeexpr.py:96:9: error[invalid-type-form] Variable of type `Literal[3]` is not allowed in a type expression
-annotations_typeexpr.py:97:10: error[invalid-type-form] Boolean literals are not allowed in this context in a type expression
-annotations_typeexpr.py:98:10: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-annotations_typeexpr.py:99:10: error[invalid-type-form] Unary operations are not allowed in type expressions
-annotations_typeexpr.py:100:10: error[invalid-type-form] Boolean operations are not allowed in type expressions
-annotations_typeexpr.py:101:10: error[fstring-type-annotation] Type expressions cannot use f-strings
-annotations_typeexpr.py:102:10: error[invalid-type-form] Variable of type `<module 'types'>` is not allowed in a type expression
-callables_annotation.py:25:5: error[missing-argument] No argument provided for required parameter 2
-callables_annotation.py:26:11: error[invalid-argument-type] Argument is incorrect: Expected `str`, found `Literal[2]`
-callables_annotation.py:27:15: error[too-many-positional-arguments] Too many positional arguments: expected 2, got 3
-callables_annotation.py:29:5: error[missing-argument] No arguments provided for required parameters 1, 2
-callables_annotation.py:29:8: error[unknown-argument] Argument `a` does not match any known parameter
-callables_annotation.py:29:13: error[unknown-argument] Argument `b` does not match any known parameter
-callables_annotation.py:35:8: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
-callables_annotation.py:55:5: error[invalid-type-form] Special form `typing.Callable` expected exactly two arguments (parameter types and return type)
-callables_annotation.py:55:14: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`
-callables_annotation.py:56:14: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`
-callables_annotation.py:57:18: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `list[int]`?
-callables_annotation.py:58:5: error[invalid-type-form] Special form `typing.Callable` expected exactly two arguments (parameter types and return type)
-callables_annotation.py:58:14: error[invalid-type-form] The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`
-callables_kwargs.py:24:5: error[type-assertion-failure] Argument does not have asserted type `int`
-callables_kwargs.py:32:9: error[type-assertion-failure] Argument does not have asserted type `str`
-callables_kwargs.py:35:5: error[type-assertion-failure] Argument does not have asserted type `str`
-callables_kwargs.py:41:5: error[type-assertion-failure] Argument does not have asserted type `TD1`
-callables_kwargs.py:52:11: error[too-many-positional-arguments] Too many positional arguments to function `func1`: expected 0, got 3
-callables_kwargs.py:62:5: error[missing-argument] No argument provided for required parameter `v3` of function `func2`
-callables_kwargs.py:64:11: error[invalid-argument-type] Argument to function `func2` is incorrect: Expected `str`, found `Literal[1]`
-callables_kwargs.py:65:5: error[missing-argument] No argument provided for required parameter `v3` of function `func2`
-callables_protocol.py:97:1: error[invalid-assignment] Object of type `def cb4_bad1(x: int) -> None` is not assignable to `Proto4`
-callables_protocol.py:121:1: error[invalid-assignment] Object of type `def cb6_bad1(*vals: bytes, *, max_len: int | None = None) -> list[bytes]` is not assignable to `NotProto6`
-callables_protocol.py:179:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `R@__call__`
 callables_subtyping.py:26:5: error[invalid-assignment] Object of type `(int, /) -> int` is not assignable to `(int | float, /) -> int | float`
 callables_subtyping.py:29:5: error[invalid-assignment] Object of type `(int | float, /) -> int | float` is not assignable to `(int, /) -> int`
-classes_classvar.py:38:11: error[invalid-type-form] Type qualifier `typing.ClassVar` expected exactly 1 argument, got 2
-classes_classvar.py:39:14: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-classes_classvar.py:40:14: error[unresolved-reference] Name `var` used when not defined
-classes_classvar.py:52:5: error[invalid-assignment] Object of type `dict[Unknown, Unknown]` is not assignable to `list[str]`
-classes_classvar.py:55:17: error[invalid-type-form] Type qualifier `typing.ClassVar` is not allowed in type expressions (only in annotation expressions)
-classes_classvar.py:69:23: error[invalid-type-form] `ClassVar` is not allowed in function parameter annotations
-classes_classvar.py:70:12: error[invalid-type-form] `ClassVar` annotations are only allowed in class-body scopes
-classes_classvar.py:71:18: error[invalid-type-form] `ClassVar` annotations are not allowed for non-name targets
-classes_classvar.py:73:26: error[invalid-type-form] `ClassVar` is not allowed in function return type annotations
-classes_classvar.py:77:8: error[invalid-type-form] `ClassVar` annotations are only allowed in class-body scopes
-classes_classvar.py:111:1: error[invalid-attribute-access] Cannot assign to ClassVar `stats` from an instance of type `Starship`
-classes_classvar.py:140:1: error[invalid-assignment] Object of type `ProtoAImpl` is not assignable to `ProtoA`
-constructors_call_init.py:21:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `int`, found `float`
-constructors_call_init.py:25:1: error[type-assertion-failure] Argument does not have asserted type `Class1[int | float]`
-constructors_call_init.py:56:1: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Class4[int]`, found `Class4[str]`
-constructors_call_init.py:75:1: error[type-assertion-failure] Argument does not have asserted type `Class5[int | float]`
-constructors_call_init.py:91:1: error[type-assertion-failure] Argument does not have asserted type `Class6[int, str]`
-constructors_call_init.py:99:1: error[type-assertion-failure] Argument does not have asserted type `Class7[str, int]`
-constructors_call_init.py:130:9: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 2
 constructors_call_metaclass.py:23:1: error[type-assertion-failure] Argument does not have asserted type `Never`
 constructors_call_metaclass.py:23:13: error[missing-argument] No argument provided for required parameter `x` of function `__new__`
 constructors_call_metaclass.py:36:1: error[type-assertion-failure] Argument does not have asserted type `int | Meta2`
@@ -190,32 +74,6 @@
 constructors_call_new.py:117:1: error[type-assertion-failure] Argument does not have asserted type `Class8[list[str]]`
 constructors_call_new.py:125:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Class9`
 constructors_call_new.py:140:47: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Class11[int]`
-constructors_call_type.py:40:5: error[missing-argument] No arguments provided for required parameters `x`, `y` of function `__new__`
-constructors_call_type.py:50:5: error[missing-argument] No arguments provided for required parameters `x`, `y` of bound method `__init__`
-constructors_call_type.py:59:9: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 2
-constructors_callable.py:36:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:37:1: error[type-assertion-failure] Argument does not have asserted type `Class1`
-constructors_callable.py:49:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:50:1: error[type-assertion-failure] Argument does not have asserted type `Class2`
-constructors_callable.py:57:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@Class3`
-constructors_callable.py:63:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:64:1: error[type-assertion-failure] Argument does not have asserted type `Class3`
-constructors_callable.py:73:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-constructors_callable.py:77:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:78:1: error[type-assertion-failure] Argument does not have asserted type `int`
-constructors_callable.py:97:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:100:5: error[type-assertion-failure] Argument does not have asserted type `Never`
-constructors_callable.py:105:5: error[type-assertion-failure] Argument does not have asserted type `Never`
-constructors_callable.py:125:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:126:1: error[type-assertion-failure] Argument does not have asserted type `Class6Proxy`
-constructors_callable.py:142:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:162:5: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:164:1: error[type-assertion-failure] Argument does not have asserted type `Class7[int]`
-constructors_callable.py:165:1: error[type-assertion-failure] Argument does not have asserted type `Class7[str]`
-constructors_callable.py:182:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:183:1: error[type-assertion-failure] Argument does not have asserted type `Class8[str]`
-constructors_callable.py:193:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:194:1: error[type-assertion-failure] Argument does not have asserted type `Class9`
 dataclasses_descriptors.py:23:62: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int | Desc1`
 dataclasses_descriptors.py:50:63: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `list[T@Desc2] | T@Desc2`
 dataclasses_descriptors.py:66:1: error[type-assertion-failure] Argument does not have asserted type `int`
@@ -227,20 +85,7 @@
 dataclasses_final.py:38:1: error[invalid-assignment] Cannot assign to final attribute `final_with_default` on type `<class 'D'>`
 dataclasses_frozen.py:16:1: error[invalid-assignment] Property `a` defined in `DC1` is read-only
 dataclasses_frozen.py:17:1: error[invalid-assignment] Property `b` defined in `DC1` is read-only
-dataclasses_kwonly.py:23:11: error[too-many-positional-arguments] Too many positional arguments: expected 1, got 2
-dataclasses_kwonly.py:32:1: error[missing-argument] No argument provided for required parameter `a`
-dataclasses_kwonly.py:32:5: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `Literal["hi"]`
-dataclasses_kwonly.py:35:1: error[missing-argument] No argument provided for required parameter `a`
-dataclasses_kwonly.py:35:5: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `Literal["hi"]`
-dataclasses_kwonly.py:35:11: error[parameter-already-assigned] Multiple values provided for parameter `b`
-dataclasses_kwonly.py:38:5: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `Literal["hi"]`
-dataclasses_kwonly.py:38:11: error[invalid-argument-type] Argument is incorrect: Expected `str`, found `Literal[1]`
-dataclasses_kwonly.py:61:1: error[missing-argument] No argument provided for required parameter `c`
-dataclasses_kwonly.py:61:9: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `float`
-dataclasses_kwonly.py:61:14: error[parameter-already-assigned] Multiple values provided for parameter `b`
 dataclasses_order.py:50:4: error[unsupported-operator] Operator `<` is not supported for types `DC1` and `DC2`
-dataclasses_postinit.py:28:7: error[unresolved-attribute] Type `DC1` has no attribute `x`
-dataclasses_postinit.py:29:7: error[unresolved-attribute] Type `DC1` has no attribute `y`
 dataclasses_slots.py:56:1: error[unresolved-attribute] Type `<class 'DC5'>` has no attribute `__slots__`
 dataclasses_slots.py:57:1: error[unresolved-attribute] Type `DC5` has no attribute `__slots__`
 dataclasses_slots.py:66:1: error[unresolved-attribute] Type `<class 'DC6'>` has no attribute `__slots__`
@@ -266,61 +111,14 @@
 dataclasses_transform_class.py:106:24: error[unknown-argument] Argument `id` does not match any known parameter of bound method `__init__`
 dataclasses_transform_class.py:119:18: error[unknown-argument] Argument `id` does not match any known parameter of bound method `__init__`
 dataclasses_transform_class.py:119:24: error[unknown-argument] Argument `name` does not match any known parameter of bound method `__init__`
-dataclasses_transform_converter.py:25:6: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@model_field`
-dataclasses_transform_converter.py:48:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Unknown, /) -> Unknown`, found `def bad_converter1() -> int`
-dataclasses_transform_converter.py:49:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Unknown, /) -> Unknown`, found `def bad_converter2(*, x: int) -> int`
-dataclasses_transform_converter.py:107:5: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 6
-dataclasses_transform_converter.py:108:5: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 6
-dataclasses_transform_converter.py:109:5: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 6
-dataclasses_transform_converter.py:112:11: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 6
-dataclasses_transform_converter.py:114:1: error[invalid-assignment] Object of type `Literal["f1"]` is not assignable to attribute `field0` of type `int`
-dataclasses_transform_converter.py:115:1: error[invalid-assignment] Object of type `Literal["f6"]` is not assignable to attribute `field3` of type `ConverterClass`
-dataclasses_transform_converter.py:116:1: error[invalid-assignment] Object of type `Literal[b"f6"]` is not assignable to attribute `field3` of type `ConverterClass`
-dataclasses_transform_converter.py:119:1: error[invalid-assignment] Object of type `Literal[1]` is not assignable to attribute `field3` of type `ConverterClass`
-dataclasses_transform_converter.py:121:11: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 7
-dataclasses_transform_converter.py:130:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Literal[1], /) -> Unknown`, found `def converter_simple(s: str) -> int`
 dataclasses_transform_field.py:49:43: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> @Todo`
-dataclasses_transform_func.py:57:1: error[invalid-assignment] Object of type `Literal[3]` is not assignable to attribute `name` of type `str`
-dataclasses_transform_func.py:61:6: error[unsupported-operator] Operator `<` is not supported for types `Customer1` and `Customer1`
-dataclasses_transform_func.py:65:36: error[unknown-argument] Argument `salary` does not match any known parameter
-dataclasses_transform_func.py:77:36: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@create_model_frozen`
-dataclasses_transform_func.py:97:1: error[invalid-assignment] Property `id` defined in `Customer3` is read-only
 dataclasses_transform_meta.py:60:36: error[unknown-argument] Argument `other_name` does not match any known parameter
 dataclasses_transform_meta.py:73:6: error[unsupported-operator] Operator `<` is not supported for types `Customer1` and `Customer1`
 dataclasses_transform_meta.py:79:6: error[unsupported-operator] Operator `<` is not supported for types `Customer2` and `Customer2`
-dataclasses_usage.py:50:6: error[missing-argument] No argument provided for required parameter `unit_price`
-dataclasses_usage.py:51:28: error[invalid-argument-type] Argument is incorrect: Expected `int | float`, found `Literal["price"]`
-dataclasses_usage.py:52:36: error[too-many-positional-arguments] Too many positional arguments: expected 3, got 4
-dataclasses_usage.py:83:13: error[too-many-positional-arguments] Too many positional arguments: expected 1, got 2
-dataclasses_usage.py:88:5: error[invalid-assignment] Object of type `dataclasses.Field[Literal[""]]` is not assignable to `int`
-dataclasses_usage.py:127:8: error[too-many-positional-arguments] Too many positional arguments: expected 1, got 2
-dataclasses_usage.py:130:1: error[missing-argument] No argument provided for required parameter `y` of bound method `__init__`
-dataclasses_usage.py:179:6: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 2
-directives_assert_type.py:27:5: error[type-assertion-failure] Argument does not have asserted type `int`
-directives_assert_type.py:28:5: error[type-assertion-failure] Argument does not have asserted type `int`
-directives_assert_type.py:29:5: error[type-assertion-failure] Argument does not have asserted type `int`
-directives_assert_type.py:31:5: error[missing-argument] No arguments provided for required parameters `value`, `type` of function `assert_type`
-directives_assert_type.py:32:5: error[type-assertion-failure] Argument does not have asserted type `int`
-directives_assert_type.py:33:31: error[too-many-positional-arguments] Too many positional arguments to function `assert_type`: expected 2, got 3
-directives_cast.py:15:8: error[missing-argument] No arguments provided for required parameters `typ`, `val` of function `cast`
-directives_cast.py:16:13: error[invalid-type-form] Int literals are not allowed in this context in a type expression
-directives_cast.py:17:22: error[too-many-positional-arguments] Too many positional arguments to function `cast`: expected 2, got 3
-directives_deprecated.py:18:44: warning[deprecated] The class `Ham` is deprecated: Use Spam instead
-directives_deprecated.py:24:9: warning[deprecated] The function `norwegian_blue` is deprecated: It is pining for the fjords
-directives_deprecated.py:25:13: warning[deprecated] The function `norwegian_blue` is deprecated: It is pining for the fjords
-directives_deprecated.py:34:7: warning[deprecated] The class `Ham` is deprecated: Use Spam instead
-directives_deprecated.py:69:1: warning[deprecated] The function `lorem` is deprecated: Deprecated
-directives_deprecated.py:98:7: warning[deprecated] The function `foo` is deprecated: Deprecated
 directives_no_type_check.py:15:5: error[invalid-assignment] Object of type `Literal[""]` is not assignable to `int`
 directives_no_type_check.py:29:7: error[invalid-argument-type] Argument to function `func1` is incorrect: Expected `int`, found `Literal[b"invalid"]`
 directives_no_type_check.py:29:19: error[invalid-argument-type] Argument to function `func1` is incorrect: Expected `str`, found `Literal[b"arguments"]`
 directives_no_type_check.py:32:1: error[missing-argument] No arguments provided for required parameters `a`, `b` of function `func1`
-directives_reveal_type.py:14:17: info[revealed-type] Revealed type: `int | str`
-directives_reveal_type.py:15:17: info[revealed-type] Revealed type: `list[int]`
-directives_reveal_type.py:16:17: info[revealed-type] Revealed type: `Any`
-directives_reveal_type.py:17:17: info[revealed-type] Revealed type: `ForwardReference`
-directives_reveal_type.py:19:5: error[missing-argument] No argument provided for required parameter `obj` of function `reveal_type`
-directives_reveal_type.py:20:20: error[too-many-positional-arguments] Too many positional arguments to function `reveal_type`: expected 1, got 2
 directives_type_checking.py:11:5: error[invalid-assignment] Object of type `Literal[""]` is not assignable to `int`
 directives_type_checking.py:18:1: error[type-assertion-failure] Argument does not have asserted type `list[int]`
 directives_type_ignore_file2.py:14:1: error[invalid-assignment] Object of type `Literal[""]` is not assignable to `int`
@@ -332,11 +130,6 @@
 directives_version_platform.py:36:5: error[invalid-assignment] Object of type `Literal[""]` is not assignable to `int`
 directives_version_platform.py:40:5: error[invalid-assignment] Object of type `Literal[""]` is not assignable to `int`
 directives_version_platform.py:45:5: error[invalid-assignment] Object of type `Literal[""]` is not assignable to `int`
-enums_behaviors.py:27:1: error[type-assertion-failure] Argument does not have asserted type `Color`
-enums_behaviors.py:28:1: error[type-assertion-failure] Argument does not have asserted type `Literal[Color.RED]`
-enums_behaviors.py:32:1: error[type-assertion-failure] Argument does not have asserted type `Literal[Color.BLUE]`
-enums_behaviors.py:44:21: error[subclass-of-final-class] Class `ExtendedShape` cannot inherit from final class `Shape`
-enums_expansion.py:52:9: error[type-assertion-failure] Argument does not have asserted type `CustomFlags`
 enums_member_names.py:21:1: error[type-assertion-failure] Argument does not have asserted type `Literal["RED"]`
 enums_member_names.py:22:1: error[type-assertion-failure] Argument does not have asserted type `Literal["RED"]`
 enums_member_names.py:26:5: error[type-assertion-failure] Argument does not have asserted type `Literal["RED", "BLUE"]`
@@ -348,117 +141,19 @@
 enums_member_values.py:54:1: error[type-assertion-failure] Argument does not have asserted type `Literal[1]`
 enums_member_values.py:68:1: error[type-assertion-failure] Argument does not have asserted type `Literal[1]`
 enums_member_values.py:96:1: error[type-assertion-failure] Argument does not have asserted type `int`
-enums_members.py:128:21: info[revealed-type] Revealed type: `Unknown | Literal[2]`
-enums_members.py:129:9: error[type-assertion-failure] Argument does not have asserted type `Unknown`
-enums_members.py:129:43: error[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
-enums_members.py:146:1: error[type-assertion-failure] Argument does not have asserted type `int`
-enums_members.py:147:1: error[type-assertion-failure] Argument does not have asserted type `int`
-exceptions_context_managers.py:50:5: error[type-assertion-failure] Argument does not have asserted type `int | str`
-exceptions_context_managers.py:57:5: error[type-assertion-failure] Argument does not have asserted type `int | str`
-generics_base_class.py:26:26: error[invalid-argument-type] Argument to function `takes_dict_incorrect` is incorrect: Expected `dict[str, list[object]]`, found `SymbolTable`
-generics_base_class.py:29:14: error[invalid-type-form] `typing.Generic` is not allowed in type expressions
-generics_base_class.py:30:8: error[invalid-type-form] `typing.Generic` is not allowed in type expressions
-generics_base_class.py:45:5: error[type-assertion-failure] Argument does not have asserted type `Iterator[int]`
-generics_base_class.py:49:22: error[too-many-positional-arguments] Too many positional arguments to class `LinkedList`: expected 1, got 2
-generics_base_class.py:61:18: error[too-many-positional-arguments] Too many positional arguments to class `MyDict`: expected 1, got 2
-generics_basic.py:34:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AnyStr@concat` and `AnyStr@concat`
-generics_basic.py:139:5: error[type-assertion-failure] Argument does not have asserted type `int`
-generics_basic.py:140:5: error[type-assertion-failure] Argument does not have asserted type `int`
-generics_basic.py:157:5: error[invalid-argument-type] Method `__getitem__` of type `bound method MyMap1[str, int].__getitem__(key: str, /) -> int` cannot be called with key of type `Literal[0]` on object of type `MyMap1[str, int]`
-generics_basic.py:158:5: error[invalid-argument-type] Method `__getitem__` of type `bound method MyMap2[int, str].__getitem__(key: str, /) -> int` cannot be called with key of type `Literal[0]` on object of type `MyMap2[int, str]`
-generics_basic.py:162:12: error[invalid-argument-type] `<class 'int'>` is not a valid argument to `Generic`
-generics_basic.py:163:12: error[invalid-argument-type] `<class 'int'>` is not a valid argument to `Protocol`
-generics_basic.py:171:1: error[invalid-generic-class] `Generic` base class must include all type variables used in other base classes
-generics_basic.py:172:1: error[invalid-generic-class] `Generic` base class must include all type variables used in other base classes
-generics_basic.py:199:5: error[type-assertion-failure] Argument does not have asserted type `Iterator[Any]`
-generics_defaults.py:30:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:31:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:32:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:38:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:45:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:46:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:50:1: error[missing-argument] No argument provided for required parameter `T2` of class `AllTheDefaults`
-generics_defaults.py:52:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:55:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:59:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:63:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:79:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:80:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:91:26: error[invalid-argument-type] `@Todo` is not a valid argument to `Generic`
-generics_defaults.py:94:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:95:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults.py:127:32: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T4@func1`
-generics_defaults.py:141:12: error[invalid-argument-type] `@Todo` is not a valid argument to `Generic`
-generics_defaults.py:151:12: error[invalid-argument-type] `@Todo` is not a valid argument to `Generic`
-generics_defaults.py:154:49: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int | float, bool]`?
-generics_defaults.py:155:58: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `list[bytes]`?
-generics_defaults.py:169:1: error[type-assertion-failure] Argument does not have asserted type `(Foo7[int], /) -> Foo7[int]`
 generics_defaults_referential.py:23:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
 generics_defaults_referential.py:36:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `int`, found `Literal[""]`
 generics_defaults_referential.py:37:10: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `int`, found `Literal[""]`
 generics_defaults_referential.py:94:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
 generics_defaults_referential.py:95:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_defaults_specialization.py:26:5: error[type-assertion-failure] Argument does not have asserted type `SomethingWithNoDefaults[int, str]`
-generics_defaults_specialization.py:27:5: error[type-assertion-failure] Argument does not have asserted type `SomethingWithNoDefaults[int, bool]`
-generics_defaults_specialization.py:30:1: error[non-subscriptable] Cannot subscript object of type `<class 'SomethingWithNoDefaults[int, DefaultStrT]'>` with no `__class_getitem__` method
-generics_defaults_specialization.py:45:1: error[type-assertion-failure] Argument does not have asserted type `@Todo`
 generics_paramspec_basic.py:27:38: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_components.py:83:18: error[parameter-already-assigned] Multiple values provided for parameter 1 (`x`) of function `foo`
-generics_paramspec_semantics.py:13:56: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> str`
-generics_paramspec_semantics.py:17:40: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:22:1: error[type-assertion-failure] Argument does not have asserted type `(str, bool, /) -> str`
-generics_paramspec_semantics.py:30:56: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> bool`
-generics_paramspec_semantics.py:34:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:38:28: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:53:34: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:57:34: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:76:30: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
-generics_paramspec_semantics.py:82:5: error[type-assertion-failure] Argument does not have asserted type `@Todo`
-generics_paramspec_semantics.py:82:28: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `list[int]`?
-generics_paramspec_semantics.py:84:5: error[type-assertion-failure] Argument does not have asserted type `(int, /) -> str`
-generics_paramspec_semantics.py:87:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:91:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> bool`
-generics_paramspec_semantics.py:101:54: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> bool`
-generics_paramspec_semantics.py:113:6: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `(...) -> bool`
-generics_paramspec_semantics.py:128:20: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:133:23: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:138:29: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-generics_paramspec_semantics.py:143:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
 generics_paramspec_specialization.py:32:27: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, bool]`?
 generics_paramspec_specialization.py:40:27: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[()]`?
 generics_paramspec_specialization.py:40:31: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[()]`?
 generics_paramspec_specialization.py:52:22: error[invalid-type-form] List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str, bool]`?
-generics_scoping.py:14:1: error[type-assertion-failure] Argument does not have asserted type `int`
-generics_scoping.py:15:1: error[type-assertion-failure] Argument does not have asserted type `str`
-generics_scoping.py:42:1: error[type-assertion-failure] Argument does not have asserted type `str`
-generics_scoping.py:43:1: error[type-assertion-failure] Argument does not have asserted type `bytes`
-generics_self_advanced.py:11:24: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@ParentA`
-generics_self_advanced.py:18:1: error[type-assertion-failure] Argument does not have asserted type `ParentA`
-generics_self_advanced.py:19:1: error[type-assertion-failure] Argument does not have asserted type `ChildA`
-generics_self_advanced.py:28:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@ParentB`
-generics_self_advanced.py:35:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
-generics_self_advanced.py:36:9: error[type-assertion-failure] Argument does not have asserted type `list[Self@ChildB]`
-generics_self_advanced.py:37:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
-generics_self_advanced.py:38:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
-generics_self_advanced.py:43:9: error[type-assertion-failure] Argument does not have asserted type `list[Self@ChildB]`
-generics_self_advanced.py:44:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
-generics_self_advanced.py:45:9: error[type-assertion-failure] Argument does not have asserted type `Self@ChildB`
 generics_self_attributes.py:26:33: error[invalid-argument-type] Argument is incorrect: Expected `Self@LinkedList | None`, found `LinkedList[int]`
 generics_self_attributes.py:29:5: error[invalid-assignment] Object of type `OrdinalLinkedList` is not assignable to attribute `next` of type `Self@LinkedList | None`
 generics_self_attributes.py:32:5: error[invalid-assignment] Object of type `LinkedList[int]` is not assignable to attribute `next` of type `Self@LinkedList | None`
-generics_self_basic.py:14:9: error[type-assertion-failure] Argument does not have asserted type `Self@Shape`
-generics_self_basic.py:20:16: error[invalid-return-type] Return type does not match returned value: expected `Self@Shape`, found `Shape`
-generics_self_basic.py:33:16: error[invalid-return-type] Return type does not match returned value: expected `Self@Shape`, found `Shape`
-generics_self_basic.py:51:1: error[type-assertion-failure] Argument does not have asserted type `Shape`
-generics_self_basic.py:52:1: error[type-assertion-failure] Argument does not have asserted type `Circle`
-g...*[Comment body truncated]*

@LaBatata101
Copy link
Contributor Author

I'm getting some tests failing with this error

unreachable.md - Unreachable code - No (incorrect) diagn… - Exhaustive check of … (7a81433212273398)

  crates/ty_python_semantic/resources/mdtest/unreachable.md:287 Attempting to "pull types" caused a panic at /home/labatata/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/86ca4a9/src/function/execute.rs:202:25
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287 Note: either fix the panic or add the `<!-- pull-types:skip -->` directive to this test
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287 FunctionType < 'db >::signature_(Id(1c0a)): execute: too many cycle iterations
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287 run with `RUST_BACKTRACE=1` environment variable to display a backtrace
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287 query stacktrace:
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287    0: infer_scope_types(Id(801g1)) -> (R81, Durability::LOW)
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287              at crates/ty_python_semantic/src/types/infer.rs:134
  crates/ty_python_semantic/resources/mdtest/unreachable.md:287

To rerun this specific test, set the environment variable: MDTEST_TEST_FILTER='unreachable.md - Unreachable code - No (incorrect) diagn… - Exhaustive check of … (7a81433212273398)'
MDTEST_TEST_FILTER='unreachable.md - Unreachable code - No (incorrect) diagn… - Exhaustive check of … (7a81433212273398)' cargo test -p ty_python_semantic --test mdtest -- mdtest__unreachable

I don't know what's the cause of this, but I remember running the tests before befb08e and everything ran fine.

@dcreager
Copy link
Member

First off, my apologies that this PR has dragged on as long as it has, @LaBatata101.

I discussed this a bit with the team over the past couple of days, and we no longer think the approach that I suggested in astral-sh/ty#95 (comment) is the right way to tackle this. Partly because of how tedious it has been to implement while fitting in with the rest of the type inference code. But more importantly, because we realized that this is a special case of a more general specialization constraint solver that we are implementing. #19838 will move us in the direction of finding typevar specializations as part of doing an assignability check, instead of it being a standalone operation like it is at the moment. And I think that will end up subsuming astral-sh/ty#95, since we should be able to infer the {T = U} specialization while doing the assignability check on Callable[[T], T] and Callable[[U], U].

Given that, I think we should close this PR in favor of the more general constraint solver. If the new solver were many months out, it might be worth finishing this up and landing it as a stopgap. But we want to have the new solver in place for the beta, and it doesn't seem worth asking you to sink more time into this if will end up being replaced soon anyway.

@carljm carljm closed this Aug 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

typevar identity should not matter for generic function subtyping/assignability

6 participants