From b261df87989167862fb63387d4b07dfd923e322d Mon Sep 17 00:00:00 2001 From: Juerg Billeter Date: Sat, 15 Dec 2007 11:54:52 +0000 Subject: [PATCH] update to be compatible with new pointer types 2007-12-15 Juerg Billeter * gee/hashmap.vala, gee/hashset.vala: update to be compatible with new pointer types * vala/parser.y, vala/vala.h, vala/valaclass.vala, vala/valadatatype.vala, vala/valamemorymanager.vala, vala/valanulltype.vala, vala/valapointertype.vala, vala/valasemanticanalyzer.vala, vala/valasymbolresolver.vala, vala/valavoidtype.vala, gobject/valaccodegenerator.vala, gobject/valaccodegeneratormethod.vala: use PointerType svn path=/trunk/; revision=774 --- ChangeLog | 12 +++++++++ gee/hashmap.vala | 24 ++++++++--------- gee/hashset.vala | 18 ++++++------- gobject/valaccodegenerator.vala | 8 +++--- gobject/valaccodegeneratormethod.vala | 18 ++++++------- vala/parser.y | 49 +++++++++++++++++++++++++++++------ vala/vala.h | 2 ++ vala/valaclass.vala | 6 +++-- vala/valadatatype.vala | 7 ++--- vala/valamemorymanager.vala | 40 ++++++++++++++++------------ vala/valanulltype.vala | 21 +++++++++++++++ vala/valapointertype.vala | 31 +++++++++++++++++++++- vala/valasemanticanalyzer.vala | 33 ++++++++++++----------- vala/valasymbolresolver.vala | 16 ++---------- vala/valavoidtype.vala | 4 +++ 15 files changed, 194 insertions(+), 95 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5527f11..15c8da3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2007-12-15 Jürg Billeter + * gee/hashmap.vala, gee/hashset.vala: update to be compatible with new + pointer types + + * vala/parser.y, vala/vala.h, vala/valaclass.vala, + vala/valadatatype.vala, vala/valamemorymanager.vala, + vala/valanulltype.vala, vala/valapointertype.vala, + vala/valasemanticanalyzer.vala, vala/valasymbolresolver.vala, + vala/valavoidtype.vala, gobject/valaccodegenerator.vala, + gobject/valaccodegeneratormethod.vala: use PointerType + +2007-12-15 Jürg Billeter + * vala/Makefile.am, vala/valaarraytype.vala, vala/valaclass.vala, vala/valaclasstype.vala, vala/valainterface.vala, vala/valainterfacetype.vala, vala/valareferencetype.vala, diff --git a/gee/hashmap.vala b/gee/hashmap.vala index 3557199..c6b3377 100644 --- a/gee/hashmap.vala +++ b/gee/hashmap.vala @@ -74,22 +74,22 @@ public class Gee.HashMap : Object, Map { return new ValueCollection (this); } - private Node* lookup_node (K key) { + private Node** lookup_node (K key) { uint hash_value = _key_hash_func (key); - Node* node = &_nodes[hash_value % _array_size]; - while ((*node) != null && (hash_value != (*node).key_hash || !_key_equal_func ((*node).key, key))) { - node = &((*node).next); + Node** node = &_nodes[hash_value % _array_size]; + while ((*node) != null && (hash_value != ((Node) (*node)).key_hash || !_key_equal_func (((Node) (*node)).key, key))) { + node = &(((Node) (*node)).next); } return node; } public bool contains (K key) { - Node* node = lookup_node (key); + Node** node = lookup_node (key); return (*node != null); } public V get (K key) { - weak Node node = *lookup_node (key); + weak Node node = (Node) (*lookup_node (key)); if (node != null) { return node.value; } else { @@ -98,9 +98,9 @@ public class Gee.HashMap : Object, Map { } public void set (K key, V value) { - Node* node = lookup_node (key); + Node** node = lookup_node (key); if (*node != null) { - (*node).value = value; + ((Node) (*node)).value = value; } else { uint hash_value = _key_hash_func (key); *node = new Node (key, value, hash_value); @@ -111,11 +111,11 @@ public class Gee.HashMap : Object, Map { } public bool remove (K key) { - Node* node = lookup_node (key); + Node** node = lookup_node (key); if (*node != null) { - (*node).key = null; - (*node).value = null; - *node = (*node).next; + ((Node) (*node)).key = null; + ((Node) (*node)).value = null; + *node = ((Node) (*node)).next; _nnodes--; resize (); _stamp++; diff --git a/gee/hashset.vala b/gee/hashset.vala index b901c7f..a01b810 100644 --- a/gee/hashset.vala +++ b/gee/hashset.vala @@ -61,17 +61,17 @@ public class Gee.HashSet : Object, Iterable, Collection, Set { _nodes = new Node[_array_size]; } - private Node* lookup_node (G key) { + private Node** lookup_node (G key) { uint hash_value = _hash_func (key); - Node* node = &_nodes[hash_value % _array_size]; - while ((*node) != null && (hash_value != (*node).key_hash || !_equal_func ((*node).key, key))) { - node = &((*node).next); + Node** node = &_nodes[hash_value % _array_size]; + while ((*node) != null && (hash_value != ((Node) (*node)).key_hash || !_equal_func (((Node) (*node)).key, key))) { + node = &(((Node) (*node)).next); } return node; } public bool contains (G key) { - Node* node = lookup_node (key); + Node** node = lookup_node (key); return (*node != null); } @@ -80,7 +80,7 @@ public class Gee.HashSet : Object, Iterable, Collection, Set { } public bool add (G key) { - Node* node = lookup_node (key); + Node** node = lookup_node (key); if (*node != null) { return false; } else { @@ -94,10 +94,10 @@ public class Gee.HashSet : Object, Iterable, Collection, Set { } public bool remove (G key) { - Node* node = lookup_node (key); + Node** node = lookup_node (key); if (*node != null) { - (*node).key = null; - *node = (*node).next; + ((Node) (*node)).key = null; + *node = ((Node) (*node)).next; _nnodes--; resize (); _stamp++; diff --git a/gobject/valaccodegenerator.vala b/gobject/valaccodegenerator.vala index 0d61f3f..84e85ba 100644 --- a/gobject/valaccodegenerator.vala +++ b/gobject/valaccodegenerator.vala @@ -1206,7 +1206,7 @@ public class Vala.CCodeGenerator : CodeGenerator { cerror_block.add_statement (new CCodeExpressionStatement (cpropagate)); if (current_return_type != null && current_return_type.data_type != null) { - cerror_block.add_statement (new CCodeReturnStatement (default_value_for_type (current_return_type.data_type))); + cerror_block.add_statement (new CCodeReturnStatement (default_value_for_type (current_return_type))); } else { cerror_block.add_statement (new CCodeReturnStatement ()); } @@ -1913,7 +1913,7 @@ public class Vala.CCodeGenerator : CodeGenerator { temp_ref_vars.clear (); if (current_return_type != null && current_return_type.data_type != null) { - cfrag.append (new CCodeReturnStatement (default_value_for_type (current_return_type.data_type))); + cfrag.append (new CCodeReturnStatement (default_value_for_type (current_return_type))); } else { cfrag.append (new CCodeReturnStatement ()); } @@ -2746,9 +2746,9 @@ public class Vala.CCodeGenerator : CodeGenerator { return cexpr; } - if (context.checking && target_type.data_type.is_subtype_of (gtypeinstance_type)) { + if (context.checking && target_type.data_type != null && target_type.data_type.is_subtype_of (gtypeinstance_type)) { return new InstanceCast (cexpr, target_type.data_type); - } else if (target_type.data_type.is_reference_type () && expression_type.get_cname () != target_type.get_cname ()) { + } else if (target_type.data_type != null && target_type.data_type.is_reference_type () && expression_type.get_cname () != target_type.get_cname ()) { return new CCodeCastExpression (cexpr, target_type.get_cname ()); } else { return cexpr; diff --git a/gobject/valaccodegeneratormethod.vala b/gobject/valaccodegeneratormethod.vala index 6d643ad..981d510 100644 --- a/gobject/valaccodegeneratormethod.vala +++ b/gobject/valaccodegeneratormethod.vala @@ -541,18 +541,18 @@ public class Vala.CCodeGenerator { } private CCodeStatement create_method_type_check_statement (Method! m, DataType! return_type, Typesymbol! t, bool non_null, string! var_name) { - return create_type_check_statement (m, return_type.data_type, t, non_null, var_name); + return create_type_check_statement (m, return_type, t, non_null, var_name); } private CCodeStatement create_property_type_check_statement (Property! prop, bool getter, Typesymbol! t, bool non_null, string! var_name) { if (getter) { - return create_type_check_statement (prop, prop.type_reference.data_type, t, non_null, var_name); + return create_type_check_statement (prop, prop.type_reference, t, non_null, var_name); } else { - return create_type_check_statement (prop, null, t, non_null, var_name); + return create_type_check_statement (prop, new VoidType (), t, non_null, var_name); } } - private CCodeStatement create_type_check_statement (CodeNode! method_node, Typesymbol ret_type, Typesymbol! t, bool non_null, string! var_name) { + private CCodeStatement create_type_check_statement (CodeNode! method_node, DataType ret_type, Typesymbol! t, bool non_null, string! var_name) { var ccheck = new CCodeFunctionCall (); if ((t is Class && ((Class) t).is_subtype_of (gobject_type)) || (t is Interface && !((Interface) t).declaration_only)) { @@ -573,7 +573,7 @@ public class Vala.CCodeGenerator { ccheck.add_argument (cnonnull); } - if (ret_type == null) { + if (ret_type is VoidType) { /* void function */ ccheck.call = new CCodeIdentifier ("g_return_if_fail"); } else { @@ -591,11 +591,11 @@ public class Vala.CCodeGenerator { return new CCodeExpressionStatement (ccheck); } - private CCodeExpression default_value_for_type (Typesymbol! type) { - if (type.is_reference_type () || type is Pointer) { + private CCodeExpression default_value_for_type (DataType! type) { + if ((type.data_type != null && type.data_type.is_reference_type ()) || type is PointerType || type.data_type is Pointer) { return new CCodeConstant ("NULL"); - } else if (type.get_default_value () != null) { - return new CCodeConstant (type.get_default_value ()); + } else if (type.data_type != null && type.data_type.get_default_value () != null) { + return new CCodeConstant (type.data_type.get_default_value ()); } return null; } diff --git a/vala/parser.y b/vala/parser.y index d24ea2a..6c4eb7c 100644 --- a/vala/parser.y +++ b/vala/parser.y @@ -566,6 +566,18 @@ type { $$ = VALA_DATA_TYPE (vala_void_type_new ()); } + | VOID stars + { + int pointer_level; + + $$ = VALA_DATA_TYPE (vala_void_type_new ()); + + for (pointer_level = $2; pointer_level > 0; pointer_level--) { + ValaDataType *base_type = $$; + $$ = VALA_DATA_TYPE (vala_pointer_type_new (base_type)); + g_object_unref (base_type); + } + } ; opt_argument_list @@ -1854,6 +1866,25 @@ local_variable_type vala_unresolved_type_set_non_null (VALA_UNRESOLVED_TYPE ($$), TRUE); } } + | VOID + { + ValaSourceReference *src = src(@1); + $$ = VALA_DATA_TYPE (vala_void_type_new ()); + g_object_unref (src); + } + | VOID stars + { + int pointer_level; + ValaSourceReference *src = src(@1); + $$ = VALA_DATA_TYPE (vala_void_type_new ()); + g_object_unref (src); + + for (pointer_level = $2; pointer_level > 0; pointer_level--) { + ValaDataType *base_type = $$; + $$ = VALA_DATA_TYPE (vala_pointer_type_new (base_type)); + g_object_unref (base_type); + } + } ; opt_op_neg @@ -2706,8 +2737,8 @@ class_member_declaration } | field_declaration { - /* skip declarations with errors */ - if ($1 != NULL) { + /* skip declarations with errors */ + if ($1 != NULL) { vala_class_add_field (VALA_CLASS (symbol_stack->data), $1); g_object_unref ($1); } @@ -2777,12 +2808,14 @@ field_declaration src = src_com(@5, $1); - if (vala_unresolved_type_get_is_ref (VALA_UNRESOLVED_TYPE ($5)) || vala_unresolved_type_get_is_out (VALA_UNRESOLVED_TYPE ($5))) { - vala_report_error (src, "`ref' and `out' may only be used for parameters."); - } - if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($5))) { - vala_unresolved_type_set_takes_ownership (VALA_UNRESOLVED_TYPE ($5), TRUE); - } + if (VALA_IS_UNRESOLVED_TYPE ($5)) { + if (vala_unresolved_type_get_is_ref (VALA_UNRESOLVED_TYPE ($5)) || vala_unresolved_type_get_is_out (VALA_UNRESOLVED_TYPE ($5))) { + vala_report_error (src, "`ref' and `out' may only be used for parameters."); + } + if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($5))) { + vala_unresolved_type_set_takes_ownership (VALA_UNRESOLVED_TYPE ($5), TRUE); + } + } $$ = vala_code_context_create_field (context, vala_symbol_get_name (VALA_SYMBOL ($6)), $5, vala_variable_declarator_get_initializer ($6), src); g_object_unref (src); diff --git a/vala/vala.h b/vala/vala.h index 40a2af0..2e242fd 100644 --- a/vala/vala.h +++ b/vala/vala.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -79,4 +80,5 @@ #include #include #include +#include #include diff --git a/vala/valaclass.vala b/vala/valaclass.vala index 00f3fe0..935f16d 100644 --- a/vala/valaclass.vala +++ b/vala/valaclass.vala @@ -164,8 +164,10 @@ public class Vala.Class : Typesymbol { * @param f a field */ public void add_field (Field! f) { - // non_null fields not yet supported due to initialization issues - ((UnresolvedType) f.type_reference).non_null = false; + if (f.type_reference is UnresolvedType) { + // non_null fields not yet supported due to initialization issues + ((UnresolvedType) f.type_reference).non_null = false; + } fields.add (f); if (f.access == SymbolAccessibility.PRIVATE && f.instance) { _has_private_fields = true; diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala index 9569db5..3d1acf2 100644 --- a/vala/valadatatype.vala +++ b/vala/valadatatype.vala @@ -337,13 +337,14 @@ public class Vala.DataType : CodeNode { } /* only null is compatible to null */ - if (target_type.data_type == null && target_type.type_parameter == null) { - return (data_type == null && target_type.type_parameter == null); + if (!(target_type is PointerType) && target_type.data_type == null && target_type.type_parameter == null) { + return (data_type == null && type_parameter == null); } if (data_type == null) { /* null can be cast to any reference or array type or pointer type */ if (target_type.type_parameter != null || + target_type is PointerType || target_type.data_type.is_reference_type () || target_type.is_out || target_type.data_type is Pointer || @@ -357,7 +358,7 @@ public class Vala.DataType : CodeNode { return false; } - if (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null) { + if (target_type is PointerType || (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null)) { /* any reference or array type or pointer type can be cast to a generic pointer */ if (type_parameter != null || data_type.is_reference_type () || diff --git a/vala/valamemorymanager.vala b/vala/valamemorymanager.vala index 21fdf31..0af9c05 100644 --- a/vala/valamemorymanager.vala +++ b/vala/valamemorymanager.vala @@ -78,10 +78,12 @@ public class Vala.MemoryManager : CodeVisitor { public override void visit_field (Field! f) { if (f.initializer != null) { - if (f.type_reference.takes_ownership) { - visit_possibly_missing_copy_expression (f.initializer); - } else { - visit_possibly_leaked_expression (f.initializer); + if (!(f.type_reference is PointerType)) { + if (f.type_reference.takes_ownership) { + visit_possibly_missing_copy_expression (f.initializer); + } else { + visit_possibly_leaked_expression (f.initializer); + } } } } @@ -129,10 +131,12 @@ public class Vala.MemoryManager : CodeVisitor { decl.accept_children (this); if (decl.initializer != null) { - if (decl.type_reference.takes_ownership) { - visit_possibly_missing_copy_expression (decl.initializer); - } else { - visit_possibly_leaked_expression (decl.initializer); + if (!(decl.type_reference is PointerType)) { + if (decl.type_reference.takes_ownership) { + visit_possibly_missing_copy_expression (decl.initializer); + } else { + visit_possibly_leaked_expression (decl.initializer); + } } } } @@ -160,10 +164,12 @@ public class Vala.MemoryManager : CodeVisitor { if (current_symbol is Method) { var m = (Method) current_symbol; - if (m.return_type.transfers_ownership) { - visit_possibly_missing_copy_expression (stmt.return_expression); - } else { - visit_possibly_leaked_expression (stmt.return_expression); + if (!(m.return_type is PointerType)) { + if (m.return_type.transfers_ownership) { + visit_possibly_missing_copy_expression (stmt.return_expression); + } else { + visit_possibly_leaked_expression (stmt.return_expression); + } } } else { /* property get accessor */ @@ -287,10 +293,12 @@ public class Vala.MemoryManager : CodeVisitor { if (a.left is PointerIndirection || a.left.symbol_reference is Signal) { } else { - if (a.left.static_type.takes_ownership) { - visit_possibly_missing_copy_expression (a.right); - } else { - visit_possibly_leaked_expression (a.right); + if (!(a.left.static_type is PointerType)) { + if (a.left.static_type.takes_ownership) { + visit_possibly_missing_copy_expression (a.right); + } else { + visit_possibly_leaked_expression (a.right); + } } } } diff --git a/vala/valanulltype.vala b/vala/valanulltype.vala index 2efbaaa..3be0201 100644 --- a/vala/valanulltype.vala +++ b/vala/valanulltype.vala @@ -28,4 +28,25 @@ using GLib; public class Vala.NullType : ReferenceType { public NullType () { } + + 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; + } + + /* null can be cast to any reference or array type or pointer type */ + if (target_type.type_parameter != null || + target_type is PointerType || + target_type.data_type.is_reference_type () || + target_type.is_out || + target_type.data_type is Pointer || + target_type.data_type is Array || + target_type.data_type is Callback || + target_type.data_type.get_attribute ("PointerType") != null) { + return true; + } + + /* null is not compatible with any other type (i.e. value types) */ + return false; + } } diff --git a/vala/valapointertype.vala b/vala/valapointertype.vala index f8cf00a..9851a2a 100644 --- a/vala/valapointertype.vala +++ b/vala/valapointertype.vala @@ -29,8 +29,37 @@ public class Vala.PointerType : DataType { /** * The base type the pointer is referring to. */ - public weak DataType base_type { get; set; } + public DataType base_type { get; set; } public PointerType (construct DataType! base_type) { } + + public override string! to_string () { + return base_type.to_string () + "*"; + } + + public override string get_cname (bool var_type = false, bool const_type = false) { + if (base_type.data_type != null && base_type.data_type.is_reference_type ()) { + return base_type.get_cname (var_type, const_type); + } else { + return base_type.get_cname (var_type, const_type) + "*"; + } + } + + public override DataType! copy () { + return new PointerType (base_type); + } + + 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; + } + + /* temporarily ignore type parameters */ + if (target_type.type_parameter != null) { + return true; + } + + return false; + } } diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 9f8bb55..6baf0bc 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -708,7 +708,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { if (memory_management) { if (decl.initializer.static_type.transfers_ownership) { /* rhs transfers ownership of the expression */ - if (!decl.type_reference.takes_ownership) { + if (!(decl.type_reference is PointerType) && !decl.type_reference.takes_ownership) { /* lhs doesn't own the value */ decl.error = true; Report.error (decl.source_reference, "Invalid assignment from owned expression to unowned variable"); @@ -942,15 +942,13 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return; } - if (stmt.return_expression == null && current_return_type.data_type != null) { + if (stmt.return_expression == null && !(current_return_type is VoidType)) { stmt.error = true; Report.error (stmt.source_reference, "Return without value in non-void function"); return; } - if (stmt.return_expression != null && - current_return_type.data_type == null && - current_return_type.type_parameter == null) { + if (stmt.return_expression != null && current_return_type is VoidType) { Report.error (stmt.source_reference, "Return with value in void function"); return; } @@ -2080,17 +2078,20 @@ public class Vala.SemanticAnalyzer : CodeVisitor { Report.error (expr.source_reference, "internal error: unknown type of inner expression"); return; } - if (!(expr.inner.static_type.data_type is Pointer)) { + if (expr.inner.static_type is PointerType) { + var pointer_type = (PointerType) expr.inner.static_type; + expr.static_type = pointer_type.base_type; + } else if (expr.inner.static_type.data_type is Pointer) { + var pointer = (Pointer) expr.inner.static_type.data_type; + + expr.static_type = new DataType (); + expr.static_type.data_type = pointer.referent_type; + expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership; + } else { expr.error = true; Report.error (expr.source_reference, "Pointer indirection not supported for this expression"); return; } - - var pointer = (Pointer) expr.inner.static_type.data_type; - - expr.static_type = new DataType (); - expr.static_type.data_type = pointer.referent_type; - expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership; } public override void visit_addressof_expression (AddressofExpression! expr) { @@ -2108,9 +2109,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return; } - expr.static_type = new DataType (); - expr.static_type.data_type = expr.inner.static_type.data_type.get_pointer (); - expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership; + expr.static_type = new PointerType (expr.inner.static_type); } public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) { @@ -2707,7 +2706,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { if (memory_management) { if (a.right.static_type.transfers_ownership) { /* rhs transfers ownership of the expression */ - if (!a.left.static_type.takes_ownership) { + if (!(a.left.static_type is PointerType) && !a.left.static_type.takes_ownership) { /* lhs doesn't own the value */ a.error = true; Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable"); @@ -2743,7 +2742,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } var element_type = args.get (0); - if (!element_type.takes_ownership) { + if (!(element_type is PointerType) && !element_type.takes_ownership) { /* lhs doesn't own the value */ a.error = true; Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable"); diff --git a/vala/valasymbolresolver.vala b/vala/valasymbolresolver.vala index 76269a8..aaf5c61 100644 --- a/vala/valasymbolresolver.vala +++ b/vala/valasymbolresolver.vala @@ -265,20 +265,8 @@ public class Vala.SymbolResolver : CodeVisitor { } } - if (unresolved_type.pointer_level > 0) { - if (type.data_type == null) { - type.error = true; - Report.error (type.source_reference, "Pointer to `%s' not supported".printf (unresolved_type.type_name)); - return null; - } - var referent_type = new DataType (); - referent_type.data_type = type.data_type; - - if (type.data_type.is_reference_type ()) { - referent_type.takes_ownership = type.takes_ownership; - } - type.data_type = referent_type.data_type.get_pointer (); - type.add_type_argument (referent_type); + for (int pointer_level = unresolved_type.pointer_level; pointer_level > 0; pointer_level--) { + type = new PointerType (type); } /* check for array */ diff --git a/vala/valavoidtype.vala b/vala/valavoidtype.vala index 9398482..d7e6a6a 100644 --- a/vala/valavoidtype.vala +++ b/vala/valavoidtype.vala @@ -32,4 +32,8 @@ public class Vala.VoidType : DataType { public override bool stricter (DataType! type2) { return (type2 is VoidType); } + + public override string! to_string () { + return "void"; + } } -- 2.7.4