fix(checker): report predicate argument errors

This commit is contained in:
2026-07-07 10:02:52 +02:00
parent 4eb133ce17
commit 5e87ba2cd1

View File

@@ -2,6 +2,7 @@ from dataclasses import dataclass
from typing import Any, Callable, Optional from typing import Any, Callable, Optional
import midas.ast.midas as m import midas.ast.midas as m
from midas.ast.location import Location
from midas.checker.preamble import Preamble from midas.checker.preamble import Preamble
from midas.checker.registry import TypesRegistry from midas.checker.registry import TypesRegistry
from midas.checker.reporter import FileReporter from midas.checker.reporter import FileReporter
@@ -143,7 +144,7 @@ class Evaluator(m.Expr.Visitor[Any]):
match callee: match callee:
case Predicate(): case Predicate():
return self._evaluate_predicate(callee, args, kwargs) return self._evaluate_predicate(expr.location, callee, args, kwargs)
case _ if callable(callee): case _ if callable(callee):
return callee(*args, **kwargs) return callee(*args, **kwargs)
case _: case _:
@@ -181,6 +182,7 @@ class Evaluator(m.Expr.Visitor[Any]):
def _evaluate_predicate( def _evaluate_predicate(
self, self,
location: Location,
predicate: Predicate, predicate: Predicate,
args: list[Any], args: list[Any],
kwargs: dict[str, Any], kwargs: dict[str, Any],
@@ -202,7 +204,7 @@ class Evaluator(m.Expr.Visitor[Any]):
self.scopes.append({}) self.scopes.append({})
match predicate.type: match predicate.type:
case Function(returns=Function() as inner): case Function(returns=Function() as inner):
self._map_args(predicate.type, args, kwargs) self._map_args(location, predicate.type, args, kwargs)
res = PartialPredicate( res = PartialPredicate(
type=inner, type=inner,
body=predicate.body, body=predicate.body,
@@ -211,7 +213,7 @@ class Evaluator(m.Expr.Visitor[Any]):
) )
case Function(): case Function():
self._map_args(predicate.type, args, kwargs) self._map_args(location, predicate.type, args, kwargs)
res = self.evaluate(predicate.body) res = self.evaluate(predicate.body)
case _: case _:
@@ -219,7 +221,13 @@ class Evaluator(m.Expr.Visitor[Any]):
self.scopes.pop() self.scopes.pop()
return res return res
def _map_args(self, function: Function, args: list[Any], kwargs: dict[str, Any]): def _map_args(
self,
location: Location,
function: Function,
args: list[Any],
kwargs: dict[str, Any],
):
"""Map call arguments to a function's parameters and set their values in context """Map call arguments to a function's parameters and set their values in context
Each argument is mapped to a parameter of the function, then its value Each argument is mapped to a parameter of the function, then its value
@@ -238,9 +246,20 @@ class Evaluator(m.Expr.Visitor[Any]):
} }
for i, arg in enumerate(args): for i, arg in enumerate(args):
if i >= len(positional):
if self.reporter is not None:
self.reporter.error(
location,
f"Too many positional arguments, expected at most {len(positional)}, got {len(args)}",
)
break
param: Function.Parameter = positional[i] param: Function.Parameter = positional[i]
self.set_value(param.name, arg) self.set_value(param.name, arg)
for name, arg in kwargs.items(): for name, arg in kwargs.items():
if name not in keywords:
if self.reporter is not None:
self.reporter.error(location, f"Unknown keyword argument '{name}'")
break
param: Function.Parameter = keywords[name] param: Function.Parameter = keywords[name]
self.set_value(param.name, arg) self.set_value(param.name, arg)