move experimental null reference checking to separate visitor
authorJuerg Billeter <j@bitron.ch>
Mon, 14 Apr 2008 15:54:19 +0000 (15:54 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Mon, 14 Apr 2008 15:54:19 +0000 (15:54 +0000)
2008-04-14  Juerg Billeter  <j@bitron.ch>

* vala/Makefile.am, vala/valaarraytype.vala,
  vala/valaclasstype.vala, vala/valacodenode.vala,
  vala/valadatatype.vala, vala/valaerrortype.vala,
  vala/valaintegertype.vala, vala/valainterfacetype.vala,
  vala/valamethodtype.vala, vala/valanullchecker.vala,
  vala/valanulltype.vala, vala/valaparser.vala,
  vala/valapointertype.vala, vala/valasemanticanalyzer.vala,
  vala/valasymbolresolver.vala, vala/valatypeparametertype.vala,
  vala/valaunresolvedtype.vala, vala/valavaluetype.vala,
  gobject/valaccodegenerator.vala, compiler/valacompiler.vala,
  vapigen/valagidlparser.vala: move experimental null reference
  checking to separate visitor

svn path=/trunk/; revision=1221

22 files changed:
ChangeLog
compiler/valacompiler.vala
gobject/valaccodegenerator.vala
vala/Makefile.am
vala/valaarraytype.vala
vala/valaclasstype.vala
vala/valacodenode.vala
vala/valadatatype.vala
vala/valaerrortype.vala
vala/valaintegertype.vala
vala/valainterfacetype.vala
vala/valamethodtype.vala
vala/valanullchecker.vala [new file with mode: 0644]
vala/valanulltype.vala
vala/valaparser.vala
vala/valapointertype.vala
vala/valasemanticanalyzer.vala
vala/valasymbolresolver.vala
vala/valatypeparametertype.vala
vala/valaunresolvedtype.vala
vala/valavaluetype.vala
vapigen/valagidlparser.vala

index 6a77175..7b6a8a4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2008-04-14  Jürg Billeter  <j@bitron.ch>
+
+       * vala/Makefile.am, vala/valaarraytype.vala,
+         vala/valaclasstype.vala, vala/valacodenode.vala,
+         vala/valadatatype.vala, vala/valaerrortype.vala,
+         vala/valaintegertype.vala, vala/valainterfacetype.vala,
+         vala/valamethodtype.vala, vala/valanullchecker.vala,
+         vala/valanulltype.vala, vala/valaparser.vala,
+         vala/valapointertype.vala, vala/valasemanticanalyzer.vala,
+         vala/valasymbolresolver.vala, vala/valatypeparametertype.vala,
+         vala/valaunresolvedtype.vala, vala/valavaluetype.vala,
+         gobject/valaccodegenerator.vala, compiler/valacompiler.vala,
+         vapigen/valagidlparser.vala: move experimental null reference
+         checking to separate visitor
+
 2008-04-14  Marc-Andre Lureau  <marcandre.lureau@gmail.com>
 
        * vapi/glib-2.0.vapi (Value): renamed register_transform to
index 48a7f7e..4f79567 100644 (file)
@@ -252,6 +252,15 @@ class Vala.Compiler : Object {
                        return quit ();
                }
 
+               if (context.non_null_experimental) {
+                       var null_checker = new NullChecker ();
+                       null_checker.check (context);
+
+                       if (Report.get_errors () > 0) {
+                               return quit ();
+                       }
+               }
+
                var memory_manager = new MemoryManager ();
                memory_manager.analyze (context);
 
index 081eafe..84c2227 100644 (file)
@@ -1331,7 +1331,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
                // g_free (NULL) is allowed
                bool uses_gfree = (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free");
                uses_gfree = uses_gfree || type is ArrayType;
-               if ((context.non_null_experimental && !type.requires_null_check) || uses_gfree) {
+               if (uses_gfree) {
                        return new CCodeParenthesizedExpression (cassign);
                }
 
@@ -2700,7 +2700,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
 
                var ccall = new CCodeFunctionCall (dupexpr);
 
-               if (((context.non_null_experimental && !expr.static_type.requires_null_check) && expr.static_type.type_parameter == null) || expr is StringLiteral) {
+               if (expr is StringLiteral) {
                        // expression is non-null
                        ccall.add_argument ((CCodeExpression) expr.ccodenode);
                        
index 7b6f0ef..e4c23de 100644 (file)
@@ -90,6 +90,7 @@ libvalacore_la_VALASOURCES = \
        valanamedargument.vala \
        valanamespace.vala \
        valanamespacereference.vala \
+       valanullchecker.vala \
        valanullliteral.vala \
        valanulltype.vala \
        valaobjectcreationexpression.vala \
index b8e745f..12ba61b 100644 (file)
@@ -121,7 +121,6 @@ public class Vala.ArrayType : ReferenceType {
                result.takes_ownership = takes_ownership;
                result.is_out = is_out;
                result.nullable = nullable;
-               result.requires_null_check = requires_null_check;
                result.floating_reference = floating_reference;
                result.is_ref = is_ref;
                
@@ -144,7 +143,7 @@ public class Vala.ArrayType : ReferenceType {
                return element_type.to_string () + "[]";
        }
 
-       public override bool compatible (DataType target_type, bool enable_non_null) {
+       public override bool compatible (DataType target_type) {
                if (target_type is PointerType || (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null)) {
                        /* any array type can be cast to a generic pointer */
                        return true;
@@ -162,10 +161,6 @@ public class Vala.ArrayType : ReferenceType {
 
                if (element_type.compatible (target_array_type.element_type)
                    && target_array_type.element_type.compatible (element_type)) {
-                       if (requires_null_check && !target_type.nullable) {
-                               // incompatibility between null and non-null types
-                               return !enable_non_null;
-                       }
                        return true;
                }
 
index 94ef2f9..c20ee70 100644 (file)
@@ -43,7 +43,6 @@ public class Vala.ClassType : ReferenceType {
                result.takes_ownership = takes_ownership;
                result.is_out = is_out;
                result.nullable = nullable;
-               result.requires_null_check = requires_null_check;
                result.floating_reference = floating_reference;
                result.is_ref = is_ref;
                
index 4d65e1f..05ffa70 100644 (file)
@@ -32,13 +32,13 @@ public abstract class Vala.CodeNode : Object {
        /**
         * Parent of this code node.
         */
-       public weak CodeNode parent_node { get; set; }
+       public weak CodeNode? parent_node { get; set; }
 
        /**
         * References the location in the source file where this code node has
         * been written.
         */
-       public SourceReference source_reference { get; set; }
+       public SourceReference? source_reference { get; set; }
        
        /**
         * Contains all attributes that have been specified for this code node.
@@ -48,7 +48,7 @@ public abstract class Vala.CodeNode : Object {
        /**
         * Generated CCodeNode that corresponds to this code node.
         */
-       public CCodeNode ccodenode {
+       public CCodeNode? ccodenode {
                get {
                        return _ccodenode;
                }
@@ -66,7 +66,7 @@ public abstract class Vala.CodeNode : Object {
        /**
         * Binding to the generated code.
         */
-       public CodeBinding code_binding { get; set; }
+       public CodeBinding? code_binding { get; set; }
 
        /**
         * Specifies whether a fatal error has been detected in this code node.
@@ -117,7 +117,7 @@ public abstract class Vala.CodeNode : Object {
                return null;
        }
        
-       private CCodeNode _ccodenode;
+       private CCodeNode? _ccodenode;
 
        /**
         * Returns a string that represents this code node.
index 4b4ddec..f760adf 100644 (file)
@@ -51,12 +51,6 @@ public abstract class Vala.DataType : CodeNode {
        public bool nullable { get; set; }
 
        /**
-        * Specifies that the expression may not be dereferenced without
-        * prior null check.
-        */
-       public bool requires_null_check { get; set; }
-
-       /**
         * The referred data type.
         */
        public weak Typesymbol data_type { get; set; }
@@ -324,7 +318,7 @@ public abstract class Vala.DataType : CodeNode {
                }
        }
 
-       public virtual bool compatible (DataType target_type, bool enable_non_null = true) {
+       public virtual bool compatible (DataType target_type) {
                if (target_type is DelegateType && this is DelegateType) {
                        return ((DelegateType) target_type).delegate_symbol == ((DelegateType) this).delegate_symbol;
                }
@@ -361,10 +355,6 @@ public abstract class Vala.DataType : CodeNode {
                }
 
                if (data_type == target_type.data_type) {
-                       if (requires_null_check && !target_type.nullable && data_type != null && data_type.is_reference_type ()) {
-                               // incompatibility between null and non-null types
-                               return !enable_non_null;
-                       }
                        return true;
                }
 
@@ -386,10 +376,6 @@ public abstract class Vala.DataType : CodeNode {
                }
 
                if (data_type != null && target_type.data_type != null && data_type.is_subtype_of (target_type.data_type)) {
-                       if (requires_null_check && !target_type.nullable && data_type.is_reference_type ()) {
-                               // incompatibility between null and non-null types
-                               return !enable_non_null;
-                       }
                        return true;
                }
 
index 29651d7..1414152 100644 (file)
@@ -38,7 +38,7 @@ public class Vala.ErrorType : ReferenceType {
                this.source_reference = source_reference;
        }
 
-       public override bool compatible (DataType target_type, bool enable_non_null = true) {
+       public override bool compatible (DataType target_type) {
                /* temporarily ignore type parameters */
                if (target_type.type_parameter != null) {
                        return true;
index 04d51ac..b2bee55 100644 (file)
@@ -39,7 +39,7 @@ public class Vala.IntegerType : ValueType {
                return type;
        }
 
-       public override bool compatible (DataType target_type, bool enable_non_null = true) {
+       public override bool compatible (DataType target_type) {
                if (target_type.data_type is Struct && literal.get_type_name () == "int") {
                        // int literals are implicitly convertible to integer types
                        // of a lower rank if the value of the literal is within
@@ -59,6 +59,6 @@ public class Vala.IntegerType : ValueType {
                        }
                }
 
-               return base.compatible (target_type, enable_non_null);
+               return base.compatible (target_type);
        }
 }
index d728872..c154c57 100644 (file)
@@ -43,7 +43,6 @@ public class Vala.InterfaceType : ReferenceType {
                result.takes_ownership = takes_ownership;
                result.is_out = is_out;
                result.nullable = nullable;
-               result.requires_null_check = requires_null_check;
                result.floating_reference = floating_reference;
                result.is_ref = is_ref;
                
index 95c39c2..62fedf9 100644 (file)
@@ -49,7 +49,7 @@ public class Vala.MethodType : DataType {
                return new MethodType (method_symbol);
        }
 
-       public override bool compatible (DataType target_type, bool enable_non_null = true) {
+       public override bool compatible (DataType target_type) {
                var dt = target_type as DelegateType;
                if (dt == null) {
                        // method types incompatible to anything but delegates
diff --git a/vala/valanullchecker.vala b/vala/valanullchecker.vala
new file mode 100644 (file)
index 0000000..e38a324
--- /dev/null
@@ -0,0 +1,241 @@
+/* valanullchecker.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor checking null references.
+ */
+public class Vala.NullChecker : CodeVisitor {
+       private CodeContext context;
+
+       DataType current_return_type;
+
+       public NullChecker () {
+       }
+
+       public void check (CodeContext context) {
+               this.context = context;
+
+               context.accept (this);
+       }
+
+       void check_compatible (Expression expr, DataType target_type) {
+               if (!target_type.nullable) {
+                       if (expr.static_type is NullType) {
+                               Report.error (expr.source_reference, "`null' incompatible with `%s'".printf (target_type.to_string ()));
+                       } else if (expr.static_type.nullable) {
+                               Report.warning (expr.source_reference, "`%s' incompatible with `%s'".printf (expr.static_type.to_string (), target_type.to_string ()));
+                       }
+               }
+       }
+
+       void check_non_null (Expression expr) {
+               if (expr.static_type is NullType) {
+                       Report.error (expr.source_reference, "null dereference");
+               } else if (expr.static_type.nullable) {
+                       Report.warning (expr.source_reference, "possible null dereference");
+               }
+       }
+
+       public override void visit_source_file (SourceFile file) {
+               file.accept_children (this);
+       }
+
+       public override void visit_class (Class cl) {
+               cl.accept_children (this);
+       }
+
+       public override void visit_struct (Struct st) {
+               st.accept_children (this);
+       }
+
+       public override void visit_interface (Interface iface) {
+               iface.accept_children (this);
+       }
+
+       public override void visit_enum (Enum en) {
+               en.accept_children (this);
+       }
+
+       public override void visit_field (Field f) {
+               f.accept_children (this);
+       }
+
+       public override void visit_method (Method m) {
+               var old_return_type = current_return_type;
+               current_return_type = m.return_type;
+
+               m.accept_children (this);
+
+               current_return_type = old_return_type;
+       }
+
+       public override void visit_creation_method (CreationMethod m) {
+               m.accept_children (this);
+       }
+
+       public override void visit_formal_parameter (FormalParameter p) {
+               p.accept_children (this);
+
+               if (p.default_expression != null) {
+                       check_compatible (p.default_expression, p.type_reference);
+               }
+       }
+
+       public override void visit_property (Property prop) {
+               prop.accept_children (this);
+       }
+
+       public override void visit_property_accessor (PropertyAccessor acc) {
+               acc.accept_children (this);
+       }
+
+       public override void visit_constructor (Constructor c) {
+               c.accept_children (this);
+       }
+
+       public override void visit_destructor (Destructor d) {
+               d.accept_children (this);
+       }
+
+       public override void visit_block (Block b) {
+               b.accept_children (this);
+       }
+
+       public override void visit_variable_declarator (VariableDeclarator decl) {
+               decl.accept_children (this);
+
+               if (decl.initializer != null) {
+                       check_compatible (decl.initializer, decl.type_reference);
+               }
+       }
+
+       public override void visit_if_statement (IfStatement stmt) {
+               stmt.accept_children (this);
+
+               check_non_null (stmt.condition);
+       }
+
+       public override void visit_switch_section (SwitchSection section) {
+               section.accept_children (this);
+       }
+
+       public override void visit_while_statement (WhileStatement stmt) {
+               stmt.accept_children (this);
+
+               check_non_null (stmt.condition);
+       }
+
+       public override void visit_do_statement (DoStatement stmt) {
+               stmt.accept_children (this);
+
+               check_non_null (stmt.condition);
+       }
+
+       public override void visit_for_statement (ForStatement stmt) {
+               stmt.accept_children (this);
+
+               check_non_null (stmt.condition);
+       }
+
+       public override void visit_foreach_statement (ForeachStatement stmt) {
+               stmt.accept_children (this);
+
+               check_non_null (stmt.collection);
+       }
+
+       public override void visit_return_statement (ReturnStatement stmt) {
+               stmt.accept_children (this);
+
+               if (stmt.return_expression != null) {
+                       check_compatible (stmt.return_expression, current_return_type);
+               }
+       }
+
+       public override void visit_throw_statement (ThrowStatement stmt) {
+               stmt.accept_children (this);
+
+               check_non_null (stmt.error_expression);
+       }
+
+       public override void visit_try_statement (TryStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_catch_clause (CatchClause clause) {
+               clause.accept_children (this);
+       }
+
+       public override void visit_delete_statement (DeleteStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_invocation_expression (InvocationExpression expr) {
+               expr.accept_children (this);
+
+               var mtype = expr.call.static_type as MethodType;
+               var ma = expr.call as MemberAccess;
+               if (mtype != null && mtype.method_symbol.instance && ma != null) {
+                       if (ma.inner == null) {
+                               // implicit this call, always non-null
+                       } else {
+                               check_non_null (ma.inner);
+                       }
+               }
+       }
+
+       public override void visit_element_access (ElementAccess expr) {
+               check_non_null (expr.container);
+       }
+
+       public override void visit_postfix_expression (PostfixExpression expr) {
+               check_non_null (expr.inner);
+       }
+
+       public override void visit_unary_expression (UnaryExpression expr) {
+               switch (expr.operator) {
+               case UnaryOperator.PLUS:
+               case UnaryOperator.MINUS:
+               case UnaryOperator.LOGICAL_NEGATION:
+               case UnaryOperator.BITWISE_COMPLEMENT:
+               case UnaryOperator.INCREMENT:
+               case UnaryOperator.DECREMENT:
+                       check_non_null (expr.inner);
+                       break;
+               }
+       }
+
+       public override void visit_conditional_expression (ConditionalExpression expr) {
+               check_non_null (expr.condition);
+       }
+
+       public override void visit_lambda_expression (LambdaExpression l) {
+               l.accept_children (this);
+       }
+
+       public override void visit_assignment (Assignment a) {
+               a.accept_children (this);
+
+               check_compatible (a.right, a.left.static_type);
+       }
+}
index 47655aa..8c7a157 100644 (file)
@@ -30,7 +30,7 @@ public class Vala.NullType : ReferenceType {
                this.source_reference = source_reference;
        }
 
-       public override bool compatible (DataType target_type, bool enable_non_null = true) {
+       public override bool compatible (DataType target_type) {
                if (!(target_type is PointerType) && (target_type is NullType || (target_type.data_type == null && target_type.type_parameter == null))) {
                        return true;
                }
@@ -47,8 +47,7 @@ public class Vala.NullType : ReferenceType {
                if (target_type.data_type.is_reference_type () ||
                    target_type is ArrayType ||
                    target_type is DelegateType) {
-                       // incompatibility between null and non-null types
-                       return !enable_non_null;
+                       return true;
                }
 
                /* null is not compatible with any other type (i.e. value types) */
index 503d61e..42880a8 100644 (file)
@@ -390,7 +390,6 @@ public class Vala.Parser : CodeVisitor {
                type.pointer_level = stars;
                type.array_rank = array_rank;
                type.nullable = nullable;
-               type.requires_null_check = nullable;
                type.transfers_ownership = transfers_ownership;
                return type;
        }
@@ -1263,8 +1262,6 @@ public class Vala.Parser : CodeVisitor {
                        if (!((UnresolvedType) type).is_weak) {
                                type.takes_ownership = true;
                        }
-                       type.requires_null_check = false;
-                       type.nullable = true;
                        decl = context.create_local_variable_declaration (type, get_src (begin));
                        foreach (VariableDeclarator var_decl in declarators) {
                                var_decl.type_reference = type.copy ();
index 6571142..1c35c7e 100644 (file)
@@ -52,7 +52,7 @@ public class Vala.PointerType : DataType {
                return new PointerType (base_type);
        }
 
-       public override bool compatible (DataType target_type, bool enable_non_null = true) {
+       public override bool compatible (DataType target_type) {
                if (target_type is PointerType || (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null)) {
                        return true;
                }
@@ -64,7 +64,7 @@ public class Vala.PointerType : DataType {
 
                if (base_type.is_reference_type_or_type_parameter ()) {
                        // Object* is compatible with Object if Object is a reference type
-                       return base_type.compatible (target_type, enable_non_null);
+                       return base_type.compatible (target_type);
                }
 
                return false;
index 3172ff0..b48a827 100644 (file)
@@ -904,13 +904,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        if (unary != null && (unary.operator == UnaryOperator.REF || unary.operator == UnaryOperator.OUT)) {
                                // TODO check type for ref and out expressions
                        } else if (!e.static_type.compatible (e.expected_type)) {
-                               if (!e.static_type.compatible (e.expected_type, false)) {
-                                       error = true;
-                                       e.error = true;
-                                       Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.expected_type.to_string (), e.static_type.to_string ()));
-                               } else if (context.non_null_experimental) {
-                                       Report.warning (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.expected_type.to_string (), e.static_type.to_string ()));
-                               }
+                               error = true;
+                               e.error = true;
+                               Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.expected_type.to_string (), e.static_type.to_string ()));
                        }
                }
 
@@ -1061,12 +1057,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        var array_type = (ArrayType) collection_type;
                        element_data_type = array_type.element_type;
                        need_type_check = true;
-               } else if (collection_type.compatible (glist_type, false) || collection_type.compatible (gslist_type, false)) {         
+               } else if (collection_type.compatible (glist_type) || collection_type.compatible (gslist_type)) {
                        if (collection_type.get_type_arguments ().size > 0) {
                                element_data_type = (DataType) collection_type.get_type_arguments ().get (0);
                                need_type_check = true;
                        }
-               } else if (iterable_type != null && collection_type.compatible (iterable_type, false)) {
+               } else if (iterable_type != null && collection_type.compatible (iterable_type)) {
                        stmt.iterator_variable_declarator = new VariableDeclarator ("%s_it".printf (stmt.variable_name));
                        stmt.iterator_variable_declarator.type_reference = new InterfaceType (iterator_type);
                        stmt.iterator_variable_declarator.type_reference.takes_ownership = true;
@@ -1131,12 +1127,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
                if (stmt.return_expression != null &&
                     !stmt.return_expression.static_type.compatible (current_return_type)) {
-                       if (!stmt.return_expression.static_type.compatible (current_return_type, false)) {
-                               Report.error (stmt.source_reference, "Return: Cannot convert from `%s' to `%s'".printf (stmt.return_expression.static_type.to_string (), current_return_type.to_string ()));
-                               return;
-                       } else if (context.non_null_experimental) {
-                               Report.warning (stmt.source_reference, "Return value may not be null");
-                       }
+                       Report.error (stmt.source_reference, "Return: Cannot convert from `%s' to `%s'".printf (stmt.return_expression.static_type.to_string (), current_return_type.to_string ()));
+                       return;
                }
 
                if (stmt.return_expression != null &&
@@ -1815,13 +1807,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                                return false;
                                        }
                                } else if (!arg.static_type.compatible (param.type_reference)) {
-                                       if (!arg.static_type.compatible (param.type_reference, false)) {
-                                               expr.error = true;
-                                               Report.error (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.to_string (), param.type_reference.to_string ()));
-                                               return false;
-                                       } else if (context.non_null_experimental) {
-                                               Report.warning (expr.source_reference, "Argument %d: Argument may not be null".printf (i + 1));
-                                       }
+                                       expr.error = true;
+                                       Report.error (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.to_string (), param.type_reference.to_string ()));
+                                       return false;
                                } else {
                                        // 0 => null, 1 => in, 2 => ref, 3 => out
                                        int arg_type = 1;
@@ -2681,15 +2669,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
                        if (!expr.right.static_type.compatible (expr.left.static_type)
                            && !expr.left.static_type.compatible (expr.right.static_type)) {
-                               if (!expr.right.static_type.compatible (expr.left.static_type, false)
-                                   && !expr.left.static_type.compatible (expr.right.static_type, false)) {
-                                       Report.error (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible".printf (expr.right.static_type.to_string (), expr.left.static_type.to_string ()));
-                                       expr.error = true;
-                                       return;
-                               } else if (context.non_null_experimental) {
-                                       // warn about incompatibility between null and non-null types
-                                       Report.warning (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible".printf (expr.right.static_type.to_string (), expr.left.static_type.to_string ()));
-                               }
+                               Report.error (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible".printf (expr.right.static_type.to_string (), expr.left.static_type.to_string ()));
+                               expr.error = true;
+                               return;
                        }
 
                        if (expr.left.static_type.compatible (string_type)
@@ -3010,14 +2992,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                 * i.e. a.{left|right}.static_type == null, skip type check */
 
                                if (!a.right.static_type.compatible (a.left.static_type)) {
-                                       if (!a.right.static_type.compatible (a.left.static_type, false)) {
-                                               a.error = true;
-                                               Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
-                                               return;
-                                       } else if (context.non_null_experimental) {
-                                               // warn about incompatibility between null and non-null types
-                                               Report.warning (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
-                                       }
+                                       a.error = true;
+                                       Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
+                                       return;
                                }
 
                                if (a.right.static_type.transfers_ownership) {
@@ -3038,14 +3015,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        var ea = (ElementAccess) a.left;
 
                        if (!a.right.static_type.compatible (a.left.static_type)) {
-                               if (!a.right.static_type.compatible (a.left.static_type, false)) {
-                                       a.error = true;
-                                       Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
-                                       return;
-                               } else if (context.non_null_experimental) {
-                                       // warn about incompatibility between null and non-null types
-                                       Report.warning (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
-                               }
+                               a.error = true;
+                               Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
+                               return;
                        }
 
                        if (a.right.static_type.transfers_ownership) {
index b71afd9..082d89d 100644 (file)
@@ -270,7 +270,6 @@ public class Vala.SymbolResolver : CodeVisitor {
                type.is_ref = unresolved_type.is_ref;
                type.is_out = unresolved_type.is_out;
                type.nullable = unresolved_type.nullable;
-               type.requires_null_check = unresolved_type.requires_null_check;
                foreach (DataType type_arg in unresolved_type.get_type_arguments ()) {
                        type.add_type_argument (type_arg);
                }
@@ -292,11 +291,6 @@ public class Vala.SymbolResolver : CodeVisitor {
                         */
                        type.takes_ownership = false;
                        type.transfers_ownership = false;
-
-                       /* reset nullable of value-types for local variables */
-                       if (type.nullable && !type.requires_null_check) {
-                               type.nullable = false;
-                       }
                }
 
                /* check for array */
@@ -306,7 +300,6 @@ public class Vala.SymbolResolver : CodeVisitor {
                        element_type.is_ref = false;
                        element_type.is_out = false;
                        element_type.nullable = false;
-                       element_type.requires_null_check = false;
 
                        type = new ArrayType (element_type, unresolved_type.array_rank, unresolved_type.source_reference);
                        type.add_type_argument (element_type);
@@ -316,7 +309,6 @@ public class Vala.SymbolResolver : CodeVisitor {
                        type.is_ref = unresolved_type.is_ref;
                        type.is_out = unresolved_type.is_out;
                        type.nullable = unresolved_type.nullable;
-                       type.requires_null_check = unresolved_type.nullable;
                }
 
                return type;
@@ -334,6 +326,9 @@ public class Vala.SymbolResolver : CodeVisitor {
 
        public override void visit_variable_declarator (VariableDeclarator decl) {
                decl.accept_children (this);
+               if (decl.type_reference is ReferenceType) {
+                       decl.type_reference.nullable = true;
+               }
        }
 
        public override void visit_initializer_list (InitializerList list) {
index eee2b73..0cb12aa 100644 (file)
@@ -37,7 +37,6 @@ public class Vala.TypeParameterType : DataType {
                result.takes_ownership = takes_ownership;
                result.is_out = is_out;
                result.nullable = nullable;
-               result.requires_null_check = requires_null_check;
                result.floating_reference = floating_reference;
                result.is_ref = is_ref;
 
index 97de2ea..10f06b3 100644 (file)
@@ -109,7 +109,6 @@ public class Vala.UnresolvedType : DataType {
                result.takes_ownership = takes_ownership;
                result.is_out = is_out;
                result.nullable = nullable;
-               result.requires_null_check = requires_null_check;
                result.unresolved_symbol = unresolved_symbol.copy ();
                result.array_rank = array_rank;
                result.pointer_level = pointer_level;
index 43b07c9..29f582f 100644 (file)
@@ -43,7 +43,6 @@ public class Vala.ValueType : DataType {
                result.takes_ownership = takes_ownership;
                result.is_out = is_out;
                result.nullable = nullable;
-               result.requires_null_check = requires_null_check;
                result.floating_reference = floating_reference;
                result.is_ref = is_ref;
                
index 8d2c565..e21f6bd 100644 (file)
@@ -1336,7 +1336,6 @@ public class Vala.GIdlParser : CodeVisitor {
                                        } else if (nv[0] == "nullable") {
                                                if (eval (nv[1]) == "1") {
                                                        param_type.nullable = true;
-                                                       param_type.requires_null_check = true;
                                                }
                                        } else if (nv[0] == "transfer_ownership") {
                                                if (eval (nv[1]) == "1") {
@@ -1683,7 +1682,6 @@ public class Vala.GIdlParser : CodeVisitor {
                                        } else if (nv[0] == "nullable") {
                                                if (eval (nv[1]) == "1") {
                                                        param_type.nullable = true;
-                                                       param_type.requires_null_check = true;
                                                }
                                        } else if (nv[0] == "type_name") {
                                                param_type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));