Skip to content

Contextual typing works only with the first element in a union #793

Closed

Description

@rchen152

Describe the Bug

I was surprised to not see an issue for this yet (unless I just missed it?). Opening one for V1 tracking. Contextual typing doesn't play well with union types, as seen here:

testcase!(
bug = "Both assignments should be allowed. When decomposing the contextual hint, we eagerly resolve vars to the 'first' branch of the union. Note: due to the union's sorted representation, the first branch is not necessarily the first in source order.",
test_contextual_typing_against_unions,
r#"
class A: ...
class B: ...
class B2(B): ...
class C: ...
x: list[A] | list[B] = [B2()] # E: `list[B2]` is not assignable to `list[A] | list[B]`
y: list[B] | list[C] = [B2()]
"#,
);

Sandbox Link

No response

(Only applicable for extension issues) IDE Information

No response

Activity

  1. added this to the V1 Release milestone on Jul 31, 2025
  2. added theissue type on Jul 31, 2025
  3. samwgoldman commented on Jul 31, 2025

    @samwgoldman
    Member

    Yeah, I started working on this but put it down to work on overloaded constructor calls. There are a couple open issues assigned to me with the same root cause. I can take this or you can take it over if you have already started :)

  4. rchen152 commented on Jul 31, 2025

    @rchen152
    ContributorAuthor

    I'm not working on this right now - just opened an issue because I couldn't find one and I knew this is a bug we care about :)

    But once I get #750 sorted out, I may pick up #164 if it's still open, since that affects our ability to type-check usages of pydantic.ConfigDict. I looked into it briefly, and I think the TypedDict bug is related to this union issue but not the same thing. We skip these TypedDict cases in expr_infer entirely when the hint is a union:

    if let Some(hint @ Type::TypedDict(typed_dict)) = hint {
    self.check_dict_items_against_typed_dict(
    flattened_items,
    typed_dict,
    false,
    x.range,
    errors,
    );
    hint.clone()
    } else if let Some(hint @ Type::PartialTypedDict(typed_dict)) = hint {
    self.check_dict_items_against_typed_dict(
    flattened_items,
    typed_dict,
    true,
    x.range,
    errors,
    );
    hint.clone()

  5. rchen152 commented on Jan 14, 2026

    @rchen152
    ContributorAuthor

    Here's another example:

    def f() -> list[dict[str, object]]:
        cases2: list[dict[str, bool] | dict[str, str]] = []
        return [{**case} for case in cases2]  # false positive: Expected a mapping, got dict[str, bool] | dict[str, str]
    

    sandbox

  6. hot123s commented on Jan 28, 2026

    @hot123s

    I've encountered the same problem

    from contextlib import asynccontextmanager, contextmanager
    from typing import AsyncContextManager, ContextManager, Union
    
    
    @contextmanager
    def test_context():
        yield 1
    
    
    @asynccontextmanager
    async def test_async_context():
        yield 1
    
    
    def test(x: int) -> Union[ContextManager, AsyncContextManager]:
        if x:
            return test_context()
        else:
            return test_async_context()
    
    
    async def aa():
        async with test(1) as x:
            pass
    

    sandbox

  7. self-assigned this
    on Mar 15, 2026
  8. rchen152 commented on Mar 15, 2026

    @rchen152
    ContributorAuthor

    Grabbing this one because my work on #105 affects how Varible::Unwrap works, so I may be able to fix this (or at least it's probably not a great idea for someone else to try to fix it in parallel with my changes).

  9. rchen152 commented on Apr 30, 2026

    @rchen152
    ContributorAuthor

    Closing the loop on the outstanding tasks/questions that remained on this issue:

    • Hint decomposition being slower than we like: I opened Decomposition of HintRef is slow #3268.
    • In addition to splitting union hints, do we need to split Type::Type and/or Type::Quantified restrictions?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

contextual-typingissues related to contextual typinggoogleissues from google

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions