Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1303,11 +1303,11 @@ def add_invertible_flag(
dest="local_partial_types",
help=argparse.SUPPRESS,
)
# --native-parser enables the native parser (experimental)
add_invertible_flag(
"--native-parser",
default=False,
help="Enable faster parser that parses directly to mypy AST",
"--no-native-parser",
default=True,
dest="native_parser",
help="Do not use faster parser that parses directly to mypy AST",
)
# --logical-deps adds some more dependencies that are not semantically needed, but
# may be helpful to determine relative importance of classes and functions for overall
Expand Down
25 changes: 25 additions & 0 deletions mypy/nativeparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
WithStmt,
YieldExpr,
YieldFromExpr,
check_param_names,
)
from mypy.options import Options
from mypy.patterns import (
Expand Down Expand Up @@ -628,6 +629,11 @@ def read_parameters(state: State, data: ReadBuffer) -> tuple[list[Argument], boo
set_line_column_range(var, arg)
arguments.append(arg)

def fail_arg(msg: str, ctx: Argument) -> None:
# To match the old parser (for now).
state.add_error(msg, ctx.line, ctx.column, blocker=True, code="syntax")

check_param_names([arg.variable.name for arg in arguments], arguments, fail_arg)
return arguments, has_ann


Expand All @@ -638,6 +644,22 @@ def check_type_param_defaults(
state.check_min_version("Type parameter defaults", (3, 13), line, column)


def check_type_param_values(
state: State, type_params: list[TypeParam], line: int, column: int
) -> None:
for type_param in type_params:
if len(type_param.values) == 1:
state.add_error(
message_registry.TYPE_VAR_TOO_FEW_CONSTRAINED_TYPES.value,
line,
column,
blocker=False,
code="misc",
)
# For compatibility with old parser.
type_param.values = []


def read_type_params(state: State, data: ReadBuffer) -> list[TypeParam]:
"""Read type parameters (PEP 695 generics)."""
type_params: list[TypeParam] = []
Expand Down Expand Up @@ -716,6 +738,7 @@ def read_func_def(state: State, data: ReadBuffer) -> FuncDef:
"Improved type parameter syntax", (3, 12), func_def.line, func_def.column
)
check_type_param_defaults(state, type_params, func_def.line, func_def.column)
check_type_param_values(state, type_params, func_def.line, func_def.column)
if typ:
typ.line = func_def.line
typ.column = func_def.column
Expand Down Expand Up @@ -770,6 +793,7 @@ def read_class_def(state: State, data: ReadBuffer) -> ClassDef:
"Improved type parameter syntax", (3, 12), class_def.line, class_def.column
)
check_type_param_defaults(state, type_params, class_def.line, class_def.column)
check_type_param_values(state, type_params, class_def.line, class_def.column)
expect_end_tag(data)
if state.options.include_docstrings:
class_def.docstring = get_docstring(body)
Expand Down Expand Up @@ -836,6 +860,7 @@ def read_type_alias_stmt(state: State, data: ReadBuffer) -> TypeAliasStmt:
read_loc(data, stmt)
state.check_min_version('"type" statements', (3, 12), stmt.line, stmt.column)
check_type_param_defaults(state, type_params, stmt.line, stmt.column)
check_type_param_values(state, type_params, stmt.line, stmt.column)
expect_end_tag(data)
return stmt

Expand Down
4 changes: 2 additions & 2 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,8 @@ def __init__(self) -> None:
self.logical_deps = False
# If True, partial types can't span a module top level and a function
self.local_partial_types = True
# If True, use the native parser (experimental)
self.native_parser = False
# If True, use the native parser
self.native_parser = True
# Some behaviors are changed when using Bazel (https://bazel.build).
self.bazel = False
# If True, export inferred types for all expressions as BuildResult.types
Expand Down
6 changes: 3 additions & 3 deletions mypy/test/testcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ def run_case_once(
options = parse_options(original_program_text, testcase, incremental_step)
options.use_builtins_fixtures = True
options.show_traceback = True
options.native_parser = bool(os.environ.get("TEST_NATIVE_PARSER"))
options.reveal_verbose_types = not testcase.name.endswith("_no_verbose_reveal")

if options.num_workers:
Expand All @@ -152,8 +151,9 @@ def run_case_once(
if testcase.name.endswith("_parallel_only"):
raise pytest.skip("Test is only for parallel mode")

if options.native_parser and testcase.name.endswith("_no_native_parse"):
raise pytest.skip("Test not supported by native parser yet")
if testcase.name.endswith("_old_parser"):
# This test is only for the old parser.
options.native_parser = False

# Enable some options automatically based on test file name.
if "columns" in testcase.file:
Expand Down
3 changes: 3 additions & 0 deletions mypy/test/testdeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
options.export_types = True
options.preserve_asts = True
options.allow_empty_bodies = True
if testcase.name.endswith("_old_parser"):
# This test is only for the old parser.
options.native_parser = False
messages, files, type_map = self.build(src, options)
a = messages
if files is None or type_map is None:
Expand Down
11 changes: 11 additions & 0 deletions mypy/test/testfinegrained.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
)

# Set to True to perform (somewhat expensive) checks for duplicate AST nodes after merge
from mypy.test.update_data import update_testcase_output

CHECK_CONSISTENCY = False


Expand Down Expand Up @@ -130,6 +132,10 @@ def run_case(self, testcase: DataDrivenTestCase) -> None:
# Normalize paths in test output (for Windows).
a = [line.replace("\\", "/") for line in a]

# This may not work perfectly, since it was designed for testcheck.py, use with care.
if testcase.output != a and testcase.config.getoption("--update-data", False):
update_testcase_output(testcase, a, incremental_step=1)

assert_string_arrays_equal(
testcase.output, a, f"Invalid output ({testcase.file}, line {testcase.line})"
)
Expand All @@ -155,6 +161,11 @@ def get_options(self, source: str, testcase: DataDrivenTestCase, build_cache: bo
options.export_types = "inspect" in testcase.file
# Treat empty bodies safely for these test cases.
options.allow_empty_bodies = not testcase.name.endswith("_no_empty")

if testcase.name.endswith("_old_parser") or testcase.name.endswith("_old_parser_cached"):
# This test is only for the old parser.
options.native_parser = False

options.reveal_verbose_types = True
if re.search("flags:.*--follow-imports", source) is None:
# Override the default for follow_imports
Expand Down
9 changes: 9 additions & 0 deletions mypy/test/testparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from mypy.parse import parse
from mypy.test.data import DataDrivenTestCase, DataSuite
from mypy.test.helpers import assert_string_arrays_equal, find_test_files, parse_options
from mypy.test.update_data import update_testcase_output
from mypy.util import get_mypy_comments


Expand Down Expand Up @@ -99,6 +100,9 @@ def test_parse_error(testcase: DataDrivenTestCase) -> None:
options.python_version = defaults.PYTHON3_VERSION
if options.python_version != sys.version_info[:2]:
skip()
if testcase.name.endswith("_old_parser"):
# This test is only for the old parser.
options.native_parser = False
# Compile temporary file. The test file contains non-ASCII characters.
errors = Errors(options)
parse(
Expand All @@ -115,6 +119,11 @@ def test_parse_error(testcase: DataDrivenTestCase) -> None:
except CompileError as e:
if e.module_with_blocker is not None:
assert e.module_with_blocker == "__main__"

# This may not work perfectly, since it was designed for testcheck.py, use with care.
if testcase.output != e.messages and testcase.config.getoption("--update-data", False):
update_testcase_output(testcase, e.messages, incremental_step=1)

# Verify that there was a compile error and that the error messages
# are equivalent.
assert_string_arrays_equal(
Expand Down
9 changes: 9 additions & 0 deletions mypy/test/testsemanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

# Semantic analyzer test cases: dump parse tree
# Semantic analysis test case description files.
from mypy.test.update_data import update_testcase_output
from mypy.types import TypeStrVisitor

semanal_files = find_test_files(
Expand Down Expand Up @@ -63,6 +64,9 @@ def test_semanal(testcase: DataDrivenTestCase) -> None:
src = "\n".join(testcase.input)
options = get_semanal_options(src, testcase)
options.python_version = testfile_pyversion(testcase.file)
if testcase.name.endswith("_old_parser"):
# This test is only for the old parser.
options.native_parser = False
result = build.build(
sources=[BuildSource("main", None, src)], options=options, alt_lib_path=test_temp_dir
)
Expand Down Expand Up @@ -112,6 +116,11 @@ def test_semanal_error(testcase: DataDrivenTestCase) -> None:
a = e.messages
if testcase.normalize_output:
a = normalize_error_messages(a)

# This may not work perfectly, since it was designed for testcheck.py, use with care.
if testcase.output != a and testcase.config.getoption("--update-data", False):
update_testcase_output(testcase, a, incremental_step=1)

assert_string_arrays_equal(
testcase.output, a, f"Invalid compiler output ({testcase.file}, line {testcase.line})"
)
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3207,7 +3207,7 @@ def test_mypy_build(self) -> None:
output = run_stubtest(stub="+", runtime="", options=[])
assert output == (
"error: not checking stubs due to failed mypy compile:\n{}.pyi:1: "
"error: Invalid syntax [syntax]\n".format(TEST_MODULE_NAME)
"error: Expected an expression [syntax]\n".format(TEST_MODULE_NAME)
)

output = run_stubtest(stub="def f(): ...\ndef f(): ...", runtime="", options=[])
Expand Down
8 changes: 4 additions & 4 deletions test-data/unit/check-async-await.test
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ async def f() -> None:
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncForTypeComments_no_native_parse]

-- Native parser does not support type comments in `for` and `with` statements.
[case testAsyncForTypeComments_old_parser]
from typing import AsyncIterator, Union
class C(AsyncIterator[int]):
async def __anext__(self) -> int: return 0
Expand Down Expand Up @@ -342,8 +342,8 @@ async def f() -> None:
[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAsyncWithTypeComments_no_native_parse]

-- Native parser does not support type comments in `for` and `with` statements.
[case testAsyncWithTypeComments_old_parser]
class C:
async def __aenter__(self) -> int: pass
async def __aexit__(self, x, y, z) -> None: pass
Expand Down
5 changes: 3 additions & 2 deletions test-data/unit/check-basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,11 @@ x = 1
x in 1, # E: Unsupported right operand type for in ("int")
[builtins fixtures/tuple.pyi]

[case testTrailingCommaInIfParsing_no_native_parse]
[case testTrailingCommaInIfParsing]
if x in 1, : pass
[out]
main:1: error: Invalid syntax
main:1: error: Expected `:`, found `,`
main:1: error: Expected a statement

[case testInitReturnTypeError]
class C:
Expand Down
14 changes: 7 additions & 7 deletions test-data/unit/check-columns.test
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Test column numbers in messages. --show-column-numbers is enabled implicitly by test runner.

[case testColumnsSyntaxError_no_native_parse]
[case testColumnsSyntaxError]
f()
1 +
[out]
main:2:5: error: Invalid syntax
main:2:5: error: Expected an expression

[case testColumnsNestedFunctions]
import typing
Expand Down Expand Up @@ -146,8 +146,7 @@ if int():
def f(a: 'A') -> None: pass
(f(b=object())) # E:6: Unexpected keyword argument "b" for "f"

[case testColumnInvalidType_no_native_parse]

[case testColumnInvalidType]
from typing import Iterable

bad = 0
Expand All @@ -158,8 +157,8 @@ def f(x: bad): # E:10: Variable "__main__.bad" is not valid as a type \
# N:8: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases

if int():
def g(x): # E:5: Variable "__main__.bad" is not valid as a type \
# N:5: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
def g(x): # E:11: Variable "__main__.bad" is not valid as a type \
# N:11: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
# type: (bad) -> None
y = 0 # type: bad # E:9: Variable "__main__.bad" is not valid as a type \
# N:9: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
Expand Down Expand Up @@ -342,12 +341,13 @@ if int():
main:2:11: error: Syntax error in type annotation
main:2:11: note: Suggestion: Is there a spurious trailing comma?

[case testColumnSyntaxErrorInTypeAnnotation2_no_native_parse]
[case testColumnSyntaxErrorInTypeAnnotation2]
if int():
# TODO: It would be better to point to the type comment
xyz = 0 # type: blurbnard blarb
[out]
main:3:5: error: Syntax error in type comment "blurbnard blarb"
main:3:5: error: Invalid type comment or annotation

[case testColumnProperty]
class A:
Expand Down
Loading
Loading