Line data Source code
1 : /* valadelegatetype.vala
2 : *
3 : * Copyright (C) 2007-2012 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * The type of an instance of a delegate.
27 : */
28 583368 : public class Vala.DelegateType : CallableType {
29 : public weak Delegate delegate_symbol {
30 1651657 : get {
31 1651657 : return (Delegate) symbol;
32 : }
33 : }
34 :
35 682371 : public bool is_called_once { get; set; }
36 :
37 581939 : DelegateTargetField? target_field;
38 581939 : DelegateDestroyField? destroy_field;
39 :
40 1745817 : public DelegateType (Delegate delegate_symbol, SourceReference? source_reference = null) {
41 581939 : base (delegate_symbol, source_reference);
42 581939 : this.is_called_once = (delegate_symbol.get_attribute_string ("CCode", "scope") == "async");
43 : }
44 :
45 21 : public override Symbol? get_member (string member_name) {
46 21 : if (member_name == "target") {
47 21 : return get_target_field ();
48 6 : } else if (member_name == "destroy") {
49 12 : return get_destroy_field ();
50 : }
51 21 : return null;
52 : }
53 :
54 15 : unowned DelegateTargetField get_target_field () {
55 15 : if (target_field == null) {
56 15 : target_field = new DelegateTargetField (source_reference);
57 15 : target_field.access = SymbolAccessibility.PUBLIC;
58 : }
59 15 : return target_field;
60 : }
61 :
62 6 : unowned DelegateDestroyField get_destroy_field () {
63 6 : if (destroy_field == null) {
64 6 : destroy_field = new DelegateDestroyField (source_reference);
65 6 : destroy_field.access = SymbolAccessibility.PUBLIC;
66 : }
67 6 : return destroy_field;
68 : }
69 :
70 89443 : public override DataType copy () {
71 89443 : var result = new DelegateType (delegate_symbol, source_reference);
72 89443 : result.value_owned = value_owned;
73 89443 : result.nullable = nullable;
74 :
75 122005 : foreach (DataType arg in get_type_arguments ()) {
76 16281 : result.add_type_argument (arg.copy ());
77 : }
78 :
79 89443 : result.is_called_once = is_called_once;
80 :
81 89443 : return result;
82 : }
83 :
84 39 : public override bool equals (DataType type2) {
85 39 : return compatible (type2);
86 : }
87 :
88 480778 : public override bool is_accessible (Symbol sym) {
89 480778 : return delegate_symbol.is_accessible (sym);
90 : }
91 :
92 912799 : public override bool check (CodeContext context) {
93 912799 : if (is_called_once && !value_owned) {
94 1 : Report.warning (source_reference, "delegates with scope=\"async\" must be owned");
95 : }
96 :
97 912799 : if (!delegate_symbol.check (context)) {
98 0 : error = true;
99 0 : return false;
100 : }
101 :
102 : // check whether there is the expected amount of type-arguments
103 912799 : if (!check_type_arguments (context, true)) {
104 3 : error = true;
105 3 : return false;
106 : }
107 :
108 912799 : return true;
109 : }
110 :
111 8898 : public override bool compatible (DataType target_type) {
112 8898 : unowned DelegateType? dt_target = target_type as DelegateType;
113 8902 : if (dt_target == null) {
114 48 : return false;
115 : }
116 :
117 : // trivial case
118 8854 : if (delegate_symbol == dt_target.delegate_symbol) {
119 8850 : return true;
120 : }
121 :
122 31 : if (delegate_symbol.has_target != dt_target.delegate_symbol.has_target) {
123 48 : return false;
124 : }
125 :
126 : // target-delegate is allowed to ensure stricter return type (stronger postcondition)
127 30 : if (!get_return_type ().stricter (dt_target.get_return_type ().get_actual_type (dt_target, null, this))) {
128 48 : return false;
129 : }
130 :
131 30 : var parameters = get_parameters ();
132 30 : Iterator<Parameter> params_it = parameters.iterator ();
133 :
134 50 : if (dt_target.delegate_symbol.parent_symbol is Signal && dt_target.delegate_symbol.sender_type != null && parameters.size == dt_target.get_parameters ().size + 1) {
135 : // target-delegate has sender parameter
136 20 : params_it.next ();
137 :
138 : // target-delegate is allowed to accept arguments of looser types (weaker precondition)
139 20 : var p = params_it.get ();
140 20 : if (!dt_target.delegate_symbol.sender_type.stricter (p.variable_type)) {
141 0 : return false;
142 : }
143 : }
144 :
145 88 : foreach (Parameter param in dt_target.get_parameters ()) {
146 31 : if (!params_it.next ()) {
147 1 : return false;
148 : }
149 :
150 30 : var p = params_it.get ();
151 30 : if (p != null && (param.ellipsis || param.params_array)) {
152 1 : if (param.ellipsis != p.ellipsis || param.params_array != p.params_array) {
153 0 : return false;
154 : }
155 1 : break;
156 : }
157 :
158 : // target-delegate is allowed to accept arguments of looser types (weaker precondition)
159 29 : if (!param.variable_type.get_actual_type (this, null, this).stricter (p.variable_type)) {
160 0 : return false;
161 : }
162 : }
163 :
164 : /* target-delegate may not expect more arguments */
165 29 : if (params_it.next ()) {
166 0 : return false;
167 : }
168 :
169 : // target-delegate may throw less but not more errors than the delegate
170 29 : var error_types = new ArrayList<DataType> ();
171 29 : delegate_symbol.get_error_types (error_types);
172 29 : foreach (DataType error_type in error_types) {
173 2 : bool match = false;
174 2 : var delegate_error_types = new ArrayList<DataType> ();
175 2 : dt_target.delegate_symbol.get_error_types (delegate_error_types);
176 6 : foreach (DataType delegate_error_type in delegate_error_types) {
177 2 : if (error_type.compatible (delegate_error_type)) {
178 0 : match = true;
179 0 : break;
180 : }
181 : }
182 :
183 0 : if (!match) {
184 2 : return false;
185 : }
186 : }
187 :
188 27 : return true;
189 : }
190 :
191 19125 : public override bool is_disposable () {
192 19125 : return delegate_symbol.has_target && value_owned && !is_called_once;
193 : }
194 : }
|