support implicit namespace specification in callback declaration support
authorJürg Billeter <j@bitron.ch>
Tue, 4 Jul 2006 20:42:41 +0000 (20:42 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Tue, 4 Jul 2006 20:42:41 +0000 (20:42 +0000)
2006-07-04  Jürg Billeter  <j@bitron.ch>

* vala/parser.y: support implicit namespace specification in callback
  declaration
* vala/valasemanticanalyzer.vala, vala/valamemorymanager.vala,
  vala/valacodegenerator.vala: support callbacks
* vala/valaassignment.vala, vala/valabinaryexpression.vala: improve
  documentation
* vala/valabooleanliteral.vala, vala/valabreakstatement.vala,
  vala/valacallback.vala: add interface documentation, use implicit
  namespace specification
* vala/valacallback.vala: add matches_method method, mark as
  non-reference type
* ccode/valaccodetypedefinition.vala: replace typedef_name by
  declarator, add interface documentation, use implicit namespace
  specification
* tests/test-013.vala: test break
* tests/test-014.vala: test callback
* tests/Makefile.am: update

svn path=/trunk/; revision=64

14 files changed:
vala/ChangeLog
vala/ccode/valaccodetypedefinition.vala
vala/tests/Makefile.am
vala/tests/test-013.vala [new file with mode: 0644]
vala/tests/test-014.vala [new file with mode: 0644]
vala/vala/parser.y
vala/vala/valaassignment.vala
vala/vala/valabinaryexpression.vala
vala/vala/valabooleanliteral.vala
vala/vala/valabreakstatement.vala
vala/vala/valacallback.vala
vala/vala/valacodegenerator.vala
vala/vala/valamemorymanager.vala
vala/vala/valasemanticanalyzer.vala

index b7a001f..9a6fcdf 100644 (file)
@@ -1,5 +1,25 @@
 2006-07-04  Jürg Billeter  <j@bitron.ch>
 
+       * vala/parser.y: support implicit namespace specification in callback
+         declaration
+       * vala/valasemanticanalyzer.vala, vala/valamemorymanager.vala,
+         vala/valacodegenerator.vala: support callbacks
+       * vala/valaassignment.vala, vala/valabinaryexpression.vala: improve
+         documentation
+       * vala/valabooleanliteral.vala, vala/valabreakstatement.vala,
+         vala/valacallback.vala: add interface documentation, use implicit
+         namespace specification
+       * vala/valacallback.vala: add matches_method method, mark as
+         non-reference type
+       * ccode/valaccodetypedefinition.vala: replace typedef_name by
+         declarator, add interface documentation, use implicit namespace
+         specification
+       * tests/test-013.vala: test break
+       * tests/test-014.vala: test callback
+       * tests/Makefile.am: update
+
+2006-07-04  Jürg Billeter  <j@bitron.ch>
+
        * vala/valablock.vala: add interface documentation, use implicit
          namespace specification
        * tests/test-011.vala: test binary expressions
index 8aee708..6d8ee50 100644 (file)
 
 using GLib;
 
-namespace Vala {
-       public class CCodeTypeDefinition : CCodeNode {
-               public string type_name { get; construct; }
-               public string typedef_name { get; construct; }
+/**
+ * Represents a typedef in the C code.
+ */
+public class Vala.CCodeTypeDefinition : CCodeNode {
+       /**
+        * The type name.
+        */
+       public string type_name { get; set; }
+       
+       /**
+        * The type declarator.
+        */
+       public CCodeDeclarator declarator { get; set; }
+       
+       public override void write (CCodeWriter writer) {
+               writer.write_indent ();
+               writer.write_string ("typedef ");
+               
+               writer.write_string (type_name);
+               
+               writer.write_string (" ");
+               
+               declarator.write (writer);
                
-               public override void write (CCodeWriter writer) {
-                       writer.write_indent ();
-                       writer.write_string ("typedef ");
-                       writer.write_string (type_name);
-                       writer.write_string (" ");
-                       writer.write_string (typedef_name);
-                       writer.write_string (";");
-                       writer.write_newline ();
-               }
+               writer.write_string (";");
+               writer.write_newline ();
        }
 }
index e390a36..1a684b0 100644 (file)
@@ -13,4 +13,6 @@ EXTRA_DIST = \
        test-010.vala \
        test-011.vala \
        test-012.vala \
+       test-013.vala \
+       test-014.vala \
        $(NULL)
diff --git a/vala/tests/test-013.vala b/vala/tests/test-013.vala
new file mode 100644 (file)
index 0000000..d0231ec
--- /dev/null
@@ -0,0 +1,17 @@
+using GLib;
+
+class Maman.Bar {
+       static int main (int argc, string[] argv) {
+               stdout.printf ("Break Test: 1");
+               
+               int i;
+               for (i = 0; i < 10; i++) {
+                       stdout.printf (" 2");
+                       break;
+               }
+               
+               stdout.printf (" 3\n");
+               
+               return 0;
+       }
+}
diff --git a/vala/tests/test-014.vala b/vala/tests/test-014.vala
new file mode 100644 (file)
index 0000000..ecbb547
--- /dev/null
@@ -0,0 +1,21 @@
+using GLib;
+
+callback int Maman.ActionCallback ();
+
+class Maman.Bar {
+       static int do_action () {
+               return 2;
+       }
+
+       static int main (int argc, string[] argv) {
+               stdout.printf ("Callback Test: 1");
+               
+               ActionCallback cb = do_action;
+               
+               stdout.printf (" %d", cb ());
+               
+               stdout.printf (" 3\n");
+               
+               return 0;
+       }
+}
index 6c3fdcc..b6a9eb9 100644 (file)
@@ -1427,6 +1427,12 @@ namespace_member_declaration
                        vala_namespace_add_callback (current_namespace, $1);
                        g_object_unref ($1);
                }
+
+               if (current_namespace_implicit) {
+                       /* current namespace has been declared implicitly */
+                       current_namespace = vala_source_file_get_global_namespace (current_source_file);
+                       current_namespace_implicit = FALSE;
+               }
          }
        | field_declaration
          {
@@ -2292,28 +2298,42 @@ flags_member_declaration
        ;
 
 callback_declaration
-       : comment opt_attributes opt_access_modifier CALLBACK type identifier_or_new OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
+       : comment opt_attributes opt_access_modifier CALLBACK type IDENTIFIER opt_name_specifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
          {
                GList *l;
+               char *name = $6;
+         
+               if ($7 != NULL) {
+                       ValaSourceReference *ns_src = src(@6);
+                       current_namespace = vala_namespace_new ($6, ns_src);
+                       g_free ($6);
+                       g_object_unref (ns_src);
+                       current_namespace_implicit = TRUE;
+
+                       vala_source_file_add_namespace (current_source_file, current_namespace);
+                       g_object_unref (current_namespace);
+                       
+                       name = $7;
+               }
                
                ValaSourceReference *src = src_com(@6, $1);
-               $$ = vala_callback_new ($6, $5, src);
+               $$ = vala_callback_new (name, $5, src);
                g_object_unref (src);
                if ($3 != 0) {
                        VALA_DATA_TYPE($$)->access = $3;
                }
                VALA_CODE_NODE($$)->attributes = $2;
                
-               for (l = $8; l != NULL; l = l->next) {
+               for (l = $9; l != NULL; l = l->next) {
                        vala_callback_add_parameter ($$, l->data);
                        g_object_unref (l->data);
                }
-               if ($8 != NULL) {
-                       g_list_free ($8);
+               if ($9 != NULL) {
+                       g_list_free ($9);
                }
 
                g_object_unref ($5);
-               g_free ($6);
+               g_free (name);
          }
        ;
 
index 7304b28..64ac462 100644 (file)
@@ -24,6 +24,8 @@ using GLib;
 
 /**
  * Represents an assignment expression in the source code.
+ *
+ * Supports =, |=, &=, ^=, +=, -=, *=, /=, %=, <<=, >>=.
  */
 public class Vala.Assignment : Expression {
        /**
index 0f825b9..e4dc6a0 100644 (file)
@@ -24,6 +24,8 @@ using GLib;
 
 /**
  * Represents an expression with two operands in the source code.
+ *
+ * Supports +, -, *, /, %, <<, >>, <, >, <=, >=, ==, !=, &, |, ^, &&, ||.
  */
 public class Vala.BinaryExpression : Expression {
        /**
index 02c57a5..a0fac5f 100644 (file)
 
 using GLib;
 
-namespace Vala {
-       public class BooleanLiteral : Literal {
-               public bool value { get; set; }
+/**
+ * Represents a literal boolean, i.e. true or false.
+ */
+public class Vala.BooleanLiteral : Literal {
+       /**
+        * The literal value.
+        */
+       public bool value { get; set; }
 
-               public static ref BooleanLiteral! new (bool b, SourceReference source) {
-                       return (new BooleanLiteral (value = b, source_reference = source));
-               }
-               
-               public override void accept (CodeVisitor! visitor) {
-                       visitor.visit_boolean_literal (this);
-               }
+       /**
+        * Creates a new boolean literal.
+        *
+        * @param b      boolean value
+        * @param source reference to source code
+        * @return       newly created boolean literal
+        */
+       public static ref BooleanLiteral! new (bool b, SourceReference source) {
+               return (new BooleanLiteral (value = b, source_reference = source));
+       }
+       
+       public override void accept (CodeVisitor! visitor) {
+               visitor.visit_boolean_literal (this);
        }
 }
index 4df127b..0bce118 100644 (file)
 
 using GLib;
 
-namespace Vala {
-       public class BreakStatement : Statement {
-               public static ref BreakStatement! new (SourceReference source) {
-                       return (new BreakStatement (source_reference = source));
-               }
-               
-               public override void accept (CodeVisitor! visitor) {
-                       visitor.visit_break_statement (this);
-               }
+/**
+ * Represents a break statement in the source code.
+ */
+public class Vala.BreakStatement : Statement {
+       /**
+        * Creates a new break statement.
+        *
+        * @param source reference to source code
+        * @return       newly created break statement
+        */
+       public static ref BreakStatement! new (SourceReference source) {
+               return (new BreakStatement (source_reference = source));
+       }
+       
+       public override void accept (CodeVisitor! visitor) {
+               visitor.visit_break_statement (this);
        }
 }
index 36fa483..c02ab25 100644 (file)
 
 using GLib;
 
-namespace Vala {
-       public class Callback : DataType {
-               public TypeReference return_type { get; set; }
-               private List<FormalParameter> parameters;
-               
-               public static ref Callback new (string! name, TypeReference return_type, SourceReference source) {
-                       return (new Callback (name = name, return_type = return_type, source_reference = source));
+/**
+ * Represents a function callback type.
+ */
+public class Vala.Callback : DataType {
+       /**
+        * The return type of this callback.
+        */
+       public TypeReference return_type { get; set; }
+       
+       private List<FormalParameter> parameters;
+       private string cname;
+       
+       /**
+        * Creates a new callback.
+        *
+        * @param name        callback type name
+        * @param return_type return type
+        * @param source      reference to source code
+        * @return            newly created callback
+        */
+       public static ref Callback new (string! name, TypeReference return_type, SourceReference source) {
+               return (new Callback (name = name, return_type = return_type, source_reference = source));
+       }
+       
+       /**
+        * Append paramater to this callback function.
+        *
+        * @param param a formal parameter
+        */
+       public void add_parameter (FormalParameter! param) {
+               parameters.append (param);
+       }
+
+       /**
+        * Return copy of parameter list.
+        *
+        * @return parameter list
+        */
+       public ref List<FormalParameter> get_parameters () {
+               return parameters.copy ();
+       }
+       
+       /**
+        * Checks whether the arguments and return type of the specified method
+        * matches this callback.
+        *
+        * @param m a method
+        * @return  true if the specified method is compatible to this callback
+        */
+       public bool matches_method (Method! m) {
+               if (m.return_type.type != return_type.type) {
+                       return false;
                }
                
-               public void add_parameter (FormalParameter! param) {
-                       parameters.append (param);
+               var method_params = m.get_parameters ();
+               var method_params_it = method_params;
+               foreach (FormalParameter param in parameters) {
+                       /* method is allowed to accept less arguments */
+                       if (method_params_it == null) {
+                               break;
+                       }
+                       
+                       var method_param = (FormalParameter) method_params_it.data;
+                       if (method_param.type_reference.type != param.type_reference.type) {
+                               return false;
+                       }
+                       
+                       method_params_it = method_params_it.next;
                }
                
-               public ref List<FormalParameter> get_parameters () {
-                       return parameters.copy ();
+               /* method may not expect more arguments */
+               if (method_params_it != null) {
+                       return false;
                }
                
-               public override void accept (CodeVisitor! visitor) {
-                       visitor.visit_begin_callback (this);
-                       
-                       return_type.accept (visitor);
-                       
-                       foreach (FormalParameter! param in parameters) {
-                               param.accept (visitor);
-                       }
-
-                       visitor.visit_end_callback (this);
+               return true;
+       }
+       
+       public override void accept (CodeVisitor! visitor) {
+               visitor.visit_begin_callback (this);
+               
+               return_type.accept (visitor);
+               
+               foreach (FormalParameter! param in parameters) {
+                       param.accept (visitor);
                }
 
-               private string cname;
-               public override string! get_cname () {
-                       if (cname == null) {
-                               cname = "%s%s".printf (@namespace.get_cprefix (), name);
-                       }
-                       return cname;
-               }
+               visitor.visit_end_callback (this);
+       }
 
-               public override bool is_reference_type () {
-                       return true;
-               }
-               
-               public override string get_ref_function () {
-                       return "";
-               }
-               
-               public override string get_free_function () {
-                       return "";
+       public override string! get_cname () {
+               if (cname == null) {
+                       cname = "%s%s".printf (@namespace.get_cprefix (), name);
                }
+               return cname;
+       }
+
+       public override bool is_reference_type () {
+               return false;
        }
 }
index 426b222..263a67a 100644 (file)
@@ -108,12 +108,12 @@ namespace Vala {
                                        foreach (Namespace ns in namespaces) {
                                                var structs = ns.get_structs ();
                                                foreach (Struct st in structs) {
-                                                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (st.get_cname ()), typedef_name = st.get_cname ()));
+                                                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (st.get_cname ()), declarator = new CCodeVariableDeclarator (name = st.get_cname ())));
                                                }
                                                var classes = ns.get_classes ();
                                                foreach (Class cl in classes) {
-                                                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (cl.get_cname ()), typedef_name = cl.get_cname ()));
-                                                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%sClass".printf (cl.get_cname ()), typedef_name = "%sClass".printf (cl.get_cname ())));
+                                                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (cl.get_cname ()), declarator = new CCodeVariableDeclarator (name = cl.get_cname ())));
+                                                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%sClass".printf (cl.get_cname ()), declarator = new CCodeVariableDeclarator (name = "%sClass".printf (cl.get_cname ()))));
                                                }
                                        }
                                }
@@ -230,10 +230,10 @@ namespace Vala {
 
 
                        if (cl.source_reference.file.cycle == null) {
-                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_struct.name), typedef_name = cl.get_cname ()));
-                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), typedef_name = "%sClass".printf (cl.get_cname ())));
+                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_struct.name), declarator = new CCodeVariableDeclarator (name = cl.get_cname ())));
+                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), declarator = new CCodeVariableDeclarator (name = "%sClass".printf (cl.get_cname ()))));
                        }
-                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_priv_struct.name), typedef_name = "%sPrivate".printf (cl.get_cname ())));
+                       header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_priv_struct.name), declarator = new CCodeVariableDeclarator (name = "%sPrivate".printf (cl.get_cname ()))));
                        
                        instance_struct.add_field (cl.base_class.get_cname (), "parent");
                        instance_struct.add_field ("%sPrivate *".printf (cl.get_cname ()), "priv");
@@ -597,8 +597,8 @@ namespace Vala {
 
 
                        if (iface.source_reference.file.cycle == null) {
-                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (iface.get_cname ()), typedef_name = iface.get_cname ()));
-                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), typedef_name = "%sInterface".printf (iface.get_cname ())));
+                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (iface.get_cname ()), declarator = new CCodeVariableDeclarator (name = iface.get_cname ())));
+                               header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), declarator = new CCodeVariableDeclarator (name = "%sInterface".printf (iface.get_cname ()))));
                        }
                        
                        type_struct.add_field ("GTypeInterface", "parent");
@@ -631,6 +631,24 @@ namespace Vala {
                        cenum.add_value (ev.get_cname (), null);
                }
 
+               public override void visit_end_callback (Callback! cb) {
+                       var ctypedef = new CCodeTypeDefinition ();
+                       
+                       ctypedef.type_name = cb.return_type.get_cname ();
+                       
+                       var cfundecl = new CCodeFunctionDeclarator (name = cb.get_cname ());
+                       foreach (FormalParameter param in cb.get_parameters ()) {
+                               cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
+                       }
+                       ctypedef.declarator = cfundecl;
+                       
+                       if (cb.access == MemberAccessibility.PUBLIC) {
+                               header_type_declaration.append (ctypedef);
+                       } else {
+                               source_type_member_declaration.append (ctypedef);
+                       }
+               }
+
                public override void visit_constant (Constant! c) {
                        if (c.symbol.parent_symbol.node is DataType) {
                                var t = (DataType) c.symbol.parent_symbol.node;
@@ -1549,17 +1567,27 @@ namespace Vala {
                public override void visit_end_invocation_expression (InvocationExpression! expr) {
                        var ccall = new CCodeFunctionCall (call = (CCodeExpression) expr.call.ccodenode);
                        
-                       var m = (Method) expr.call.symbol_reference.node;
-                       var base_method = m;
-                       if (m.is_override) {
-                               base_method = m.base_method;
+                       Method m = null;
+                       List<FormalParameter> params;
+                       if (expr.call.symbol_reference.node is VariableDeclarator) {
+                               var decl = (VariableDeclarator) expr.call.symbol_reference.node;
+                               var cb = (Callback) decl.type_reference.type;
+                               params = cb.get_parameters ();
+                       } else {
+                               m = (Method) expr.call.symbol_reference.node;
+                               params = m.get_parameters ();
                        }
                        
                        /* explicitly use strong reference as ccall gets unrefed
                         * at end of inner block
                         */
                        ref CCodeExpression instance;
-                       if (m.instance) {
+                       if (m != null && m.instance) {
+                               var base_method = m;
+                               if (m.is_override) {
+                                       base_method = m.base_method;
+                               }
+
                                var req_cast = false;
                                if (expr.call is SimpleName) {
                                        instance = new CCodeIdentifier (name = "self");
@@ -1586,7 +1614,6 @@ namespace Vala {
                                }
                        }
                        
-                       var params = m.get_parameters ();
                        var i = 1;
                        foreach (Expression arg in expr.argument_list) {
                                /* explicitly use strong reference as ccall gets
@@ -1636,11 +1663,11 @@ namespace Vala {
                                params = params.next;
                        }
                        
-                       if (m.instance && m.instance_last) {
+                       if (m != null && m.instance && m.instance_last) {
                                ccall.add_argument (instance);
                        }
                        
-                       if (m.instance && m.returns_modified_pointer) {
+                       if (m != null && m.instance && m.returns_modified_pointer) {
                                expr.ccodenode = new CCodeAssignment (left = instance, right = ccall);
                        } else {
                                expr.ccodenode = ccall;
index ff3ad69..39eca3f 100644 (file)
@@ -99,8 +99,9 @@ namespace Vala {
                        List<FormalParameter> params;
                        
                        var msym = expr.call.symbol_reference;
-                       if (msym.node is Callback) {
-                               var cb = (Callback) msym.node;
+                       if (msym.node is VariableDeclarator) {
+                               var decl = (VariableDeclarator) msym.node;
+                               var cb = (Callback) decl.type_reference.type;
                                params = cb.get_parameters ();
                        } else {
                                var m = (Method) msym.node;
index afa5d66..5a364ab 100644 (file)
@@ -225,19 +225,54 @@ namespace Vala {
                public override void visit_variable_declarator (VariableDeclarator! decl) {
                        if (decl.type_reference == null) {
                                /* var type */
+                               
+                               if (decl.initializer == null) {
+                                       decl.error = true;
+                                       Report.error (decl.source_reference, "var declaration not allowed without initializer");
+                                       return;
+                               }
+                               if (decl.initializer.static_type == null) {
+                                       decl.error = true;
+                                       Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
+                                       return;
+                               }
+                               
                                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.initializer != null && memory_management) {
-                               if (decl.initializer.static_type.is_ref) {
-                                       /* rhs transfers ownership of the expression */
-                                       if (!decl.type_reference.is_lvalue_ref) {
-                                               /* lhs doesn't own the value
-                                                * promote lhs type */
+                       
+                       if (decl.initializer != null) {
+                               if (decl.initializer.static_type == null) {
+                                       if (decl.initializer.symbol_reference.node is Method &&
+                                           decl.type_reference.type is Callback) {
+                                               var m = (Method) decl.initializer.symbol_reference.node;
+                                               var cb = (Callback) decl.type_reference.type;
                                                
-                                               decl.type_reference.is_lvalue_ref = true;
+                                               /* check whether method matches callback type */
+                                               if (!cb.matches_method (m)) {
+                                                       decl.error = true;
+                                                       Report.error (decl.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+                                                       return;
+                                               }
+                                               
+                                               decl.initializer.static_type = decl.type_reference;
+                                       } else {
+                                               decl.error = true;
+                                               Report.error (decl.source_reference, "expression type not allowed as initializer");
+                                               return;
+                                       }
+                               }
+                       
+                               if (memory_management) {
+                                       if (decl.initializer.static_type.is_ref) {
+                                               /* rhs transfers ownership of the expression */
+                                               if (!decl.type_reference.is_lvalue_ref) {
+                                                       /* lhs doesn't own the value
+                                                        * promote lhs type */
+                                                       
+                                                       decl.type_reference.is_lvalue_ref = true;
+                                               }
                                        }
                                }
                        }
@@ -515,14 +550,25 @@ namespace Vala {
                        TypeReference ret_type;
                        List<FormalParameter> params;
                        
-                       if (msym.node is Callback) {
-                               var cb = (Callback) msym.node;
-                               ret_type = cb.return_type;
-                               params = cb.get_parameters ();
-                       } else {
+                       if (msym.node is VariableDeclarator) {
+                               var decl = (VariableDeclarator) msym.node;
+                               if (decl.type_reference.type is Callback) {
+                                       var cb = (Callback) decl.type_reference.type;
+                                       ret_type = cb.return_type;
+                                       params = cb.get_parameters ();
+                               } else {
+                                       expr.error = true;
+                                       Report.error (expr.source_reference, "invocation not supported in this context");
+                                       return;
+                               }
+                       } else if (msym.node is Method) {
                                var m = (Method) msym.node;
                                ret_type = m.return_type;
                                params = m.parameters;
+                       } else {
+                               expr.error = true;
+                               Report.error (expr.source_reference, "invocation not supported in this context");
+                               return;
                        }
                
                        expr.static_type = ret_type;
@@ -758,8 +804,28 @@ namespace Vala {
                                var sig = (Signal) a.left.symbol_reference.node;
                        } else if (a.left.symbol_reference.node is Property) {
                                var prop = (Property) a.left.symbol_reference.node;
+                       } else if (a.left.symbol_reference.node is VariableDeclarator && a.right.static_type == null) {
+                               var decl = (VariableDeclarator) a.left.symbol_reference.node;
+                               if (a.right.symbol_reference.node is Method &&
+                                   decl.type_reference.type is Callback) {
+                                       var m = (Method) a.right.symbol_reference.node;
+                                       var cb = (Callback) decl.type_reference.type;
+                                       
+                                       /* check whether method matches callback type */
+                                       if (!cb.matches_method (m)) {
+                                               decl.error = true;
+                                               Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+                                               return;
+                                       }
+                                       
+                                       a.right.static_type = decl.type_reference;
+                               } else {
+                                       a.error = true;
+                                       Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
+                                       return;
+                               }
                        } else if (a.left.static_type != null && a.right.static_type != null) {
-                                if (!is_type_compatible (a.right.static_type, a.left.static_type)) {
+                               if (!is_type_compatible (a.right.static_type, a.left.static_type)) {
                                        /* if there was an error on either side,
                                         * i.e. a.{left|right}.static_type == null, skip type check */
                                        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 ()));