Skip to content

Commit f61de59

Browse files
authored
v.generics: improve the new generic stage, pass more tests (#26391)
1 parent ffc6eaf commit f61de59

4 files changed

Lines changed: 144 additions & 34 deletions

File tree

‎vlib/v/comptime/comptime.v‎

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -134,42 +134,68 @@ pub fn (mut c Comptime) stmt(mut node ast.Stmt) ast.Stmt {
134134

135135
type StmtOrExpr = ast.Expr | ast.Stmt
136136

137+
pub fn (mut c Comptime) check_type_equality(left_type ast.Type, right ast.Expr) !bool {
138+
if right is ast.ComptimeType {
139+
if right.kind == .array {
140+
return c.table.sym(left_type).info is ast.Array
141+
|| c.table.sym(left_type).info is ast.ArrayFixed
142+
} else if right.kind == .array_dynamic {
143+
return c.table.sym(left_type).info is ast.Array
144+
} else if right.kind == .array_fixed {
145+
return c.table.sym(left_type).info is ast.ArrayFixed
146+
} else if right.kind == .iface {
147+
return c.table.sym(left_type).info is ast.Interface
148+
} else if right.kind == .map {
149+
return c.table.sym(left_type).info is ast.Map
150+
} else if right.kind == .struct {
151+
return c.table.sym(left_type).info is ast.Struct
152+
} else if right.kind == .enum {
153+
return c.table.sym(left_type).info is ast.Enum
154+
} else if right.kind == .sum_type {
155+
return c.table.sym(left_type).info is ast.SumType
156+
} else if right.kind == .alias {
157+
return c.table.sym(left_type).info is ast.Alias
158+
} else if right.kind == .int {
159+
return left_type.is_int()
160+
} else if right.kind == .string {
161+
return left_type.is_string()
162+
} else if right.kind == .float {
163+
return left_type.is_float()
164+
}
165+
// TODO do the other types
166+
} else if right is ast.TypeNode {
167+
sym := c.table.sym(right.typ)
168+
if sym.info is ast.Interface {
169+
return c.table.does_type_implement_interface(left_type, right.typ)
170+
} else {
171+
return left_type == right.typ
172+
}
173+
}
174+
return error('Cannot solve')
175+
}
176+
137177
pub fn (mut c Comptime) is_true(expr ast.Expr) !bool {
138178
match expr {
139179
ast.InfixExpr {
140180
match expr.op {
141181
.key_is {
142182
if expr.left is ast.TypeNode {
143-
if expr.right is ast.ComptimeType {
144-
if expr.right.kind == .array {
145-
return c.table.sym(expr.left.typ).info is ast.Array
146-
} else if expr.right.kind == .iface {
147-
return c.table.sym(expr.left.typ).info is ast.Interface
148-
} else if expr.right.kind == .map {
149-
return c.table.sym(expr.left.typ).info is ast.Map
150-
} else if expr.right.kind == .struct {
151-
return c.table.sym(expr.left.typ).info is ast.Struct
152-
} else if expr.right.kind == .int {
153-
return expr.left.typ.is_int()
154-
}
155-
// TODO do the other types
156-
} else if expr.right is ast.TypeNode {
157-
sym := c.table.sym(expr.right.typ)
158-
if sym.info is ast.Interface {
159-
return c.table.does_type_implement_interface(expr.left.typ,
160-
expr.right.typ)
161-
} else {
162-
return expr.left.typ == expr.right.typ
163-
}
164-
}
183+
return c.check_type_equality(expr.left.typ, expr.right)!
165184
} else if expr.left is ast.SelectorExpr {
166185
if expr.left.field_name == 'typ' && expr.left.expr is ast.Ident {
167186
if expr.left.expr.info is ast.IdentFn {
168187
if expr.right is ast.TypeNode {
169188
return expr.left.expr.info.typ == expr.right.typ
170189
}
171190
}
191+
} else if expr.left.field_name == 'unaliased_typ' {
192+
if expr.left.expr is ast.Ident {
193+
unaliased_type := c.table.unaliased_type(expr.left.expr.obj.typ)
194+
return c.check_type_equality(unaliased_type, expr.right)!
195+
}
172196
}
197+
} else if expr.left is ast.Ident {
198+
return c.check_type_equality(expr.left.obj.typ, expr.right)!
173199
}
174200
}
175201
.and {

‎vlib/v/gen/c/auto_str_methods.v‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ fn (mut g Gen) get_str_fn(typ ast.Type) string {
7878
if sym.is_builtin() && !str_fn_name.starts_with('builtin__') {
7979
str_fn_name = 'builtin__${str_fn_name}'
8080
}
81-
if sym.has_method_with_generic_parent('str') {
81+
if sym.has_method_with_generic_parent('str') && !g.pref.new_generic_solver {
8282
match mut sym.info {
8383
ast.Struct, ast.SumType, ast.Interface {
8484
str_fn_name = g.generic_fn_name(sym.info.concrete_types, str_fn_name)
@@ -1070,7 +1070,7 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
10701070
left_fn_name := util.no_dots(left_cc_type)
10711071
'${left_fn_name}_str'
10721072
}
1073-
if sym.info is ast.Struct {
1073+
if sym.info is ast.Struct && !g.pref.new_generic_solver {
10741074
field_fn_name = g.generic_fn_name(sym.info.concrete_types, field_fn_name)
10751075
}
10761076
field_fn_name

‎vlib/v/gen/c/cgen.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4716,7 +4716,7 @@ fn (mut g Gen) gen_closure_fn(expr_styp string, m ast.Fn, name string) {
47164716
mut method_name := m.name
47174717
rec_sym := g.table.sym(receiver.typ)
47184718
if rec_sym.info is ast.Struct {
4719-
if rec_sym.info.concrete_types.len > 0 {
4719+
if rec_sym.info.concrete_types.len > 0 && !g.pref.new_generic_solver {
47204720
method_name = g.generic_fn_name(rec_sym.info.concrete_types, m.name)
47214721
}
47224722
}

‎vlib/v/generics/generics.v‎

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import strings
88

99
// Stage for solving generics
1010

11+
const result_name = ast.result_name
12+
const option_name = ast.option_name
13+
1114
pub struct Generics {
1215
pref &pref.Preferences
1316
pub mut:
@@ -328,8 +331,19 @@ pub fn (mut g Generics) stmt(mut node ast.Stmt) ast.Stmt {
328331
return node
329332
}
330333

334+
pub fn (mut g Generics) styp(t ast.Type) string {
335+
if !t.has_option_or_result() {
336+
return g.base_type(t)
337+
} else if t.has_flag(.option) {
338+
// Register an optional if it's not registered yet
339+
return g.register_option(t)
340+
} else {
341+
return g.register_result(t)
342+
}
343+
}
344+
331345
// incomplete implementation: TODO
332-
pub fn (mut g Generics) styp(_t ast.Type) string {
346+
fn (mut g Generics) base_type(_t ast.Type) string {
333347
t := g.unwrap_generic(_t)
334348
if styp := g.styp_cache[t] {
335349
return styp
@@ -351,6 +365,62 @@ pub fn (mut g Generics) styp(_t ast.Type) string {
351365
return styp
352366
}
353367

368+
// incomplete implementation: TODO
369+
fn (mut g Generics) register_option(t ast.Type) string {
370+
styp, _ := g.option_type_name(t)
371+
return if !t.has_flag(.option_mut_param_t) { styp } else { '${styp}*' }
372+
}
373+
374+
// incomplete implementation: TODO
375+
fn (mut g Generics) register_result(t ast.Type) string {
376+
styp, _ := g.result_type_name(t)
377+
return styp
378+
}
379+
380+
// TODO: this really shouldn't be separate from typ
381+
// but I(emily) would rather have this generation
382+
// all unified in one place so that it doesn't break
383+
// if one location changes
384+
fn (mut g Generics) option_type_name(t ast.Type) (string, string) {
385+
mut base := g.base_type(t)
386+
mut styp := ''
387+
sym := g.table.sym(t)
388+
if sym.info is ast.FnType {
389+
base = 'anon_fn_${g.table.fn_type_signature(sym.info.func)}'
390+
}
391+
if sym.language == .c && sym.kind == .struct {
392+
styp = '${option_name}_${base.replace(' ', '_')}'
393+
} else {
394+
styp = '${option_name}_${base}'
395+
}
396+
if t.has_flag(.generic) || t.is_ptr() {
397+
styp = styp.replace('*', '_ptr')
398+
}
399+
return styp, base
400+
}
401+
402+
fn (mut g Generics) result_type_name(t ast.Type) (string, string) {
403+
mut base := g.base_type(t)
404+
if t.has_flag(.option) {
405+
g.register_option(t)
406+
base = '_option_' + base
407+
}
408+
mut styp := ''
409+
sym := g.table.sym(t)
410+
if sym.info is ast.FnType {
411+
base = 'anon_fn_${g.table.fn_type_signature(sym.info.func)}'
412+
}
413+
if sym.language == .c && sym.kind == .struct {
414+
styp = '${result_name}_${base.replace(' ', '_')}'
415+
} else {
416+
styp = '${result_name}_${base}'
417+
}
418+
if t.has_flag(.generic) || t.is_ptr() {
419+
styp = styp.replace('*', '_ptr')
420+
}
421+
return styp, base
422+
}
423+
354424
// cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo)
355425
fn (mut g Generics) cc_type(typ ast.Type, is_prefix_struct bool) string {
356426
sym := g.table.sym(g.unwrap_generic(typ))
@@ -382,12 +452,15 @@ fn (mut g Generics) cc_type(typ ast.Type, is_prefix_struct bool) string {
382452
return styp
383453
}
384454

385-
pub fn (mut g Generics) method_concrete_name(old_name string, concrete_types []ast.Type, receiver_type ast.Type) string {
455+
pub fn (mut g Generics) method_concrete_name(old_name string, concrete_types []ast.Type, _receiver_type ast.Type) string {
386456
mut name := old_name
387-
if receiver_type != 0 {
388-
info := g.table.sym(g.unwrap_generic(receiver_type)).info
389-
if info is ast.Struct {
390-
fn_conc_types := concrete_types[info.generic_types.len..] // concrete types without the generic types of the struct
457+
if _receiver_type != 0 {
458+
mut info := g.table.sym(g.unwrap_generic(_receiver_type)).info
459+
if mut info is ast.Alias {
460+
info = g.table.sym(g.table.unaliased_type(g.unwrap_generic(_receiver_type))).info
461+
}
462+
if mut info is ast.Struct {
463+
fn_conc_types := concrete_types#[info.generic_types.len..] // concrete types without the generic types of the struct
391464

392465
if fn_conc_types.len > 0 {
393466
name += '_T'
@@ -397,7 +470,7 @@ pub fn (mut g Generics) method_concrete_name(old_name string, concrete_types []a
397470
g.styp(typ.set_nr_muls(0))
398471
}
399472
return name
400-
} else if info is ast.Interface {
473+
} else if mut info is ast.Interface {
401474
return name
402475
}
403476
}
@@ -585,6 +658,10 @@ pub fn (mut g Generics) expr(mut node ast.Expr) ast.Expr {
585658
}
586659
}
587660
}
661+
mut receiver_type := g.unwrap_generic(node.receiver_type)
662+
if receiver_type.has_flag(.generic) {
663+
receiver_type = receiver_type.clear_flag(.generic)
664+
}
588665
return ast.Expr(ast.CallExpr{
589666
...node
590667
name: if node.is_method {
@@ -593,7 +670,7 @@ pub fn (mut g Generics) expr(mut node ast.Expr) ast.Expr {
593670
g.concrete_name(node.name, all_concrete_types)
594671
}
595672
left_type: g.unwrap_generic(node.left_type)
596-
receiver_type: g.unwrap_generic(node.receiver_type)
673+
receiver_type: receiver_type
597674
return_type: g.unwrap_generic(node.return_type)
598675
return_type_generic: ast.no_type
599676
fn_var_type: g.unwrap_generic(node.fn_var_type)
@@ -611,6 +688,13 @@ pub fn (mut g Generics) expr(mut node ast.Expr) ast.Expr {
611688
arg.expr = g.expr(mut arg.expr)
612689
}
613690
node.or_block = g.expr(mut node.or_block) as ast.OrExpr
691+
if node.is_method && g.table.sym(node.receiver_type).info is ast.Alias {
692+
// Workaround needed for markused
693+
unaliased_type := g.table.unaliased_type(g.unwrap_generic(node.receiver_type))
694+
if g.table.sym(unaliased_type).has_method(node.name) {
695+
node.receiver_type = unaliased_type
696+
}
697+
}
614698
if node.receiver_type.has_flag(.generic) {
615699
node.receiver_type = node.receiver_type.clear_flag(.generic)
616700
}
@@ -916,7 +1000,7 @@ pub fn (mut g Generics) expr(mut node ast.Expr) ast.Expr {
9161000
ast.MatchExpr {
9171001
if g.cur_concrete_types.len > 0 {
9181002
mut branches := node.branches.clone()
919-
for mut branch in node.branches {
1003+
for mut branch in branches {
9201004
branch.stmts = branch.stmts.clone()
9211005
branch.exprs = branch.exprs.clone()
9221006
branch.exprs = g.exprs(mut branch.exprs)

0 commit comments

Comments
 (0)