Skip to content

Commit 85c7355

Browse files
committed
ast/interpreter: make types closer to the truth
reduce_arguments and flatten_args operate on values that are TYPE_var | mparser.BaseNode | some other types, but this is hidden behind Any. Introduce TYPE_ivar and TYPE_ikwargs to make the representation a bit closer to the truth. Of course, because this replaces Any, a lot of casts and "type: ignore" comments are needed. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 440b22a commit 85c7355

3 files changed

Lines changed: 46 additions & 36 deletions

File tree

mesonbuild/ast/interpreter.py

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
if T.TYPE_CHECKING:
5858
from .visitor import AstVisitor
5959
from ..interpreter import Interpreter
60-
from ..interpreterbase import TYPE_var, TYPE_nvar
60+
from ..interpreterbase import TYPE_var, TYPE_kwargs
6161
from ..mparser import (
6262
AndNode,
6363
ComparisonNode,
@@ -68,7 +68,13 @@
6868
TestCaseClauseNode,
6969
UMinusNode,
7070
)
71-
from ..mesonlib import SubProject
71+
from ..mesonlib import HoldableObject, SubProject
72+
73+
TYPE_ivar = T.Union[str, int, bool, 'HoldableObject', 'MesonInterpreterObject',
74+
'UnknownValue', 'IntrospectionBuildTarget', 'IntrospectionFile',
75+
'IntrospectionDependency', list['TYPE_ivar'], dict[str | UnknownValue, 'TYPE_ivar']]
76+
TYPE_nvar = T.Union[TYPE_ivar, mparser.BaseNode]
77+
TYPE_nkwargs = T.Dict[str, TYPE_nvar]
7278

7379
_T = T.TypeVar('_T')
7480
_V = T.TypeVar('_V')
@@ -282,24 +288,28 @@ def func_subdir(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str
282288
buildfilename = os.path.join(subdir, environment.build_filename)
283289
sys.stderr.write(f'Unable to find build file {buildfilename} --> Skipping\n')
284290

285-
def inner_method_call(self, obj: BaseNode, method_name: str, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Any:
286-
for arg in itertools.chain(args, kwargs.values()):
291+
def inner_method_call(self, iobj: TYPE_ivar, method_name: str, iargs: T.List[TYPE_ivar], nkwargs: TYPE_nkwargs) -> TYPE_ivar:
292+
for arg in itertools.chain(iargs, nkwargs.values()):
287293
if isinstance(arg, UnknownValue):
288294
return UnknownValue()
289295

290-
if isinstance(obj, str):
291-
result = StringHolder(obj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
292-
elif isinstance(obj, bool):
293-
result = BooleanHolder(obj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
294-
elif isinstance(obj, int):
295-
result = IntegerHolder(obj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
296-
elif isinstance(obj, list):
296+
args = T.cast('list[TYPE_var]', iargs)
297+
kwargs = T.cast('TYPE_kwargs', nkwargs)
298+
if isinstance(iobj, str):
299+
result = StringHolder(iobj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
300+
elif isinstance(iobj, bool):
301+
result = BooleanHolder(iobj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
302+
elif isinstance(iobj, int):
303+
result = IntegerHolder(iobj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
304+
elif isinstance(iobj, list):
305+
obj = T.cast('list[TYPE_var]', iobj) # assuming ArrayHolder is fine with receiving TYPE_ivars...
297306
result = ArrayHolder(obj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
298-
elif isinstance(obj, dict):
307+
elif isinstance(iobj, dict):
308+
obj = T.cast('dict[str, TYPE_var]', iobj) # assuming DictHolder is fine with receiving TYPE_ivars...
299309
result = DictHolder(obj, T.cast('Interpreter', self)).method_call(method_name, args, kwargs)
300310
else:
301311
return UnknownValue()
302-
return result
312+
return T.cast('TYPE_ivar', result)
303313

304314
def method_call(self, node: mparser.MethodNode) -> None:
305315
invocable = node.source_object
@@ -342,17 +352,19 @@ def evaluate_indexing(self, node: IndexNode) -> None:
342352
self.evaluate_statement(node.iobject)
343353
self.evaluate_statement(node.index)
344354

345-
def reduce_arguments(
355+
# this returns a different type than the supertype; TYPE_nvar and TYPE_nkwargs
356+
# are limited to the AstInterpreter
357+
def reduce_arguments( # type: ignore[override]
346358
self,
347359
args: mparser.ArgumentNode,
348360
key_resolver: T.Callable[[mparser.BaseNode], str] = default_resolve_key,
349361
duplicate_key_error: T.Optional[str] = None,
350-
) -> T.Tuple[T.List[T.Any], T.Any]:
362+
) -> T.Tuple[T.List[TYPE_ivar], TYPE_nkwargs]:
351363
for arg in args.arguments:
352364
self.evaluate_statement(arg)
353365
for value in args.kwargs.values():
354366
self.evaluate_statement(value)
355-
kwargs = {}
367+
kwargs: TYPE_nkwargs = {}
356368
for key, val in args.kwargs.items():
357369
kwargs[key_resolver(key)] = val
358370
if args.incorrect_order():
@@ -537,7 +549,7 @@ def get_cur_value(self, var_name: str) -> T.Union[BaseNode, UnknownValue]:
537549
# node = [123, somedep.found()]
538550
# ```
539551
# `node_to_runtime_value` will return `[123, UnknownValue()]`.
540-
def node_to_runtime_value(self, node: T.Union[UnknownValue, BaseNode, TYPE_var]) -> T.Any:
552+
def node_to_runtime_value(self, node: T.Union[UnknownValue, TYPE_ivar, mparser.BaseNode]) -> TYPE_ivar:
541553
if isinstance(node, (mparser.StringNode, mparser.BooleanNode, mparser.NumberNode)):
542554
return node.value
543555
elif isinstance(node, mparser.StringNode):
@@ -550,7 +562,7 @@ def node_to_runtime_value(self, node: T.Union[UnknownValue, BaseNode, TYPE_var])
550562
elif isinstance(node, ArrayNode):
551563
return [self.node_to_runtime_value(x) for x in node.args.arguments]
552564
elif isinstance(node, mparser.DictNode):
553-
result: T.Dict[str | UnknownValue, T.Any] = {}
565+
result: T.Dict[str | UnknownValue, TYPE_ivar] = {}
554566
for raw_k, raw_v in node.args.kwargs.items():
555567
k = self.node_to_runtime_value(raw_k)
556568
if not isinstance(k, (str, UnknownValue)):
@@ -572,8 +584,8 @@ def node_to_runtime_value(self, node: T.Union[UnknownValue, BaseNode, TYPE_var])
572584
else:
573585
return self.node_to_runtime_value(funcval)
574586
elif isinstance(node, ArithmeticNode):
575-
left = self.node_to_runtime_value(node.left)
576-
right = self.node_to_runtime_value(node.right)
587+
left: TYPE_ivar = self.node_to_runtime_value(node.left)
588+
right: TYPE_ivar = self.node_to_runtime_value(node.right)
577589
if isinstance(left, list) and isinstance(right, UnknownValue):
578590
return left + [right]
579591
if isinstance(right, list) and isinstance(left, UnknownValue):
@@ -590,11 +602,11 @@ def node_to_runtime_value(self, node: T.Union[UnknownValue, BaseNode, TYPE_var])
590602
if not isinstance(right, list):
591603
right = [right]
592604
return left + right
593-
return left + right
605+
return left + right # type: ignore[operator]
594606
elif node.operation == '-':
595-
return left - right
607+
return left - right # type: ignore[operator]
596608
elif node.operation == '*':
597-
return left * right
609+
return left * right # type: ignore[operator]
598610
elif node.operation == '/':
599611
if isinstance(left, int) and isinstance(right, int):
600612
return left // right
@@ -610,7 +622,7 @@ def node_to_runtime_value(self, node: T.Union[UnknownValue, BaseNode, TYPE_var])
610622
index = self.node_to_runtime_value(node.index)
611623
if isinstance(iobject, UnknownValue) or isinstance(index, UnknownValue):
612624
return UnknownValue()
613-
return iobject[index]
625+
return iobject[index] # type: ignore[index]
614626
elif isinstance(node, mparser.ComparisonNode):
615627
left = self.node_to_runtime_value(node.left)
616628
right = self.node_to_runtime_value(node.right)
@@ -621,9 +633,9 @@ def node_to_runtime_value(self, node: T.Union[UnknownValue, BaseNode, TYPE_var])
621633
elif node.ctype == '!=':
622634
return left != right
623635
elif node.ctype == 'in':
624-
return left in right
636+
return left in right # type: ignore[operator]
625637
elif node.ctype == 'not in':
626-
return left not in right
638+
return left not in right # type: ignore[operator]
627639
elif isinstance(node, mparser.TernaryNode):
628640
cond = self.node_to_runtime_value(node.condition)
629641
if isinstance(cond, UnknownValue):
@@ -724,7 +736,7 @@ def func_unset_variable(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.
724736
self.cur_assignments[var_name].append((self.nesting.copy(), node))
725737

726738
def nodes_to_pretty_filelist(self, root_path: Path, subdir: str, nodes: T.List[BaseNode]) -> T.List[T.Union[str, UnknownValue]]:
727-
def src_to_abs(src: T.Union[str, IntrospectionFile, UnknownValue]) -> T.Union[str, UnknownValue]:
739+
def src_to_abs(src: TYPE_ivar) -> T.Union[str, UnknownValue]:
728740
if isinstance(src, str):
729741
return os.path.normpath(os.path.join(root_path, subdir, src))
730742
elif isinstance(src, IntrospectionFile):
@@ -737,9 +749,8 @@ def src_to_abs(src: T.Union[str, IntrospectionFile, UnknownValue]) -> T.Union[st
737749
rtvals: T.List[T.Any] = self.flatten_args(nodes)
738750
return [src_to_abs(x) for x in rtvals]
739751

740-
def flatten_args(self, args: T.Sequence[TYPE_nvar]) -> T.List[TYPE_var]:
741-
# BaseNode resolves to Any. :/
742-
flattened_args: T.List[T.Union[TYPE_var, T.Any]] = []
752+
def flatten_args(self, args: T.Sequence[TYPE_nvar]) -> T.List[TYPE_ivar]:
753+
flattened_args: T.List[TYPE_ivar] = []
743754

744755
# Resolve the contents of args
745756
for i in args:
@@ -760,11 +771,13 @@ def flatten_args(self, args: T.Sequence[TYPE_nvar]) -> T.List[TYPE_var]:
760771

761772
def flatten_args_hack(self, args: T.List[TYPE_var]) -> T.List[TYPE_var]:
762773
# Unlike method calls, functions are invoked even if one or more values
763-
# are unknown. The types in this declaration are completely wrong;
764-
# the right solution would involve making TYPE_var an argument to
774+
# are unknown. The return type is actually T.List[TYPE_ivar], and
775+
# while callers declare args as T.List[TYPE_var], they receive a
776+
# list of TYPE_ivar too.
777+
# The right solution would involve making TYPE_var an argument to
765778
# InterpreterBase, so that FunctionType is also changed to not
766779
# use TYPE_var.
767-
return self.flatten_args(args)
780+
return T.cast('T.List[TYPE_var]', self.flatten_args(T.cast('T.List[TYPE_ivar]', args)))
768781

769782
def evaluate_testcase(self, node: TestCaseClauseNode) -> Disabler | None:
770783
return Disabler(subproject=self.subproject)

mesonbuild/interpreterbase/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
'TV_func',
5252
'TYPE_elementary',
5353
'TYPE_var',
54-
'TYPE_nvar',
5554
'TYPE_kwargs',
5655
'TYPE_key_resolver',
5756
'TYPE_HoldableTypes',
@@ -73,7 +72,6 @@
7372
TV_func,
7473
TYPE_elementary,
7574
TYPE_var,
76-
TYPE_nvar,
7775
TYPE_kwargs,
7876
TYPE_key_resolver,
7977
TYPE_HoldableTypes,

mesonbuild/interpreterbase/baseobjects.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
TYPE_elementary: TypeAlias = T.Union[str, int, bool, T.Sequence['TYPE_elementary'], T.Dict[str, 'TYPE_elementary']]
2626
TYPE_var: TypeAlias = T.Union[TYPE_elementary, HoldableObject, 'MesonInterpreterObject', T.Sequence['TYPE_var'], T.Dict[str, 'TYPE_var']]
27-
TYPE_nvar = T.Union[TYPE_var, mparser.BaseNode]
2827
TYPE_kwargs = T.Dict[str, TYPE_var]
2928
TYPE_key_resolver = T.Callable[[mparser.BaseNode], str]
3029
TYPE_op_arg = T.TypeVar('TYPE_op_arg', bound='TYPE_var', contravariant=True)

0 commit comments

Comments
 (0)