Fix function call message change for small number of args (#21432)
Refs https://github.com/python/mypy/issues/21427
I used `2` as a magic number, because in my opinion it is easier to tell
the difference when all errors show up for the small number of args.
---------
Co-authored-by: hauntsaninja <hauntsaninja@gmail.com>
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
index 123c5f8..71ffa7c 100644
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -1787,6 +1787,7 @@
might_have_shifted_args = (
not self.msg.prefer_simple_messages()
+ and len(args) >= 2 # see gh-21427
and all(k == ARG_POS for k in callee.arg_kinds)
and all(k == ARG_POS for k in arg_kinds)
and len(arg_kinds) == len(callee.arg_kinds) - 1
diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test
index bd2bf26..893eefb 100644
--- a/test-data/unit/check-functions.test
+++ b/test-data/unit/check-functions.test
@@ -3814,9 +3814,9 @@
main:3: error: Missing positional argument "y" in call to "f"
[case testMissingPositionalArgShiftDetectedFirst]
-def f(x: int, y: str, z: bytes) -> None: ...
+def f(x: int, y: str, z: bytes, last: float) -> None: ...
-f("hello", b'x')
+f("hello", b'x', 1.5)
[builtins fixtures/primitives.pyi]
[out]
main:3: error: Missing positional argument "x" in call to "f"
@@ -3891,3 +3891,46 @@
main:3: error: Missing positional argument "z" in call to "f"
main:3: error: Argument 1 to "f" has incompatible type "str"; expected "int"
main:3: error: Argument 2 to "f" has incompatible type "bytes"; expected "str"
+
+[case testMissingPositionalArgNamesHigherN]
+# See https://github.com/python/mypy/issues/21427
+def convert2(first: int, second: str) -> None: ...
+
+# Possibly omitted arg, but we still issue two errors because there is only one argument
+convert2("hello") # E: Missing positional argument "second" in call to "convert2" \
+ # E: Argument 1 to "convert2" has incompatible type "str"; expected "int"
+
+# Other cases
+convert2() # E: Missing positional arguments "first", "second" in call to "convert2"
+
+convert2("hello", 1) # E: Argument 1 to "convert2" has incompatible type "str"; expected "int" \
+ # E: Argument 2 to "convert2" has incompatible type "int"; expected "str"
+
+def convert3(first: int, second: str, third: float) -> None: ...
+
+# Possibly omitted arg, but we now only issue one error
+convert3("hello", 3.15) # E: Missing positional argument "first" in call to "convert3"
+
+# Other cases
+convert3("hello") # E: Missing positional arguments "second", "third" in call to "convert3" \
+ # E: Argument 1 to "convert3" has incompatible type "str"; expected "int"
+
+convert3(3.15, "hello") # E: Missing positional argument "third" in call to "convert3" \
+ # E: Argument 1 to "convert3" has incompatible type "float"; expected "int"
+
+def convert4(first: int, second: str, third: float, fourth: bytes) -> None: ...
+
+# Possibly omitted arg, but we now only issue one error
+convert4("hello", 3.15, b'') # E: Missing positional argument "first" in call to "convert4"
+
+# Other cases
+convert4("hello") # E: Missing positional arguments "second", "third", "fourth" in call to "convert4" \
+ # E: Argument 1 to "convert4" has incompatible type "str"; expected "int"
+
+convert4("hello", 3.15) # E: Missing positional arguments "third", "fourth" in call to "convert4" \
+ # E: Argument 1 to "convert4" has incompatible type "str"; expected "int" \
+ # E: Argument 2 to "convert4" has incompatible type "float"; expected "str"
+
+convert4(b'', "hello", 3.15) # E: Missing positional argument "fourth" in call to "convert4" \
+ # E: Argument 1 to "convert4" has incompatible type "bytes"; expected "int"
+[builtins fixtures/primitives.pyi]