codegen: Custom abstract methods of GLib.Source are handled differently
[vala-gnome.git] / vala / valadelegatetype.vala
blob8e62d750bad266887440989c13a433d0c7815a6b
1 /* valadelegatetype.vala
3 * Copyright (C) 2007-2012 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * The type of an instance of a delegate.
28 public class Vala.DelegateType : CallableType {
29 public Delegate delegate_symbol { get; set; }
31 public bool is_called_once { get; set; }
33 public DelegateType (Delegate delegate_symbol) {
34 this.delegate_symbol = delegate_symbol;
35 this.is_called_once = (delegate_symbol.get_attribute_string ("CCode", "scope") == "async");
38 public override bool is_invokable () {
39 return true;
42 public override DataType? get_return_type () {
43 return delegate_symbol.return_type;
46 public override List<Parameter>? get_parameters () {
47 return delegate_symbol.get_parameters ();
50 public override string to_qualified_string (Scope? scope) {
51 // logic temporarily duplicated from DataType class
53 Symbol global_symbol = delegate_symbol;
54 while (global_symbol.parent_symbol != null && global_symbol.parent_symbol.name != null) {
55 global_symbol = global_symbol.parent_symbol;
58 Symbol sym = null;
59 Scope parent_scope = scope;
60 while (sym == null && parent_scope != null) {
61 sym = parent_scope.lookup (global_symbol.name);
62 parent_scope = parent_scope.parent_scope;
65 string s;
67 if (sym != null && global_symbol != sym) {
68 s = "global::" + delegate_symbol.get_full_name ();;
69 } else {
70 s = delegate_symbol.get_full_name ();
73 var type_args = get_type_arguments ();
74 if (type_args.size > 0) {
75 s += "<";
76 bool first = true;
77 foreach (DataType type_arg in type_args) {
78 if (!first) {
79 s += ",";
80 } else {
81 first = false;
83 if (!type_arg.value_owned) {
84 s += "weak ";
86 s += type_arg.to_qualified_string (scope);
88 s += ">";
90 if (nullable) {
91 s += "?";
93 return s;
96 public override DataType copy () {
97 var result = new DelegateType (delegate_symbol);
98 result.source_reference = source_reference;
99 result.value_owned = value_owned;
100 result.nullable = nullable;
102 foreach (DataType arg in get_type_arguments ()) {
103 result.add_type_argument (arg.copy ());
106 result.is_called_once = is_called_once;
108 return result;
111 public override bool is_accessible (Symbol sym) {
112 return delegate_symbol.is_accessible (sym);
115 public override bool check (CodeContext context) {
116 if (is_called_once && !value_owned) {
117 Report.warning (source_reference, "delegates with scope=\"async\" must be owned");
120 if (!delegate_symbol.check (context)) {
121 return false;
124 var n_type_params = delegate_symbol.get_type_parameters ().size;
125 var n_type_args = get_type_arguments ().size;
126 if (n_type_args > 0 && n_type_args < n_type_params) {
127 Report.error (source_reference, "too few type arguments");
128 return false;
129 } else if (n_type_args > 0 && n_type_args > n_type_params) {
130 Report.error (source_reference, "too many type arguments");
131 return false;
134 foreach (DataType type in get_type_arguments ()) {
135 if (!type.check (context)) {
136 return false;
140 return true;
143 public override bool compatible (DataType target_type) {
144 var dt_target = target_type as DelegateType;
145 if (dt_target == null) {
146 return false;
149 // trivial case
150 if (delegate_symbol == dt_target.delegate_symbol) {
151 return true;
154 // target-delegate is allowed to ensure stricter return type (stronger postcondition)
155 if (!get_return_type ().stricter (dt_target.get_return_type ().get_actual_type (dt_target, null, this))) {
156 return false;
159 var parameters = get_parameters ();
160 Iterator<Parameter> params_it = parameters.iterator ();
162 if (dt_target.delegate_symbol.parent_symbol is Signal && dt_target.delegate_symbol.sender_type != null && parameters.size == dt_target.get_parameters ().size + 1) {
163 // target-delegate has sender parameter
164 params_it.next ();
166 // target-delegate is allowed to accept arguments of looser types (weaker precondition)
167 var p = params_it.get ();
168 if (!dt_target.delegate_symbol.sender_type.stricter (p.variable_type)) {
169 return false;
173 foreach (Parameter param in dt_target.get_parameters ()) {
174 /* target-delegate is allowed to accept less arguments */
175 if (!params_it.next ()) {
176 break;
179 // target-delegate is allowed to accept arguments of looser types (weaker precondition)
180 var p = params_it.get ();
181 if (!param.variable_type.get_actual_type (this, null, this).stricter (p.variable_type)) {
182 return false;
186 /* target-delegate may not expect more arguments */
187 if (params_it.next ()) {
188 return false;
191 // target-delegate may throw less but not more errors than the delegate
192 foreach (DataType error_type in get_error_types ()) {
193 bool match = false;
194 foreach (DataType delegate_error_type in dt_target.get_error_types ()) {
195 if (error_type.compatible (delegate_error_type)) {
196 match = true;
197 break;
201 if (!match) {
202 return false;
206 return true;
209 public override bool is_disposable () {
210 return delegate_symbol.has_target && value_owned && !is_called_once;