checker: allow for f() or { T{} } in a generic method, for fn f() ?T {, being called with T, being a container like []int etc, not just a primitive type like int (#22672)

This commit is contained in:
Delyan Angelov 2024-10-28 16:56:12 +02:00 committed by GitHub
parent 27ff2f1628
commit cc55aa5b36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 94 additions and 0 deletions

View File

@ -1419,6 +1419,9 @@ fn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr
}
type_name := c.table.type_to_str(last_stmt_typ)
expected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())
if ret_type.has_flag(.generic) {
return
}
c.error('wrong return type `${type_name}` in the `or {}` block, expected `${expected_type_name}`',
stmt.expr.pos())
}

View File

@ -0,0 +1,91 @@
struct St[T] {
mut:
a []T
}
fn (s St[T]) peek() ?T {
if s.a.len > 0 {
return s.a[0]
} else {
return none
}
}
fn (mut s St[T]) peek_or_default() T {
return s.peek() or { T{} }
}
fn (mut s St[T]) push(e T) {
x := s.peek() or { T{} } // this is deliberate
$if x is $array {
dump(x)
if s.a.len > 0 {
assert x.len > 0
} else {
assert x.len == 0
}
}
$if x is $int {
dump(x)
if s.a.len > 0 {
assert x == 2
} else {
assert x == 0
}
}
$if x is $map {
dump(x)
if s.a.len > 0 {
assert x == {
'abc': u8(4)
'def': 7
}
}
}
s.a << e
}
fn test_ints() {
mut s := St[int]{}
r := s.peek_or_default()
s.push(2)
s.push(3)
s.push(99)
assert s.a == [2, 3, 99]
dump(s)
}
fn test_array_of_ints() {
mut s := St[[]int]{}
r := s.peek_or_default()
s.push([2, 3, 5])
s.push([]int{})
s.push([10, 20, 99])
s.push([55, 88])
assert s.a == [[2, 3, 5], []int{}, [10, 20, 99], [55, 88]]
dump(s)
}
fn test_maps_of_u8s() {
mut s := St[map[string]u8]{}
r := s.peek_or_default()
s.push({
'abc': u8(4)
'def': 7
})
s.push({
'xyz': u8(13)
})
s.push({
'zzz': u8(99)
})
assert s.a == [{
'abc': u8(4)
'def': 7
}, {
'xyz': u8(13)
}, {
'zzz': u8(99)
}]
dump(s)
}