typecheck_inline.mx raw

   1  package emit
   2  
   3  import (
   4  	"bytes"
   5  	"git.smesh.lol/moxie/pkg/syntax"
   6  	"git.smesh.lol/moxie/pkg/ssa"
   7  	"git.smesh.lol/moxie/pkg/token"
   8  	"git.smesh.lol/moxie/pkg/types"
   9  )
  10  
  11  func scanExportPragmas(src []byte) map[string]string {
  12  	result := map[string]string{}
  13  	exportPrefix := []byte("//export ")
  14  	funcPrefix := []byte("func ")
  15  	commentPrefix := []byte("//")
  16  	pendingExport := ""
  17  	i := 0
  18  	for i < len(src) {
  19  		nlIdx := bytes.IndexByte(src[i:], '\n')
  20  		var line []byte
  21  		var lineEnd int32
  22  		if nlIdx < 0 {
  23  			line = src[i:]
  24  			lineEnd = len(src)
  25  		} else {
  26  			line = src[i : i+nlIdx]
  27  			lineEnd = i + nlIdx + 1
  28  		}
  29  		trimmed := bytes.TrimSpace(line)
  30  		if len(pendingExport) > 0 {
  31  			if len(trimmed) == 0 || bytes.HasPrefix(trimmed, commentPrefix) {
  32  				i = lineEnd
  33  				continue
  34  			}
  35  			if bytes.HasPrefix(trimmed, funcPrefix) {
  36  				rest := trimmed[5:]
  37  				paren := bytes.IndexByte(rest, '(')
  38  				if paren > 0 {
  39  					funcName := string(bytes.TrimSpace(rest[:paren]))
  40  					result[funcName] = pendingExport
  41  				}
  42  			}
  43  			pendingExport = ""
  44  		} else if bytes.HasPrefix(trimmed, exportPrefix) {
  45  			pendingExport = string(bytes.TrimSpace(trimmed[9:]))
  46  		}
  47  		i = lineEnd
  48  	}
  49  	return result
  50  }
  51  
  52  func typeCheckPkg(src []byte, name string) (*types.TCPackage, *syntax.File) {
  53  	inittypes.Universe()
  54  	shortName := name
  55  	for i := len(name) - 1; i >= 0; i-- {
  56  		if name[i] == '/' {
  57  			shortName = name[i+1:]
  58  			break
  59  		}
  60  	}
  61  	pkg := newTCPackageWithUniverse(name, shortName)
  62  	scope := pkg.Scope()
  63  
  64  	src = rewriteSliceMakeLiterals(src)
  65  	src = rewriteChanMakeLiterals(src)
  66  	src = stripDuplicatePackageClauses(src)
  67  
  68  	if len(src) == 0 {
  69  		return nil, nil
  70  	}
  71  
  72  	parseErrors = nil
  73  	constValMap = nil
  74  	errh := func(err error) {
  75  		parseErrors = append(parseErrors, err.Error())
  76  	}
  77  	tcPkgSrc = src
  78  	CompileExportMap = scanExportPragmas(src)
  79  	file, _ := syntax.ParseBytes(token.NewFileBase(name|".mx"), src, errh, nil, 0)
  80  	if file == nil {
  81  		return nil, nil
  82  	}
  83  	for _, d := range file.DeclList {
  84  		switch d := d.(type) {
  85  		case *syntax.ImportDecl:
  86  			if d.Path == nil {
  87  				continue
  88  			}
  89  			path := d.Path.Value
  90  			if len(path) >= 2 && path[0] == '"' {
  91  				path = path[1 : len(path)-1]
  92  			}
  93  			EnsureImportRegistry()
  94  			imported := ImportRegistry[path]
  95  			if imported == nil {
  96  				continue
  97  			}
  98  			if path == "unsafe" && imported.Scope().Lookup("Pointer") == nil {
  99  				imported.Scope().Insert(types.NewTypeName(imported, "Pointer", types.Typ[types.UnsafePointer]))
 100  			}
 101  			localName := imported.Name()
 102  			if d.LocalPkgName != nil {
 103  				localName = d.LocalPkgName.Value
 104  			}
 105  			scope.Insert(types.NewPkgName(pkg, localName, imported))
 106  		case *syntax.VarDecl:
 107  			for _, n := range d.NameList {
 108  				scope.Insert(types.NewTCVar(pkg, n.Value, nil))
 109  			}
 110  		case *syntax.FuncDecl:
 111  			if d.Recv == nil && d.Name.Value != "init" {
 112  				scope.Insert(types.NewTCFunc(pkg, d.Name.Value, nil))
 113  			}
 114  		case *syntax.TypeDecl:
 115  			scope.Insert(types.NewTypeName(pkg, d.Name.Value, nil))
 116  		case *syntax.ConstDecl:
 117  			for _, n := range d.NameList {
 118  				scope.Insert(types.NewTCConst(pkg, n.Value, nil, nil))
 119  			}
 120  		}
 121  	}
 122  
 123  	var curConstGroup *Group
 124  	var prevConstValues syntax.Expr
 125  	var prevConstType syntax.Expr
 126  	iotaVal := int64(-1)
 127  	for _, d := range file.DeclList {
 128  		if td, ok := d.(*syntax.TypeDecl); ok {
 129  			obj := scope.Lookup(td.Name.Value)
 130  			if obj != nil {
 131  				if tn, ok2 := obj.(*types.TypeName); ok2 {
 132  					types.NewNamed(tn, nil)
 133  				}
 134  			}
 135  		}
 136  	}
 137  	for _, d := range file.DeclList {
 138  		if cd, ok := d.(*syntax.ConstDecl); ok {
 139  			if cd.Group == nil || cd.Group != curConstGroup {
 140  				curConstGroup = cd.Group
 141  				iotaVal = int64(0)
 142  				prevConstValues = nil
 143  				prevConstType = nil
 144  			} else {
 145  				iotaVal++
 146  			}
 147  			valExpr := cd.Values
 148  			typeExpr := cd.Type
 149  			if valExpr == nil {
 150  				valExpr = prevConstValues
 151  				if typeExpr == nil {
 152  					typeExpr = prevConstType
 153  				}
 154  			} else {
 155  				prevConstValues = cd.Values
 156  				prevConstType = cd.Type
 157  			}
 158  			typ := tcResolveNameInline(typeExpr, scope)
 159  			if typ == nil && valExpr != nil {
 160  				typ = tcInferTypeFromExpr(valExpr, scope)
 161  			}
 162  			var val types.ConstVal
 163  			if valExpr != nil {
 164  				val = tcEvalConstExpr(valExpr, scope, iotaVal)
 165  			}
 166  			if typ == nil && val != nil {
 167  				typ = types.UntypedTypeOfCV(val)
 168  			}
 169  			for _, n := range cd.NameList {
 170  				if val != nil {
 171  					if ci, ok2 := val.(*types.ConstInt); ok2 {
 172  						if constValMap == nil {
 173  							constValMap = map[string]int64{}
 174  						}
 175  						constValMap[n.Value] = ci.V
 176  					}
 177  				}
 178  				obj := scope.Lookup(n.Value)
 179  				if obj != nil {
 180  					if c, ok := obj.(*types.TCConst); ok {
 181  						c.SetType(typ)
 182  						c.SetVal(val)
 183  					}
 184  				}
 185  			}
 186  		}
 187  	}
 188  	for _, d := range file.DeclList {
 189  		if cd, ok := d.(*syntax.ConstDecl); ok {
 190  			for _, n := range cd.NameList {
 191  				obj := scope.Lookup(n.Value)
 192  				if obj == nil {
 193  					continue
 194  				}
 195  				c, ok2 := obj.(*types.TCConst)
 196  				if !ok2 || c.Val() != nil {
 197  					continue
 198  				}
 199  				valExpr := cd.Values
 200  				if valExpr == nil {
 201  					continue
 202  				}
 203  				val := tcEvalConstExpr(valExpr, scope, int64(0))
 204  				if val != nil {
 205  					c.SetVal(val)
 206  					if c.Type() == nil {
 207  						c.SetType(types.UntypedTypeOfCV(val))
 208  					}
 209  				}
 210  			}
 211  		}
 212  	}
 213  	for _, d := range file.DeclList {
 214  		if td, ok := d.(*syntax.TypeDecl); ok {
 215  			obj := scope.Lookup(td.Name.Value)
 216  			if obj != nil {
 217  				if tn, ok2 := obj.(*types.TypeName); ok2 {
 218  					named, ok3 := tn.Type().(*types.Named)
 219  					if ok3 {
 220  						typ := tcResolveNameInline(td.Type, scope)
 221  						named.SetUnderlying(typ)
 222  					}
 223  				}
 224  			}
 225  		}
 226  	}
 227  	for _, d := range file.DeclList {
 228  		switch d := d.(type) {
 229  		case *syntax.VarDecl:
 230  			typ := tcResolveNameInline(d.Type, scope)
 231  			if arr, ok := typ.(*types.Array); ok && arr.Len() < 0 && d.Values != nil {
 232  				if cl, ok2 := d.Values.(*syntax.CompositeLit); ok2 {
 233  					typ = types.NewArray(arr.Elem(), int64(len(cl.ElemList)))
 234  				}
 235  			}
 236  			if typ == nil && d.Values != nil {
 237  				typ = tcInferTypeFromExpr(d.Values, scope)
 238  			}
 239  			for _, n := range d.NameList {
 240  				obj := scope.Lookup(n.Value)
 241  				if obj != nil {
 242  					if v, ok := obj.(*types.TCVar); ok {
 243  						v.SetType(typ)
 244  					}
 245  				}
 246  			}
 247  		case *syntax.FuncDecl:
 248  			if d.Recv == nil && d.Name.Value != "init" {
 249  				if len(d.TParamList) > 0 {
 250  					if genericFuncDecls == nil {
 251  						genericFuncDecls = map[string]*syntax.FuncDecl{}
 252  					}
 253  					genericFuncDecls[name+"."+d.Name.Value] = d
 254  					if genericPkgScopes == nil {
 255  						genericPkgScopes = map[string]*types.Scope{}
 256  					}
 257  					genericPkgScopes[name] = pkg.Scope()
 258  					continue
 259  				}
 260  				sig := tcResolveFuncInline(d.Type, scope)
 261  				obj := scope.Lookup(d.Name.Value)
 262  				if obj != nil {
 263  					if fn, ok := obj.(*types.TCFunc); ok && sig != nil {
 264  						fn.SetType(sig)
 265  					}
 266  				}
 267  			}
 268  		}
 269  	}
 270  	print("  tcpkg-methods\n")
 271  	for _, d := range file.DeclList {
 272  		if fd, ok := d.(*syntax.FuncDecl); ok && fd.Recv != nil {
 273  			recvType := tcResolveRecvType(fd.Recv, scope)
 274  			if recvType == nil {
 275  				continue
 276  			}
 277  			sig := tcResolveFuncInlineWithRecv(fd.Type, fd.Recv, scope)
 278  			fn := types.NewTCFunc(pkg, fd.Name.Value, sig)
 279  			isPtr := false
 280  			var named *types.Named
 281  			if pt, ok := recvType.(*types.Pointer); ok {
 282  				if okv, okok := pt.Elem().(*types.Named); okok {
 283  					named = okv
 284  				}
 285  				isPtr = true
 286  			} else {
 287  				if okv, okok := recvType.(*types.Named); okok {
 288  					named = okv
 289  				}
 290  			}
 291  			if named != nil {
 292  				if isPtr {
 293  					fn.SetPtrRecv(true)
 294  				}
 295  				named.AddMethod(fn)
 296  			}
 297  		}
 298  	}
 299  
 300  	return pkg, file
 301  }
 302  
 303  func releasePerPkgState() {
 304  	parseErrors = nil
 305  	compileErrors = nil
 306  	constValMap = nil
 307  	CompileExportMap = nil
 308  	tcPkgSrc = nil
 309  }
 310  
 311  func TypeCheckOnly(src []byte, name string) {
 312  	pkg, file := typeCheckPkg(src, name)
 313  	if pkg != nil && file != nil {
 314  		registerCompiledExports(pkg)
 315  	}
 316  	hasGenerics := pkg != nil && genericPkgScopes != nil && genericPkgScopes[pkg.Path()] != nil
 317  	if pkg != nil && !hasGenerics {
 318  		pkg.Release()
 319  	}
 320  	if file != nil {
 321  		file.DeclList = nil
 322  	}
 323  	releasePerPkgState()
 324  }
 325  
 326  func CompileToIR(src []byte, name string, triple string) string {
 327  	pkg, file := typeCheckPkg(src, name)
 328  	if file == nil {
 329  		out := "; parse error parseErrs=" | simpleItoa(len(parseErrors)) | "\n"
 330  		for _, pe := range parseErrors {
 331  			out = out | "; " | pe | "\n"
 332  		}
 333  		releasePerPkgState()
 334  		return out
 335  	}
 336  
 337  	prog := ssa.NewSSAProgram()
 338  	ssaPkg := prog.CreatePackage(pkg, []*syntax.File{file}, nil)
 339  	emitter := newIREmitter(ssaPkg, triple)
 340  	ir := emitter.emit()
 341  
 342  	if len(compileErrors) > 0 {
 343  		out := "; compile error\n"
 344  		for _, ce := range compileErrors {
 345  			out = out | "; " | ce | "\n"
 346  		}
 347  		emitter.releaseAfterEmit()
 348  		ssaPkg.release()
 349  		prog.release()
 350  		if pkg != nil {
 351  			pkg.Release()
 352  		}
 353  		file.DeclList = nil
 354  		releasePerPkgState()
 355  		return out
 356  	}
 357  
 358  	if len(ir) > 0 && ir[0] != ';' {
 359  		registerCompiledExports(pkg)
 360  	}
 361  
 362  	emitter.releaseAfterEmit()
 363  	ssaPkg.release()
 364  	prog.release()
 365  	hasGenerics := genericPkgScopes != nil && genericPkgScopes[pkg.Path()] != nil
 366  	if pkg != nil && !hasGenerics {
 367  		pkg.Release()
 368  	}
 369  	file.DeclList = nil
 370  	releasePerPkgState()
 371  	return ir
 372  }
 373  
 374  func registerCompiledExports(pkg *types.TCPackage) {
 375  	EnsureImportRegistry()
 376  	path := pkg.Path()
 377  	regPkg := types.NewTCPackage(path, pkg.Name())
 378  	for _, name := range pkg.Scope().Names() {
 379  		if len(name) == 0 || name[0] < 'A' || name[0] > 'Z' {
 380  			continue
 381  		}
 382  		obj := pkg.Scope().Lookup(name)
 383  		if obj != nil {
 384  			regPkg.Scope().Insert(obj)
 385  		}
 386  	}
 387  	ImportRegistry[path] = regPkg
 388  }
 389  
 390  func tcInferTypeFromExpr(e syntax.Expr, scope *types.Scope) syntax.Type {
 391  	switch e := e.(type) {
 392  	case *syntax.BasicLit:
 393  		switch e.Kind {
 394  		case token.StringLit:
 395  			return types.Typ[types.TCString]
 396  		case token.IntLit:
 397  			return types.Typ[types.Int32]
 398  		case token.FloatLit:
 399  			return types.Typ[types.Float64]
 400  		}
 401  	case *syntax.Name:
 402  		if e.Value == "true" || e.Value == "false" {
 403  			return types.Typ[types.Bool]
 404  		}
 405  		return tcResolveNameInline(e, scope)
 406  	case *syntax.CallExpr:
 407  		ft := tcResolveNameInline(e.Fun, scope)
 408  		if sig, ok := ft.(*types.Signature); ok && sig != nil {
 409  			res := sig.Results()
 410  			if res != nil && res.Len() == 1 {
 411  				return res.At(0).Type()
 412  			}
 413  			if res != nil && res.Len() > 1 {
 414  				return res
 415  			}
 416  		}
 417  		return ft
 418  	case *syntax.CompositeLit:
 419  		t := tcResolveNameInline(e.Type, scope)
 420  		if arr, ok := t.(*types.Array); ok && arr.Len() < 0 {
 421  			return types.NewArray(arr.Elem(), int64(len(e.ElemList)))
 422  		}
 423  		return t
 424  	case *syntax.Operation:
 425  		if e.Y == nil && e.Op == And {
 426  			return types.NewPointer(tcInferTypeFromExpr(e.X, scope))
 427  		}
 428  	}
 429  	return nil
 430  }
 431  
 432  var constValMap map[string]int64
 433  var tcPkgSrc []byte
 434  
 435  func resolveArrayLenFromSrc(p token.Pos, cmap map[string]int64) int64 {
 436  	line := p.Line()
 437  	col := p.Col()
 438  	if line == 0 || col == 0 || tcPkgSrc == nil {
 439  		return -1
 440  	}
 441  	off := 0
 442  	curLine := uint32(1)
 443  	for off < len(tcPkgSrc) && curLine < line {
 444  		if tcPkgSrc[off] == '\n' {
 445  			curLine++
 446  		}
 447  		off++
 448  	}
 449  	off += int32(col) - 1
 450  	if off >= len(tcPkgSrc) || tcPkgSrc[off] != '[' {
 451  		return -1
 452  	}
 453  	off++
 454  	for off < len(tcPkgSrc) && tcPkgSrc[off] == ' ' {
 455  		off++
 456  	}
 457  	start := off
 458  	for off < len(tcPkgSrc) {
 459  		c := tcPkgSrc[off]
 460  		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
 461  			off++
 462  		} else {
 463  			break
 464  		}
 465  	}
 466  	if off == start {
 467  		return -1
 468  	}
 469  	name := string(tcPkgSrc[start:off])
 470  	if v, ok := cmap[name]; ok {
 471  		if off < len(tcPkgSrc) && tcPkgSrc[off] == '+' {
 472  			off++
 473  			for off < len(tcPkgSrc) && tcPkgSrc[off] == ' ' {
 474  				off++
 475  			}
 476  			numStart := off
 477  			for off < len(tcPkgSrc) && tcPkgSrc[off] >= '0' && tcPkgSrc[off] <= '9' {
 478  				off++
 479  			}
 480  			if off > numStart {
 481  				addend := int64(0)
 482  				for i := numStart; i < off; i++ {
 483  					addend = addend*10 + int64(tcPkgSrc[i]-'0')
 484  				}
 485  				return v + addend
 486  			}
 487  		}
 488  		return v
 489  	}
 490  	n := int64(0)
 491  	isNum := true
 492  	for i := start; i < off; i++ {
 493  		c := tcPkgSrc[i]
 494  		if c >= '0' && c <= '9' {
 495  			n = n*10 + int64(c-'0')
 496  		} else {
 497  			isNum = false
 498  			break
 499  		}
 500  	}
 501  	if isNum && off > start {
 502  		return n
 503  	}
 504  	return -1
 505  }
 506  
 507  func resolveArrayLenFromConstMap(e syntax.Expr, cmap map[string]int64) int64 {
 508  	line := e.Pos().Line()
 509  	col := e.Pos().Col()
 510  	if line == 0 || col == 0 || tcPkgSrc == nil {
 511  		return -1
 512  	}
 513  	curLine := uint32(1)
 514  	off := 0
 515  	for off < len(tcPkgSrc) && curLine < line {
 516  		if tcPkgSrc[off] == '\n' {
 517  			curLine++
 518  		}
 519  		off++
 520  	}
 521  	off += int32(col) - 1
 522  	if off >= len(tcPkgSrc) {
 523  		return -1
 524  	}
 525  	start := off
 526  	for off < len(tcPkgSrc) {
 527  		c := tcPkgSrc[off]
 528  		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
 529  			off++
 530  		} else {
 531  			break
 532  		}
 533  	}
 534  	if off == start {
 535  		return -1
 536  	}
 537  	name := string(tcPkgSrc[start:off])
 538  	if v, ok := cmap[name]; ok {
 539  		return v
 540  	}
 541  	return -1
 542  }
 543  
 544  func tcEvalConstExpr(e syntax.Expr, scope *types.Scope, iotaVal int64) types.ConstVal {
 545  	if e == nil {
 546  		return nil
 547  	}
 548  	switch e := e.(type) {
 549  	case *syntax.BasicLit:
 550  		return types.EvalBasicLitLocal(e)
 551  	case *syntax.Name:
 552  		if e.Value == "iota" && iotaVal >= 0 {
 553  			return &types.ConstInt{V:iotaVal}
 554  		}
 555  		if scope != nil {
 556  			_, obj := scope.LookupParent(e.Value)
 557  			if c, ok := obj.(*types.TCConst); ok && c.Val() != nil {
 558  				return c.Val()
 559  			}
 560  		}
 561  		if constValMap != nil {
 562  			if v, ok := constValMap[e.Value]; ok {
 563  				return &types.ConstInt{V:v}
 564  			}
 565  		}
 566  	case *syntax.Operation:
 567  		if e.Y == nil {
 568  			xr := tcEvalConstExpr(e.X, scope, iotaVal)
 569  			if xr == nil {
 570  				return nil
 571  			}
 572  			return evalUnaryLocal(e.Op, xr)
 573  		}
 574  		xr := tcEvalConstExpr(e.X, scope, iotaVal)
 575  		yr := tcEvalConstExpr(e.Y, scope, iotaVal)
 576  		if xr == nil || yr == nil {
 577  			return nil
 578  		}
 579  		return evalBinaryLocal(e.Op, xr, yr)
 580  	case *syntax.ParenExpr:
 581  		return tcEvalConstExpr(e.X, scope, iotaVal)
 582  	case *syntax.CallExpr:
 583  		if id, ok := e.Fun.(*syntax.Name); ok && id.Value == "len" && len(e.ArgList) == 1 {
 584  			if lit, ok2 := e.ArgList[0].(*syntax.BasicLit); ok2 && lit.Kind == token.StringLit {
 585  				lv := types.EvalBasicLitLocal(lit)
 586  				if cs, ok3 := lv.(*types.ConstStr); ok3 {
 587  					return &types.ConstInt{V:int64(len(cs.S))}
 588  				}
 589  			}
 590  			inner := tcEvalConstExpr(e.ArgList[0], scope, iotaVal)
 591  			if cs, ok2 := inner.(*types.ConstStr); ok2 {
 592  				return &types.ConstInt{V:int64(len(cs.S))}
 593  			}
 594  		}
 595  		if sel, ok := e.Fun.(*syntax.SelectorExpr); ok {
 596  			if pkg, ok2 := sel.X.(*syntax.Name); ok2 && pkg.Value == "unsafe" {
 597  				switch sel.Sel.Value {
 598  				case "Sizeof", "Alignof", "Offsetof":
 599  					return &types.ConstInt{V:8}
 600  				}
 601  			}
 602  		}
 603  		if len(e.ArgList) != 1 {
 604  			return nil
 605  		}
 606  		inner := tcEvalConstExpr(e.ArgList[0], scope, iotaVal)
 607  		if inner == nil {
 608  			return nil
 609  		}
 610  		targetType := tcResolveNameInline(e.Fun, scope)
 611  		if targetType == nil {
 612  			return inner
 613  		}
 614  		return convertConstLocal(inner, targetType)
 615  	case *syntax.SelectorExpr:
 616  		pkgName, ok := e.X.(*syntax.Name)
 617  		if !ok {
 618  			return nil
 619  		}
 620  		var imported *types.TCPackage
 621  		if scope != nil {
 622  			_, obj := scope.LookupParent(pkgName.Value)
 623  			if pn, ok2 := obj.(*types.PkgName); ok2 && pn.Imported() != nil {
 624  				imported = pn.Imported()
 625  			}
 626  		}
 627  		if imported == nil {
 628  			EnsureImportRegistry()
 629  			imported = ImportRegistry[pkgName.Value]
 630  		}
 631  		if imported == nil {
 632  			return nil
 633  		}
 634  		member := imported.Scope().Lookup(e.Sel.Value)
 635  		if member == nil {
 636  			return nil
 637  		}
 638  		if k, ok := member.(*types.TCConst); ok && k.Val() != nil {
 639  			return k.Val()
 640  		}
 641  		return nil
 642  	}
 643  	return nil
 644  }
 645  
 646  func tcResolveNameInline(e syntax.Expr, scope *types.Scope) syntax.Type {
 647  	if e == nil {
 648  		return nil
 649  	}
 650  	switch e := e.(type) {
 651  	case *syntax.Name:
 652  		var obj Object
 653  		if scope != nil {
 654  			_, obj = scope.LookupParent(e.Value)
 655  		} else {
 656  			_, obj = types.Universe.LookupParent(e.Value)
 657  		}
 658  		if obj != nil {
 659  			if tn, ok := obj.(*types.TypeName); ok {
 660  				return tn.Type()
 661  			}
 662  			if fn, ok := obj.(*types.TCFunc); ok {
 663  				if sig := fn.Signature(); sig != nil {
 664  					return sig
 665  				}
 666  			}
 667  		}
 668  	case *syntax.SelectorExpr:
 669  		pkgName, ok := e.X.(*syntax.Name)
 670  		if ok && scope != nil {
 671  			_, pkgObj := scope.LookupParent(pkgName.Value)
 672  			if pn, ok2 := pkgObj.(*types.PkgName); ok2 && pn.Imported() != nil {
 673  				typeObj := pn.Imported().Scope().Lookup(e.Sel.Value)
 674  				if typeObj != nil {
 675  					if tn, ok3 := typeObj.(*types.TypeName); ok3 {
 676  						return tn.Type()
 677  					}
 678  					if fn, ok3 := typeObj.(*types.TCFunc); ok3 {
 679  						if sig := fn.Signature(); sig != nil {
 680  							return sig
 681  						}
 682  					}
 683  				}
 684  			}
 685  		}
 686  		// Fallback: check ImportRegistry directly for external package types
 687  		if pkgName, ok := e.X.(*syntax.Name); ok {
 688  			var irKeys []string
 689  			for k := range ImportRegistry {
 690  				irKeys = append(irKeys, k)
 691  			}
 692  			for i := 1; i < len(irKeys); i++ {
 693  				for j := i; j > 0 && irKeys[j] < irKeys[j-1]; j-- {
 694  					irKeys[j], irKeys[j-1] = irKeys[j-1], irKeys[j]
 695  				}
 696  			}
 697  			for _, k := range irKeys {
 698  				pkg := ImportRegistry[k]
 699  				if pkg.Name() == pkgName.Value {
 700  					typeObj := pkg.Scope().Lookup(e.Sel.Value)
 701  					if typeObj != nil {
 702  						if tn, ok2 := typeObj.(*types.TypeName); ok2 {
 703  							return tn.Type()
 704  						}
 705  					}
 706  					break
 707  				}
 708  			}
 709  		}
 710  	case *syntax.Operation:
 711  		if e.Y == nil && e.Op == Mul {
 712  			base := tcResolveNameInline(e.X, scope)
 713  			if base == nil {
 714  				base = types.Typ[types.Int8]
 715  			}
 716  			return types.NewPointer(base)
 717  		}
 718  	case *types.SliceType:
 719  		elem := tcResolveNameInline(e.Elem, scope)
 720  		if elem != nil {
 721  			if b, ok := elem.(*types.Basic); ok && b.Kind() == Uint8 {
 722  				return types.Typ[types.TCString]
 723  			}
 724  			return types.NewSlice(elem)
 725  		}
 726  	case *syntax.ArrayType:
 727  		elem := tcResolveNameInline(e.Elem, scope)
 728  		if elem != nil {
 729  			n := int64(-1)
 730  			if lit, ok := e.Len.(*syntax.BasicLit); ok {
 731  				n = irParseInt64(lit.Value)
 732  			} else if e.Len != nil {
 733  				cv := tcEvalConstExpr(e.Len, scope, -1)
 734  				if cv != nil {
 735  					if ci, ok := cv.(*types.ConstInt); ok {
 736  						n = ci.V
 737  					}
 738  				}
 739  				if n == -1 && constValMap != nil {
 740  					n = resolveArrayLenFromSrc(e.pos, constValMap)
 741  				}
 742  			}
 743  			return types.NewArray(elem, n)
 744  		}
 745  	case *syntax.MapType:
 746  		key := tcResolveNameInline(e.Key, scope)
 747  		val := tcResolveNameInline(e.Value, scope)
 748  		if key != nil && val != nil {
 749  			return types.NewTCMap(key, val)
 750  		}
 751  	case *syntax.StructType:
 752  		var fields []*types.TCVar
 753  		var tags []string
 754  		for i, field := range e.FieldList {
 755  			typ := tcResolveNameInline(field.Type, scope)
 756  			fname := ""
 757  			if field.Name != nil {
 758  				fname = field.Name.Value
 759  			} else {
 760  				fname = typeBaseName(typ)
 761  			}
 762  			fields = append(fields, NewTCField(nil, fname, typ, field.Name == nil))
 763  			tag := ""
 764  			if i < len(e.TagList) && e.TagList[i] != nil {
 765  				tag = e.TagList[i].Value
 766  			}
 767  			tags = append(tags, tag)
 768  		}
 769  		return types.NewTCStruct(fields, tags)
 770  	case *syntax.FuncType:
 771  		return tcResolveFuncInline(e, scope)
 772  	case *syntax.InterfaceType:
 773  		return tcResolveInterfaceInline(e, scope)
 774  	case *syntax.ChanType:
 775  		elem := tcResolveNameInline(e.Elem, scope)
 776  		if elem == nil {
 777  			elem = types.NewTCStruct(nil, nil)
 778  		}
 779  		var dir types.TCChanDir
 780  		switch e.Dir {
 781  		case syntax.SendOnly:
 782  			dir = types.TCSendOnly
 783  		case syntax.RecvOnly:
 784  			dir = types.TCRecvOnly
 785  		default:
 786  			dir = types.TCSendRecv
 787  		}
 788  		return types.NewTCChan(dir, elem)
 789  	case *syntax.DotsType:
 790  		elem := tcResolveNameInline(e.Elem, scope)
 791  		if elem != nil {
 792  			if b, ok := elem.(*types.Basic); ok && b.Kind() == Uint8 {
 793  				return types.Typ[types.TCString]
 794  			}
 795  			return types.NewSlice(elem)
 796  		}
 797  	}
 798  	return nil
 799  }
 800  
 801  func tcResolveInterfaceInline(e *syntax.InterfaceType, scope *types.Scope) *types.TCInterface {
 802  	var methods []*types.IfaceMethod
 803  	var embeds []syntax.Type
 804  	for _, f := range e.MethodList {
 805  		if f.Name == nil {
 806  			if f.Type != nil {
 807  				embed := tcResolveNameInline(f.Type, scope)
 808  				if embed != nil {
 809  					embeds = append(embeds, embed)
 810  				}
 811  			}
 812  			continue
 813  		}
 814  		ft, ok := f.Type.(*syntax.FuncType)
 815  		if !ok {
 816  			continue
 817  		}
 818  		sig := tcResolveFuncInline(ft, scope)
 819  		if sig != nil {
 820  			methods = append(methods, types.NewTCIfaceMethod(f.Name.Value, sig))
 821  		}
 822  	}
 823  	iface := types.NewTCInterface(methods, embeds)
 824  	iface.Complete()
 825  	return iface
 826  }
 827  
 828  func stripDuplicatePackageClauses(src []byte) []byte {
 829  	found := false
 830  	var out []byte
 831  	i := 0
 832  	for i < len(src) {
 833  		nlIdx := bytes.IndexByte(src[i:], '\n')
 834  		var line []byte
 835  		var lineEnd int32
 836  		if nlIdx < 0 {
 837  			line = src[i:]
 838  			lineEnd = len(src)
 839  		} else {
 840  			line = src[i : i+nlIdx]
 841  			lineEnd = i + nlIdx + 1
 842  		}
 843  		trimmed := bytes.TrimSpace(line)
 844  		if bytes.HasPrefix(trimmed, "package ") {
 845  			if found {
 846  				if out == nil {
 847  					out = []byte{:0:len(src)}
 848  					out = append(out, src[:i]...)
 849  				}
 850  				for k := 0; k < len(line); k++ {
 851  					out = append(out, ' ')
 852  				}
 853  				if nlIdx >= 0 {
 854  					out = append(out, '\n')
 855  				}
 856  				i = lineEnd
 857  				continue
 858  			}
 859  			found = true
 860  		}
 861  		if out != nil {
 862  			out = append(out, src[i:lineEnd]...)
 863  		}
 864  		i = lineEnd
 865  	}
 866  	if out == nil {
 867  		return src
 868  	}
 869  	return out
 870  }
 871  
 872  func rewriteSliceMakeLiterals(src []byte) []byte {
 873  	var out []byte
 874  	i := 0
 875  	for i < len(src) {
 876  		start := bytes.Index(src[i:], []byte("{:"))
 877  		if start < 0 {
 878  			out = append(out, src[i:]...)
 879  			break
 880  		}
 881  		start = start + i
 882  		lbrack := findSliceTypeStart(src, start)
 883  		if lbrack < 0 {
 884  			out = append(out, src[i:start+2]...)
 885  			i = start + 2
 886  			continue
 887  		}
 888  		close := findMatchingBrace(src, start)
 889  		if close < 0 {
 890  			out = append(out, src[i:start+2]...)
 891  			i = start + 2
 892  			continue
 893  		}
 894  		inner := src[start+2 : close]
 895  		colonIdx := bytes.IndexByte(inner, ':')
 896  		typeText := src[lbrack:start]
 897  		out = append(out, src[i:lbrack]...)
 898  		if colonIdx < 0 {
 899  			out = append(out, "make("...)
 900  			out = append(out, typeText...)
 901  			out = append(out, ", "...)
 902  			out = append(out, bytes.TrimSpace(inner)...)
 903  			out = append(out, ')')
 904  		} else {
 905  			lenExpr := bytes.TrimSpace(inner[:colonIdx])
 906  			capExpr := bytes.TrimSpace(inner[colonIdx+1:])
 907  			out = append(out, "make("...)
 908  			out = append(out, typeText...)
 909  			out = append(out, ", "...)
 910  			out = append(out, lenExpr...)
 911  			out = append(out, ", "...)
 912  			out = append(out, capExpr...)
 913  			out = append(out, ')')
 914  		}
 915  		i = close + 1
 916  	}
 917  	if out == nil {
 918  		return src
 919  	}
 920  	return out
 921  }
 922  
 923  func findSliceTypeStart(src []byte, braceIdx int32) int32 {
 924  	j := braceIdx - 1
 925  	for j >= 0 && (src[j] == ' ' || src[j] == '\t' || src[j] == '\n') {
 926  		j--
 927  	}
 928  	if j < 0 {
 929  		return -1
 930  	}
 931  	depth := 0
 932  	parenDepth := 0
 933  	candidate := -1
 934  	for j >= 0 {
 935  		ch := src[j]
 936  		if ch == ')' {
 937  			parenDepth++
 938  		} else if ch == '(' {
 939  			if parenDepth == 0 {
 940  				if candidate >= 0 {
 941  					return candidate
 942  				}
 943  				return -1
 944  			}
 945  			parenDepth--
 946  		} else if parenDepth > 0 {
 947  			j--
 948  			continue
 949  		}
 950  		if ch == ']' {
 951  			depth++
 952  		} else if ch == '[' {
 953  			depth--
 954  			if depth == 0 {
 955  				candidate = j
 956  			}
 957  		} else if ch == '{' || ch == ';' {
 958  			if candidate >= 0 {
 959  				return candidate
 960  			}
 961  			return -1
 962  		} else if depth == 0 && parenDepth == 0 {
 963  			if candidate >= 0 {
 964  				return candidate
 965  			}
 966  			if ch == ' ' || ch == '\t' || ch == '\n' || ch == '*' || ch == '(' || ch == ')' {
 967  				j--
 968  				continue
 969  			}
 970  			if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '.' {
 971  				j--
 972  				continue
 973  			}
 974  			return -1
 975  		}
 976  		j--
 977  	}
 978  	if candidate >= 0 {
 979  		return candidate
 980  	}
 981  	return -1
 982  }
 983  
 984  func findMatchingBrace(src []byte, openIdx int32) int32 {
 985  	depth := 1
 986  	for i := openIdx + 1; i < len(src); i++ {
 987  		if src[i] == '{' {
 988  			depth++
 989  		} else if src[i] == '}' {
 990  			depth--
 991  			if depth == 0 {
 992  				return i
 993  			}
 994  		}
 995  	}
 996  	return -1
 997  }
 998  
 999  func rewriteChanMakeLiterals(src []byte) []byte {
1000  	chanKw := []byte("chan ")
1001  	var out []byte
1002  	i := 0
1003  	for i < len(src) {
1004  		idx := bytes.Index(src[i:], chanKw)
1005  		if idx < 0 {
1006  			if out != nil {
1007  				out = append(out, src[i:]...)
1008  			}
1009  			break
1010  		}
1011  		idx = idx + i
1012  		j := idx + 5
1013  		for j < len(src) && (src[j] == ' ' || src[j] == '\t') {
1014  			j++
1015  		}
1016  		if j >= len(src) {
1017  			if out != nil {
1018  				out = append(out, src[i:]...)
1019  			}
1020  			break
1021  		}
1022  		if src[j] == '<' && j+1 < len(src) && src[j+1] == '-' {
1023  			if out != nil {
1024  				out = append(out, src[i:j+2]...)
1025  			}
1026  			i = j + 2
1027  			continue
1028  		}
1029  		for j < len(src) && (src[j] != '{' && src[j] != '\n' && src[j] != ';' && src[j] != '(' && src[j] != ')') {
1030  			if src[j] == ' ' || src[j] == '\t' {
1031  				break
1032  			}
1033  			j++
1034  		}
1035  		if j >= len(src) || src[j] != '{' {
1036  			if out == nil {
1037  				i = idx + 4
1038  			} else {
1039  				out = append(out, src[i:idx+4]...)
1040  				i = idx + 4
1041  			}
1042  			continue
1043  		}
1044  		braceOpen := j
1045  		endsStruct := braceOpen >= 6 && string(src[braceOpen-6:braceOpen]) == "struct"
1046  		if !endsStruct && braceOpen >= 7 {
1047  			k := braceOpen - 1
1048  			for k > idx && (src[k] == ' ' || src[k] == '\t') {
1049  				k--
1050  			}
1051  			if k >= 5 && string(src[k-5:k+1]) == "struct" {
1052  				endsStruct = true
1053  			}
1054  		}
1055  		if endsStruct {
1056  			structClose := findMatchingBrace(src, braceOpen)
1057  			if structClose < 0 {
1058  				if out == nil {
1059  					i = idx + 4
1060  				} else {
1061  					out = append(out, src[i:idx+4]...)
1062  					i = idx + 4
1063  				}
1064  				continue
1065  			}
1066  			nj := structClose + 1
1067  			if nj >= len(src) || src[nj] != '{' {
1068  				if out == nil {
1069  					i = structClose + 1
1070  				} else {
1071  					out = append(out, src[i:structClose+1]...)
1072  					i = structClose + 1
1073  				}
1074  				continue
1075  			}
1076  			braceOpen = nj
1077  		}
1078  		close := findMatchingBrace(src, braceOpen)
1079  		if close < 0 {
1080  			if out == nil {
1081  				i = idx + 4
1082  			} else {
1083  				out = append(out, src[i:idx+4]...)
1084  				i = idx + 4
1085  			}
1086  			continue
1087  		}
1088  		inner := bytes.TrimSpace(src[braceOpen+1 : close])
1089  		chanType := src[idx : braceOpen]
1090  		for len(chanType) > 0 && (chanType[len(chanType)-1] == ' ' || chanType[len(chanType)-1] == '\t') {
1091  			chanType = chanType[:len(chanType)-1]
1092  		}
1093  		if out == nil {
1094  			out = []byte{:0:len(src)}
1095  			out = append(out, src[:idx]...)
1096  		} else {
1097  			out = append(out, src[i:idx]...)
1098  		}
1099  		if len(inner) == 0 {
1100  			out = append(out, "make("...)
1101  			out = append(out, chanType...)
1102  			out = append(out, ')')
1103  		} else {
1104  			out = append(out, "make("...)
1105  			out = append(out, chanType...)
1106  			out = append(out, ", "...)
1107  			out = append(out, inner...)
1108  			out = append(out, ')')
1109  		}
1110  		i = close + 1
1111  	}
1112  	if out == nil {
1113  		return src
1114  	}
1115  	return out
1116  }
1117  
1118  func tcResolveRecvType(recv *syntax.Field, scope *types.Scope) syntax.Type {
1119  	if recv == nil {
1120  		return nil
1121  	}
1122  	return tcResolveNameInline(recv.Type, scope)
1123  }
1124  
1125  func tcResolveFuncInlineWithRecv(ft *syntax.FuncType, recv *syntax.Field, scope *types.Scope) *types.Signature {
1126  	if ft == nil {
1127  		return nil
1128  	}
1129  	var recvVar *types.TCVar
1130  	if recv != nil {
1131  		recvTyp := tcResolveNameInline(recv.Type, scope)
1132  		recvName := ""
1133  		if recv.Name != nil {
1134  			recvName = recv.Name.Value
1135  		}
1136  		recvVar = types.NewTCVar(nil, recvName, recvTyp)
1137  	}
1138  	params := tcResolveFieldList(ft.ParamList, scope)
1139  	results := tcResolveFieldList(ft.ResultList, scope)
1140  	variadic := false
1141  	if len(ft.ParamList) > 0 {
1142  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*syntax.DotsType); ok {
1143  			variadic = true
1144  		}
1145  	}
1146  	return types.NewSignature(recvVar, params, results, variadic)
1147  }
1148  
1149  func tcResolveFieldList(fields []*syntax.Field, scope *types.Scope) *types.Tuple {
1150  	if len(fields) == 0 {
1151  		return nil
1152  	}
1153  	var vars []*types.TCVar
1154  	for _, f := range fields {
1155  		typ := tcResolveNameInline(f.Type, scope)
1156  		pname := ""
1157  		if f.Name != nil {
1158  			pname = f.Name.Value
1159  		}
1160  		vars = append(vars, types.NewTCVar(nil, pname, typ))
1161  	}
1162  	return types.NewTuple(vars...)
1163  }
1164  
1165  func tcResolveFuncInline(ft *syntax.FuncType, scope *types.Scope) *types.Signature {
1166  	if ft == nil {
1167  		return nil
1168  	}
1169  	var params []*types.TCVar
1170  	for _, p := range ft.ParamList {
1171  		typ := tcResolveNameInline(p.Type, scope)
1172  		pname := ""
1173  		if p.Name != nil {
1174  			pname = p.Name.Value
1175  		}
1176  		params = append(params, types.NewTCVar(nil, pname, typ))
1177  	}
1178  	var results []*types.TCVar
1179  	for _, r := range ft.ResultList {
1180  		typ := tcResolveNameInline(r.Type, scope)
1181  		rname := ""
1182  		if r.Name != nil {
1183  			rname = r.Name.Value
1184  		}
1185  		results = append(results, types.NewTCVar(nil, rname, typ))
1186  	}
1187  	variadic := false
1188  	if len(ft.ParamList) > 0 {
1189  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*syntax.DotsType); ok {
1190  			variadic = true
1191  		}
1192  	}
1193  	var pTuple *types.Tuple
1194  	if len(params) > 0 {
1195  		pTuple = types.NewTuple(params...)
1196  	}
1197  	var rTuple *types.Tuple
1198  	if len(results) > 0 {
1199  		rTuple = types.NewTuple(results...)
1200  	}
1201  	return types.NewSignature(nil, pTuple, rTuple, variadic)
1202  }
1203  
1204  func (e *irEmitter) instrOperands(instr ssa.SSAInstruction) []ssa.SSAValue {
1205  	switch i := instr.(type) {
1206  	case *ssa.SSAStore:
1207  		return []ssa.SSAValue{i.Addr, i.Val}
1208  	case *ssa.SSAUnOp:
1209  		return []ssa.SSAValue{i.X}
1210  	case *ssa.SSABinOp:
1211  		return []ssa.SSAValue{i.X, i.Y}
1212  	case *ssa.SSACall:
1213  		out := []ssa.SSAValue{i.Call.Value}
1214  		for _, a := range i.Call.Args {
1215  			out = append(out, a)
1216  		}
1217  		return out
1218  	case *ssa.SSAFieldAddr:
1219  		return []ssa.SSAValue{i.X}
1220  	case *ssa.SSAIndexAddr:
1221  		return []ssa.SSAValue{i.X, i.Index}
1222  	case *ssa.SSAExtract:
1223  		return []ssa.SSAValue{i.Tuple}
1224  	case *ssa.SSAPhi:
1225  		return i.Edges
1226  	case *ssa.SSAReturn:
1227  		var out []ssa.SSAValue
1228  		for _, r := range i.Results {
1229  			out = append(out, r)
1230  		}
1231  		return out
1232  	case *ssa.SSAIf:
1233  		return []ssa.SSAValue{i.Cond}
1234  	case *ssa.SSAConvert:
1235  		return []ssa.SSAValue{i.X}
1236  	case *ssa.SSAChangeType:
1237  		return []ssa.SSAValue{i.X}
1238  	case *ssa.SSAMakeInterface:
1239  		return []ssa.SSAValue{i.X}
1240  	case *ssa.SSATypeAssert:
1241  		return []ssa.SSAValue{i.X}
1242  	case *ssa.SSASlice:
1243  		out := []ssa.SSAValue{i.X}
1244  		if i.Low != nil { out = append(out, i.Low) }
1245  		if i.High != nil { out = append(out, i.High) }
1246  		if i.Max != nil { out = append(out, i.Max) }
1247  		return out
1248  	case *ssa.SSAMapUpdate:
1249  		return []ssa.SSAValue{i.Map, i.Key, i.Value}
1250  	case *ssa.SSALookup:
1251  		return []ssa.SSAValue{i.X, i.Index}
1252  	case *ssa.SSARange:
1253  		return []ssa.SSAValue{i.X}
1254  	case *ssa.SSANext:
1255  		return []ssa.SSAValue{i.Iter}
1256  	case *ssa.SSASend:
1257  		return []ssa.SSAValue{i.Chan, i.X}
1258  	case *ssa.SSAMakeSlice:
1259  		out := []ssa.SSAValue{i.Len}
1260  		if i.Cap != nil { out = append(out, i.Cap) }
1261  		if i.Data != nil { out = append(out, i.Data) }
1262  		return out
1263  	}
1264  	return nil
1265  }
1266