mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker/cgen: interface smart casts
This commit is contained in:
parent
912bc8bca1
commit
d547f74cb0
@ -2983,7 +2983,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
|||||||
c.error('non-bool type `$typ_sym.source_name` used as if condition', branch.pos)
|
c.error('non-bool type `$typ_sym.source_name` used as if condition', branch.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// smartcast sumtypes when using `is`
|
// smartcast sumtypes and interfaces when using `is`
|
||||||
if branch.cond is ast.InfixExpr {
|
if branch.cond is ast.InfixExpr {
|
||||||
infix := branch.cond as ast.InfixExpr
|
infix := branch.cond as ast.InfixExpr
|
||||||
if infix.op == .key_is &&
|
if infix.op == .key_is &&
|
||||||
@ -2994,7 +2994,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
|||||||
// Register shadow variable or `as` variable with actual type
|
// Register shadow variable or `as` variable with actual type
|
||||||
if is_variable {
|
if is_variable {
|
||||||
left_sym := c.table.get_type_symbol(infix.left_type)
|
left_sym := c.table.get_type_symbol(infix.left_type)
|
||||||
if left_sym.kind == .sum_type && branch.left_as_name.len > 0 {
|
if left_sym.kind in [.sum_type, .interface_] && branch.left_as_name.len > 0 {
|
||||||
mut is_mut := false
|
mut is_mut := false
|
||||||
mut scope := c.file.scope.innermost(branch.body_pos.pos)
|
mut scope := c.file.scope.innermost(branch.body_pos.pos)
|
||||||
if infix.left is ast.Ident as infix_left {
|
if infix.left is ast.Ident as infix_left {
|
||||||
|
@ -1134,20 +1134,20 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type)
|
|||||||
got_sym := g.table.get_type_symbol(got_type)
|
got_sym := g.table.get_type_symbol(got_type)
|
||||||
if expected_is_ptr && got_is_ptr {
|
if expected_is_ptr && got_is_ptr {
|
||||||
exp_der_styp := g.typ(expected_deref_type)
|
exp_der_styp := g.typ(expected_deref_type)
|
||||||
g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){.obj = ')
|
g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){._object = ')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(', .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
|
g.write(', .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
|
||||||
} else if expected_is_ptr {
|
} else if expected_is_ptr {
|
||||||
exp_der_styp := g.typ(expected_deref_type)
|
exp_der_styp := g.typ(expected_deref_type)
|
||||||
g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){.obj = memdup(&($got_styp[]) {')
|
g.write('/* sum type cast */ ($exp_styp) memdup(&($exp_der_styp){._object = memdup(&($got_styp[]) {')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
|
g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
|
||||||
} else if got_is_ptr {
|
} else if got_is_ptr {
|
||||||
g.write('/* sum type cast */ ($exp_styp) {.obj = ')
|
g.write('/* sum type cast */ ($exp_styp) {._object = ')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(', .typ = $got_idx /* $got_sym.name */}')
|
g.write(', .typ = $got_idx /* $got_sym.name */}')
|
||||||
} else {
|
} else {
|
||||||
g.write('/* sum type cast */ ($exp_styp) {.obj = memdup(&($got_styp[]) {')
|
g.write('/* sum type cast */ ($exp_styp) {._object = memdup(&($got_styp[]) {')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}')
|
g.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}')
|
||||||
}
|
}
|
||||||
@ -2604,7 +2604,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
|||||||
g.expr(node.cond)
|
g.expr(node.cond)
|
||||||
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
|
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
|
||||||
g.write(dot_or_ptr)
|
g.write(dot_or_ptr)
|
||||||
g.writeln('obj; // ST it')
|
g.writeln('_object; // ST it')
|
||||||
if node.var_name.len > 0 {
|
if node.var_name.len > 0 {
|
||||||
// for now we just copy it
|
// for now we just copy it
|
||||||
g.writeln('\t$it_type* $node.var_name = it;')
|
g.writeln('\t$it_type* $node.var_name = it;')
|
||||||
@ -2788,7 +2788,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|||||||
} else {
|
} else {
|
||||||
g.write('.')
|
g.write('.')
|
||||||
}
|
}
|
||||||
g.writeln('obj;')
|
g.writeln('_object;')
|
||||||
g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;')
|
g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;')
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
@ -3773,7 +3773,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
|||||||
g.type_definitions.writeln('// | ${sv:4d} = ${g.typ(sv):-20s}')
|
g.type_definitions.writeln('// | ${sv:4d} = ${g.typ(sv):-20s}')
|
||||||
}
|
}
|
||||||
g.type_definitions.writeln('typedef struct {')
|
g.type_definitions.writeln('typedef struct {')
|
||||||
g.type_definitions.writeln(' void* obj;')
|
g.type_definitions.writeln(' void* _object;')
|
||||||
g.type_definitions.writeln(' int typ;')
|
g.type_definitions.writeln(' int typ;')
|
||||||
g.type_definitions.writeln('} $name;')
|
g.type_definitions.writeln('} $name;')
|
||||||
g.type_definitions.writeln('')
|
g.type_definitions.writeln('')
|
||||||
@ -4704,7 +4704,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
|
|||||||
g.write('/* as */ ($styp*)__as_cast(')
|
g.write('/* as */ ($styp*)__as_cast(')
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
g.write(dot)
|
g.write(dot)
|
||||||
g.write('obj, ')
|
g.write('_object, ')
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
g.write(dot)
|
g.write(dot)
|
||||||
g.write('typ, /*expected:*/$node.typ)')
|
g.write('typ, /*expected:*/$node.typ)')
|
||||||
|
@ -23,7 +23,7 @@ fn (c &Cat) speak(s string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (c Cat) name_detailed(pet_name string) string {
|
fn (c Cat) name_detailed(pet_name string) string {
|
||||||
return '$pet_name the ${typeof(c)}, breed:${c.breed}'
|
return '$pet_name the ${typeof(c)}, breed:$c.breed'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Cat) set_breed(new string) {
|
fn (mut c Cat) set_breed(new string) {
|
||||||
@ -46,7 +46,7 @@ fn (d Dog) name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (d Dog) name_detailed(pet_name string) string {
|
fn (d Dog) name_detailed(pet_name string) string {
|
||||||
return '$pet_name the ${typeof(d)}, breed:${d.breed}'
|
return '$pet_name the ${typeof(d)}, breed:$d.breed'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut d Dog) set_breed(new string) {
|
fn (mut d Dog) set_breed(new string) {
|
||||||
@ -67,10 +67,12 @@ fn perform_speak(a Animal) {
|
|||||||
assert name == 'Dog' || name == 'Cat'
|
assert name == 'Dog' || name == 'Cat'
|
||||||
if a is Dog {
|
if a is Dog {
|
||||||
assert name == 'Dog'
|
assert name == 'Dog'
|
||||||
|
assert a.breed == 'Labrador Retriever' // test smart casting
|
||||||
|
println(a.breed)
|
||||||
}
|
}
|
||||||
println(a.name())
|
println(a.name())
|
||||||
println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible)
|
println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible)
|
||||||
// assert a is Dog || a is Cat // TODO: enable when available
|
assert a is Dog || a is Cat
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_speak_on_ptr(a &Animal) {
|
fn perform_speak_on_ptr(a &Animal) {
|
||||||
@ -78,12 +80,12 @@ fn perform_speak_on_ptr(a &Animal) {
|
|||||||
assert true
|
assert true
|
||||||
name := a.name()
|
name := a.name()
|
||||||
assert name == 'Dog' || name == 'Cat'
|
assert name == 'Dog' || name == 'Cat'
|
||||||
// if a is Dog {
|
if a is Dog {
|
||||||
// assert name == 'Dog'
|
assert name == 'Dog'
|
||||||
// }
|
}
|
||||||
println(a.name())
|
println(a.name())
|
||||||
println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible)
|
println('Got animal of type: ${typeof(a)}') // TODO: get implementation type (if possible)
|
||||||
// assert a is Dog || a is Cat // TODO: enable when available
|
assert a is Dog || a is Cat
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_perform_speak() {
|
fn test_perform_speak() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user