From 113a1595149b72ee0a572ed215db616c5a6d8a20 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 24 Sep 2020 09:53:41 -0700 Subject: use an immutable list for an lru_cached functions When mutable items are stored in an lru cache, changing the returned items changes the cached items as well. Therefore we want to ensure that we're not mutating them. Using the ImmutableListProtocol allows mypy to find mutations and reject them. This doesn't solve the problem of mutable values inside the values, so you could have to do things like: ```python ImmutableListProtocol[ImmutableListProtocol[str]] ``` or equally hacky. It can also be used for input types and acts a bit like C's const: ```python def foo(arg: ImmutableListProtocol[str]) -> T.List[str]: arg[1] = 'foo' # works while running, but mypy errors ``` --- mesonbuild/compilers/compilers.py | 1 + mesonbuild/compilers/mixins/clike.py | 5 +++-- mesonbuild/compilers/mixins/gnu.py | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'mesonbuild/compilers') diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 4eeaec7..361f5d6 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1023,6 +1023,7 @@ class Compiler(metaclass=abc.ABCMeta): raise EnvironmentException('This compiler does not have a preprocessor') def get_default_include_dirs(self) -> T.List[str]: + # TODO: This is a candidate for returning an immutable list return [] def get_largefile_args(self) -> T.List[str]: diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 0637439..0c0ade3 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -42,6 +42,7 @@ from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: from ...dependencies import Dependency + from ..._typing import ImmutableListProtocol from ...environment import Environment from ...compilers.compilers import Compiler from ...programs import ExternalProgram @@ -207,7 +208,7 @@ class CLikeCompiler(Compiler): @functools.lru_cache() def _get_library_dirs(self, env: 'Environment', - elf_class: T.Optional[int] = None) -> T.List[str]: + elf_class: T.Optional[int] = None) -> 'ImmutableListProtocol[str]': # TODO: replace elf_class with enum dirs = self.get_compiler_dirs(env, 'libraries') if elf_class is None or elf_class == 0: @@ -253,7 +254,7 @@ class CLikeCompiler(Compiler): return self._get_library_dirs(env, elf_class).copy() @functools.lru_cache() - def _get_program_dirs(self, env: 'Environment') -> T.List[str]: + def _get_program_dirs(self, env: 'Environment') -> 'ImmutableListProtocol[str]': ''' Programs used by the compiler. Also where toolchain DLLs such as libstdc++-6.dll are found with MinGW. diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index b007ff0..9a94703 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -28,6 +28,7 @@ from ... import mlog from ...mesonlib import OptionKey if T.TYPE_CHECKING: + from ..._typing import ImmutableListProtocol from ...environment import Environment from ..compilers import Compiler else: @@ -92,7 +93,7 @@ gnu_color_args = { @functools.lru_cache(maxsize=None) -def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: str) -> T.List[str]: +def gnulike_default_include_dirs(compiler: T.Tuple[str, ...], lang: str) -> 'ImmutableListProtocol[str]': lang_map = { 'c': 'c', 'cpp': 'c++', @@ -189,7 +190,7 @@ class GnuLikeCompiler(Compiler, metaclass=abc.ABCMeta): return gnulike_instruction_set_args.get(instruction_set, None) def get_default_include_dirs(self) -> T.List[str]: - return gnulike_default_include_dirs(tuple(self.exelist), self.language) + return gnulike_default_include_dirs(tuple(self.exelist), self.language).copy() @abc.abstractmethod def openmp_flags(self) -> T.List[str]: -- cgit v1.1