v / vlib / v2 / transformer / interface.v
323 lines · 299 sloc · 7.88 KB · 83b622f651c1df985ef933e49692445526b99ce3
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4
5module transformer
6
7import v2.ast
8import v2.types
9
10// is_interface_var checks if a variable is an interface type by looking up its type in scope
11fn (t &Transformer) is_interface_var(name string) bool {
12 // Special case: 'err' in or-blocks is always IError interface
13 if name == 'err' {
14 return true
15 }
16 typ := t.lookup_var_type(name) or { return false }
17 return typ is types.Interface
18}
19
20// is_interface_receiver checks if an expression's type is an interface type
21fn (t &Transformer) is_interface_receiver(expr ast.Expr) bool {
22 match expr {
23 ast.Ident {
24 return t.is_interface_var(expr.name)
25 }
26 ast.ParenExpr {
27 return t.is_interface_receiver(expr.expr)
28 }
29 ast.ModifierExpr {
30 return t.is_interface_receiver(expr.expr)
31 }
32 else {}
33 }
34
35 if typ := t.get_interface_receiver_type(expr) {
36 base := t.unwrap_alias_and_pointer_type(typ)
37 return base is types.Interface
38 }
39 return false
40}
41
42fn (t &Transformer) get_interface_receiver_type(expr ast.Expr) ?types.Type {
43 if typ := t.get_expr_type(expr) {
44 return typ
45 }
46 if typ := t.resolve_expr_type(expr) {
47 return typ
48 }
49 if expr is ast.IndexExpr {
50 if expr.expr is ast.RangeExpr {
51 return none
52 }
53 if container_type := t.get_expr_type(expr.lhs) {
54 base := t.unwrap_alias_and_pointer_type(container_type)
55 if base is types.Array {
56 return base.elem_type
57 }
58 if base is types.ArrayFixed {
59 return base.elem_type
60 }
61 if base is types.Map {
62 return base.value_type
63 }
64 }
65 }
66 return none
67}
68
69// is_interface_cast checks if an expression is an interface cast like Calculator(value)
70fn (t &Transformer) is_interface_cast(expr ast.Expr) bool {
71 if t.get_interface_cast_inner_expr(expr) != none {
72 return true
73 }
74 return false
75}
76
77// get_expr_type_name returns the concrete type name for an expression using the type checker env
78fn (t &Transformer) get_expr_type_name(expr ast.Expr) ?string {
79 if typ := t.get_expr_type(expr) {
80 name := t.type_to_c_name(typ)
81 if name != '' {
82 return name
83 }
84 }
85 // For simple identifiers, try scope lookup
86 if expr is ast.Ident {
87 if typ := t.lookup_var_type(expr.name) {
88 name := t.type_to_c_name(typ)
89 if name != '' {
90 return name
91 }
92 }
93 }
94 return none
95}
96
97fn (t &Transformer) get_interface_cast_concrete_type(expr ast.Expr) ?string {
98 match expr {
99 ast.ParenExpr {
100 return t.get_interface_cast_concrete_type(expr.expr)
101 }
102 ast.CallOrCastExpr {
103 if t.interface_type_expr_is_interface(expr.lhs) {
104 if concrete := t.get_expr_type_name(expr.expr) {
105 return concrete
106 }
107 }
108 }
109 ast.CallExpr {
110 if expr.args.len == 1 && t.interface_type_expr_is_interface(expr.lhs) {
111 if concrete := t.get_expr_type_name(expr.args[0]) {
112 return concrete
113 }
114 }
115 }
116 ast.CastExpr {
117 if t.interface_type_expr_is_interface(expr.typ) {
118 if concrete := t.get_expr_type_name(expr.expr) {
119 return concrete
120 }
121 }
122 }
123 else {}
124 }
125
126 return none
127}
128
129fn (t &Transformer) get_interface_cast_inner_expr(expr ast.Expr) ?ast.Expr {
130 match expr {
131 ast.ParenExpr {
132 return t.get_interface_cast_inner_expr(expr.expr)
133 }
134 ast.CallOrCastExpr {
135 if t.interface_type_expr_is_interface(expr.lhs) {
136 return expr.expr
137 }
138 }
139 ast.CallExpr {
140 if expr.args.len == 1 && t.interface_type_expr_is_interface(expr.lhs) {
141 return expr.args[0]
142 }
143 }
144 ast.CastExpr {
145 if t.interface_type_expr_is_interface(expr.typ) {
146 return expr.expr
147 }
148 }
149 else {}
150 }
151
152 return none
153}
154
155fn (t &Transformer) interface_type_expr_is_interface(expr ast.Expr) bool {
156 type_name := t.expr_to_type_name(expr)
157 if type_name != '' {
158 if typ := t.lookup_type(type_name) {
159 return typ is types.Interface
160 }
161 }
162 if expr is ast.Ident {
163 mut scope := t.get_current_scope() or { return false }
164 obj := scope.lookup_parent(expr.name, 0) or { return false }
165 if obj is types.Type {
166 return obj is types.Interface
167 }
168 }
169 return false
170}
171
172fn (t &Transformer) get_interface_array_init_concrete_type(expr &ast.ArrayInitExpr) ?string {
173 if !expr_array_has_valid_data(expr.exprs) {
174 return none
175 }
176 mut concrete_type := ''
177 for e in expr.exprs {
178 concrete := t.get_interface_cast_concrete_type(e) or { return none }
179 if concrete_type == '' {
180 concrete_type = concrete
181 } else if concrete_type != concrete {
182 return none
183 }
184 }
185 if concrete_type != '' {
186 return concrete_type
187 }
188 return none
189}
190
191fn (t &Transformer) get_interface_array_expr_concrete_type(expr ast.Expr) ?string {
192 match expr {
193 ast.Ident {
194 return t.get_interface_concrete_type(expr.name)
195 }
196 ast.ParenExpr {
197 return t.get_interface_array_expr_concrete_type(expr.expr)
198 }
199 ast.ArrayInitExpr {
200 return t.get_interface_array_init_concrete_type(&expr)
201 }
202 ast.CallExpr {
203 if expr.lhs is ast.SelectorExpr {
204 sel := expr.lhs as ast.SelectorExpr
205 if sel.rhs.name in ['repeat', 'clone'] {
206 return t.get_interface_array_expr_concrete_type(sel.lhs)
207 }
208 }
209 }
210 ast.CallOrCastExpr {
211 if expr.lhs is ast.SelectorExpr {
212 sel := expr.lhs as ast.SelectorExpr
213 if sel.rhs.name in ['repeat', 'clone'] {
214 return t.get_interface_array_expr_concrete_type(sel.lhs)
215 }
216 }
217 }
218 else {}
219 }
220
221 return none
222}
223
224fn (t &Transformer) get_interface_assignment_concrete_type(expr ast.Expr) ?string {
225 if concrete := t.get_interface_cast_concrete_type(expr) {
226 return concrete
227 }
228 if concrete := t.get_interface_array_expr_concrete_type(expr) {
229 return concrete
230 }
231 if expr is ast.Ident {
232 return t.get_interface_concrete_type(expr.name)
233 }
234 if expr is ast.ParenExpr {
235 return t.get_interface_assignment_concrete_type(expr.expr)
236 }
237 return none
238}
239
240fn (t &Transformer) get_interface_concrete_type_for_expr(expr ast.Expr) ?string {
241 match expr {
242 ast.Ident {
243 return t.get_interface_concrete_type(expr.name)
244 }
245 ast.ParenExpr {
246 return t.get_interface_concrete_type_for_expr(expr.expr)
247 }
248 ast.ModifierExpr {
249 return t.get_interface_concrete_type_for_expr(expr.expr)
250 }
251 ast.IndexExpr {
252 return t.get_interface_array_expr_concrete_type(expr.lhs)
253 }
254 else {}
255 }
256
257 return none
258}
259
260fn (t &Transformer) get_native_default_interface_concrete_type(expr ast.Expr, method_name string) ?string {
261 prng_methods := ['seed', 'u8', 'u16', 'u32', 'u64', 'block_size', 'free']
262 if method_name !in prng_methods {
263 return none
264 }
265 if t.cur_module == 'rand' {
266 return 'wyrand__WyRandRNG'
267 }
268 receiver_type := t.get_interface_receiver_type(expr) or { return none }
269 base := t.unwrap_alias_and_pointer_type(receiver_type)
270 if base !is types.Interface {
271 return none
272 }
273 iface_name := t.type_to_c_name(base)
274 if iface_name !in ['PRNG', 'rand__PRNG'] {
275 return none
276 }
277 return 'wyrand__WyRandRNG'
278}
279
280fn (mut t Transformer) native_interface_receiver_arg(expr ast.Expr, concrete string) ast.Expr {
281 concrete_type := t.c_name_to_type(concrete) or { return expr }
282 return t.native_interface_receiver_arg_with_type(expr, concrete_type)
283}
284
285fn (mut t Transformer) native_interface_receiver_arg_with_type(expr ast.Expr, concrete_type types.Type) ast.Expr {
286 match expr {
287 ast.IndexExpr {
288 pos := t.next_synth_pos()
289 t.register_synth_type(pos, concrete_type)
290 return ast.Expr(ast.IndexExpr{
291 lhs: expr.lhs
292 expr: expr.expr
293 is_gated: expr.is_gated
294 pos: pos
295 })
296 }
297 ast.ParenExpr {
298 return ast.Expr(ast.ParenExpr{
299 expr: t.native_interface_receiver_arg_with_type(expr.expr, concrete_type)
300 pos: expr.pos
301 })
302 }
303 ast.ModifierExpr {
304 return ast.Expr(ast.ModifierExpr{
305 kind: expr.kind
306 expr: t.native_interface_receiver_arg_with_type(expr.expr, concrete_type)
307 pos: expr.pos
308 })
309 }
310 else {}
311 }
312
313 return expr
314}
315
316// get_interface_concrete_type returns the concrete type name for an interface variable
317// if it was tracked during interface cast lowering (native backend only)
318fn (t &Transformer) get_interface_concrete_type(name string) ?string {
319 if concrete := t.interface_concrete_types[name] {
320 return concrete
321 }
322 return none
323}
324