Skip to content

Conversation

@mtshiba
Copy link
Contributor

@mtshiba mtshiba commented Nov 13, 2025

Summary

I found that trying to use a directly recursive type alias like this would result in a stack overflow:

type Itself = Itself

def foo(Itself: Itself):
    x: Itself

This should be reported as an invalid type alias, but a stack overflow should be fixed immediately anyway. We now consider the value type to be Unknown in such cases.

Test Plan

New test case in mdtest\pep695_type_aliases.md

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 13, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 13, 2025

mypy_primer results

No ecosystem changes detected ✅

No memory usage changes detected ✅

@mtshiba mtshiba marked this pull request as ready for review November 13, 2025 19:31
@AlexWaygood AlexWaygood added ty Multi-file analysis & type inference bug Something isn't working labels Nov 13, 2025
reveal_type(y) # revealed: Never

# TODO emit a diagnostic on this line
type Itself = Itself
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 fix also work for compound types like list[Itself]?

Copy link
Contributor

Choose a reason for hiding this comment

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

Those generally already work, without this PR: https://play.ty.dev/a65c2d75-e9c1-4a74-85e3-f96db2dd9c60

Copy link
Contributor

Choose a reason for hiding this comment

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

Another case that may be worth testing is multi-step direct recursion:

type A = B
type B = A

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, unfortunately, it seems the panic still persists in the case of mutually recursive aliases:

type A = B
type B = A

def bar(a: B):
    x: a

Therefore, the measure is insufficient, and we should check the consequences of eagerly expanding a type alias value type before we first use of it.
This may be an issue that needs to be resolved in #20566.

Copy link
Contributor

@carljm carljm 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!

Comment on lines +251 to +252
def foo(Itself: Itself):
x: Itself
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO it's a bit odd to test that you can annotate a parameter as Itself, and then use that parameter again as an annotation. It may work due to how we treat Unknown in a type annotation, but I don't think this is something we want to commit to in a test.

I would probably just have done this instead:

Suggested change
def foo(Itself: Itself):
x: Itself
def foo(x: Itself):
reveal_type(x) # Unknown

Is there a particular reason why you think it's important to test this "annotated value as annotation" behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In fact, in that example, no panic occurs, and the revealed type is Never.

https://play.ty.dev/4732e30a-301c-4753-b95f-aed34cf08585

Should the original code be placed in the corpus as a regression test?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I wondered if this part was necessary to reproduce the panic. That explains why I didn't catch this case in my previous work on recursive type aliases. Makes it much less likely people will run into this, but of course it should still be fixed.

I think it's OK for a test like this to be in mdtests, I would just expect some commentary (specifically about annotating with a value type) that "this is a very strange thing to do, but this is a regression test to ensure it doesn't panic"

@mtshiba mtshiba marked this pull request as draft November 14, 2025 10:08
@mtshiba
Copy link
Contributor Author

mtshiba commented Nov 14, 2025

Detecting mutually recursive invalid type aliases was harder than expected, and I decided to address it in #20566.

Related commits:
ac44afa
2a9b9a2

I will close this PR.

@mtshiba mtshiba closed this Nov 14, 2025
@mtshiba mtshiba deleted the direct-recursive-type-alias branch November 14, 2025 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants