Skip to content

Commit 44f8ba6

Browse files
authored
type_resolver: fix recheck identification for anonfn on structinit (fix regression of #18294) (#23882)
1 parent 615e74d commit 44f8ba6

File tree

2 files changed

+101
-1
lines changed

2 files changed

+101
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import v.reflection
2+
3+
const provide_key = 'provide'
4+
5+
type InjectCb = fn () !
6+
7+
pub interface Object {}
8+
9+
pub struct Service {
10+
typ int @[required]
11+
inject InjectCb @[required]
12+
name string @[required]
13+
originalptr voidptr @[required]
14+
mut:
15+
instance &Object @[required]
16+
}
17+
18+
pub struct Module {
19+
mut:
20+
services map[int]Service = map[int]Service{}
21+
}
22+
23+
pub fn (mut self Module) inject_to_object[T](mut new_service T) ! {
24+
$for field in T.fields {
25+
mut service := self.get_service_from_field(field, T.name)!
26+
$if field.indirections > 0 {
27+
if mut service is Service {
28+
if service.typ != field.typ {
29+
return error("Type of property '${field.name}' in '${T.name}' must be ${service.name} as Reference")
30+
}
31+
unsafe {
32+
new_service.$(field.name) = service.originalptr
33+
}
34+
}
35+
} $else {
36+
if service is Service {
37+
println('Warning: field ${field.name} must be a reference to enable autoinject')
38+
}
39+
}
40+
}
41+
}
42+
43+
pub fn (mut self Module) register[T]() &T {
44+
mut new_service := &T{}
45+
typ_idx := typeof[T]().idx
46+
typ := reflection.get_type(typ_idx) or { panic('Type not found ${T.name}') }
47+
48+
if typ_idx in self.services {
49+
panic('Type ${typ.name} has been already registered')
50+
}
51+
52+
self.services[typ_idx] = Service{
53+
name: T.name
54+
typ: typ_idx
55+
instance: new_service
56+
originalptr: new_service
57+
inject: fn [mut self, mut new_service] [T]() ! {
58+
self.inject_to_object[T](mut new_service)!
59+
}
60+
}
61+
return new_service
62+
}
63+
64+
fn get_key(attrs []string) string {
65+
return attrs[0] or { 'key' }
66+
}
67+
68+
type ServiceOrNone = Service | bool
69+
70+
fn (mut self Module) get_service_from_field(field FieldData, t_name string) !ServiceOrNone {
71+
if 'inject' in field.attrs {
72+
return self.get_service(field.typ) or {
73+
return error('Invalid injection type for field ${field.name} in ${t_name}')
74+
}
75+
}
76+
return false
77+
}
78+
79+
fn (mut self Module) get_service(service_idx int) !Service {
80+
return self.services[service_idx] or {
81+
service_info := reflection.get_type(service_idx) or { return err }
82+
return error('Service with name ${service_info.name} not available, see available: ${self.services.keys()}')
83+
}
84+
}
85+
86+
struct Something {
87+
count int
88+
}
89+
90+
struct SomethingDifferent {
91+
text string
92+
}
93+
94+
fn test_main() {
95+
mut mod := Module{}
96+
mod.register[SomethingDifferent]()
97+
mod.register[Something]()
98+
assert true
99+
}

vlib/v/type_resolver/comptime_resolver.v

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ pub fn (mut t TypeResolver) get_comptime_selector_var_type(node ast.ComptimeSele
1818
pub fn (t &ResolverInfo) has_comptime_expr(node ast.Expr) bool {
1919
return (node is ast.Ident && node.ct_expr)
2020
|| (node is ast.IndexExpr && t.has_comptime_expr(node.left))
21-
|| node is ast.ComptimeSelector
21+
|| node is ast.ComptimeSelector || (node is ast.StructInit
22+
&& node.init_fields.any(it.expr is ast.AnonFn && it.expr.decl.generic_names.len > 0))
2223
|| (node is ast.PostfixExpr && t.has_comptime_expr(node.expr))
2324
|| (node is ast.SelectorExpr && t.has_comptime_expr(node.expr))
2425
|| (node is ast.InfixExpr && (t.has_comptime_expr(node.left)

0 commit comments

Comments
 (0)