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

Fix typing for most of the AST module #12633

Merged
merged 4 commits into from
Jan 9, 2024
Merged
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
25 changes: 13 additions & 12 deletions mesonbuild/ast/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
if T.TYPE_CHECKING:
from .visitor import AstVisitor
from ..interpreter import Interpreter
from ..interpreterbase import TYPE_nkwargs, TYPE_nvar
from ..interpreterbase import SubProject, TYPE_nkwargs, TYPE_var
from ..mparser import (
AndNode,
ComparisonNode,
Expand Down Expand Up @@ -84,8 +84,9 @@ class MockRunTarget(MesonInterpreterObject):
_T = T.TypeVar('_T')
_V = T.TypeVar('_V')


class AstInterpreter(InterpreterBase):
def __init__(self, source_root: str, subdir: str, subproject: str, visitors: T.Optional[T.List[AstVisitor]] = None):
def __init__(self, source_root: str, subdir: str, subproject: SubProject, visitors: T.Optional[T.List[AstVisitor]] = None):
super().__init__(source_root, subdir, subproject)
self.visitors = visitors if visitors is not None else []
self.processed_buildfiles: T.Set[str] = set()
Expand Down Expand Up @@ -159,15 +160,15 @@ def _unholder_args(self, args: _T, kwargs: _V) -> T.Tuple[_T, _V]:
def _holderify(self, res: _T) -> _T:
return res

def func_do_nothing(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> bool:
def func_do_nothing(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> bool:
return True

def load_root_meson_file(self) -> None:
super().load_root_meson_file()
for i in self.visitors:
self.ast.accept(i)

def func_subdir(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None:
def func_subdir(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> None:
args = self.flatten_args(args)
if len(args) != 1 or not isinstance(args[0], str):
sys.stderr.write(f'Unable to evaluate subdir({args}) in AstInterpreter --> Skipping\n')
Expand Down Expand Up @@ -210,7 +211,7 @@ def evaluate_fstring(self, node: mparser.FormatStringNode) -> str:
assert isinstance(node, mparser.FormatStringNode)
return node.value

def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> TYPE_nvar:
def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> TYPE_var:
return self.reduce_arguments(cur.args)[0]

def evaluate_arithmeticstatement(self, cur: ArithmeticNode) -> int:
Expand Down Expand Up @@ -261,9 +262,9 @@ def reduce_arguments(
args: mparser.ArgumentNode,
key_resolver: T.Callable[[mparser.BaseNode], str] = default_resolve_key,
duplicate_key_error: T.Optional[str] = None,
) -> T.Tuple[T.List[TYPE_nvar], TYPE_nkwargs]:
) -> T.Tuple[T.List[TYPE_var], TYPE_nkwargs]:
if isinstance(args, ArgumentNode):
kwargs: T.Dict[str, TYPE_nvar] = {}
kwargs: T.Dict[str, TYPE_var] = {}
for key, val in args.kwargs.items():
kwargs[key_resolver(key)] = val
if args.incorrect_order():
Expand Down Expand Up @@ -372,7 +373,7 @@ def quick_resolve(n: BaseNode, loop_detect: T.Optional[T.List[str]] = None) -> T
elif isinstance(node, MethodNode):
src = quick_resolve(node.source_object)
margs = self.flatten_args(node.args.arguments, include_unknown_args, id_loop_detect)
mkwargs: T.Dict[str, TYPE_nvar] = {}
mkwargs: T.Dict[str, TYPE_var] = {}
method_name = node.name.value
try:
if isinstance(src, str):
Expand All @@ -392,7 +393,7 @@ def quick_resolve(n: BaseNode, loop_detect: T.Optional[T.List[str]] = None) -> T
if isinstance(result, BaseNode):
result = self.resolve_node(result, include_unknown_args, id_loop_detect)
elif isinstance(result, list):
new_res: T.List[TYPE_nvar] = []
new_res: T.List[TYPE_var] = []
for i in result:
if isinstance(i, BaseNode):
resolved = self.resolve_node(i, include_unknown_args, id_loop_detect)
Expand All @@ -404,14 +405,14 @@ def quick_resolve(n: BaseNode, loop_detect: T.Optional[T.List[str]] = None) -> T

return result

def flatten_args(self, args_raw: T.Union[TYPE_nvar, T.Sequence[TYPE_nvar]], include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[TYPE_nvar]:
def flatten_args(self, args_raw: T.Union[TYPE_var, T.Sequence[TYPE_var]], include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[TYPE_var]:
# Make sure we are always dealing with lists
if isinstance(args_raw, list):
args = args_raw
else:
args = [args_raw]

flattened_args: T.List[TYPE_nvar] = []
flattened_args: T.List[TYPE_var] = []

# Resolve the contents of args
for i in args:
Expand All @@ -425,7 +426,7 @@ def flatten_args(self, args_raw: T.Union[TYPE_nvar, T.Sequence[TYPE_nvar]], incl
flattened_args += [i]
return flattened_args

def flatten_kwargs(self, kwargs: T.Dict[str, TYPE_nvar], include_unknown_args: bool = False) -> T.Dict[str, TYPE_nvar]:
def flatten_kwargs(self, kwargs: T.Dict[str, TYPE_var], include_unknown_args: bool = False) -> T.Dict[str, TYPE_var]:
flattened_kwargs = {}
for key, val in kwargs.items():
if isinstance(val, BaseNode):
Expand Down
45 changes: 23 additions & 22 deletions mesonbuild/ast/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
from .. import coredata as cdata
from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary
from ..compilers import detect_compiler_for
from ..interpreterbase import InvalidArguments
from ..interpreterbase import InvalidArguments, SubProject
from ..mesonlib import MachineChoice, OptionKey
from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, BaseStringNode
from .interpreter import AstInterpreter

if T.TYPE_CHECKING:
from ..build import BuildTarget
from ..interpreterbase import TYPE_nvar
from ..interpreterbase import TYPE_var
from .visitor import AstVisitor


Expand Down Expand Up @@ -51,7 +51,7 @@ def __init__(self,
backend: str,
visitors: T.Optional[T.List[AstVisitor]] = None,
cross_file: T.Optional[str] = None,
subproject: str = '',
subproject: SubProject = SubProject(''),
subproject_dir: str = 'subprojects',
env: T.Optional[environment.Environment] = None):
visitors = visitors if visitors is not None else []
Expand Down Expand Up @@ -85,7 +85,7 @@ def __init__(self,
'both_libraries': self.func_both_lib,
})

def func_project(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None:
def func_project(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> None:
if self.project_node:
raise InvalidArguments('Second call to project()')
self.project_node = node
Expand Down Expand Up @@ -126,7 +126,7 @@ def func_project(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[s
if os.path.isdir(subprojects_dir):
for i in os.listdir(subprojects_dir):
if os.path.isdir(os.path.join(subprojects_dir, i)):
self.do_subproject(i)
self.do_subproject(SubProject(i))

self.coredata.init_backend_options(self.backend)
options = {k: v for k, v in self.environment.options.items() if k.is_backend()}
Expand All @@ -135,7 +135,7 @@ def func_project(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[s
self._add_languages(proj_langs, True, MachineChoice.HOST)
self._add_languages(proj_langs, True, MachineChoice.BUILD)

def do_subproject(self, dirname: str) -> None:
def do_subproject(self, dirname: SubProject) -> None:
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
subpr = os.path.join(subproject_dir_abs, dirname)
try:
Expand All @@ -146,9 +146,10 @@ def do_subproject(self, dirname: str) -> None:
except (mesonlib.MesonException, RuntimeError):
return

def func_add_languages(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None:
def func_add_languages(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> None:
kwargs = self.flatten_kwargs(kwargs)
required = kwargs.get('required', True)
assert isinstance(required, (bool, cdata.UserFeatureOption)), 'for mypy'
if isinstance(required, cdata.UserFeatureOption):
required = required.is_enabled()
if 'native' in kwargs:
Expand All @@ -158,7 +159,7 @@ def func_add_languages(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.
for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]:
self._add_languages(args, required, for_machine)

def _add_languages(self, raw_langs: T.List[TYPE_nvar], required: bool, for_machine: MachineChoice) -> None:
def _add_languages(self, raw_langs: T.List[TYPE_var], required: bool, for_machine: MachineChoice) -> None:
langs: T.List[str] = []
for l in self.flatten_args(raw_langs):
if isinstance(l, str):
Expand All @@ -185,7 +186,7 @@ def _add_languages(self, raw_langs: T.List[TYPE_nvar], required: bool, for_machi
options[k] = v
self.coredata.add_compiler_options(options, lang, for_machine, self.environment)

def func_dependency(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> None:
def func_dependency(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> None:
args = self.flatten_args(args)
kwargs = self.flatten_kwargs(kwargs)
if not args:
Expand All @@ -209,7 +210,7 @@ def func_dependency(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dic
'node': node
}]

def build_target(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs_raw: T.Dict[str, TYPE_nvar], targetclass: T.Type[BuildTarget]) -> T.Optional[T.Dict[str, T.Any]]:
def build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs_raw: T.Dict[str, TYPE_var], targetclass: T.Type[BuildTarget]) -> T.Optional[T.Dict[str, T.Any]]:
args = self.flatten_args(args)
if not args or not isinstance(args[0], str):
return None
Expand Down Expand Up @@ -270,7 +271,7 @@ def traverse_nodes(inqueue: T.List[BaseNode]) -> T.List[BaseNode]:
empty_sources: T.List[T.Any] = []
# Passing the unresolved sources list causes errors
kwargs_reduced['_allow_no_sources'] = True
target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, [], objects,
target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, None, objects,
Copy link
Member

Choose a reason for hiding this comment

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

Oh fun... if self.structured_sources and an empty list is falsey.

self.environment, self.coredata.compilers[for_machine], kwargs_reduced)
target.process_compilers_late()

Expand All @@ -292,7 +293,7 @@ def traverse_nodes(inqueue: T.List[BaseNode]) -> T.List[BaseNode]:
self.targets += [new_target]
return new_target

def build_library(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def build_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
default_library = self.coredata.get_option(OptionKey('default_library'))
if default_library == 'shared':
return self.build_target(node, args, kwargs, SharedLibrary)
Expand All @@ -302,28 +303,28 @@ def build_library(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[
return self.build_target(node, args, kwargs, SharedLibrary)
return None

def func_executable(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_executable(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_target(node, args, kwargs, Executable)

def func_static_lib(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_static_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_target(node, args, kwargs, StaticLibrary)

def func_shared_lib(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_shared_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_target(node, args, kwargs, SharedLibrary)

def func_both_lib(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_both_lib(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_target(node, args, kwargs, SharedLibrary)

def func_shared_module(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_shared_module(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_target(node, args, kwargs, SharedModule)

def func_library(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_library(node, args, kwargs)

def func_jar(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_jar(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
return self.build_target(node, args, kwargs, Jar)

def func_build_target(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]:
def func_build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Optional[T.Dict[str, T.Any]]:
if 'target_type' not in kwargs:
return None
target_type = kwargs.pop('target_type')
Expand Down Expand Up @@ -358,11 +359,11 @@ def extract_subproject_dir(self) -> T.Optional[str]:
and also calls parse_project() on every subproject.
'''
if not self.ast.lines:
return
return None
project = self.ast.lines[0]
# first line is always project()
if not isinstance(project, FunctionNode):
return
return None
for kw, val in project.args.kwargs.items():
assert isinstance(kw, IdNode), 'for mypy'
if kw.value == 'subproject_dir':
Expand Down
18 changes: 10 additions & 8 deletions mesonbuild/ast/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ def visit_NumberNode(self, node: mparser.NumberNode) -> None:
node.lineno = self.curr_line or node.lineno

def escape(self, val: str) -> str:
return val.translate(str.maketrans({'\'': '\\\'',
'\\': '\\\\'}))
return val.translate(str.maketrans(T.cast(
'T.Dict[str, T.Union[str, int]]',
{'\'': '\\\'', '\\': '\\\\'})))

def visit_StringNode(self, node: mparser.StringNode) -> None:
assert isinstance(node.value, str)
Expand All @@ -78,7 +79,7 @@ def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None:
self.append("f'" + self.escape(node.value) + "'", node)
node.lineno = self.curr_line or node.lineno

def visit_MultilineStringNode(self, node: mparser.StringNode) -> None:
def visit_MultilineStringNode(self, node: mparser.MultilineFormatStringNode) -> None:
assert isinstance(node.value, str)
self.append("'''" + node.value + "'''", node)
node.lineno = self.curr_line or node.lineno
Expand Down Expand Up @@ -241,21 +242,22 @@ def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None:

class RawPrinter(AstVisitor):

def __init__(self):
def __init__(self) -> None:
self.result = ''

def visit_default_func(self, node: mparser.BaseNode):
self.result += node.value
def visit_default_func(self, node: mparser.BaseNode) -> None:
# XXX: this seems like it could never actually be reached...
self.result += node.value # type: ignore[attr-defined]
if node.whitespaces:
node.whitespaces.accept(self)

def visit_unary_operator(self, node: mparser.UnaryOperatorNode):
def visit_unary_operator(self, node: mparser.UnaryOperatorNode) -> None:
node.operator.accept(self)
node.value.accept(self)
if node.whitespaces:
node.whitespaces.accept(self)

def visit_binary_operator(self, node: mparser.BinaryOperatorNode):
def visit_binary_operator(self, node: mparser.BinaryOperatorNode) -> None:
node.left.accept(self)
node.operator.accept(self)
node.right.accept(self)
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/ast/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def visit_StringNode(self, node: mparser.StringNode) -> None:
def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None:
self.visit_default_func(node)

def visit_MultilineStringNode(self, node: mparser.StringNode) -> None:
def visit_MultilineStringNode(self, node: mparser.MultilineFormatStringNode) -> None:
self.visit_default_func(node)

def visit_FormatMultilineStringNode(self, node: mparser.FormatStringNode) -> None:
Expand Down Expand Up @@ -138,7 +138,7 @@ def visit_IfNode(self, node: mparser.IfNode) -> None:
node.condition.accept(self)
node.block.accept(self)

def visit_ElseNode(self, node: mparser.IfNode) -> None:
def visit_ElseNode(self, node: mparser.ElseNode) -> None:
self.visit_default_func(node)
node.block.accept(self)

Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ def can_compile_remove_sources(compiler: 'Compiler', sources: T.List['FileOrStri
removed = True
return removed

def process_compilers_late(self):
def process_compilers_late(self) -> None:
"""Processes additional compilers after kwargs have been evaluated.

This can add extra compilers that might be required by keyword
Expand Down
4 changes: 4 additions & 0 deletions run_mypy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
'mesonbuild/wrap/',

# specific files
'mesonbuild/ast/introspection.py',
'mesonbuild/ast/printer.py',
'mesonbuild/ast/postprocess.py',
'mesonbuild/ast/visitor.py',
dcbaker marked this conversation as resolved.
Show resolved Hide resolved
'mesonbuild/arglist.py',
'mesonbuild/backend/backends.py',
'mesonbuild/backend/nonebackend.py',
Expand Down
Loading