Skip to content

Error message for TypeForm arguments with a single unresolvable forward reference is misleading #21695

Open

Description

@Daverball

Bug Report

When passing a single stringified type expression to a function accepting a TypeForm argument, which cannot be fully resolved, due to e.g. a missing import, we get an arg-type error instead of an error, telling us why the type expression is invalid.

To Reproduce
https://mypy-play.net/?mypy=master&python=3.14&gist=891447236311046360886ba63c1fac83

from typing_extensions import TypeForm

def foo[T](x: TypeForm[T]) -> None:
    pass

foo("Unresolvable")

Expected Behavior

mypy should emit a name-error for Unresolvable, since it was never defined. The given example is probably the most controversial case though, since someone may actually accidentally be passing an invalid string literal, but the same thing happens for less controversial cases like "list[Unresolvable]". But I think either way it makes more sense to treat the given string literal as a type expression and emit the same errors you would emit if you saw the same string literal in an annotation.

Actual Behavior

error: Argument 1 to "foo" has incompatible type "str"; expected "TypeForm[Never]"  [arg-type]

This error does not help us solve the problem in our code at all.

Your Environment

  • Mypy version used: 2.2
  • Python version used: 3.14

Activity

  1. ilevkivskyi commented on Jul 10, 2026

    @ilevkivskyi
    Member

    cc @davidfstr in case you are interested.

  2. davidfstr commented on Jul 10, 2026

    @davidfstr
    Contributor

    we get an arg-type error of the form:

    Instead of an error, telling us why the type expression is invalid.

    By the time the type checker pass notices that the first parameter of foo("Unresolvable") wants a TypeForm, any errors related to attempting to parse "Unresolvable" (done in the earlier semantic analyzer pass) have been thrown away. It's not really feasible (for performance/memory reasons) to preserve those errors for rare situations like this where they're desired later in the type checker pass.

    Workaround

    Replace foo("Unresolvable") with foo(TypeForm("Unresolvable")) to get a descriptive error.

    Full Fix

    Make it possible to parse stringified type forms in the type checker pass, not just the semantic analyzer pass. This would be a high-effort change. If it could be pulled off, it would eliminate the need to parse type forms in the semantic analyzer pass at all, which would eliminate all the related performance issues that I'm trying to fix piecemeal with followup PRs like #21596 .

  3. Daverball commented on Sep 22, 2026

    @Daverball
    ContributorAuthor

    @davidfstr I think we should still be able to improve the UX without hurting performance by emitting a different error when a string literal is passed into a TypeForm argument than the standard arg-type error for the type mismatch str against TypeForm. It doesn't have to be the actual reason for why the forward reference failed to be interpreted as a TypeForm during semantic analysis, it's good enough if the error tells users that some error may have occurred when trying to resolve that literal as a forward reference, and to add a hint that tells users to wrap the forward reference in a TypeForm call if they want to get a more specific error. The error category can probably stay arg-type, since we can't know for sure if the string literal was supposed to be a forward reference, or if they just got the argument order wrong and it actually was supposed to just be a string literal. Although a dedicated error category or misc could also make sense.

    This should be a reasonable stop-gap measure until we can implement a full fix. Although even with the full fix it might be more appropriate to emit the error in the TypeForm only as a hint for a potential cause for why this argument is invalid and keep the error otherwise the same as suggested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-type-formTypeForm might fix this

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions