This commit is contained in:
Felipe Pena 2025-08-28 09:39:36 -03:00
parent 9e1273ae71
commit 06327c8054
4 changed files with 113 additions and 6 deletions

View file

@ -2190,16 +2190,15 @@ pub fn (mut t Table) unwrap_generic_type_ex(typ Type, generic_names []string, co
Interface { Interface {
// resolve generic types inside methods // resolve generic types inside methods
mut imethods := ts.info.methods.clone() mut imethods := ts.info.methods.clone()
gn_names := t.get_real_generic_names(typ, generic_names)
for mut method in imethods { for mut method in imethods {
if unwrap_typ := t.convert_generic_type(method.return_type, generic_names, if unwrap_typ := t.convert_generic_type(method.return_type, gn_names,
concrete_types) concrete_types[..gn_names.len])
{ {
method.return_type = unwrap_typ method.return_type = unwrap_typ
} }
for mut param in method.params { for mut param in method.params {
if unwrap_typ := t.convert_generic_type(param.typ, generic_names, if unwrap_typ := t.convert_generic_type(param.typ, gn_names, concrete_types) {
concrete_types)
{
param.typ = unwrap_typ param.typ = unwrap_typ
} }
} }
@ -2289,6 +2288,7 @@ pub fn (mut t Table) generic_insts_to_concrete() {
fields[i].typ = t.unwrap_generic_type(fields[i].typ, fields[i].typ = t.unwrap_generic_type(fields[i].typ,
generic_names, info.concrete_types) generic_names, info.concrete_types)
} }
if t_typ := t.convert_generic_type(fields[i].typ, generic_names, if t_typ := t.convert_generic_type(fields[i].typ, generic_names,
info.concrete_types) info.concrete_types)
{ {
@ -2464,6 +2464,18 @@ pub fn (mut t Table) generic_insts_to_concrete() {
} }
} }
// Extracts all generic names from Type<A>[B] => B when <A>[B] is present
// otherwise generic_names is returned
pub fn (t &Table) get_real_generic_names(typ Type, generic_names []string) []string {
if typ.has_flag(.generic) {
typ_name := t.type_to_str(typ)
if typ_name.contains('>[') {
return typ_name.split('>[')[1].all_before_last(']').split(',')
}
}
return generic_names
}
// Extracts all type names from given types, notice that MultiReturn will be decompose // Extracts all type names from given types, notice that MultiReturn will be decompose
// and will not included in returned string // and will not included in returned string
pub fn (t &Table) get_generic_names(generic_types []Type) []string { pub fn (t &Table) get_generic_names(generic_types []Type) []string {

View file

@ -1107,6 +1107,7 @@ pub fn (mut g Gen) get_sumtype_variant_name(typ ast.Type, sym ast.TypeSymbol) st
pub fn (mut g Gen) write_typeof_functions() { pub fn (mut g Gen) write_typeof_functions() {
g.writeln('') g.writeln('')
g.writeln('// >> typeof() support for sum types / interfaces') g.writeln('// >> typeof() support for sum types / interfaces')
mut already_generated_ifaces := map[string]bool{}
for ityp, sym in g.table.type_symbols { for ityp, sym in g.table.type_symbols {
if sym.kind == .sum_type { if sym.kind == .sum_type {
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms { if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
@ -1177,6 +1178,10 @@ pub fn (mut g Gen) write_typeof_functions() {
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms { if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
continue continue
} }
if sym.cname in already_generated_ifaces {
continue
}
already_generated_ifaces[sym.cname] = true
g.definitions.writeln('${g.static_non_parallel}char * v_typeof_interface_${sym.cname}(int sidx);') g.definitions.writeln('${g.static_non_parallel}char * v_typeof_interface_${sym.cname}(int sidx);')
if g.pref.parallel_cc { if g.pref.parallel_cc {
g.extern_out.writeln('extern char * v_typeof_interface_${sym.cname}(int sidx);') g.extern_out.writeln('extern char * v_typeof_interface_${sym.cname}(int sidx);')
@ -1805,11 +1810,15 @@ static inline void __${sym.cname}_pushval(${sym.cname} ch, ${push_arg} val) {
interface_non_generic_syms << sym interface_non_generic_syms << sym
} }
} }
mut already_generated_ifaces := map[string]bool{}
for sym in interface_non_generic_syms { for sym in interface_non_generic_syms {
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms { if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
continue continue
} }
g.write_interface_typesymbol_declaration(sym) if sym.cname !in already_generated_ifaces {
g.write_interface_typesymbol_declaration(sym)
already_generated_ifaces[sym.cname] = true
}
} }
} }
@ -7859,6 +7868,7 @@ fn (mut g Gen) interface_table() string {
} }
mut sb := strings.new_builder(100) mut sb := strings.new_builder(100)
mut conversion_functions := strings.new_builder(100) mut conversion_functions := strings.new_builder(100)
mut already_generated_ifaces := map[string]bool{}
interfaces := g.table.type_symbols.filter(it.kind == .interface && it.info is ast.Interface) interfaces := g.table.type_symbols.filter(it.kind == .interface && it.info is ast.Interface)
for isym in interfaces { for isym in interfaces {
inter_info := isym.info as ast.Interface inter_info := isym.info as ast.Interface
@ -7868,6 +7878,10 @@ fn (mut g Gen) interface_table() string {
if g.pref.skip_unused && isym.idx !in g.table.used_features.used_syms { if g.pref.skip_unused && isym.idx !in g.table.used_features.used_syms {
continue continue
} }
if isym.cname in already_generated_ifaces {
continue
}
already_generated_ifaces[isym.cname] = true
// interface_name is for example Speaker // interface_name is for example Speaker
interface_name := isym.cname interface_name := isym.cname
// generate a struct that references interface methods // generate a struct that references interface methods

View file

@ -1573,6 +1573,7 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) {
} }
if (w.used_option + w.used_result + w.used_none) > 0 { if (w.used_option + w.used_result + w.used_none) > 0 {
w.mark_const_as_used('none__') w.mark_const_as_used('none__')
w.fn_by_name('memdup')
} }
if include_panic_deps || w.uses_external_type || w.uses_asserts || w.uses_debugger if include_panic_deps || w.uses_external_type || w.uses_asserts || w.uses_debugger
|| w.uses_interp { || w.uses_interp {
@ -1591,6 +1592,7 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) {
w.fn_by_name(ref_array_idx_str + '.push') w.fn_by_name(ref_array_idx_str + '.push')
w.fn_by_name(string_idx_str + '.substr') w.fn_by_name(string_idx_str + '.substr')
w.fn_by_name('v_fixed_index') w.fn_by_name('v_fixed_index')
w.fn_by_name('fast_string_eq')
w.mark_by_sym_name('StrIntpData') w.mark_by_sym_name('StrIntpData')
w.mark_by_sym_name('StrIntpMem') w.mark_by_sym_name('StrIntpMem')
} }

View file

@ -0,0 +1,79 @@
pub struct Range[T] {
pub:
from T
to T
inclusive bool
pub mut:
step T = T(1)
i T
mut:
started bool
}
pub fn (mut r Range[T]) next[T]() ?T {
if !r.started {
r.started = true
assert r.step > 0
if r.from > r.to {
r.step = -r.step
}
r.i = r.from
}
i := r.i
next_i := i + r.step
if r.inclusive {
if r.step < 0 && i < r.to {
return none
}
if r.step > 0 && i > r.to {
return none
}
} else {
if r.step < 0 && i <= r.to {
return none
}
if r.step > 0 && i >= r.to {
return none
}
}
r.i = next_i
return i
}
pub interface Iterator[T] {
mut:
next() ?T
}
pub struct Zip[A, B] {
mut:
a Iterator[A]
b Iterator[B]
}
pub struct Pair[A, B] {
a A
b B
}
pub fn (mut z Zip[A, B]) next[A, B]() ?Pair[A, B] {
a := z.a.next()?
b := z.b.next()?
return Pair[A, B]{a, b}
}
fn test_main() {
mut r1 := Range{
from: 5
to: 10
}
_ := Iterator[int](r1)
mut r2 := Range{
from: 10
to: 5
}
_ := Iterator[int](r2)
_ := Zip[int, int]{}
}