Commit f699908b authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

set is_lvalue_ref in property declarations use non-null parameter types

2006-06-14  Jürg Billeter  <j@bitron.ch>

	* 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
parent 8991394c
2006-06-14 Jürg Billeter <j@bitron.ch>
* 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 <j@bitron.ch>
* vala/parser.y: set is_lvalue_ref for variables and fields
......
......@@ -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 \
......
/* 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 <j@bitron.ch>
*/
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 (")");
}
}
}
......@@ -27,11 +27,11 @@ namespace Vala {
public CCodeExpression call { get; construct; }
List<CCodeExpression> 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 (" (");
......
......@@ -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 ();
......
......@@ -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));
}
;
......
......@@ -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 */
......
......@@ -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<SourceFile> chain) {
private void visit (SourceFile! file, List<SourceFile> chain) {
var l = chain.copy ();
l.append (file);
......
......@@ -45,7 +45,10 @@ namespace Vala {
CCodeFunction function;
CCodeBlock block;
/* all temporary variables */
List<VariableDeclarator> temp_vars;
/* temporary variables that own their content */
List<VariableDeclarator> 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<VariableDeclarator> 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<VariableDeclarator> 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);
}
}
......
......@@ -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<VariableDeclarator> temp_vars;
......
......@@ -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);
}
}
}
}
......@@ -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 ();