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 // 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 } { if s == unsafe { nil } {
return none return unsafe { nil }
} }
for sc := unsafe { s }; true; sc = sc.parent { for sc := unsafe { s }; true; sc = sc.parent {
if field := sc.struct_fields[name] { if field := sc.struct_fields[name] {
if field.struct_type == struct_type && field.name == field_name { if field.struct_type == struct_type && field.name == field_name {
return field return &ScopeStructField{
...field
}
} }
} }
if sc.dont_lookup_parent() { if sc.dont_lookup_parent() {
break break
} }
} }
return none return unsafe { nil }
} }
pub fn (s &Scope) find_var(name string) ?&Var { 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 field_sym.kind in [.sum_type, .interface] || field.typ.has_flag(.option) {
if !prevent_sum_type_unwrapping_once { 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() 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() 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 smartcasts << field.smartcasts
} }
// smartcast either if the value is immutable or if the mut argument is explicitly given // 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 mut field_typ := field.typ
if field.typ.has_flag(.option) { if field.typ.has_flag(.option) {
// unwrapped callback (if f.func != none {}) // 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) method_name)
{ if scope_field != unsafe { nil } {
field_typ = scope_field.smartcasts.last() field_typ = scope_field.smartcasts.last()
node.is_unwrapped_fn_selector = true node.is_unwrapped_fn_selector = true
} else { } 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 { } 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 { if v.smartcasts.len > 0 && unwrapped_expected_type == v.orig_type {
is_already_sum_type = true is_already_sum_type = true
} }
@ -4178,7 +4179,8 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
if !prevent_sum_type_unwrapping_once { if !prevent_sum_type_unwrapping_once {
// check first if field is sum type because scope searching is expensive // check first if field is sum type because scope searching is expensive
scope := g.file.scope.innermost(node.pos.pos) 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 nested_unwrap := is_option && field.smartcasts.len > 1
is_option_unwrap = is_option && field.smartcasts.len > 0 is_option_unwrap = is_option && field.smartcasts.len > 0
&& field.typ.clear_flag(.option) == field.smartcasts.last() && 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) field_sym := g.table.sym(field.typ)
if field_sym.kind in [.sum_type, .interface] { if field_sym.kind in [.sum_type, .interface] {
if !prevent_sum_type_unwrapping_once { 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() 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 { if node.expr is ast.Ident && node.is_field_typ {
return t.get_type_from_comptime_var(node.expr) 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 { if field.smartcasts.len > 0 {
return field.smartcasts.last() 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 // Struct[T] can have field with generic type
if struct_sym.info is ast.Struct && struct_sym.info.generic_types.len > 0 { 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 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) t.get_type_or_default(node.expr, node.expr_type), node.field_name)
{ if f_unwrap != unsafe { nil } {
return f_unwrap.smartcasts.last() return f_unwrap.smartcasts.last()
} }
return field.typ return field.typ