cgen: support `typeof(x).idx`, as well as `iface.type_idx()` (#11178)
parent
8dc043ba2c
commit
deb26b92b9
|
@ -2081,8 +2081,13 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
c.error('optional type cannot be called directly', call_expr.left.position())
|
c.error('optional type cannot be called directly', call_expr.left.position())
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
if left_type_sym.kind in [.sum_type, .interface_] && method_name == 'type_name' {
|
if left_type_sym.kind in [.sum_type, .interface_] {
|
||||||
return ast.string_type
|
if method_name == 'type_name' {
|
||||||
|
return ast.string_type
|
||||||
|
}
|
||||||
|
if method_name == 'type_idx' {
|
||||||
|
return ast.int_type
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if left_type == ast.void_type {
|
if left_type == ast.void_type {
|
||||||
c.error('`void` type has no methods', call_expr.left.position())
|
c.error('`void` type has no methods', call_expr.left.position())
|
||||||
|
@ -3374,10 +3379,12 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
||||||
return ast.int_type
|
return ast.int_type
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if node.field_name != 'name' {
|
if node.field_name == 'name' {
|
||||||
c.error('invalid field `.$node.field_name` for type `$node.expr`',
|
return ast.string_type
|
||||||
node.pos)
|
} else if node.field_name == 'idx' {
|
||||||
|
return ast.int_type
|
||||||
}
|
}
|
||||||
|
c.error('invalid field `.$node.field_name` for type `$node.expr`', node.pos)
|
||||||
return ast.string_type
|
return ast.string_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8007,6 +8014,8 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
c.error('method overrides built-in array method', node.pos)
|
c.error('method overrides built-in array method', node.pos)
|
||||||
} else if sym.kind == .sum_type && node.name == 'type_name' {
|
} else if sym.kind == .sum_type && node.name == 'type_name' {
|
||||||
c.error('method overrides built-in sum type method', node.pos)
|
c.error('method overrides built-in sum type method', node.pos)
|
||||||
|
} else if sym.kind == .sum_type && node.name == 'type_idx' {
|
||||||
|
c.error('method overrides built-in sum type method', node.pos)
|
||||||
} else if sym.kind == .multi_return {
|
} else if sym.kind == .multi_return {
|
||||||
c.error('cannot define method on multi-value', node.method_type_pos)
|
c.error('cannot define method on multi-value', node.method_type_pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,7 +528,7 @@ pub fn (mut g Gen) finish() {
|
||||||
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')
|
||||||
for typ in g.table.type_symbols {
|
for ityp, typ in g.table.type_symbols {
|
||||||
if typ.kind == .sum_type {
|
if typ.kind == .sum_type {
|
||||||
sum_info := typ.info as ast.SumType
|
sum_info := typ.info as ast.SumType
|
||||||
if sum_info.is_generic {
|
if sum_info.is_generic {
|
||||||
|
@ -554,6 +554,26 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||||
g.writeln('\t}')
|
g.writeln('\t}')
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
|
g.writeln('')
|
||||||
|
g.writeln('int v_typeof_sumtype_idx_${typ.cname}(int sidx) { /* $typ.name */ ')
|
||||||
|
if g.pref.build_mode == .build_module {
|
||||||
|
g.writeln('\t\tif( sidx == _v_type_idx_${typ.cname}() ) return ${int(ityp)};')
|
||||||
|
for v in sum_info.variants {
|
||||||
|
subtype := g.table.get_type_symbol(v)
|
||||||
|
g.writeln('\tif( sidx == _v_type_idx_${subtype.cname}() ) return ${int(v)};')
|
||||||
|
}
|
||||||
|
g.writeln('\treturn ${int(ityp)};')
|
||||||
|
} else {
|
||||||
|
tidx := g.table.find_type_idx(typ.name)
|
||||||
|
g.writeln('\tswitch(sidx) {')
|
||||||
|
g.writeln('\t\tcase $tidx: return ${int(ityp)};')
|
||||||
|
for v in sum_info.variants {
|
||||||
|
g.writeln('\t\tcase $v: return ${int(v)};')
|
||||||
|
}
|
||||||
|
g.writeln('\t\tdefault: return ${int(ityp)};')
|
||||||
|
g.writeln('\t}')
|
||||||
|
}
|
||||||
|
g.writeln('}')
|
||||||
} else if typ.kind == .interface_ {
|
} else if typ.kind == .interface_ {
|
||||||
inter_info := typ.info as ast.Interface
|
inter_info := typ.info as ast.Interface
|
||||||
if inter_info.is_generic {
|
if inter_info.is_generic {
|
||||||
|
@ -566,6 +586,14 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||||
}
|
}
|
||||||
g.writeln('\treturn "unknown ${util.strip_main_name(typ.name)}";')
|
g.writeln('\treturn "unknown ${util.strip_main_name(typ.name)}";')
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
|
g.writeln('')
|
||||||
|
g.writeln('int v_typeof_interface_idx_${typ.cname}(int sidx) { /* $typ.name */ ')
|
||||||
|
for t in inter_info.types {
|
||||||
|
subtype := g.table.get_type_symbol(t)
|
||||||
|
g.writeln('\tif (sidx == _${typ.cname}_${subtype.cname}_index) return ${int(t)};')
|
||||||
|
}
|
||||||
|
g.writeln('\treturn ${int(ityp)};')
|
||||||
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('// << typeof() support for sum types')
|
g.writeln('// << typeof() support for sum types')
|
||||||
|
@ -3663,6 +3691,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||||
// typeof(expr).name
|
// typeof(expr).name
|
||||||
g.type_name(node.name_type)
|
g.type_name(node.name_type)
|
||||||
return
|
return
|
||||||
|
} else if node.field_name == 'idx' {
|
||||||
|
// typeof(expr).idx
|
||||||
|
g.write(int(g.unwrap_generic(node.name_type)).str())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
g.error('unknown generic field', node.pos)
|
g.error('unknown generic field', node.pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -628,6 +628,13 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) conversion_function_call(prefix string, postfix string, node ast.CallExpr) {
|
||||||
|
g.write('${prefix}( (')
|
||||||
|
g.expr(node.left)
|
||||||
|
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
||||||
|
g.write(')${dot}_typ )$postfix')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) method_call(node ast.CallExpr) {
|
fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
||||||
if node.left_type == 0 {
|
if node.left_type == 0 {
|
||||||
|
@ -744,20 +751,33 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if left_sym.kind == .sum_type && node.name == 'type_name' {
|
if left_sym.kind in [.sum_type, .interface_] {
|
||||||
g.write('charptr_vstring_literal( /* $left_sym.name */ v_typeof_sumtype_${typ_sym.cname}( (')
|
if node.name == 'type_name' {
|
||||||
g.expr(node.left)
|
if left_sym.kind == .sum_type {
|
||||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
g.conversion_function_call('charptr_vstring_literal( /* $left_sym.name */ v_typeof_sumtype_$typ_sym.cname',
|
||||||
g.write(')${dot}_typ ))')
|
')', node)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if left_sym.kind == .interface_ && node.name == 'type_name' {
|
if left_sym.kind == .interface_ {
|
||||||
g.write('charptr_vstring_literal( /* $left_sym.name */ v_typeof_interface_${typ_sym.cname}( (')
|
g.conversion_function_call('charptr_vstring_literal( /* $left_sym.name */ v_typeof_interface_$typ_sym.cname',
|
||||||
g.expr(node.left)
|
')', node)
|
||||||
dot := if node.left_type.is_ptr() { '->' } else { '.' }
|
return
|
||||||
g.write(')${dot}_typ ))')
|
}
|
||||||
return
|
}
|
||||||
|
if node.name == 'type_idx' {
|
||||||
|
if left_sym.kind == .sum_type {
|
||||||
|
g.conversion_function_call('/* $left_sym.name */ v_typeof_sumtype_idx_$typ_sym.cname',
|
||||||
|
'', node)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if left_sym.kind == .interface_ {
|
||||||
|
g.conversion_function_call('/* $left_sym.name */ v_typeof_interface_idx_$typ_sym.cname',
|
||||||
|
'', node)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.name == 'str' {
|
if node.name == 'str' {
|
||||||
mut rec_type := node.receiver_type
|
mut rec_type := node.receiver_type
|
||||||
if rec_type.has_flag(.shared_f) {
|
if rec_type.has_flag(.shared_f) {
|
||||||
|
|
|
@ -514,8 +514,8 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
line_nr := p.tok.line_nr
|
line_nr := p.tok.line_nr
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
|
|
||||||
if name == 'type_name' {
|
if name in ['type_name', 'type_idx'] {
|
||||||
p.error_with_pos('cannot override built-in method `type_name`', method_start_pos)
|
p.error_with_pos('cannot override built-in method `$name`', method_start_pos)
|
||||||
return ast.InterfaceDecl{}
|
return ast.InterfaceDecl{}
|
||||||
}
|
}
|
||||||
if ts.has_method(name) {
|
if ts.has_method(name) {
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
// NB: .type_name() and .type_idx() called on an interface instance are more expensive
|
||||||
|
// than typeof(instance).name and typeof(instance).idx, since they will search and return
|
||||||
|
// the name and type index of the concrete interface instance.
|
||||||
|
//
|
||||||
|
// typeof(interface_instance).name returns the interface name, in the example here it will
|
||||||
|
// be always 'Animal'.
|
||||||
|
//
|
||||||
|
// interface_instance.type_name() will return 'Dog' or 'Cat' in this example, depending on
|
||||||
|
// what instance it is called.
|
||||||
|
//
|
||||||
|
// Similarly, typeof(interface_instance).idx will always return the same type index for all
|
||||||
|
// kinds of Animal.
|
||||||
|
|
||||||
|
interface Animal {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Dog {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cat {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SumType = int | string
|
||||||
|
|
||||||
|
fn test_type_idx() {
|
||||||
|
d := Dog{
|
||||||
|
name: 'Carlos'
|
||||||
|
}
|
||||||
|
c := Cat{
|
||||||
|
name: 'Tom'
|
||||||
|
}
|
||||||
|
ad := Animal(d)
|
||||||
|
ac := Animal(c)
|
||||||
|
dump(ad)
|
||||||
|
dump(ac)
|
||||||
|
divider___()
|
||||||
|
dump(typeof(ad).name)
|
||||||
|
dump(typeof(ac).name)
|
||||||
|
assert typeof(ad).name == 'Animal'
|
||||||
|
assert typeof(ac).name == 'Animal'
|
||||||
|
dump(typeof(ad).idx)
|
||||||
|
dump(typeof(ac).idx)
|
||||||
|
assert typeof(ad).idx == typeof(ac).idx
|
||||||
|
divider___()
|
||||||
|
dump(ad.type_name())
|
||||||
|
dump(ac.type_name())
|
||||||
|
assert ad.type_name() == 'Dog'
|
||||||
|
assert ac.type_name() == 'Cat'
|
||||||
|
dump(ad.type_idx())
|
||||||
|
dump(ac.type_idx())
|
||||||
|
assert ad.type_idx() != ac.type_idx()
|
||||||
|
assert ac.type_idx() != typeof(ad).idx
|
||||||
|
divider___()
|
||||||
|
dump(typeof(d).name)
|
||||||
|
dump(typeof(c).name)
|
||||||
|
assert typeof(d).name == 'Dog'
|
||||||
|
assert typeof(c).name == 'Cat'
|
||||||
|
dump(typeof(d).idx)
|
||||||
|
dump(typeof(c).idx)
|
||||||
|
assert typeof(d).idx != typeof(c).idx
|
||||||
|
assert typeof(d).idx != typeof(ad).idx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_sumtype_type_idx() {
|
||||||
|
s := 'abc'
|
||||||
|
i := 123
|
||||||
|
ss := SumType(s)
|
||||||
|
si := SumType(i)
|
||||||
|
divider___()
|
||||||
|
dump(s)
|
||||||
|
dump(i)
|
||||||
|
dump(ss)
|
||||||
|
dump(si)
|
||||||
|
dump(typeof(s).idx)
|
||||||
|
dump(typeof(i).idx)
|
||||||
|
dump(typeof(ss).idx)
|
||||||
|
dump(typeof(si).idx)
|
||||||
|
assert typeof(ss).idx != typeof(s).idx
|
||||||
|
assert typeof(s).idx != typeof(i).idx
|
||||||
|
assert typeof(ss).idx == typeof(si).idx
|
||||||
|
divider___()
|
||||||
|
dump(ss.type_name())
|
||||||
|
dump(si.type_name())
|
||||||
|
assert ss.type_name() == 'string'
|
||||||
|
assert si.type_name() == 'int'
|
||||||
|
assert ss.type_name() != si.type_name()
|
||||||
|
dump(ss.type_idx())
|
||||||
|
dump(si.type_idx())
|
||||||
|
assert ss.type_idx() == typeof(s).idx
|
||||||
|
assert si.type_idx() == typeof(i).idx
|
||||||
|
assert ss.type_idx() != si.type_idx()
|
||||||
|
assert typeof(ss).idx != ss.type_idx()
|
||||||
|
assert typeof(si).idx != si.type_idx()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn divider___() {
|
||||||
|
println('------------------------------------------------------------')
|
||||||
|
}
|
Loading…
Reference in New Issue