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)
}
pub fn (mut app App) init() {
pub fn (app App) init() {
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.waitgroup.add(njobs)
for i := 0; i < njobs; i++ {
go process_in_thread(pool,i)
go process_in_thread(mut pool,i)
}
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)
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') {
// 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 {
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
if arg_typ_sym.kind == .interface_ {
c.type_implements(typ, arg.typ, call_arg.expr.position())

View File

@ -384,8 +384,10 @@ typedef struct {
.alias {
parent := &g.table.types[typ.parent_idx]
styp := typ.name.replace('.', '__')
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('.', '__') }
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('.',
'__') }
g.definitions.writeln('typedef $parent_styp $styp;')
}
.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()
expected_is_ptr := expected_type.is_ptr()
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()
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]
@ -901,7 +905,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
if return_type != table.void_type && return_type != 0 {
sym := g.table.get_type_symbol(return_type)
// 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
// TODO Handle in if_expr
is_optional := return_type.flag_is(.optional)
@ -1317,6 +1322,9 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.CharLiteral {
g.write("'$it.val'")
}
ast.ComptimeCall {
g.write('/*c*/')
}
ast.ConcatExpr {
g.concat_expr(it)
}
@ -1836,7 +1844,8 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.writeln('// match 0')
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 {
g.inside_ternary++
// 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]
fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
match expr {
ast.CallExpr {
return g.table.get_type_symbol(it.return_type).kind == .multi_return
}
else {
return false
}
ast.CallExpr { return g.table.get_type_symbol(it.return_type).kind == .multi_return }
else { return false }
}
}
fn (mut g Gen) return_statement(node ast.Return) {
@ -2247,20 +2251,15 @@ fn (mut g Gen) return_statement(node ast.Return) {
} else {
styp = g.typ(g.fn_decl.return_type)
}
// Use this to keep the tmp assignments in order
mut multi_unpack := ''
g.write('($styp){')
mut arg_idx := 0
for i, expr in node.exprs {
// Check if we are dealing with a multi return and handle it seperately
if g.expr_is_multi_return_call(expr) {
c := expr as ast.CallExpr
expr_sym := g.table.get_type_symbol(c.return_type)
// Create a tmp for this call
tmp := g.new_tmp_var()
s := g.go_before_stmt(0)
@ -2270,7 +2269,6 @@ fn (mut g Gen) return_statement(node ast.Return) {
g.writeln(';')
multi_unpack += g.go_before_stmt(0)
g.write(s)
expr_types := expr_sym.mr_info().types
for j, _ in expr_types {
g.write('.arg$arg_idx=${tmp}.arg$j')
@ -2279,10 +2277,8 @@ fn (mut g Gen) return_statement(node ast.Return) {
}
arg_idx++
}
continue
}
g.write('.arg$arg_idx=')
g.expr(expr)
arg_idx++
@ -2291,11 +2287,9 @@ fn (mut g Gen) return_statement(node ast.Return) {
}
}
g.write('}')
if fn_return_is_optional {
g.write(' }, sizeof($styp))')
}
// Make sure to add our unpacks
g.insert_before_stmt(multi_unpack)
} 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 {
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
g.cur_fn = &it
defer {
@ -760,3 +763,7 @@ fn (mut g Gen) is_gui_app() bool {
}
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)`
p.next() // `<`
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.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)
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
// 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
}

View File

@ -210,6 +210,6 @@ fn test_generic_fn_with_variadics(){
p(s)
p(i)
p(abc)
p('Good','morning','world')
p('Good', 'morning', 'world')
}
*/

View File

@ -142,7 +142,7 @@ pub fn run<T>(port int) {
//app.reset()
for {
conn := l.accept() or { panic('accept() failed') }
handle_conn(conn, mut app)
handle_conn<T>(conn, mut app)
//foobar<T>()
// TODO move this to handle_conn<T>(conn, app)
//message := readall(conn)