checker/cgen: interface smart casts

pull/6212/head
Alexander Medvednikov 2020-08-24 11:10:11 +02:00
parent 912bc8bca1
commit d547f74cb0
3 changed files with 19 additions and 17 deletions

View File

@ -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)
}
}
// smartcast sumtypes when using `is`
// smartcast sumtypes and interfaces when using `is`
if branch.cond is ast.InfixExpr {
infix := branch.cond as ast.InfixExpr
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
if is_variable {
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 scope := c.file.scope.innermost(branch.body_pos.pos)
if infix.left is ast.Ident as infix_left {

View File

@ -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)
if expected_is_ptr && got_is_ptr {
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.write(', .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
} else if expected_is_ptr {
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.write('}, sizeof($got_styp)), .typ = $got_idx /* $got_sym.name */}, sizeof($exp_der_styp))')
} 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.write(', .typ = $got_idx /* $got_sym.name */}')
} 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.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)
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.writeln('obj; // ST it')
g.writeln('_object; // ST it')
if node.var_name.len > 0 {
// for now we just copy it
g.writeln('\t$it_type* $node.var_name = it;')
@ -2788,7 +2788,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
} else {
g.write('.')
}
g.writeln('obj;')
g.writeln('_object;')
g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;')
}
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('typedef struct {')
g.type_definitions.writeln(' void* obj;')
g.type_definitions.writeln(' void* _object;')
g.type_definitions.writeln(' int typ;')
g.type_definitions.writeln('} $name;')
g.type_definitions.writeln('')
@ -4704,7 +4704,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
g.write('/* as */ ($styp*)__as_cast(')
g.expr(node.expr)
g.write(dot)
g.write('obj, ')
g.write('_object, ')
g.expr(node.expr)
g.write(dot)
g.write('typ, /*expected:*/$node.typ)')

View File

@ -23,7 +23,7 @@ fn (c &Cat) speak(s 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) {
@ -46,7 +46,7 @@ fn (d Dog) name() 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) {
@ -67,10 +67,12 @@ fn perform_speak(a Animal) {
assert name == 'Dog' || name == 'Cat'
if a is Dog {
assert name == 'Dog'
assert a.breed == 'Labrador Retriever' // test smart casting
println(a.breed)
}
println(a.name())
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) {
@ -78,12 +80,12 @@ fn perform_speak_on_ptr(a &Animal) {
assert true
name := a.name()
assert name == 'Dog' || name == 'Cat'
// if a is Dog {
// assert name == 'Dog'
// }
if a is Dog {
assert name == 'Dog'
}
println(a.name())
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() {