Skip to content

Commit 78df3a7

Browse files
Merge branch 'vlang:master' into http3-quic-h3-client
2 parents 97dfbe7 + d934e4b commit 78df3a7

46 files changed

Lines changed: 809 additions & 243 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

vlib/v3/driver/driver.v

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,38 @@ fn prepare_v3_cache_external_inputs(mut state V3ModuleCacheState, a &flat.FlatAs
24712471
return !has_untracked_c_include && can_scope_static_inputs && can_extract_native_types
24722472
}
24732473

2474+
fn ast_has_native_source_include(a &flat.FlatAst) bool {
2475+
for node in a.nodes {
2476+
if node.kind != .directive
2477+
|| node.value !in ['include', 'insert', 'preinclude', 'postinclude'] {
2478+
continue
2479+
}
2480+
path := node.typ.trim_space().trim('"')
2481+
if path.ends_with('.c') || path.ends_with('.m') || path.ends_with('.mm') {
2482+
return true
2483+
}
2484+
}
2485+
return false
2486+
}
2487+
2488+
fn register_native_source_typedefs(mut tc types.TypeChecker, state &V3ModuleCacheState) {
2489+
for roots in state.module_native_roots.values() {
2490+
for path in roots {
2491+
source := os.read_file(path) or { continue }
2492+
for name, present in modulecache.c_source_typedef_identifiers(source) {
2493+
if !present || name.len == 0 {
2494+
continue
2495+
}
2496+
c_name := 'C.${name}'
2497+
if c_name !in tc.structs {
2498+
tc.structs[c_name] = []types.StructField{}
2499+
}
2500+
tc.c_typedef_structs[c_name] = true
2501+
}
2502+
}
2503+
}
2504+
}
2505+
24742506
fn cache_c_compiler_predefined_macros(flags []string, ccompiler string, target pref.Target, native_inputs_language string) (map[string]string, bool) {
24752507
path := os.join_path(os.vtmp_dir(), 'v3_compiler_macros_${tempname.unique_token()}.c')
24762508
defer {
@@ -7882,6 +7914,12 @@ pub fn run(args []string) {
78827914
exit(1)
78837915
}
78847916
}
7917+
// Source includes can introduce typedef structs used by V declarations and
7918+
// literals before Cgen sees the included translation unit. Resolve those rare
7919+
// inputs before checking so the type is available to semantic lookup.
7920+
if !cache_state.external_inputs_ready && ast_has_native_source_include(a) {
7921+
_ = prepare_v3_cache_external_inputs(mut cache_state, a, prefs, user_files, cache_c_flags)
7922+
}
78857923

78867924
// Type-collect + check BEFORE transform, so the transformer is type-aware
78877925
// (like v2: check runs before transform). The transformer reads cached
@@ -7929,6 +7967,7 @@ pub fn run(args []string) {
79297967
}
79307968
mut cvsw := time.new_stopwatch()
79317969
pre_tc.collect(a)
7970+
register_native_source_typedefs(mut pre_tc, &cache_state)
79327971
if translated_mode {
79337972
for file in user_files {
79347973
pre_tc.translated_files[file] = true

vlib/v3/gen/c/array.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ fn (mut g FlatGen) gen_array_method_call_fallback(node flat.Node, mname string,
842842
// gen_array_pointers_expr emits `array.pointers()` without compiling the erased
843843
// raw `array` builtin body, which has no concrete element type in v3 Cgen.
844844
fn (mut g FlatGen) gen_array_pointers_expr(base_id flat.NodeId, is_ptr bool) {
845-
base_type := types.unwrap_pointer(g.tc.resolve_type(base_id))
845+
base_type := types.unwrap_pointer(g.usable_expr_type(base_id))
846846
if fixed := array_fixed_type(base_type) {
847847
g.gen_fixed_array_pointers_expr(base_id, is_ptr, fixed)
848848
return

vlib/v3/gen/c/fn.v

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5637,10 +5637,11 @@ fn (mut g FlatGen) gen_call(id flat.NodeId, node flat.Node) {
56375637
return
56385638
}
56395639
}
5640-
if target_name == 'array.pointers' || fn_name == 'array.pointers' {
5640+
if target_name in ['array.pointers', '__v3_fixed_array_pointers']
5641+
|| fn_name in ['array.pointers', '__v3_fixed_array_pointers'] {
56415642
if node.children_count > 1 {
56425643
arg_id := g.a.child(&node, 1)
5643-
g.gen_array_pointers_expr(arg_id, g.tc.resolve_type(arg_id) is types.Pointer)
5644+
g.gen_array_pointers_expr(arg_id, g.usable_expr_type(arg_id) is types.Pointer)
56445645
} else {
56455646
g.write('array_new(sizeof(voidptr), 0, 0)')
56465647
}
@@ -9988,6 +9989,9 @@ fn (mut g FlatGen) optional_type_name_for_expr(id flat.NodeId, typ types.Type) s
99889989
}
99899990
if int(id) >= 0 && int(id) < g.a.nodes.len {
99909991
node := g.a.nodes[int(id)]
9992+
if g.cur_fn_is_specialized && node.kind == .struct_init && type_is_optional_result(typ) {
9993+
return g.concrete_optional_type_name(typ)
9994+
}
99919995
if node.kind == .ident {
99929996
if local_ct := g.local_storage_c_type(node.value) {
99939997
if local_ct == 'Optional' || local_ct.starts_with('Optional_') {
@@ -14084,7 +14088,15 @@ fn (mut g FlatGen) gen_lowered_mut_value_storage_arg(arg_id flat.NodeId, arg_nod
1408414088
if g.tc.c_type(g.usable_expr_type(arg_id)) != g.tc.c_type(expected) {
1408514089
return false
1408614090
}
14087-
g.gen_expr(child_id)
14091+
local_ct := g.local_storage_c_type(child.value) or { '' }
14092+
expected_ct := g.tc.c_type(expected)
14093+
if local_ct == '${expected_ct}*' {
14094+
// `for mut item in []&T` stores the binding as `T**`. The lowered
14095+
// `*item` is already the `T*` expected by a `mut T` parameter.
14096+
g.gen_expr(arg_id)
14097+
} else {
14098+
g.gen_expr(child_id)
14099+
}
1408814100
return true
1408914101
}
1409014102

@@ -15739,6 +15751,15 @@ fn (mut g FlatGen) implicit_veb_ctx_type() types.Type {
1573915751
}
1574015752

1574115753
fn (mut g FlatGen) fn_node_return_type(node flat.Node, module_name string) types.Type {
15754+
// Runtime helpers in `builtin` can share their bare name with a user function
15755+
// in `main`. The global bare-name signature table is ambiguous in that case;
15756+
// the declaration annotation remains module-local and authoritative.
15757+
if module_name in ['', 'main', 'builtin'] && c_main_runtime_shadow_fn_names[node.value] {
15758+
declared := g.tc.parse_resolution_type(node.typ)
15759+
if declared !is types.Unknown {
15760+
return declared
15761+
}
15762+
}
1574215763
if g.tc.autofree_mode && module_name in ['', 'main'] {
1574315764
for key in [node.value, dotted_fn_name_in_module(module_name, node.value)] {
1574415765
if raw_return := g.tc.fn_ret_type_texts[key] {

vlib/v3/gen/c/interface.v

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,18 @@ fn (mut g FlatGen) interface_dispatch_def_string(iface_name string, cn string, m
161161
}
162162

163163
fn (g &FlatGen) interface_dispatch_receiver_expr(concrete string, concrete_params []types.Type, wants_ptr bool) string {
164-
cct := g.interface_concrete_storage_c_type(concrete)
164+
concrete_cct := g.interface_concrete_storage_c_type(concrete)
165165
if concrete_params.len == 0 {
166-
return if wants_ptr { '(${cct}*)i->_object' } else { '*(${cct}*)i->_object' }
166+
return if wants_ptr {
167+
'(${concrete_cct}*)i->_object'
168+
} else {
169+
'*(${concrete_cct}*)i->_object'
170+
}
167171
}
168172
concrete_type := g.interface_concrete_type(concrete)
169173
expected_type := concrete_params[0]
170174
if path := g.embedded_receiver_path_for_expected(concrete_type, expected_type) {
171-
base := '(${cct}*)i->_object'
175+
base := '(${concrete_cct}*)i->_object'
172176
mut access := base
173177
mut access_is_ptr := true
174178
for field in path {
@@ -181,7 +185,23 @@ fn (g &FlatGen) interface_dispatch_receiver_expr(concrete string, concrete_param
181185
}
182186
return if wants_ptr { '&(${access})' } else { '*(${access})' }
183187
}
184-
return if wants_ptr { '(${cct}*)i->_object' } else { '*(${cct}*)i->_object' }
188+
// Generic interface indexes retain the open receiver spelling (Box), while
189+
// the selected method signature carries its materialized receiver
190+
// (Box[Local]). The boxed object uses the latter storage type.
191+
expected_value_type := types.unwrap_pointer(expected_type)
192+
mut storage_cct := if expected_value_type is types.Unknown {
193+
concrete_cct
194+
} else {
195+
g.tc.c_type(expected_value_type)
196+
}
197+
if storage_cct.starts_with('fn_ptr:') {
198+
storage_cct = naming.fn_ptr_type_name(storage_cct)
199+
}
200+
return if wants_ptr {
201+
'(${storage_cct}*)i->_object'
202+
} else {
203+
'*(${storage_cct}*)i->_object'
204+
}
185205
}
186206

187207
fn (g &FlatGen) interface_arg_conversion_expr(name string, source_type types.Type, target_type types.Type) ?string {

vlib/v3/gen/c/stmt.v

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3648,7 +3648,8 @@ fn (g &FlatGen) heap_local_memdup_expr(source_expr string, base_type types.Type,
36483648
}
36493649
for name in names {
36503650
if align := g.struct_decl_alignment_for_name(name) {
3651-
align_arg := struct_decl_alignment_memdup_arg(align, base_ct)
3651+
align_ct := g.struct_decl_alignment_c_type(clean_base.name(), base_ct)
3652+
align_arg := struct_decl_alignment_memdup_arg(align, align_ct)
36523653
return '(${base_ct}*)v3_aligned_memdup(${src}, sizeof(${base_ct}), ${align_arg})'
36533654
}
36543655
}
@@ -5529,6 +5530,12 @@ fn (mut g FlatGen) gen_decl_assign(node flat.Node) {
55295530
} else {
55305531
g.usable_expr_type(rhs_id)
55315532
}
5533+
if rhs.kind == .call && lhs.typ.starts_with('(') && lhs.typ.contains(',') {
5534+
declared_ret := g.declared_call_return_type(rhs_id)
5535+
if declared_ret is types.MultiReturn {
5536+
v_type = declared_ret
5537+
}
5538+
}
55325539
if rhs.kind == .call && rhs.children_count > 0 {
55335540
callee := g.a.child_node(&rhs, 0)
55345541
if callee.kind == .selector {
@@ -5570,6 +5577,12 @@ fn (mut g FlatGen) gen_decl_assign(node flat.Node) {
55705577
v_type = rhs_type
55715578
}
55725579
}
5580+
if rhs.kind == .struct_init && v_type is types.Struct && v_type.name == 'Optional' {
5581+
rhs_type := g.usable_expr_type(rhs_id)
5582+
if rhs_type is types.OptionType || rhs_type is types.ResultType {
5583+
v_type = rhs_type
5584+
}
5585+
}
55735586
if rhs.kind == .struct_init {
55745587
init_name := g.struct_init_effective_type_name(rhs_id, rhs)
55755588
if init_name.starts_with('&') {

vlib/v3/gen/c/struct.v

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ fn is_anonymous_struct_type_name(name string) bool {
131131
}
132132

133133
fn (mut g FlatGen) struct_init_effective_type_name(id flat.NodeId, node flat.Node) string {
134+
if node.typ == node.value && node.typ.contains('[') && node.typ.contains('.') {
135+
// A specialized clone's explicit type annotation is newer than the
136+
// checker's expression cache and can retain nested main-module locks.
137+
return node.typ
138+
}
134139
if node.value.starts_with('main.') && !node.value['main.'.len..].contains('.') {
135140
// Monomorphization pins a caller-owned program type with `main.` when the
136141
// generic declaration's module has a same-named type. The expression type
@@ -447,7 +452,12 @@ fn (mut g FlatGen) gen_struct_init(id flat.NodeId) {
447452
}
448453
if is_optional_init && !has_expected_optional
449454
&& (g.cur_fn_is_specialized || g.name_uses_specialized_generic_abi(g.cur_fn_name)) {
450-
name = g.fn_return_type_name(g.cur_fn_ret)
455+
concrete_type := if node_type is types.OptionType || node_type is types.ResultType {
456+
node_type
457+
} else {
458+
g.cur_fn_ret
459+
}
460+
name = g.concrete_optional_type_name(concrete_type)
451461
}
452462
// A bare generic literal stores its fields under the concrete instance key (`Box[int]`);
453463
// the bare `node.value` (`Box`) entry is removed by monomorphization, so resolve the
@@ -800,6 +810,15 @@ fn (mut g FlatGen) struct_init_has_fixed_array_field(node flat.Node, type_name s
800810
}
801811
}
802812
}
813+
if fields := g.struct_fields_for_type(type_name) {
814+
for field in fields {
815+
if fixed := array_fixed_type(field.typ) {
816+
if g.field_needs_default_init(fixed.elem_type) {
817+
return true
818+
}
819+
}
820+
}
821+
}
803822
return false
804823
}
805824

@@ -957,6 +976,23 @@ fn (mut g FlatGen) gen_struct_init_with_fixed_array_fields_impl(node flat.Node,
957976
g.gen_fixed_array_copy_source(fixed_values[i], fixed_field_types[i])
958977
g.write(', sizeof(${tmp}.${cfield}));')
959978
}
979+
if fields := g.struct_fields_for_type(lookup_name) {
980+
for field in fields {
981+
if field.name in set_fields {
982+
continue
983+
}
984+
if fixed := array_fixed_type(field.typ) {
985+
if g.field_needs_default_init(fixed.elem_type) {
986+
cfield := c_field_name(field.name)
987+
for idx in 0 .. fixed.len {
988+
g.write(' ${tmp}.${cfield}[${idx}] = ')
989+
g.gen_default_value_for_type(fixed.elem_type)
990+
g.write(';')
991+
}
992+
}
993+
}
994+
}
995+
}
960996
if heap {
961997
if align := g.struct_decl_alignment_for_init_names(node.value, name) {
962998
align_arg := struct_decl_alignment_memdup_arg(align, name)
@@ -3842,6 +3878,37 @@ fn struct_decl_alignment_memdup_arg(align StructDeclAlignment, c_type string) st
38423878
return '__alignof__(${c_type})'
38433879
}
38443880

3881+
fn (g &FlatGen) struct_decl_alignment_c_type(type_name string, fallback string) string {
3882+
resolved_name := g.struct_init_resolved_decl_name(type_name)
3883+
if resolved_name.len == 0 {
3884+
return fallback
3885+
}
3886+
ct := g.tc.c_type(g.tc.parse_type(resolved_name))
3887+
if ct.len == 0 || ct == 'void' {
3888+
return fallback
3889+
}
3890+
if fallback != ct && fallback.ends_with('__${ct}') {
3891+
return fallback
3892+
}
3893+
if qualified_ct := g.unique_qualified_struct_c_type(ct) {
3894+
return qualified_ct
3895+
}
3896+
// Main-module declarations are bare-keyed in the semantic tables, while C
3897+
// emits their typedefs with the `main__` namespace.
3898+
if !resolved_name.contains('.') && resolved_name in g.tc.structs {
3899+
decl_module := g.tc.struct_modules[resolved_name] or { '' }
3900+
if decl_module in ['', 'main'] {
3901+
return 'main__${g.cname(resolved_name)}'
3902+
}
3903+
}
3904+
if info := g.find_struct_decl(resolved_name) {
3905+
if !resolved_name.contains('.') && info.module in ['', 'main'] {
3906+
return 'main__${g.cname(resolved_name)}'
3907+
}
3908+
}
3909+
return ct
3910+
}
3911+
38453912
fn (g &FlatGen) struct_type_alias_target(type_name string) ?string {
38463913
qname := g.tc.qualify_name(type_name)
38473914
if target := g.tc.type_aliases[qname] {
@@ -4386,7 +4453,8 @@ fn (mut g FlatGen) gen_heap_assoc_expr(node flat.Node) {
43864453
}
43874454
}
43884455
if align := g.heap_assoc_struct_alignment(node, target_type, target_name, ct) {
4389-
align_arg := struct_decl_alignment_memdup_arg(align, ct)
4456+
align_ct := g.struct_decl_alignment_c_type(target_name, ct)
4457+
align_arg := struct_decl_alignment_memdup_arg(align, align_ct)
43904458
g.write(' (${ct}*)v3_aligned_memdup(&${tmp}, sizeof(${ct}), ${align_arg});})')
43914459
} else {
43924460
g.write(' (${ct}*)memdup(&${tmp}, sizeof(${ct}));})')

vlib/v3/parser/parser.v

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5302,18 +5302,25 @@ fn (mut p Parser) parse_comptime_expr() flat.NodeId {
53025302
p.next() // skip $
53035303
match p.tok {
53045304
.key_typeof {
5305+
p.record_diagnostic('`$typeof` is not supported; use `typeof(...)` instead', dollar_pos)
53055306
return p.typeof_expr()
53065307
}
53075308
.key_sizeof {
5309+
p.record_diagnostic('`$sizeof` is not supported; use `sizeof(...)` instead', dollar_pos)
53085310
return p.sizeof_expr()
53095311
}
53105312
.key_isreftype {
5313+
p.record_diagnostic('`$isreftype` is not supported; use `isreftype(...)` instead',
5314+
dollar_pos)
53115315
return p.isreftype_expr()
53125316
}
53135317
.key_offsetof {
5318+
p.record_diagnostic('`$__offsetof` is not supported; use `__offsetof(...)` instead',
5319+
dollar_pos)
53145320
return p.offsetof_expr()
53155321
}
53165322
.key_dump {
5323+
p.record_diagnostic('`$dump` is not supported; use `dump(...)` instead', dollar_pos)
53175324
return p.dump_expr()
53185325
}
53195326
else {}
@@ -7835,7 +7842,7 @@ fn (mut p Parser) asm_stmt() flat.NodeId {
78357842
if p.tok == .semicolon {
78367843
p.next()
78377844
}
7838-
if !p.prefs.supports_inline_asm && has_unsupported_content {
7845+
if !p.prefs.supports_inline_asm && (has_memory_clobber || has_unsupported_content) {
78397846
p.record_diagnostic('inline assembly is not supported by the selected V3 backend', asm_pos)
78407847
}
78417848
return p.add_node(flat.Node{
@@ -9491,9 +9498,6 @@ fn (mut p Parser) prefix_expr() flat.NodeId {
94919498
return p.if_stmt()
94929499
}
94939500
.key_match {
9494-
if p.peek() in [.lpar, .lsbr] {
9495-
return p.keyword_ident_expr()
9496-
}
94979501
return p.match_stmt()
94989502
}
94999503
.key_fn {
@@ -11416,7 +11420,7 @@ fn (mut p Parser) typeof_expr() flat.NodeId {
1141611420
p.check(.lpar)
1141711421
inner := p.expr(.lowest)
1141811422
p.check(.rpar)
11419-
if !p.inside_array_init_type_expr && p.tok != .dot
11423+
if !p.inside_array_init_type_expr && p.tok != .dot && (start == 0 || p.s.src[start - 1] != `$`)
1142011424
&& p.line_nr_for_pos(start) == p.line_nr_for_pos(p.tok_pos) {
1142111425
p.record_warning_span('use e.g. `typeof(expr).name` or `sum_type_instance.type_name()` instead',
1142211426
start, start + 'typeof'.len)

0 commit comments

Comments
 (0)