generics: generic call inside generic call; checker: check mut args at call

pull/5114/head
Alexander Medvednikov 2020-05-29 04:30:00 +02:00
parent f0a9b88ac4
commit 81b44dc2c9
9 changed files with 50 additions and 29 deletions

View File

@ -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('.')
} }

View File

@ -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()
} }

View File

@ -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())

View File

@ -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 {

View File

@ -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)
}

View File

@ -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()

View File

@ -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
} }

View File

@ -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')
} }
*/ */

View File

@ -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)