Skip to content

Filter signatures by relevant parameters in no-matching-overload errors#3782

Closed
rchen152 wants to merge 7 commits into
facebook:mainfrom
rchen152:export-D108230384
Closed

Filter signatures by relevant parameters in no-matching-overload errors#3782
rchen152 wants to merge 7 commits into
facebook:mainfrom
rchen152:export-D108230384

Conversation

@rchen152

Copy link
Copy Markdown
Contributor

Summary:
When a call to an overloaded function fails but has the right number of arguments, show only the parameters corresponding to passed arguments and required missing arguments when printing possible overloads. This makes the signatures easier to read by hiding irrelevant information.

Before:

ERROR No matching overload found for function `subprocess.run` called with arguments: (Literal[42], capture_output=Any) [no-matching-overload]
 --> empty.py:6:15
  |
6 | subprocess.run(42, capture_output=x)
  |               ^^^^^^^^^^^^^^^^^^^^^^
  |
  Possible overloads:
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: Literal[True] | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str | None = None, input: str | None = None, text: Literal[True], timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: bool | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str, errors: str | None = None, input: str | None = None, text: bool | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: bool | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str, input: str | None = None, text: bool | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, *, universal_newlines: Literal[True], startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str | None = None, input: str | None = None, text: Literal[True] | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: Literal[False] | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: None = None, errors: None = None, input: Buffer | None = None, text: Literal[False] | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[bytes] [closest match]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: bool | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str | None = None, input: Buffer | str | None = None, text: bool | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[Any]
  Argument `Literal[42]` is not assignable to parameter `args` with type `PathLike[bytes] | PathLike[str] | Sequence[StrOrBytesPath] | bytes | str` in function `subprocess.run`

After:

ERROR No matching overload found for function `subprocess.run` called with arguments: (Literal[42], capture_output=Any) [no-matching-overload]
 --> empty.py:6:15
  |
6 | subprocess.run(42, capture_output=x)
  |               ^^^^^^^^^^^^^^^^^^^^^^
  |
  Possible overloads:
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, ..., capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[bytes] [closest match]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[Any]
  Argument `Literal[42]` is not assignable to parameter `args` with type `PathLike[bytes] | PathLike[str] | Sequence[StrOrBytesPath] | bytes | str` in function `subprocess.run`

Context:

This stack is a ground-up re-implementation of #1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Differential Revision: D108230384

rchen152 added 7 commits June 11, 2026 12:13
Summary:
No functional change. I'm planning to add more info to this map, so let's first rename it and make it more structured.

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Differential Revision: D108230388
Summary:
No functional change. This will be needed to accurately map keyword arguments to their corresponding parameters.

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Differential Revision: D108230391
Summary:
Adds parameter names to the map that callable_infer builds from arguments to matched parameters. This will be used to improve signature printing in no-matching-overload errors.

No functional change.

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Differential Revision: D108230387
Summary:
No functional change. Restructures ParamList:fmt_with_type to first compute what it needs to write, then write everything in a block at the end. This will make the next diff easier to read.

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Reviewed By: yangdanny97

Differential Revision: D108230392
Summary:
Adds a `ParamOverlay` enum to control which parameters are included when displaying a ParamsList. The enum has two variants: `All` (include all params) and `Subset(SmallSet<Name>)` (include only this set of params). Anonymous params (name=None) are always included. Params that are not included are replaced with `...`. `/` and `*` markers are always included.

This will be used in the next diff to improve signature display in no-matching-overload errors.

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Differential Revision: D108230385
Summary:
Stores required parameters that were not matched by any arguments in ArgMap. This will be used to improve no-matching-overload error messages.

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Reviewed By: yangdanny97

Differential Revision: D108250102
Summary:
When a call to an overloaded function fails but has the right number of arguments, show only the parameters corresponding to passed arguments and required missing arguments when printing possible overloads. This makes the signatures easier to read by hiding irrelevant information.

Before:
```
ERROR No matching overload found for function `subprocess.run` called with arguments: (Literal[42], capture_output=Any) [no-matching-overload]
 --> empty.py:6:15
  |
6 | subprocess.run(42, capture_output=x)
  |               ^^^^^^^^^^^^^^^^^^^^^^
  |
  Possible overloads:
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: Literal[True] | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str | None = None, input: str | None = None, text: Literal[True], timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: bool | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str, errors: str | None = None, input: str | None = None, text: bool | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: bool | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str, input: str | None = None, text: bool | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, *, universal_newlines: Literal[True], startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str | None = None, input: str | None = None, text: Literal[True] | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[str]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: Literal[False] | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: None = None, errors: None = None, input: Buffer | None = None, text: Literal[False] | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[bytes] [closest match]
    (args: _CMD, bufsize: int = -1, executable: PathLike[bytes] | PathLike[str] | bytes | str | None = None, stdin: _FILE = None, stdout: _FILE = None, stderr: _FILE = None, preexec_fn: (() -> object) | None = None, close_fds: bool = True, shell: bool = False, cwd: PathLike[bytes] | PathLike[str] | bytes | str | None = None, env: Mapping[bytes, StrOrBytesPath] | Mapping[str, StrOrBytesPath] | None = None, universal_newlines: bool | None = None, startupinfo: Any = None, creationflags: int = 0, restore_signals: bool = True, start_new_session: bool = False, pass_fds: Collection[int] = ..., *, capture_output: bool = False, check: bool = False, encoding: str | None = None, errors: str | None = None, input: Buffer | str | None = None, text: bool | None = None, timeout: float | None = None, user: int | str | None = None, group: int | str | None = None, extra_groups: Iterable[int | str] | None = None, umask: int = -1, pipesize: int = -1, process_group: int | None = None) -> CompletedProcess[Any]
  Argument `Literal[42]` is not assignable to parameter `args` with type `PathLike[bytes] | PathLike[str] | Sequence[StrOrBytesPath] | bytes | str` in function `subprocess.run`
```

After:
```
ERROR No matching overload found for function `subprocess.run` called with arguments: (Literal[42], capture_output=Any) [no-matching-overload]
 --> empty.py:6:15
  |
6 | subprocess.run(42, capture_output=x)
  |               ^^^^^^^^^^^^^^^^^^^^^^
  |
  Possible overloads:
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, ..., capture_output: bool = False, ...) -> CompletedProcess[str]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[bytes] [closest match]
    (args: _CMD, ..., *, capture_output: bool = False, ...) -> CompletedProcess[Any]
  Argument `Literal[42]` is not assignable to parameter `args` with type `PathLike[bytes] | PathLike[str] | Sequence[StrOrBytesPath] | bytes | str` in function `subprocess.run`
```

Context:

This stack is a ground-up re-implementation of facebook#1447. It has a narrower focus (just omits irrelevant parameter types, doesn't try to do any handling of other kinds of call errors), reuses the existing signature display code, tracks parameters by name instead of index, and filters all overload signatures rather than just the closest one.

Differential Revision: D108230384
@meta-codesync

meta-codesync Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

@rchen152 has exported this pull request. If you are a Meta employee, you can view the originating Diff in D108230384.

@github-actions

Copy link
Copy Markdown

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@samwgoldman samwgoldman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review automatically exported from Phabricator review in Meta.

@rchen152

Copy link
Copy Markdown
Contributor Author

Merged in 15e6ff4

@rchen152 rchen152 closed this Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants