This attribute is a callable that returns a string if the value is
invalid, otherwise None. This intended for cases like the `install_*`
function's `install_mode` paramater, which is either an int or the
string "preserve", which allows us to do nice things like:
```python
class Kwargs(TypedDict):
install_mode: T.Union[int, T.Literal['preserve']]
@typed_kwargs(
'foo', KwargInfo('install_mode', ...,
validator=lambda x: None if isinstance(x, int) or x == 'preserve' else 'must be the literal "preserve"),
)
def install_data(self, node, args, kwargs: 'Kwargs'):
...
```
In this case mypy *knows* that the string is preserve, as do we, and we
can simply do tests like:
```python
if kwargs['install_mode'] == 'preserve':
...
else:
# this is an int
```
It's really inconvenient to want a thing that is always a list, but not
be able to provide a default value of a list because of mutation. To
that end the typed_kwargs method now makes a shallow copy of the default
when using a `ContainerTypeInfo` as the type. This mean that using a
default of `[]` is perfectly safe.
The only advantage they have is they have the interpreter in arguments,
but it's already available as self.interpreter. We should discourage
usage of the interpreter API and rely on ModuleState object instead in
the future.
This also lift the restriction that a module method cannot add build
targets, but that was not enforced for snippet methods anyway (and some
modules were doing it) and it's really loose restriction as it should
check for many other things if we wanted to make it consistent.
This allows representing functions like assert(), which take optional
positional arguments, which are not variadic. More importnatly you can
represent a function like (* means optional, but possitional):
```txt
func(str, *int, *str)
```
typed_pos_args will check that all of your types are correct, and if not
provide None, which allow simplifying a number of implementation details
We don't do a very good job of type checking in the interpreter,
sometimes we leave it to the mid layers of backends to do that (layering
violations) and sometimes we just don't check them at all. When we do
check them it's a ton of boilerplate and complicates the code. This
should help quite a bit.
The order of keys in dictionaries cannot be relied upon, because the hash
values are randomized by Python. Whenever we iterate on dictionaries and
meson.build generates a list during the iteration, the different iteration
orders may cause random changes in the command line and cause ninja to
rebuild a lot of files unnecessarily.
when that statement gets evaluated, the interpreter remembers the
version target and if it was part of the evaluation of a `if` condition
then the target meson version is temporally overriden within that
if-block.
Fixes: #7590
D lang compilers have an option -release (or similar) which turns off
asserts, contracts, and other runtime type checking. This patch wires
that up to the b_ndebug flag.
Fixes#7082
Currently deprecation features use the same logic as new features, but
that doesn't work correctly. FeatureNew wants to warn about cases where
you claim to support >= 0.40, but use a feature from 0.42; deprecation
wants to warn when you claim to support >= 0.50, but use a feature that
was replaced in 0.45.
To make this work we need to invert the version check in the deprecation
function, so that if the deprecation is 0.45, and the supported version
is >= 0.50, we get a true not a false.
Currently The Deprecated and New features checkers share an attribute
through a base class that should be per class. We need to duplicate this
and move it into each of the sublcasses
Fixes#7080
getattr() requires a default (return if missing) value or it raises an
AttributeError. In a few cases I changed hasattr to getattr and didn't
set a default value, so those cases could except. This corrects that.
This commit annotates most of interpreterbase.py. However,
there are stil the @wraps missing, since I am unsure what
the types are supposed to be here.