generics: generic call inside generic call; checker: check mut args at call
parent
f0a9b88ac4
commit
81b44dc2c9
|
@ -17,7 +17,7 @@ fn main() {
|
||||||
vweb.run<App>(port)
|
vweb.run<App>(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut app App) init() {
|
pub fn (app App) init() {
|
||||||
app.vweb.handle_static('.')
|
app.vweb.handle_static('.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ pub fn (mut pool PoolProcessor) work_on_pointers(items []voidptr) {
|
||||||
pool.thread_contexts << [voidptr(0)].repeat(pool.items.len)
|
pool.thread_contexts << [voidptr(0)].repeat(pool.items.len)
|
||||||
pool.waitgroup.add(njobs)
|
pool.waitgroup.add(njobs)
|
||||||
for i := 0; i < njobs; i++ {
|
for i := 0; i < njobs; i++ {
|
||||||
go process_in_thread(pool,i)
|
go process_in_thread(mut pool,i)
|
||||||
}
|
}
|
||||||
pool.waitgroup.wait()
|
pool.waitgroup.wait()
|
||||||
}
|
}
|
||||||
|
|
|
@ -860,6 +860,16 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
// TODO: impl typeof properly (probably not going to be a fn call)
|
// TODO: impl typeof properly (probably not going to be a fn call)
|
||||||
return table.string_type
|
return table.string_type
|
||||||
}
|
}
|
||||||
|
if call_expr.generic_type == table.t_type {
|
||||||
|
if c.mod != '' && c.mod != 'main' {
|
||||||
|
// Need to prepend the module when adding a generic type to a function
|
||||||
|
// `fn_gen_types['mymod.myfn'] == ['string', 'int']`
|
||||||
|
c.table.register_fn_gen_type(c.mod + '.' + fn_name, c.cur_generic_type)
|
||||||
|
} else {
|
||||||
|
c.table.register_fn_gen_type(fn_name, c.cur_generic_type)
|
||||||
|
}
|
||||||
|
// call_expr.generic_type = c.unwrap_generic(call_expr.generic_type)
|
||||||
|
}
|
||||||
// if c.fileis('json_test.v') {
|
// if c.fileis('json_test.v') {
|
||||||
// println(fn_name)
|
// println(fn_name)
|
||||||
// }
|
// }
|
||||||
|
@ -984,6 +994,10 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i {
|
if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i {
|
||||||
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
|
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
|
||||||
}
|
}
|
||||||
|
if arg.is_mut && !call_arg.is_mut {
|
||||||
|
c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`',
|
||||||
|
call_arg.expr.position())
|
||||||
|
}
|
||||||
// Handle expected interface
|
// Handle expected interface
|
||||||
if arg_typ_sym.kind == .interface_ {
|
if arg_typ_sym.kind == .interface_ {
|
||||||
c.type_implements(typ, arg.typ, call_arg.expr.position())
|
c.type_implements(typ, arg.typ, call_arg.expr.position())
|
||||||
|
|
|
@ -384,8 +384,10 @@ typedef struct {
|
||||||
.alias {
|
.alias {
|
||||||
parent := &g.table.types[typ.parent_idx]
|
parent := &g.table.types[typ.parent_idx]
|
||||||
styp := typ.name.replace('.', '__')
|
styp := typ.name.replace('.', '__')
|
||||||
is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.`
|
is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] ==
|
||||||
parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.', '__') }
|
`.`
|
||||||
|
parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.',
|
||||||
|
'__') }
|
||||||
g.definitions.writeln('typedef $parent_styp $styp;')
|
g.definitions.writeln('typedef $parent_styp $styp;')
|
||||||
}
|
}
|
||||||
.array {
|
.array {
|
||||||
|
@ -842,7 +844,9 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type)
|
||||||
got_is_ptr := got_type.is_ptr()
|
got_is_ptr := got_type.is_ptr()
|
||||||
expected_is_ptr := expected_type.is_ptr()
|
expected_is_ptr := expected_type.is_ptr()
|
||||||
neither_void := table.voidptr_type !in [got_type, expected_type]
|
neither_void := table.voidptr_type !in [got_type, expected_type]
|
||||||
if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, .placeholder] {
|
if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_,
|
||||||
|
.placeholder
|
||||||
|
] {
|
||||||
got_deref_type := got_type.deref()
|
got_deref_type := got_type.deref()
|
||||||
deref_sym := g.table.get_type_symbol(got_deref_type)
|
deref_sym := g.table.get_type_symbol(got_deref_type)
|
||||||
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
|
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
|
||||||
|
@ -901,7 +905,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
if return_type != table.void_type && return_type != 0 {
|
if return_type != table.void_type && return_type != 0 {
|
||||||
sym := g.table.get_type_symbol(return_type)
|
sym := g.table.get_type_symbol(return_type)
|
||||||
// the left vs. right is ugly and should be removed
|
// the left vs. right is ugly and should be removed
|
||||||
if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len > 1 {
|
if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len >
|
||||||
|
1 {
|
||||||
// multi return
|
// multi return
|
||||||
// TODO Handle in if_expr
|
// TODO Handle in if_expr
|
||||||
is_optional := return_type.flag_is(.optional)
|
is_optional := return_type.flag_is(.optional)
|
||||||
|
@ -1317,6 +1322,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
ast.CharLiteral {
|
ast.CharLiteral {
|
||||||
g.write("'$it.val'")
|
g.write("'$it.val'")
|
||||||
}
|
}
|
||||||
|
ast.ComptimeCall {
|
||||||
|
g.write('/*c*/')
|
||||||
|
}
|
||||||
ast.ConcatExpr {
|
ast.ConcatExpr {
|
||||||
g.concat_expr(it)
|
g.concat_expr(it)
|
||||||
}
|
}
|
||||||
|
@ -1836,7 +1844,8 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
||||||
g.writeln('// match 0')
|
g.writeln('// match 0')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary > 0
|
is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary >
|
||||||
|
0
|
||||||
if is_expr {
|
if is_expr {
|
||||||
g.inside_ternary++
|
g.inside_ternary++
|
||||||
// g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */')
|
// g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */')
|
||||||
|
@ -2202,14 +2211,9 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||||
[inline]
|
[inline]
|
||||||
fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
||||||
match expr {
|
match expr {
|
||||||
ast.CallExpr {
|
ast.CallExpr { return g.table.get_type_symbol(it.return_type).kind == .multi_return }
|
||||||
return g.table.get_type_symbol(it.return_type).kind == .multi_return
|
else { return false }
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) return_statement(node ast.Return) {
|
fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
|
@ -2247,20 +2251,15 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
} else {
|
} else {
|
||||||
styp = g.typ(g.fn_decl.return_type)
|
styp = g.typ(g.fn_decl.return_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this to keep the tmp assignments in order
|
// Use this to keep the tmp assignments in order
|
||||||
mut multi_unpack := ''
|
mut multi_unpack := ''
|
||||||
|
|
||||||
|
|
||||||
g.write('($styp){')
|
g.write('($styp){')
|
||||||
|
|
||||||
mut arg_idx := 0
|
mut arg_idx := 0
|
||||||
for i, expr in node.exprs {
|
for i, expr in node.exprs {
|
||||||
// Check if we are dealing with a multi return and handle it seperately
|
// Check if we are dealing with a multi return and handle it seperately
|
||||||
if g.expr_is_multi_return_call(expr) {
|
if g.expr_is_multi_return_call(expr) {
|
||||||
c := expr as ast.CallExpr
|
c := expr as ast.CallExpr
|
||||||
expr_sym := g.table.get_type_symbol(c.return_type)
|
expr_sym := g.table.get_type_symbol(c.return_type)
|
||||||
|
|
||||||
// Create a tmp for this call
|
// Create a tmp for this call
|
||||||
tmp := g.new_tmp_var()
|
tmp := g.new_tmp_var()
|
||||||
s := g.go_before_stmt(0)
|
s := g.go_before_stmt(0)
|
||||||
|
@ -2270,7 +2269,6 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
multi_unpack += g.go_before_stmt(0)
|
multi_unpack += g.go_before_stmt(0)
|
||||||
g.write(s)
|
g.write(s)
|
||||||
|
|
||||||
expr_types := expr_sym.mr_info().types
|
expr_types := expr_sym.mr_info().types
|
||||||
for j, _ in expr_types {
|
for j, _ in expr_types {
|
||||||
g.write('.arg$arg_idx=${tmp}.arg$j')
|
g.write('.arg$arg_idx=${tmp}.arg$j')
|
||||||
|
@ -2279,10 +2277,8 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
}
|
}
|
||||||
arg_idx++
|
arg_idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
g.write('.arg$arg_idx=')
|
g.write('.arg$arg_idx=')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
arg_idx++
|
arg_idx++
|
||||||
|
@ -2291,11 +2287,9 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write('}')
|
g.write('}')
|
||||||
|
|
||||||
if fn_return_is_optional {
|
if fn_return_is_optional {
|
||||||
g.write(' }, sizeof($styp))')
|
g.write(' }, sizeof($styp))')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to add our unpacks
|
// Make sure to add our unpacks
|
||||||
g.insert_before_stmt(multi_unpack)
|
g.insert_before_stmt(multi_unpack)
|
||||||
} else if node.exprs.len >= 1 {
|
} else if node.exprs.len >= 1 {
|
||||||
|
|
|
@ -12,6 +12,9 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||||
// || it.no_body {
|
// || it.no_body {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//if g.fileis('vweb.v') {
|
||||||
|
//println('\ngen_fn_decl() $it.name $it.is_generic $g.cur_generic_type')
|
||||||
|
//}
|
||||||
former_cur_fn := g.cur_fn
|
former_cur_fn := g.cur_fn
|
||||||
g.cur_fn = &it
|
g.cur_fn = &it
|
||||||
defer {
|
defer {
|
||||||
|
@ -760,3 +763,7 @@ fn (mut g Gen) is_gui_app() bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (g &Gen) fileis(s string) bool {
|
||||||
|
return g.file.path.contains(s)
|
||||||
|
}
|
||||||
|
|
|
@ -30,9 +30,15 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
||||||
// `foo<int>(10)`
|
// `foo<int>(10)`
|
||||||
p.next() // `<`
|
p.next() // `<`
|
||||||
p.expr_mod = ''
|
p.expr_mod = ''
|
||||||
generic_type = p.parse_type()
|
mut generic_type = p.parse_type()
|
||||||
|
if generic_type == table.t_type {
|
||||||
|
// Handle `foo<T>()`
|
||||||
|
// generic_type = p.cur_gen_type
|
||||||
|
}
|
||||||
p.check(.gt) // `>`
|
p.check(.gt) // `>`
|
||||||
p.table.register_fn_gen_type(fn_name, generic_type)
|
if generic_type != table.t_type {
|
||||||
|
p.table.register_fn_gen_type(fn_name, generic_type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
args := p.call_args()
|
args := p.call_args()
|
||||||
|
|
|
@ -482,6 +482,6 @@ pub fn (table &Table) register_fn_gen_type(fn_name string, typ Type) {
|
||||||
}
|
}
|
||||||
a << typ
|
a << typ
|
||||||
// sym := table.get_type_symbol(typ)
|
// sym := table.get_type_symbol(typ)
|
||||||
// println('registering fn gen type $sym.name')
|
// println('registering fn ($fn_name) gen type $sym.name')
|
||||||
table.fn_gen_types[fn_name] = a
|
table.fn_gen_types[fn_name] = a
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,6 @@ fn test_generic_fn_with_variadics(){
|
||||||
p(s)
|
p(s)
|
||||||
p(i)
|
p(i)
|
||||||
p(abc)
|
p(abc)
|
||||||
p('Good','morning','world')
|
p('Good', 'morning', 'world')
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub fn run<T>(port int) {
|
||||||
//app.reset()
|
//app.reset()
|
||||||
for {
|
for {
|
||||||
conn := l.accept() or { panic('accept() failed') }
|
conn := l.accept() or { panic('accept() failed') }
|
||||||
handle_conn(conn, mut app)
|
handle_conn<T>(conn, mut app)
|
||||||
//foobar<T>()
|
//foobar<T>()
|
||||||
// TODO move this to handle_conn<T>(conn, app)
|
// TODO move this to handle_conn<T>(conn, app)
|
||||||
//message := readall(conn)
|
//message := readall(conn)
|
||||||
|
|
Loading…
Reference in New Issue