@@ -5,6 +5,21 @@ module checker
5
5
import v.ast
6
6
import v.pref
7
7
8
+ // error_type_name returns a proper type name reference for error messages
9
+ // ? => Option type
10
+ // ! => Result type
11
+ // others => type `name`
12
+ [inline ]
13
+ fn (mut c Checker) error_type_name (exp_type ast.Type) string {
14
+ return if exp_type == ast.void_type.set_flag (.result) {
15
+ 'Result type'
16
+ } else if exp_type == ast.void_type.set_flag (.option) {
17
+ 'Option type'
18
+ } else {
19
+ 'type `${c.table.type_to_str(exp_type)} `'
20
+ }
21
+ }
22
+
8
23
// TODO: non deferred
9
24
fn (mut c Checker) return_stmt (mut node ast.Return) {
10
25
if c.table.cur_fn == unsafe { nil } {
@@ -22,6 +37,12 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
22
37
if node.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type {
23
38
c.error ('unexpected argument, current function does not return anything' , node.exprs[0 ].pos ())
24
39
return
40
+ } else if node.exprs.len > 1 && c.table.cur_fn.return_type == ast.void_type.set_flag (.option) {
41
+ c.error ('can only return `none` from an Option-only return function' , node.exprs[0 ].pos ())
42
+ return
43
+ } else if node.exprs.len > 1 && c.table.cur_fn.return_type == ast.void_type.set_flag (.result) {
44
+ c.error ('functions with Result-only return types can only return an error' , node.exprs[0 ].pos ())
45
+ return
25
46
} else if node.exprs.len == 0 && ! (c.expected_type == ast.void_type
26
47
|| expected_type_sym.kind == .void) {
27
48
stype := c.table.type_to_str (expected_type)
@@ -100,7 +121,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
100
121
c.warn ('Option and Result types have been split, use `!Foo` to return errors' ,
101
122
node.pos)
102
123
} else if exp_is_result && got_types_0_idx == ast.none_type_idx {
103
- c.warn ('Option and Result types have been split, use `?Foo ` to return none' , node.pos)
124
+ c.warn ('Option and Result types have been split, use `?` to return none' , node.pos)
104
125
}
105
126
if (exp_is_option
106
127
&& got_types_0_ idx in [ast.none_type_idx, ast.error_type_idx, option_type_idx])
@@ -143,13 +164,13 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
143
164
got_typ := c.unwrap_generic (got_types[i])
144
165
if got_typ.has_flag (.option) && got_typ.clear_flag (.option) != exp_type.clear_flag (.option) {
145
166
pos := node.exprs[expr_idxs[i]].pos ()
146
- c.error ('cannot use `${c.table.type_to_str(got_typ)} ` as type ` ${c.table.type_to_str (exp_type)} ` in return argument' ,
167
+ c.error ('cannot use `${c.table.type_to_str(got_typ)} ` as ${c.error_type_name (exp_type)} in return argument' ,
147
168
pos)
148
169
}
149
170
if got_typ.has_flag (.result) && (! exp_type.has_flag (.result)
150
171
|| c.table.type_to_str (got_typ) != c.table.type_to_str (exp_type)) {
151
172
pos := node.exprs[expr_idxs[i]].pos ()
152
- c.error ('cannot use `${c.table.type_to_str(got_typ)} ` as type ` ${c.table.type_to_str (exp_type)} ` in return argument' ,
173
+ c.error ('cannot use `${c.table.type_to_str(got_typ)} ` as ${c.error_type_name (exp_type)} in return argument' ,
153
174
pos)
154
175
}
155
176
if node.exprs[expr_idxs[i]] ! is ast.ComptimeCall {
@@ -161,7 +182,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
161
182
if node.exprs[expr_idxs[i]] is ast.IntegerLiteral {
162
183
var := (node.exprs[expr_idxs[i]] as ast.IntegerLiteral ).val
163
184
if var[0 ] == `-` {
164
- c.note ('cannot use a negative value as value of type ` ${c.table.type_to_str (exp_type)} ` in return argument' ,
185
+ c.note ('cannot use a negative value as value of ${c.error_type_name (exp_type)} in return argument' ,
165
186
pos)
166
187
}
167
188
}
@@ -194,7 +215,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
194
215
} else {
195
216
got_typ_sym.name
196
217
}
197
- c.error ('cannot use `${got_typ_name} ` as type ` ${c.table.type_to_str (exp_type)} ` in return argument' ,
218
+ c.error ('cannot use `${got_typ_name} ` as ${c.error_type_name (exp_type)} in return argument' ,
198
219
pos)
199
220
}
200
221
}
0 commit comments