From: Jürg Billeter Date: Wed, 14 Jun 2006 20:55:58 +0000 (+0000) Subject: set is_lvalue_ref in property declarations use non-null parameter types X-Git-Tag: VALA_0_0_1~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f699908b8dbd98ab6eb08c4c8a6b4cb98264f04a;p=thirdparty%2Fvala.git set is_lvalue_ref in property declarations use non-null parameter types 2006-06-14 Jürg Billeter * vala/parser.y: set is_lvalue_ref in property declarations * vala/valacodecontext.vala: use non-null parameter types * vala/valasymbolresolver.vala: fix lookup in namespaces of using directives, reset is_lvalue_ref where appropriate * vala/valasemanticanalyzer.vala: use non-null parameter types, correctly set is_ref and is_lvalue_ref in variable declarators * vala/valamemorymanager.vala: support methods which transfer ownership of arguments and or return value, analyze assignments * vala/valacodegenerator.vala: add missing reference increment calls, small memory management improvements * vala/valaclass.vala: use non-null parameter types * vala/valaexpression.vala: add ref_missing * vala/valastruct.vala: support ref_function attribute, use non-null parameter types * vala/valatype.vala: let get_upper_case_cname return ref string * vala/valatypereference.vala: add copy method * ccode/valaccodeconditionalexpression.vala * ccode/valaccodefunctioncall.vala: use non-null parameter types * ccode/Makefile.am: update * compiler/valacompiler.vala: process attributes before resolving symbols to have reference_type information available in resolver * vapi/glib-2.0.vala: add ref_function attributes to string and List, use ref parameters in List and HashTable until the compiler can handle it correctly svn path=/trunk/; revision=44 --- diff --git a/vala/ChangeLog b/vala/ChangeLog index 5eb5b4256..6572cc8ee 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -1,3 +1,30 @@ +2006-06-14 Jürg Billeter + + * vala/parser.y: set is_lvalue_ref in property declarations + * vala/valacodecontext.vala: use non-null parameter types + * vala/valasymbolresolver.vala: fix lookup in namespaces of using + directives, reset is_lvalue_ref where appropriate + * vala/valasemanticanalyzer.vala: use non-null parameter types, + correctly set is_ref and is_lvalue_ref in variable declarators + * vala/valamemorymanager.vala: support methods which transfer ownership + of arguments and or return value, analyze assignments + * vala/valacodegenerator.vala: add missing reference increment calls, + small memory management improvements + * vala/valaclass.vala: use non-null parameter types + * vala/valaexpression.vala: add ref_missing + * vala/valastruct.vala: support ref_function attribute, use non-null + parameter types + * vala/valatype.vala: let get_upper_case_cname return ref string + * vala/valatypereference.vala: add copy method + * ccode/valaccodeconditionalexpression.vala + * ccode/valaccodefunctioncall.vala: use non-null parameter types + * ccode/Makefile.am: update + * compiler/valacompiler.vala: process attributes before resolving + symbols to have reference_type information available in resolver + * vapi/glib-2.0.vala: add ref_function attributes to string and List, + use ref parameters in List and HashTable until the compiler can handle + it correctly + 2006-06-14 Jürg Billeter * vala/parser.y: set is_lvalue_ref for variables and fields diff --git a/vala/ccode/Makefile.am b/vala/ccode/Makefile.am index 85006f8b0..6b5f945d0 100644 --- a/vala/ccode/Makefile.am +++ b/vala/ccode/Makefile.am @@ -36,6 +36,9 @@ libvalaccode_la_SOURCES = \ valaccodecomment.c \ valaccodecomment.h \ valaccodecomment.vala \ + valaccodeconditionalexpression.c \ + valaccodeconditionalexpression.h \ + valaccodeconditionalexpression.vala \ valaccodeconstant.c \ valaccodeconstant.h \ valaccodeconstant.vala \ diff --git a/vala/ccode/valaccodeconditionalexpression.vala b/vala/ccode/valaccodeconditionalexpression.vala new file mode 100644 index 000000000..f1e2f3a15 --- /dev/null +++ b/vala/ccode/valaccodeconditionalexpression.vala @@ -0,0 +1,41 @@ +/* valaccodeconditionalexpression.vala + * + * Copyright (C) 2006 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 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 + */ + +using GLib; + +namespace Vala { + public class CCodeConditionalExpression : CCodeExpression { + public CCodeExpression condition { get; construct; } + public CCodeExpression true_expression { get; construct; } + public CCodeExpression false_expression { get; construct; } + + public override void write (CCodeWriter writer) { + writer.write_string ("("); + condition.write (writer); + writer.write_string (" ? "); + true_expression.write (writer); + writer.write_string (" : "); + false_expression.write (writer); + writer.write_string (")"); + } + } +} diff --git a/vala/ccode/valaccodefunctioncall.vala b/vala/ccode/valaccodefunctioncall.vala index bcd9b614b..4e0e6a061 100644 --- a/vala/ccode/valaccodefunctioncall.vala +++ b/vala/ccode/valaccodefunctioncall.vala @@ -27,11 +27,11 @@ namespace Vala { public CCodeExpression call { get; construct; } List arguments; - public void add_argument (CCodeExpression expr) { + public void add_argument (CCodeExpression! expr) { arguments.append (expr); } - public override void write (CCodeWriter writer) { + public override void write (CCodeWriter! writer) { call.write (writer); writer.write_string (" ("); diff --git a/vala/compiler/valacompiler.vala b/vala/compiler/valacompiler.vala index 97a69ee2f..09078e1ed 100644 --- a/vala/compiler/valacompiler.vala +++ b/vala/compiler/valacompiler.vala @@ -54,7 +54,7 @@ namespace Vala { } } - private ref string get_package_path (string pkg) { + private ref string get_package_path (string! pkg) { var basename = "%s.vala".printf (pkg); if (vapi_directories != null) { @@ -74,7 +74,7 @@ namespace Vala { return null; } - private bool add_package (string pkg) { + private bool add_package (string! pkg) { var package_path = get_package_path (pkg); if (package_path == null) { @@ -132,15 +132,15 @@ namespace Vala { return quit (); } - var resolver = new SymbolResolver (); - resolver.resolve (context); + var attributeprocessor = new AttributeProcessor (); + attributeprocessor.process (context); if (Report.get_errors () > 0) { return quit (); } - var attributeprocessor = new AttributeProcessor (); - attributeprocessor.process (context); + var resolver = new SymbolResolver (); + resolver.resolve (context); if (Report.get_errors () > 0) { return quit (); diff --git a/vala/vala/parser.y b/vala/vala/parser.y index f142dfb9b..be7e40181 100644 --- a/vala/vala/parser.y +++ b/vala/vala/parser.y @@ -1419,10 +1419,18 @@ fixed_parameter property_declaration : comment opt_attributes opt_access_modifier opt_modifiers type IDENTIFIER OPEN_BRACE get_accessor_declaration opt_set_accessor_declaration CLOSE_BRACE { + if (!vala_type_reference_get_is_weak ($5)) { + vala_type_reference_set_is_lvalue_ref ($5, TRUE); + } + $$ = vala_property_new ($6, $5, $8, $9, src_com (@5, $1)); } | comment opt_attributes opt_access_modifier opt_modifiers type IDENTIFIER OPEN_BRACE set_accessor_declaration CLOSE_BRACE { + if (!vala_type_reference_get_is_weak ($5)) { + vala_type_reference_set_is_lvalue_ref ($5, TRUE); + } + $$ = vala_property_new ($6, $5, NULL, $8, src_com (@5, $1)); } ; diff --git a/vala/vala/valaclass.vala b/vala/vala/valaclass.vala index b99d02b7b..31c7b1818 100644 --- a/vala/vala/valaclass.vala +++ b/vala/vala/valaclass.vala @@ -42,24 +42,24 @@ namespace Vala { public string lower_case_csuffix; public bool has_private_fields; - public static ref Class new (string name, SourceReference source) { + public static ref Class new (string! name, SourceReference source) { return (new Class (name = name, source_reference = source)); } - public void add_base_type (TypeReference type) { + public void add_base_type (TypeReference! type) { base_types.append (type); } - public void add_type_parameter (TypeParameter p) { + public void add_type_parameter (TypeParameter! p) { type_parameters.append (p); p.type = this; } - public void add_constant (Constant c) { + public void add_constant (Constant! c) { constants.append (c); } - public void add_field (Field f) { + public void add_field (Field! f) { fields.append (f); if (f.access == MemberAccessibility.PRIVATE) { has_private_fields = true; @@ -70,9 +70,7 @@ namespace Vala { return fields.copy (); } - public void add_method (Method m) { - return_if_fail (m != null); - + public void add_method (Method! m) { methods.append (m); } @@ -80,7 +78,7 @@ namespace Vala { return methods.copy (); } - public void add_property (Property prop) { + public void add_property (Property! prop) { properties.append (prop); if (prop.set_accessor != null && prop.set_accessor.body == null) { @@ -95,7 +93,7 @@ namespace Vala { return properties.copy (); } - public void add_signal (Signal sig) { + public void add_signal (Signal! sig) { signals.append (sig); } @@ -103,7 +101,7 @@ namespace Vala { return signals.copy (); } - public override void accept (CodeVisitor visitor) { + public override void accept (CodeVisitor! visitor) { visitor.visit_begin_class (this); foreach (TypeReference type in base_types) { @@ -152,7 +150,7 @@ namespace Vala { return cname; } - public void set_cname (string cname) { + public void set_cname (string! cname) { this.cname = cname; } @@ -163,7 +161,7 @@ namespace Vala { return lower_case_csuffix; } - public void set_lower_case_csuffix (string csuffix) { + public void set_lower_case_csuffix (string! csuffix) { this.lower_case_csuffix = csuffix; } @@ -174,7 +172,7 @@ namespace Vala { return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ()); } - public override ref string get_upper_case_cname (string infix) { + public override ref string get_upper_case_cname (string! infix) { return get_lower_case_cname (infix).up (); } @@ -182,7 +180,7 @@ namespace Vala { return true; } - void process_ccode_attribute (Attribute a) { + void process_ccode_attribute (Attribute! a) { foreach (NamedArgument arg in a.args) { if (arg.name == "cname") { /* this will already be checked during semantic analysis */ diff --git a/vala/vala/valacodecontext.vala b/vala/vala/valacodecontext.vala index 55a322a2d..896d937eb 100644 --- a/vala/vala/valacodecontext.vala +++ b/vala/vala/valacodecontext.vala @@ -33,11 +33,11 @@ namespace Vala { return source_files.copy (); } - public void add_source_file (SourceFile file) { + public void add_source_file (SourceFile! file) { source_files.append (file); } - public void accept (CodeVisitor visitor) { + public void accept (CodeVisitor! visitor) { foreach (SourceFile file in source_files) { file.accept (visitor); } @@ -85,7 +85,7 @@ namespace Vala { } - private SourceFile find_cycle_head (SourceFile file) { + private SourceFile find_cycle_head (SourceFile! file) { foreach (SourceFile dep in file.header_internal_full_dependencies) { foreach (SourceFile cycle_file in file.cycle.files) { if (dep == cycle_file) { @@ -99,7 +99,7 @@ namespace Vala { return file; } - private void visit (SourceFile file, List chain) { + private void visit (SourceFile! file, List chain) { var l = chain.copy (); l.append (file); diff --git a/vala/vala/valacodegenerator.vala b/vala/vala/valacodegenerator.vala index 067154d5a..109290b2a 100644 --- a/vala/vala/valacodegenerator.vala +++ b/vala/vala/valacodegenerator.vala @@ -45,7 +45,10 @@ namespace Vala { CCodeFunction function; CCodeBlock block; + /* all temporary variables */ List temp_vars; + /* temporary variables that own their content */ + List temp_ref_vars; private int next_temp_var_id = 0; @@ -924,6 +927,7 @@ namespace Vala { public override void visit_end_full_expression (Expression! expr) { if (!memory_management) { temp_vars = null; + temp_ref_vars = null; return; } @@ -935,17 +939,21 @@ namespace Vala { * expression */ - if (temp_vars == null) { + expr.temp_vars = temp_vars; + temp_vars = null; + + if (temp_ref_vars == null) { /* nothing to do without temporary variables */ return; } var full_expr_decl = get_temp_variable_declarator (expr.static_type); + expr.temp_vars.append (full_expr_decl); var expr_list = new CCodeCommaExpression (); expr_list.inner.append (new CCodeAssignment (left = new CCodeIdentifier (name = full_expr_decl.name), right = expr.ccodenode)); - foreach (VariableDeclarator decl in temp_vars) { + foreach (VariableDeclarator decl in temp_ref_vars) { expr_list.inner.append (get_unref_expression (decl.name, decl.type_reference)); } @@ -953,10 +961,7 @@ namespace Vala { expr.ccodenode = expr_list; - temp_vars.append (full_expr_decl); - - expr.temp_vars = temp_vars; - temp_vars = null; + temp_ref_vars = null; } private void append_temp_decl (CCodeFragment! cfrag, List temp_vars) { @@ -975,6 +980,7 @@ namespace Vala { /* free temporary objects */ if (!memory_management) { temp_vars = null; + temp_ref_vars = null; return; } @@ -988,13 +994,14 @@ namespace Vala { cfrag.append (stmt.ccodenode); - foreach (VariableDeclarator decl in temp_vars) { + foreach (VariableDeclarator decl in temp_ref_vars) { cfrag.append (new CCodeExpressionStatement (expression = get_unref_expression (decl.name, decl.type_reference))); } stmt.ccodenode = cfrag; temp_vars = null; + temp_ref_vars = null; } private void create_temp_decl (Statement! stmt, List temp_vars) { @@ -1218,10 +1225,14 @@ namespace Vala { var base_type = (Type_) current_symbol.node; process_cmember (expr, pub_inst, base_type); + + visit_expression (expr); } public override void visit_parenthesized_expression (ParenthesizedExpression! expr) { expr.ccodenode = new CCodeParenthesizedExpression (inner = (CCodeExpression) expr.inner.ccodenode); + + visit_expression (expr); } public override void visit_member_access (MemberAccess! expr) { @@ -1232,6 +1243,8 @@ namespace Vala { } process_cmember (expr, pub_inst, base_type); + + visit_expression (expr); } public override void visit_invocation_expression (InvocationExpression! expr) { @@ -1339,11 +1352,34 @@ namespace Vala { } } + private ref CCodeExpression get_ref_expression (Expression! expr) { + /* (temp = expr, temp == NULL ? temp : ref (temp)) */ + + var decl = get_temp_variable_declarator (expr.static_type); + temp_vars.prepend (decl); + + var ctemp = new CCodeIdentifier (name = decl.name); + + var cisnull = new CCodeBinaryExpression (operator = CCodeBinaryOperator.EQUALITY, left = ctemp, right = new CCodeConstant (name = "NULL")); + + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = expr.static_type.type.get_ref_function ())); + ccall.add_argument (ctemp); + + var ccomma = new CCodeCommaExpression (); + ccomma.inner.append (new CCodeAssignment (left = ctemp, right = expr.ccodenode)); + ccomma.inner.append (new CCodeConditionalExpression (condition = cisnull, true_expression = ctemp, false_expression = ccall)); + + return ccomma; + } + private void visit_expression (Expression! expr) { if (expr.ref_leaked) { var decl = get_temp_variable_declarator (expr.static_type); temp_vars.prepend (decl); + temp_ref_vars.prepend (decl); expr.ccodenode = new CCodeAssignment (left = new CCodeIdentifier (name = decl.name), right = expr.ccodenode); + } else if (expr.ref_missing) { + expr.ccodenode = get_ref_expression (expr); } } diff --git a/vala/vala/valaexpression.vala b/vala/vala/valaexpression.vala index 2ed8ef4f5..7f51b2978 100644 --- a/vala/vala/valaexpression.vala +++ b/vala/vala/valaexpression.vala @@ -35,6 +35,7 @@ namespace Vala { /* set by memory manager, used by code generator */ public bool ref_leaked; + public bool ref_missing; /* set and used by code generator */ public List temp_vars; diff --git a/vala/vala/valamemorymanager.vala b/vala/vala/valamemorymanager.vala index 72664e7d2..4677da489 100644 --- a/vala/vala/valamemorymanager.vala +++ b/vala/vala/valamemorymanager.vala @@ -24,6 +24,8 @@ using GLib; namespace Vala { public class MemoryManager : CodeVisitor { + Symbol current_symbol; + public void analyze (CodeContext! context) { context.accept (this); } @@ -36,13 +38,31 @@ namespace Vala { } } + private void visit_possibly_missing_copy_expression (Expression! expr) { + if (expr.static_type != null && + !expr.static_type.is_ref) { + /* mark reference as missing */ + expr.ref_missing = true; + } + } + + public override void visit_begin_method (Method! m) { + current_symbol = m.symbol; + } + public override void visit_expression_statement (ExpressionStatement! stmt) { visit_possibly_leaked_expression (stmt.expression); } public override void visit_return_statement (ReturnStatement! stmt) { if (stmt.return_expression != null) { - visit_possibly_leaked_expression (stmt.return_expression); + var m = (Method) current_symbol.node; + + if (m.return_type.is_ref) { + visit_possibly_missing_copy_expression (stmt.return_expression); + } else { + visit_possibly_leaked_expression (stmt.return_expression); + } } } @@ -51,8 +71,26 @@ namespace Vala { } public override void visit_invocation_expression (InvocationExpression! expr) { + var m = (Method) expr.call.symbol_reference.node; + var params = m.get_parameters (); foreach (Expression arg in expr.argument_list) { - visit_possibly_leaked_expression (arg); + if (params != null) { + var param = (FormalParameter) params.data; + if (!param.ellipsis + && ((param.type_reference.type != null + && param.type_reference.type.is_reference_type ()) + || param.type_reference.type_parameter != null)) { + if (param.type_reference.is_ref) { + visit_possibly_missing_copy_expression (arg); + } else { + visit_possibly_leaked_expression (arg); + } + } + + params = params.next; + } else { + visit_possibly_leaked_expression (arg); + } } } @@ -60,5 +98,13 @@ namespace Vala { visit_possibly_leaked_expression (expr.left); visit_possibly_leaked_expression (expr.right); } + + public override void visit_assignment (Assignment! a) { + if (a.left.static_type.is_lvalue_ref) { + visit_possibly_missing_copy_expression (a.right); + } else { + visit_possibly_leaked_expression (a.right); + } + } } } diff --git a/vala/vala/valasemanticanalyzer.vala b/vala/vala/valasemanticanalyzer.vala index b20221edb..cd91e0d4f 100644 --- a/vala/vala/valasemanticanalyzer.vala +++ b/vala/vala/valasemanticanalyzer.vala @@ -48,24 +48,24 @@ namespace Vala { context.accept (this); } - public override void visit_begin_source_file (SourceFile file) { + public override void visit_begin_source_file (SourceFile! file) { current_source_file = file; current_using_directives = file.get_using_directives (); } - public override void visit_end_source_file (SourceFile file) { + public override void visit_end_source_file (SourceFile! file) { current_using_directives = null; } - public override void visit_begin_namespace (Namespace ns) { + public override void visit_begin_namespace (Namespace! ns) { current_symbol = ns.symbol; } - public override void visit_end_namespace (Namespace ns) { + public override void visit_end_namespace (Namespace! ns) { current_symbol = current_symbol.parent_symbol; } - public override void visit_begin_class (Class cl) { + public override void visit_begin_class (Class! cl) { current_symbol = cl.symbol; if (cl.base_class != null) { @@ -73,19 +73,19 @@ namespace Vala { } } - public override void visit_end_class (Class cl) { + public override void visit_end_class (Class! cl) { current_symbol = current_symbol.parent_symbol; } - public override void visit_begin_struct (Struct st) { + public override void visit_begin_struct (Struct! st) { current_symbol = st.symbol; } - public override void visit_end_struct (Struct st) { + public override void visit_end_struct (Struct! st) { current_symbol = current_symbol.parent_symbol; } - public override void visit_field (Field f) { + public override void visit_field (Field! f) { if (f.access == MemberAccessibility.PUBLIC) { if (f.type_reference.type != null) { /* is null if it references a type parameter */ @@ -99,7 +99,7 @@ namespace Vala { } } - public override void visit_begin_method (Method m) { + public override void visit_begin_method (Method! m) { current_symbol = m.symbol; if (m.return_type.type != null) { @@ -108,7 +108,7 @@ namespace Vala { } } - public override void visit_end_method (Method m) { + public override void visit_end_method (Method! m) { current_symbol = current_symbol.parent_symbol; if (m.is_virtual || m.is_override) { @@ -135,7 +135,7 @@ namespace Vala { } } - public override void visit_formal_parameter (FormalParameter p) { + public override void visit_formal_parameter (FormalParameter! p) { if (!p.ellipsis) { if (p.type_reference.type != null) { /* is null if it references a type parameter */ @@ -145,7 +145,7 @@ namespace Vala { } } - public override void visit_end_property (Property prop) { + public override void visit_end_property (Property! prop) { if (prop.type_reference.type != null) { /* is null if it references a type parameter */ current_source_file.add_symbol_dependency (prop.type_reference.type.symbol, SourceFileDependencyType.HEADER_SHALLOW); @@ -153,37 +153,39 @@ namespace Vala { } } - public override void visit_begin_constructor (Constructor c) { + public override void visit_begin_constructor (Constructor! c) { current_symbol = c.symbol; } - public override void visit_end_constructor (Constructor c) { + public override void visit_end_constructor (Constructor! c) { current_symbol = current_symbol.parent_symbol; } - public override void visit_begin_destructor (Destructor d) { + public override void visit_begin_destructor (Destructor! d) { current_symbol = d.symbol; } - public override void visit_end_destructor (Destructor d) { + public override void visit_end_destructor (Destructor! d) { current_symbol = current_symbol.parent_symbol; } - public override void visit_named_argument (NamedArgument n) { + public override void visit_named_argument (NamedArgument! n) { } - public override void visit_begin_block (Block b) { + public override void visit_begin_block (Block! b) { current_symbol = b.symbol; } - public override void visit_end_block (Block b) { + public override void visit_end_block (Block! b) { current_symbol = current_symbol.parent_symbol; } - public override void visit_variable_declarator (VariableDeclarator decl) { + public override void visit_variable_declarator (VariableDeclarator! decl) { if (decl.type_reference == null) { /* var type */ - decl.type_reference = decl.initializer.static_type; + decl.type_reference = decl.initializer.static_type.copy (); + decl.type_reference.is_lvalue_ref = decl.type_reference.is_ref; + decl.type_reference.is_ref = false; } if (decl.type_reference.type != null) { @@ -194,7 +196,7 @@ namespace Vala { current_symbol.add (decl.name, decl.symbol); } - public override void visit_expression_statement (ExpressionStatement stmt) { + public override void visit_expression_statement (ExpressionStatement! stmt) { if (stmt.expression.static_type != null && stmt.expression.static_type.is_ref) { Report.warning (stmt.source_reference, "Short-living reference"); @@ -202,7 +204,7 @@ namespace Vala { } } - public override void visit_begin_foreach_statement (ForeachStatement stmt) { + public override void visit_begin_foreach_statement (ForeachStatement! stmt) { if (stmt.type_reference.type != null) { current_source_file.add_symbol_dependency (stmt.type_reference.type.symbol, SourceFileDependencyType.SOURCE); } @@ -214,40 +216,40 @@ namespace Vala { current_symbol.add (stmt.variable_name, stmt.symbol); } - public override void visit_boolean_literal (BooleanLiteral expr) { + public override void visit_boolean_literal (BooleanLiteral! expr) { expr.static_type = bool_type; } - public override void visit_character_literal (CharacterLiteral expr) { + public override void visit_character_literal (CharacterLiteral! expr) { expr.static_type = new TypeReference (); expr.static_type.type = (Type_) root_symbol.lookup ("char").node; } - public override void visit_integer_literal (IntegerLiteral expr) { + public override void visit_integer_literal (IntegerLiteral! expr) { expr.static_type = new TypeReference (); expr.static_type.type = (Type_) root_symbol.lookup ("int").node; } - public override void visit_real_literal (IntegerLiteral expr) { + public override void visit_real_literal (IntegerLiteral! expr) { expr.static_type = new TypeReference (); expr.static_type.type = (Type_) root_symbol.lookup ("double").node; } - public override void visit_string_literal (StringLiteral expr) { + public override void visit_string_literal (StringLiteral! expr) { expr.static_type = string_type; } - public override void visit_null_literal (NullLiteral expr) { + public override void visit_null_literal (NullLiteral! expr) { /* empty TypeReference represents null */ expr.static_type = new TypeReference (); } - public override void visit_literal_expression (LiteralExpression expr) { + public override void visit_literal_expression (LiteralExpression! expr) { expr.static_type = expr.literal.static_type; } - TypeReference get_static_type_for_node (CodeNode node) { + TypeReference get_static_type_for_node (CodeNode! node) { if (node is Field) { var f = (Field) node; return f.type_reference; @@ -273,7 +275,7 @@ namespace Vala { return null; } - Symbol symbol_lookup_inherited (Symbol sym, string name) { + Symbol symbol_lookup_inherited (Symbol! sym, string! name) { var result = sym.lookup (name); if (result == null && sym.node is Class) { var cl = (Class) sym.node; @@ -284,7 +286,7 @@ namespace Vala { return result; } - public override void visit_simple_name (SimpleName expr) { + public override void visit_simple_name (SimpleName! expr) { var sym = current_symbol; while (sym != null && expr.symbol_reference == null) { expr.symbol_reference = symbol_lookup_inherited (sym, expr.name); @@ -314,11 +316,11 @@ namespace Vala { expr.static_type = get_static_type_for_node (expr.symbol_reference.node); } - public override void visit_parenthesized_expression (ParenthesizedExpression expr) { + public override void visit_parenthesized_expression (ParenthesizedExpression! expr) { expr.static_type = expr.inner.static_type; } - public override void visit_member_access (MemberAccess expr) { + public override void visit_member_access (MemberAccess! expr) { if (expr.inner.static_type == null && expr.inner.symbol_reference == null) { /* if there was an error in the inner expression, skip this check */ @@ -349,7 +351,7 @@ namespace Vala { expr.static_type = get_static_type_for_node (expr.symbol_reference.node); } - private bool is_type_compatible (TypeReference expression_type, TypeReference expected_type) { + private bool is_type_compatible (TypeReference! expression_type, TypeReference! expected_type) { /* null can be casted to any reference or array type */ if (expression_type.type == null && (expected_type.type.is_reference_type () || expected_type.array)) { return true; @@ -400,7 +402,7 @@ namespace Vala { return false; } - public override void visit_invocation_expression (InvocationExpression expr) { + public override void visit_invocation_expression (InvocationExpression! expr) { if (expr.call.symbol_reference == null) { /* if method resolving didn't succeed, skip this check */ return; @@ -450,7 +452,7 @@ namespace Vala { } } - public override void visit_object_creation_expression (ObjectCreationExpression expr) { + public override void visit_object_creation_expression (ObjectCreationExpression! expr) { if (expr.type_reference.type == null) { /* if type resolving didn't succeed, skip this check */ return; @@ -462,7 +464,7 @@ namespace Vala { expr.static_type.is_ref = true; } - public override void visit_unary_expression (UnaryExpression expr) { + public override void visit_unary_expression (UnaryExpression! expr) { if (expr.inner.static_type == null) { /* if there was an error in the inner expression, skip type check */ return; @@ -493,7 +495,7 @@ namespace Vala { } } - public override void visit_cast_expression (CastExpression expr) { + public override void visit_cast_expression (CastExpression! expr) { if (expr.type_reference.type == null) { /* if type resolving didn't succeed, skip this check */ return; @@ -504,7 +506,7 @@ namespace Vala { expr.static_type = expr.type_reference; } - private bool check_binary_type (BinaryExpression expr, string operation) { + private bool check_binary_type (BinaryExpression! expr, string! operation) { if (!is_type_compatible (expr.right.static_type, expr.left.static_type)) { Report.error (expr.source_reference, "%s: Cannot convert from `%s' to `%s'".printf (operation, expr.right.static_type.to_string (), expr.left.static_type.to_string ())); return false; @@ -513,7 +515,7 @@ namespace Vala { return true; } - public override void visit_binary_expression (BinaryExpression expr) { + public override void visit_binary_expression (BinaryExpression! expr) { if (expr.left.static_type == null || expr.right.static_type == null) { /* if there were any errors in inner expressions, skip type check */ @@ -614,7 +616,7 @@ namespace Vala { } } - public override void visit_type_check (TypeCheck expr) { + public override void visit_type_check (TypeCheck! expr) { if (expr.type_reference.type == null) { /* if type resolving didn't succeed, skip this check */ return; @@ -625,7 +627,7 @@ namespace Vala { expr.static_type = bool_type; } - public override void visit_assignment (Assignment a) { + public override void visit_assignment (Assignment! a) { if (a.left.symbol_reference.node is Signal) { var sig = (Signal) a.left.symbol_reference.node; } else if (a.left.symbol_reference.node is Property) { @@ -649,7 +651,7 @@ namespace Vala { Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable"); } - a.left.static_type.is_ref = true; + a.left.static_type.is_lvalue_ref = true; } } else if (a.left.static_type.is_lvalue_ref) { /* lhs wants to own the value @@ -659,6 +661,8 @@ namespace Vala { } } } + + a.static_type = a.left.static_type; } } } diff --git a/vala/vala/valastruct.vala b/vala/vala/valastruct.vala index 44bc23fe5..55dcdc20d 100644 --- a/vala/vala/valastruct.vala +++ b/vala/vala/valastruct.vala @@ -30,23 +30,24 @@ namespace Vala { List methods; public string cname; + public string ref_function; public string lower_case_csuffix; bool reference_type; - public static ref Struct new (string name, SourceReference source) { + public static ref Struct new (string! name, SourceReference source) { return (new Struct (name = name, source_reference = source)); } - public void add_type_parameter (TypeParameter p) { + public void add_type_parameter (TypeParameter! p) { type_parameters.append (p); p.type = this; } - public void add_constant (Constant c) { + public void add_constant (Constant! c) { constants.append (c); } - public void add_field (Field f) { + public void add_field (Field! f) { fields.append (f); } @@ -54,7 +55,7 @@ namespace Vala { return fields.copy (); } - public void add_method (Method m) { + public void add_method (Method! m) { return_if_fail (m != null); methods.append (m); @@ -64,7 +65,7 @@ namespace Vala { return methods.copy (); } - public override void accept (CodeVisitor visitor) { + public override void accept (CodeVisitor! visitor) { visitor.visit_begin_struct (this); foreach (TypeParameter p in type_parameters) { @@ -93,7 +94,7 @@ namespace Vala { return cname; } - public void set_cname (string cname) { + public void set_cname (string! cname) { this.cname = cname; } @@ -104,7 +105,7 @@ namespace Vala { return lower_case_csuffix; } - public void set_lower_case_csuffix (string csuffix) { + public void set_lower_case_csuffix (string! csuffix) { this.lower_case_csuffix = csuffix; } @@ -123,7 +124,7 @@ namespace Vala { return reference_type; } - void process_ccode_attribute (Attribute a) { + private void process_ccode_attribute (Attribute! a) { foreach (NamedArgument arg in a.args) { if (arg.name == "cname") { /* this will already be checked during semantic analysis */ @@ -148,12 +149,27 @@ namespace Vala { } } + private void process_ref_type_attribute (Attribute! a) { + reference_type = true; + foreach (NamedArgument arg in a.args) { + if (arg.name == "ref_function") { + /* this will already be checked during semantic analysis */ + if (arg.argument is LiteralExpression) { + var lit = ((LiteralExpression) arg.argument).literal; + if (lit is StringLiteral) { + set_ref_function (((StringLiteral) lit).eval ()); + } + } + } + } + } + public void process_attributes () { foreach (Attribute a in attributes) { if (a.name == "CCode") { process_ccode_attribute (a); } else if (a.name == "ReferenceType") { - reference_type = true; + process_ref_type_attribute (a); } } } @@ -162,6 +178,18 @@ namespace Vala { return false; } + public override string get_ref_function () { + if (ref_function == null) { + Report.warning (source_reference, "type foo is missing a copy/reference increment function"); + ref_function = "g_strdup"; + } + return ref_function; + } + + public void set_ref_function (string! name) { + this.ref_function = name; + } + public override string get_free_function () { return "g_free"; } diff --git a/vala/vala/valasymbolresolver.vala b/vala/vala/valasymbolresolver.vala index dc55c547d..d4ac3c74b 100644 --- a/vala/vala/valasymbolresolver.vala +++ b/vala/vala/valasymbolresolver.vala @@ -102,11 +102,13 @@ namespace Vala { if (sym == null) { foreach (NamespaceReference ns in current_using_directives) { var local_sym = ns.namespace_symbol.lookup (type.type_name); - if (sym != null && local_sym != null) { - Report.error (type.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (type.type_name, sym.get_full_name (), local_sym.get_full_name ())); - return; + if (local_sym != null) { + if (sym != null) { + Report.error (type.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (type.type_name, sym.get_full_name (), local_sym.get_full_name ())); + return; + } + sym = local_sym; } - sym = local_sym; } } if (sym == null) { @@ -132,6 +134,13 @@ namespace Vala { } type.type = (Type_) sym.node; } + + if (type.type != null && !type.type.is_reference_type ()) { + /* reset is_lvalue_ref for contexts where types + * are ref by default (field declarations) + */ + type.is_lvalue_ref = false; + } } } } diff --git a/vala/vala/valatype.vala b/vala/vala/valatype.vala index c6960c74c..63001267c 100644 --- a/vala/vala/valatype.vala +++ b/vala/vala/valatype.vala @@ -35,7 +35,7 @@ namespace Vala { public abstract string get_ref_function (); public abstract string get_free_function (); - public abstract string get_upper_case_cname (string infix); + public abstract ref string get_upper_case_cname (string infix); public abstract string get_lower_case_cname (string infix); public List cheader_filenames; diff --git a/vala/vala/valatypereference.vala b/vala/vala/valatypereference.vala index f2de50b04..a4ad46f75 100644 --- a/vala/vala/valatypereference.vala +++ b/vala/vala/valatypereference.vala @@ -124,5 +124,20 @@ namespace Vala { return "null"; } } + + public ref TypeReference copy () { + var result = new TypeReference (); + result.is_ref = is_ref; + result.is_lvalue_ref = is_lvalue_ref; + result.is_weak = is_weak; + result.is_out = is_out; + result.array = array; + result.array_own = array_own; + result.non_null = non_null; + result.type = type; + result.type_parameter = type_parameter; + + return result; + } } } diff --git a/vala/vapi/glib-2.0.vala b/vala/vapi/glib-2.0.vala index 519de1ae4..f99a520e5 100644 --- a/vala/vapi/glib-2.0.vala +++ b/vala/vapi/glib-2.0.vala @@ -112,7 +112,7 @@ public struct unichar { public unichar tolower (); } -[ReferenceType ()] +[ReferenceType (ref_function = "g_strdup")] [CCode (cname = "char", cheader_filename = "string.h,glib.h")] public struct string { [CCode (cname = "g_str_has_suffix")] @@ -292,14 +292,14 @@ namespace GLib { string arg_description; } - [ReferenceType ()] + [ReferenceType (ref_function = "g_list_copy")] public struct List { [ReturnsModifiedPointer ()] - public void append (G data); + public void append (ref G data); [ReturnsModifiedPointer ()] - public void prepend (G data); + public void prepend (ref G data); [ReturnsModifiedPointer ()] - public void insert (G data, int position); + public void insert (ref G data, int position); [ReturnsModifiedPointer ()] public void insert_before (List sibling, G data); [ReturnsModifiedPointer ()] @@ -343,7 +343,7 @@ namespace GLib { [ReferenceType ()] public struct HashTable { public static ref HashTable new (HashFunc hash_func, EqualFunc key_equal_func); - public void insert (K key, V value); + public void insert (ref K key, ref V value); public V lookup (K key); }