Skip to content

Optional generic not accepted with --strict-optional #2678

Closed

Description

@FuegoFro

When running with --strict-optional, mypy complains about the last statement here. However, this seems like it should work, both because it does work when --strict-optional is left out, and because the revealed type looks like it should match.

from typing import Optional, Type, TypeVar


class BaseThing: pass
class ChildThing(BaseThing): pass


ThingClass = TypeVar("ThingClass", bound=BaseThing)


def get_thing(thing_class: Type[ThingClass]) -> Optional[ThingClass]:
    """ Get the thing with the given class. Stub implementation. """
    return None

thing = None  # type: Optional[ChildThing]

# Fails, complaining about `Type argument 1 of "get_thing" has incompatible value "Optional[ChildThing]"`
thing = get_thing(ChildThing)

# Revealed type is `Union[scratch_1.ChildThing*, builtins.None]`, which seems like it should 
# match Optional[ChildThing].
reveal_type(get_thing(ChildThing))

Activity

  1. gvanrossum commented on Jan 11, 2017

    @gvanrossum
    Member

    Hm, I wonder if the problem is due to a bad interaction between the ThingClass TypeVar and the Optional from the context? I think it ought to infer that if the context is Optional[ChildThing] and the return type (to be matched to that context) is Optional[ThingClass], then it must solve this to ThingClass==ChildThing, but it is then not correctly concluding that the argument type must be Type[ChildThing].

  2. ddfisher commented on Jan 11, 2017

    @ddfisher
    Collaborator

    This problem isn't Optional-specific -- it'll happen with any Union. For example:

    from typing import *
    
    class A: pass
    class B(A): pass
    
    
    T = TypeVar("T", bound=A)
    
    def f(x: Type[T]) -> Union[T, str]:
        return "foo"
    
    x = None  # type: Union[B, str]
    
    reveal_type(x)
    reveal_type(f(B))
    x = f(B)
    test.py:14: error: Revealed type is 'Union[test.B, builtins.str]'
    test.py:15: error: Revealed type is 'Union[test.B*, builtins.str]'
    test.py:16: error: Type argument 1 of "f" has incompatible value "Union[B, str]"
    

    We've known for a while that TypeVars and Unions don't play well together. There's been a bit of spot-patching so far, but I think we're at the point where a larger careful rethinking makes sense.

  3. added a commit that references this issue on Oct 2, 2018
    626ff68
  4. added a commit that references this issue on Oct 4, 2018
    6d886e9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions