Repository: mesonbuild/meson

Issue:
Reject comparison between boolean & string (or any incompatible combinations)
While reviewing libdrm's meson port I found such construction (which is typo, but anyway).

`if get_option('foo') != 'false'`

To be honest, I want meson to fail hard on this... Or at least show noisy warning.


Discussion:
Yes, we should definitely do this for comparisons against the return value of `get_option()` (since that is strictly-typed), but I am unsure if we should do this for all variables. For instance, people might be doing something like:

```meson
libfoo_path = false
if some_condition
  libfoo_path = '/usr/local/lib'
elif some_other
  libfoo_path = '/opt/lib'
endif

if libfoo_path != false
  library('somelib')
endif
```

i.e., variables do not have strict type constraints. One way to implement this would be to set a property on the returned value of all meson functions with a list of the types it can be. Then we'd know if the comparison was never going to be satisfied because it compared against an impossible type.
The point here is, I think that this should be simpler. Variables are just 'references' or 'labels' as in Python while values have a type. Then this is stated that there should be no implicit type conversion [here](http://mesonbuild.com/Syntax.html#syntax).
So I think that @ignatenkobrain you pointed a real bug, there should be an error message like 'can't compare bool and string'
> So I think that @ignatenkobrain you pointed a real bug, there should be an error message like 'can't compare bool and string'

Yes. Meson is not PHP. Implicit type conversions are bad.

Resolving patch:
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -265,6 +265,12 @@ def evaluate_if(self, node):
         if not isinstance(node.elseblock, mparser.EmptyNode):
             self.evaluate_codeblock(node.elseblock)
 
+    def validate_comparison_types(self, val1, val2):
+        if type(val1) != type(val2):
+            mlog.warning('''Trying to compare values of different types ({}, {}).
+The result of this is undefined and will become a hard error
+in a future Meson release.'''.format(type(val1).__name__, type(val2).__name__))
+
     def evaluate_comparison(self, node):
         val1 = self.evaluate_statement(node.left)
         if is_disabler(val1):
@@ -272,15 +278,11 @@ def evaluate_comparison(self, node):
         val2 = self.evaluate_statement(node.right)
         if is_disabler(val2):
             return val2
+        self.validate_comparison_types(val1, val2)
         if node.ctype == '==':
             return val1 == val2
         elif node.ctype == '!=':
             return val1 != val2
-        elif not isinstance(val1, type(val2)):
-            raise InterpreterException(
-                'Values of different types ({}, {}) cannot be compared using {}.'.format(type(val1).__name__,
-                                                                                         type(val2).__name__,
-                                                                                         node.ctype))
         elif not self.is_elementary_type(val1):
             raise InterpreterException('{} can only be compared for equality.'.format(node.left.value))
         elif not self.is_elementary_type(val2):


Test patch:
diff --git a/test cases/common/140 get define/meson.build b/test cases/common/140 get define/meson.build
--- a/test cases/common/140 get define/meson.build	
+++ b/test cases/common/140 get define/meson.build	
@@ -45,8 +45,8 @@ foreach lang : ['c', 'cpp']
   if meson.is_cross_build()
     # Can't use an empty array as a fallback here because of
     # https://github.com/mesonbuild/meson/issues/1481
-    lang_args = meson.get_cross_property(lang + '_args', false)
-    if lang_args != false
+    lang_args = meson.get_cross_property(lang + '_args', [])
+    if lang_args.length() != 0
       foreach lang_arg : lang_args
         if lang_arg.contains('MESON_TEST_ISSUE_1665')
           run_1665_test = true