checker: fix typeof evaluation for generic reference (fix #23951) (fix #23952) (#23958)

This commit is contained in:
Felipe Pena 2025-03-17 11:52:59 -03:00 committed by GitHub
parent 2a3dc5c068
commit ebfa7d86cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 49 additions and 7 deletions

View file

@ -965,6 +965,8 @@ fn (mut c Checker) change_flags_if_comptime_expr(mut left ast.Ident, right ast.E
if right_ct_var != .no_comptime {
left.obj.ct_type_var = right_ct_var
}
} else if right is ast.StructInit && right.unresolved && right.typ.has_flag(.generic) {
left.obj.ct_type_var = .generic_param
} else if right is ast.IndexExpr && c.comptime.is_comptime(right) {
right_ct_var := c.comptime.get_ct_type_var(right.left)
if right_ct_var != .no_comptime {

View file

@ -899,9 +899,7 @@ fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) {
mut expr_left := expr.left
if mut expr.left is ast.Ident {
if mut expr.left.obj is ast.Var {
if expr.left.obj.ct_type_var != .generic_param {
c.fail_if_immutable(mut expr_left)
}
c.fail_if_immutable(mut expr_left)
}
}
return '', expr.pos

View file

@ -163,7 +163,7 @@ fn (mut g Gen) expr_with_opt(expr ast.Expr, expr_typ ast.Type, ret_typ ast.Type)
}
g.expr(expr)
if expr is ast.ComptimeSelector {
return '${expr.left.str()}.${g.comptime.comptime_for_field_value.name}'
return g.gen_comptime_selector(expr)
} else {
return expr.str()
}

View file

@ -3728,7 +3728,7 @@ fn (mut g Gen) expr(node_ ast.Expr) {
mut is_unwrapped := true
if mut node.expr is ast.ComptimeSelector && node.expr.left is ast.Ident {
// val.$(field.name)?
expr_str = '${node.expr.left.str()}.${g.comptime.comptime_for_field_value.name}'
expr_str = g.gen_comptime_selector(node.expr)
} else if mut node.expr is ast.Ident && node.expr.ct_expr {
// val?
expr_str = node.expr.name

View file

@ -39,6 +39,11 @@ fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) {
}
}
fn (mut g Gen) gen_comptime_selector(expr ast.ComptimeSelector) string {
arrow_or_dot := if expr.left_type.is_ptr() { '->' } else { '.' }
return '${expr.left.str()}${arrow_or_dot}${g.comptime.comptime_for_field_value.name}'
}
fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
if node.is_embed {
// $embed_file('/path/to/file')

View file

@ -0,0 +1,37 @@
module main
fn decode_array[T](x []T) string {
return 'decode_array: x.typename = ${typeof(x).name}'
}
fn decode[T]() string {
x := T{0}
mut s := 'decode: x.typename = ${typeof(x).name}. '
s += decode_array(x)
return s
}
fn second[K, V](x map[K]V) string {
return 'second: x.typename = ${typeof(x).name}'
}
fn first[T]() string {
x := T{}
mut s := 'first: x.typename = ${typeof(x).name}. '
s += second(x)
return s
}
fn test_map() {
assert first[map[string]string]() == 'first: x.typename = map[string]string. second: x.typename = map[string]string'
assert first[map[string]int]() == 'first: x.typename = map[string]int. second: x.typename = map[string]int'
assert first[map[string]u8]() == 'first: x.typename = map[string]u8. second: x.typename = map[string]u8'
assert first[map[string]rune]() == 'first: x.typename = map[string]rune. second: x.typename = map[string]rune'
}
fn test_array() {
assert decode[[]u8]() == 'decode: x.typename = []u8. decode_array: x.typename = []u8'
assert decode[[]u16]() == 'decode: x.typename = []u16. decode_array: x.typename = []u16'
assert decode[[]int]() == 'decode: x.typename = []int. decode_array: x.typename = []int'
assert decode[[]rune]() == 'decode: x.typename = []rune. decode_array: x.typename = []rune'
}

View file

@ -22,7 +22,7 @@ mut:
struct Decoder {}
fn (d &Decoder) decode[T](typ T) T {
fn (d &Decoder) decode[T](mut typ T) T {
$for field in T.fields {
$if field.is_option {
if typ.$(field.name) != none {
@ -36,7 +36,7 @@ fn (d &Decoder) decode[T](typ T) T {
fn test_comptime() {
d := Decoder{}
result := d.decode(StructType{
result := d.decode(mut StructType{
a: 'foo'
b: 3
})