@@ -11618,235 +11618,6 @@ fn (t &Transformer) get_expr_type(expr ast.Expr) ?types.Type {
1161811618 return typ
1161911619 }
1162011620 }
11621- // Handle literal types by looking up their type in the scope
11622- if expr is ast.StringLiteral || expr is ast.StringInterLiteral {
11623- if mut scope := t.get_current_scope () {
11624- if obj := scope.lookup_parent ('string' , 0 ) {
11625- return obj.typ ()
11626- }
11627- }
11628- }
11629- if expr is ast.BasicLiteral {
11630- if expr.kind == .string {
11631- if mut scope := t.get_current_scope () {
11632- if obj := scope.lookup_parent ('string' , 0 ) {
11633- return obj.typ ()
11634- }
11635- }
11636- }
11637- }
11638- // Handle pointer type expressions like &Type
11639- if expr is ast.PrefixExpr && expr.op == token.Token.amp {
11640- inner_type := t.get_expr_type (expr.expr) or { return none }
11641- return types.Pointer{
11642- base_type: inner_type
11643- }
11644- }
11645- // Handle modifier expressions like mut Type
11646- if expr is ast.ModifierExpr {
11647- return t.get_expr_type (expr.expr)
11648- }
11649- if expr is ast.Ident {
11650- // Look up variable type from scope
11651- if var_type := t.lookup_var_type (expr.name) {
11652- return var_type
11653- }
11654- // Fall back to current scope lookup
11655- if mut scope := t.get_current_scope () {
11656- if obj := scope.lookup_parent (expr.name, 0 ) {
11657- return obj.typ ()
11658- }
11659- }
11660- // Fallback to the checker's position-based cache when scope lookup fails.
11661- // This is needed for locals that live only in nested scopes (the transformer does
11662- // not have those checker scopes), and for synthesized scopes during lowering.
11663- if pos.is_valid () {
11664- if typ := t.env.get_expr_type (pos.id) {
11665- return typ
11666- }
11667- }
11668- return none
11669- }
11670- if expr is ast.IndexExpr {
11671- // For slicing (a[i..j]), the result type is the same as the source
11672- if expr.expr is ast.RangeExpr {
11673- return t.get_expr_type (expr.lhs)
11674- }
11675- // For array/map indexing (a[i] or m[k]), get the element/value type
11676- lhs_type := t.get_expr_type (expr.lhs) or { return none }
11677- if lhs_type is types.Array {
11678- return lhs_type.elem_type
11679- }
11680- if lhs_type is types.ArrayFixed {
11681- return lhs_type.elem_type
11682- }
11683- if lhs_type is types.Map {
11684- return lhs_type.value_type
11685- }
11686- }
11687- // Handle array type expressions (for receiver types like []Expr)
11688- if expr is ast.Type {
11689- if expr is ast.ArrayType {
11690- elem_type := t.get_expr_type (expr.elem_type) or { return none }
11691- return types.Array{
11692- elem_type: elem_type
11693- }
11694- }
11695- if expr is ast.ArrayFixedType {
11696- elem_type := t.get_expr_type (expr.elem_type) or { return none }
11697- mut len := 0
11698- if expr.len is ast.BasicLiteral && expr.len.kind == .number {
11699- len = expr.len.value.int ()
11700- }
11701- return types.ArrayFixed{
11702- len: len
11703- elem_type: elem_type
11704- }
11705- }
11706- }
11707- // Handle cast expressions - type is the target type
11708- if expr is ast.CastExpr {
11709- return t.get_expr_type (expr.typ)
11710- }
11711- // Handle function calls - look up return type
11712- if expr is ast.CallExpr {
11713- mut fn_name := ''
11714- mut mod_name := ''
11715- if expr.lhs is ast.Ident {
11716- fn_name = expr.lhs.name
11717- } else if expr.lhs is ast.SelectorExpr {
11718- sel := expr.lhs as ast.SelectorExpr
11719- // Check for module.function call
11720- if sel.lhs is ast.Ident {
11721- mod_name = (sel.lhs as ast.Ident ).name
11722- fn_name = sel.rhs.name
11723- }
11724- }
11725- if fn_name != '' {
11726- // Look up function return type from environment
11727- if mod_name != '' {
11728- if fn_type := t.env.lookup_fn (mod_name, fn_name) {
11729- if ret_type := fn_type.get_return_type () {
11730- return ret_type
11731- }
11732- }
11733- } else if t.cur_module != '' {
11734- // Try current module first
11735- if fn_type := t.env.lookup_fn (t.cur_module, fn_name) {
11736- if ret_type := fn_type.get_return_type () {
11737- return ret_type
11738- }
11739- }
11740- }
11741- // Try builtin
11742- if fn_type := t.env.lookup_fn ('builtin' , fn_name) {
11743- if ret_type := fn_type.get_return_type () {
11744- return ret_type
11745- }
11746- }
11747- }
11748- }
11749- // Handle single-arg function calls or type casts (CallOrCastExpr)
11750- if expr is ast.CallOrCastExpr {
11751- mut fn_name := ''
11752- mut mod_name := ''
11753- if expr.lhs is ast.Ident {
11754- fn_name = expr.lhs.name
11755- } else if expr.lhs is ast.SelectorExpr {
11756- sel := expr.lhs as ast.SelectorExpr
11757- if sel.lhs is ast.Ident {
11758- mod_name = (sel.lhs as ast.Ident ).name
11759- fn_name = sel.rhs.name
11760- }
11761- }
11762- if fn_name != '' {
11763- // If name starts with uppercase, it might be a type cast (e.g., ast.Expr(value))
11764- if fn_name.len > 0 && fn_name[0 ] > = `A` && fn_name[0 ] < = `Z` {
11765- // Try looking up as a type first
11766- if typ := t.get_expr_type (expr.lhs) {
11767- return typ
11768- }
11769- }
11770- if mod_name != '' {
11771- if fn_type := t.env.lookup_fn (mod_name, fn_name) {
11772- if ret_type := fn_type.get_return_type () {
11773- return ret_type
11774- }
11775- }
11776- } else if t.cur_module != '' {
11777- if fn_type := t.env.lookup_fn (t.cur_module, fn_name) {
11778- if ret_type := fn_type.get_return_type () {
11779- return ret_type
11780- }
11781- }
11782- }
11783- // Try builtin module for transformed calls like int__str(x),
11784- // which are represented as CallOrCastExpr with one argument.
11785- if fn_type := t.env.lookup_fn ('builtin' , fn_name) {
11786- if ret_type := fn_type.get_return_type () {
11787- return ret_type
11788- }
11789- }
11790- }
11791- }
11792- // Handle MapInitExpr (for literal maps like {'a': 1, 'b': 2})
11793- if expr is ast.MapInitExpr {
11794- // Helper to get string type from scope
11795- mut string_type := types.Type (types.Primitive{
11796- size: 64
11797- props: .integer
11798- })
11799- if mut scope := t.get_current_scope () {
11800- if obj := scope.lookup_parent ('string' , 0 ) {
11801- string_type = obj.typ ()
11802- }
11803- }
11804- int_type := types.Type (types.Primitive{
11805- size: 64
11806- props: .integer
11807- })
11808-
11809- // Check if map has explicit type
11810- match expr.typ {
11811- ast.Type {
11812- if expr.typ is ast.MapType {
11813- mt := expr.typ as ast.MapType
11814- key_type := t.get_expr_type (mt.key_type) or { string_type }
11815- value_type := t.get_expr_type (mt.value_type) or { int_type }
11816- return types.Map{
11817- key_type: key_type
11818- value_type: value_type
11819- }
11820- }
11821- }
11822- else {}
11823- }
11824- // Infer from first key/value (for literal maps like {'a': 1})
11825- if expr.keys.len > 0 {
11826- first_key := expr.keys[0 ]
11827- first_val := expr.vals[0 ]
11828- mut key_type := int_type
11829- mut val_type := int_type
11830- if first_key is ast.StringLiteral {
11831- key_type = string_type
11832- } else if first_key is ast.BasicLiteral {
11833- if first_key.kind == .string {
11834- key_type = string_type
11835- }
11836- }
11837- if first_val is ast.StringLiteral {
11838- val_type = string_type
11839- } else if first_val is ast.BasicLiteral {
11840- if first_val.kind == .string {
11841- val_type = string_type
11842- }
11843- }
11844- return types.Map{
11845- key_type: key_type
11846- value_type: val_type
11847- }
11848- }
11849- }
1185011621 return none
1185111622}
1185211623
0 commit comments