ast: minimise allocations done for the common case in find_struct_field

This commit is contained in:
Delyan Angelov 2025-04-07 09:50:00 +03:00
parent e9ac9f1410
commit a9ff1a2624
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
7 changed files with 22 additions and 14 deletions

View File

@ -61,21 +61,23 @@ pub fn (s &Scope) find(name string) ?ScopeObject {
}
// selector_expr: name.field_name
pub fn (s &Scope) find_struct_field(name string, struct_type Type, field_name string) ?ScopeStructField {
pub fn (s &Scope) find_struct_field(name string, struct_type Type, field_name string) &ScopeStructField {
if s == unsafe { nil } {
return none
return unsafe { nil }
}
for sc := unsafe { s }; true; sc = sc.parent {
if field := sc.struct_fields[name] {
if field.struct_type == struct_type && field.name == field_name {
return field
return &ScopeStructField{
...field
}
}
}
if sc.dont_lookup_parent() {
break
}
}
return none
return unsafe { nil }
}
pub fn (s &Scope) find_var(name string) ?&Var {

View File

@ -1794,7 +1794,8 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
}
if field_sym.kind in [.sum_type, .interface] || field.typ.has_flag(.option) {
if !prevent_sum_type_unwrapping_once {
if scope_field := node.scope.find_struct_field(node.expr.str(), typ, field_name) {
scope_field := node.scope.find_struct_field(node.expr.str(), typ, field_name)
if scope_field != unsafe { nil } {
return scope_field.smartcasts.last()
}
}
@ -4379,7 +4380,8 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
}
}
expr_str := expr.expr.str()
if mut field := scope.find_struct_field(expr_str, expr.expr_type, expr.field_name) {
field := scope.find_struct_field(expr_str, expr.expr_type, expr.field_name)
if field != unsafe { nil } {
smartcasts << field.smartcasts
}
// smartcast either if the value is immutable or if the mut argument is explicitly given

View File

@ -2164,9 +2164,9 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
mut field_typ := field.typ
if field.typ.has_flag(.option) {
// unwrapped callback (if f.func != none {})
if scope_field := node.scope.find_struct_field(node.left.str(), node.left_type,
scope_field := node.scope.find_struct_field(node.left.str(), node.left_type,
method_name)
{
if scope_field != unsafe { nil } {
field_typ = scope_field.smartcasts.last()
node.is_unwrapped_fn_selector = true
} else {

View File

@ -3008,7 +3008,8 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
}
}
} else if expr is ast.SelectorExpr {
if v := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {
v := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name)
if v != unsafe { nil } {
if v.smartcasts.len > 0 && unwrapped_expected_type == v.orig_type {
is_already_sum_type = true
}
@ -4178,7 +4179,8 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
if !prevent_sum_type_unwrapping_once {
// check first if field is sum type because scope searching is expensive
scope := g.file.scope.innermost(node.pos.pos)
if field := scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name) {
field := scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name)
if field != unsafe { nil } {
nested_unwrap := is_option && field.smartcasts.len > 1
is_option_unwrap = is_option && field.smartcasts.len > 0
&& field.typ.clear_flag(.option) == field.smartcasts.last()

View File

@ -1125,7 +1125,8 @@ fn (mut g Gen) comptime_selector_type(node ast.SelectorExpr) ast.Type {
field_sym := g.table.sym(field.typ)
if field_sym.kind in [.sum_type, .interface] {
if !prevent_sum_type_unwrapping_once {
if scope_field := node.scope.find_struct_field(node.expr.str(), typ, field_name) {
scope_field := node.scope.find_struct_field(node.expr.str(), typ, field_name)
if scope_field != unsafe { nil } {
return scope_field.smartcasts.last()
}
}

View File

@ -75,7 +75,8 @@ pub fn (mut t TypeResolver) typeof_type(node ast.Expr, default_type ast.Type) as
if node.expr is ast.Ident && node.is_field_typ {
return t.get_type_from_comptime_var(node.expr)
}
if field := node.scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name) {
field := node.scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name)
if field != unsafe { nil } {
if field.smartcasts.len > 0 {
return field.smartcasts.last()
}

View File

@ -234,9 +234,9 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type {
// Struct[T] can have field with generic type
if struct_sym.info is ast.Struct && struct_sym.info.generic_types.len > 0 {
if field := t.table.find_field(struct_sym, node.field_name) {
if f_unwrap := node.scope.find_struct_field(ast.Expr(node.expr).str(),
f_unwrap := node.scope.find_struct_field(ast.Expr(node.expr).str(),
t.get_type_or_default(node.expr, node.expr_type), node.field_name)
{
if f_unwrap != unsafe { nil } {
return f_unwrap.smartcasts.last()
}
return field.typ