Skip to content

[v1.5 regression] Repeating a type guard condition causes the guard to be lost #5546

Description

@rchen152

Describe the Bug

Reported impact: 2 false-positive diagnostics in the attrs library

from typing import Any, TypeGuard

class C(Any):
    pass

def has(cls: type) -> TypeGuard[type[C]]:
    return hasattr(cls, "tag")

def f(t: type[object]) -> None:
    if has(t) or has(t):
        reveal_type(t)
        t.tag  # object has no class attribute `tag`

Sandbox Link

https://pyrefly.org/sandbox/?project=v2.pZQxD4IwEIX_ykUGGIzdXRlc3YGEigRIDDX08Pf7rmcxaEJi3Ejbd6V333u_RqZM-zTbKfhd_ZRn2IngaFMV5N76rLnBhBJNAYVFXchSkVdV7LKyBoVlnkS1x2PZduUujDz4ImMtVSj41SddYEiuhNEAiH6tcF5iEhvvdT7gGqIk-gxCGh3p2-RvhsvMLdU4VX_PPKGzLtCrfUg7wNLNyFRAcCjHBHHaUs9890djotxNnWlHc3WNNyuFIcHbPuwQknpdjlxg1KPsP7Clylq6hVoqpOHEJj1P

(Only applicable for extension issues) IDE Information

No response

Activity

  1. added this to the 1.5 milestone on Nov 5, 2026
  2. Divyansh151005 commented on Nov 12, 2026

    @Divyansh151005
    Contributor

    #claim

    Root cause: #5256 switched NarrowOp::Or from JoinStyle::SimpleMerge to JoinStyle::NarrowOf(type_info). Besides collapsing a gradual base back to Any (what #5256 needed), the NarrowOf join also returns the base type whenever base <: union(branches). A class with an Any base is assignable from anything, so type[object] <: type[C] holds and the join gives back type[object], even with two different guards (has(t) or has2(t)). 1.4.0 reveals type[C] for both.

    Plan: keep the NarrowOf join for gradual bases and for facets, but use the plain union of the branches for the root type of a non-gradual base, as before #5256.

  3. github-actions commented on Nov 12, 2026

    @github-actions

    @Divyansh151005 you've claimed this issue — it's now assigned to you. Thanks for picking it up! 🎉

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

Metadata

Metadata

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions