Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type error when creating a tuple from a Generator #5312

Closed
jatoben opened this issue Jun 16, 2023 · 3 comments
Closed

Type error when creating a tuple from a Generator #5312

jatoben opened this issue Jun 16, 2023 · 3 comments
Labels
addressed in next version Issue is fixed and will appear in next published version bug Something isn't working

Comments

@jatoben
Copy link

jatoben commented Jun 16, 2023

Describe the bug

Creating a tuple[tuple[float, float]] from a Generator[tuple[float, float], None, None] fails to type-check, unless a temporary variable is used.

To Reproduce

I have an existing API which is typed like this:

class Point:
    x: float
    y: float
    # additional members here


def get_points() -> Iterable[Point]:
    ...


def convert_point(point: Point) -> tuple[float, float]:
    ...


# Can draw either a single point represented as a tuple[float, float] or a sequence of points
def draw_path(
    points: tuple[float, float] | Sequence[tuple[float, float]], *, width: float
) -> None:
    ...

If I use tuple() to turn a generator of converted points into an immutable sequence, I get the following error:

draw_path(
    tuple(convert_point(p) for p in get_points()),
    width=0.25,
)

# error: Argument of type "Generator[tuple[float, float], None, None]" cannot be assigned to parameter "__iterable" of type "Iterable[_T_co@tuple]" in function "__new__"
#    "Generator[tuple[float, float], None, None]" is incompatible with "Iterable[float]"
#      TypeVar "_T_co@Iterable" is covariant
#        "tuple[float, float]" is incompatible with "float" (reportGeneralTypeIssues)

However, capturing the created tuple in a temporary variable first prevents the error.

points = tuple(convert_point(p) for p in get_points())
draw_path(
    points,
    width=0.25,
)

Expected behavior

I would expect equivalent type-checking results from draw_path() calls.

VS Code extension or command-line

Command-line version 1.1.314

Additional context

#5281 could perhaps be related.

@jatoben jatoben added the bug Something isn't working label Jun 16, 2023
erictraut pushed a commit that referenced this issue Jun 16, 2023
…thin an "expected type" should be used for bidirectional type inference. This addresses #5312.
erictraut added a commit that referenced this issue Jun 16, 2023
…thin an "expected type" should be used for bidirectional type inference. This addresses #5312. (#5317)

Co-authored-by: Eric Traut <[email protected]>
@erictraut
Copy link
Collaborator

Thanks for the bug report. This is related to a heuristic that pyright uses when performing bidirectional type inference in the case where the "expected type" is a union. It currently assumes that if return type of the call (in this case the tuple constructor) matches one of the subtypes in the union (in this case tuple[float, float]), it should prefer this as the "expected type" over the other subtypes. This heuristic works 99.99% of the time, but you've identified a case where it fails.

I've adjusted the heuristic so it works with this code. This will be addressed in the next release.

@erictraut erictraut added the addressed in next version Issue is fixed and will appear in next published version label Jun 16, 2023
@jatoben
Copy link
Author

jatoben commented Jun 16, 2023

Great -- thank you!

@erictraut
Copy link
Collaborator

This is included in pyright 1.1.315, which I just published. It will also be included in this week's insiders release of pylance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addressed in next version Issue is fixed and will appear in next published version bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants