ssa_resolve.mx raw

   1  package ssa
   2  
   3  import (
   4  	"git.smesh.lol/moxie/pkg/token"
   5  	"git.smesh.lol/moxie/pkg/syntax"
   6  	"git.smesh.lol/moxie/pkg/types"
   7  )
   8  
   9  func (fb *ssaFuncBuilder) resolveMethodCallWithRecv(sel *syntax.SelectorExpr, recv SSAValue) (*SSAFunction, SSAValue) {
  10  	typ := recv.SSAType()
  11  	if typ == nil {
  12  		return nil, nil
  13  	}
  14  	isPtr := false
  15  	if p, ok := types.SafeUnderlying(typ).(*types.Pointer); ok {
  16  		typ = p.Elem()
  17  		isPtr = true
  18  	}
  19  	if _, ok := types.SafeUnderlying(typ).(*types.TCInterface); ok {
  20  		if named2, ok2 := typ.(*types.Named); !ok2 || named2.NumMethods() == 0 {
  21  			return nil, nil
  22  		}
  23  	}
  24  	// Handle Basic types (builtin stringers in runtime package)
  25  	if basic, ok2 := typ.(*types.Basic); ok2 {
  26  		typeName := basic.Name()
  27  		mangledName := typeName | "." | sel.Sel.Value
  28  		extSym := "runtime." | mangledName
  29  		for i := int32(0); i < basic.NumMethods(); i++ {
  30  			m := basic.Method(i)
  31  			if m.Name() == sel.Sel.Value {
  32  				fn := fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
  33  				fn.externalSymbol = extSym
  34  				return fn, recv
  35  			}
  36  		}
  37  		resolved := types.UntypedToTyped(basic)
  38  		if resolved == nil {
  39  			return nil, nil
  40  		}
  41  		switch rt := resolved.(type) {
  42  		case *types.Basic:
  43  			typeName = rt.Name()
  44  			mangledName = typeName | "." | sel.Sel.Value
  45  			extSym = "runtime." | mangledName
  46  			for i := int32(0); i < rt.NumMethods(); i++ {
  47  				m := rt.Method(i)
  48  				if m.Name() == sel.Sel.Value {
  49  					fn := fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
  50  					fn.externalSymbol = extSym
  51  					return fn, recv
  52  				}
  53  			}
  54  			return nil, nil
  55  		case *types.Named:
  56  			typ = rt
  57  		default:
  58  			return nil, nil
  59  		}
  60  	}
  61  	named, ok := typ.(*types.Named)
  62  	if !ok {
  63  		return nil, nil
  64  	}
  65  	typeName := ""
  66  	if named.Obj() != nil {
  67  		typeName = named.Obj().Name()
  68  	}
  69  	if typeName == "" {
  70  		return nil, nil
  71  	}
  72  	resolveNamed := named
  73  	if resolveNamed.NumMethods() == 0 {
  74  		cur := types.Type(resolveNamed)
  75  		for depth := 0; depth < 10; depth++ {
  76  			n, ok2 := cur.(*types.Named)
  77  			if !ok2 || n == nil { break }
  78  			if n.NumMethods() > 0 {
  79  				resolveNamed = n
  80  				if n.Obj() != nil && n.Obj().Name() != "" {
  81  					typeName = n.Obj().Name()
  82  				}
  83  				break
  84  			}
  85  			raw := n.RawUnderlying()
  86  			if raw == nil || raw == cur { break }
  87  			cur = raw
  88  		}
  89  	}
  90  	namedPkgPath := ""
  91  	if resolveNamed.Obj() != nil && resolveNamed.Obj().Pkg() != nil {
  92  		namedPkgPath = resolveNamed.Obj().Pkg().Path()
  93  	}
  94  	samePackage := namedPkgPath != "" && namedPkgPath == fb.fn.Pkg.Pkg.Path()
  95  	mangledName := typeName | "." | sel.Sel.Value
  96  	if !samePackage && namedPkgPath != "" {
  97  		mangledName = namedPkgPath | "." | typeName | "." | sel.Sel.Value
  98  	}
  99  	var fn *SSAFunction
 100  	if samePackage {
 101  		fn, _ = fb.fn.Pkg.Members[mangledName].(*SSAFunction)
 102  	}
 103  	if fn == nil {
 104  		for i := 0; i < resolveNamed.NumMethods(); i++ {
 105  			m := resolveNamed.Method(i)
 106  			if m.Name() == sel.Sel.Value {
 107  				fn = fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
 108  				if !samePackage && namedPkgPath != "" {
 109  					fn.externalSymbol = namedPkgPath | "." | typeName | "." | sel.Sel.Value
 110  				} else if resolveNamed.Obj() != nil && resolveNamed.Obj().Pkg() == nil {
 111  					fn.externalSymbol = "runtime." | mangledName
 112  				}
 113  				break
 114  			}
 115  		}
 116  	}
 117  	if fn != nil {
 118  		if fn.Signature != nil && fn.Signature.Recv() != nil {
 119  			recvParam := fn.Signature.Recv()
 120  			_, recvIsPtr := types.SafeUnderlying(recvParam.Type()).(*types.Pointer)
 121  			if recvIsPtr && !isPtr {
 122  				if nameExpr, ok2 := sel.X.(*syntax.Name); ok2 {
 123  					obj := fb.lookupObject(nameExpr.Value)
 124  					if obj != nil {
 125  						if alloc, ok3 := fb.vars[obj]; ok3 {
 126  							recv = alloc
 127  						}
 128  					}
 129  				} else if innerSel, ok2 := sel.X.(*syntax.SelectorExpr); ok2 {
 130  					addr := fb.buildSelectorAddr(innerSel)
 131  					if addr != nil {
 132  						recv = addr
 133  					}
 134  				}
 135  			}
 136  		}
 137  		return fn, recv
 138  	}
 139  	st, ok2 := types.SafeUnderlying(named).(*types.TCStruct)
 140  	if !ok2 {
 141  		return nil, nil
 142  	}
 143  	if !isPtr {
 144  		fixed := false
 145  		if innerSel, ok3 := sel.X.(*syntax.SelectorExpr); ok3 {
 146  			addr := fb.buildSelectorAddr(innerSel)
 147  			if addr != nil {
 148  				recv = addr
 149  				fixed = true
 150  			}
 151  		}
 152  		if !fixed {
 153  			if nameExpr, ok3 := sel.X.(*syntax.Name); ok3 {
 154  				obj := fb.lookupObject(nameExpr.Value)
 155  				if obj != nil {
 156  					if a, ok4 := fb.vars[obj]; ok4 {
 157  						recv = a
 158  						fixed = true
 159  					}
 160  				}
 161  			}
 162  		}
 163  		if !fixed {
 164  			alloc := &SSAAlloc{}
 165  			alloc.typ = types.NewPointer(recv.SSAType())
 166  			alloc.name = fb.nextName()
 167  			fb.emit(alloc)
 168  			storeOp := &SSAStore{Addr: alloc, Val: recv}
 169  			fb.emit(storeOp)
 170  			recv = alloc
 171  		}
 172  	}
 173  	for i := 0; i < st.NumFields(); i++ {
 174  		f := st.Field(i)
 175  		if !f.Anonymous() {
 176  			continue
 177  		}
 178  		embedType := f.Type()
 179  		embedNamed, ok3 := embedType.(*types.Named)
 180  		if !ok3 {
 181  			if p, ok4 := embedType.(*types.Pointer); ok4 {
 182  				embedNamed, ok3 = p.Elem().(*types.Named)
 183  			}
 184  		}
 185  		if !ok3 || embedNamed.Obj() == nil {
 186  			continue
 187  		}
 188  		embedName := embedNamed.Obj().Name()
 189  		embedSamePkg := embedNamed.Obj().Pkg() != nil && embedNamed.Obj().Pkg().Path() == fb.fn.Pkg.Pkg.Path()
 190  		embedMangledName := embedName | "." | sel.Sel.Value
 191  		if !embedSamePkg && embedNamed.Obj().Pkg() != nil {
 192  			embedMangledName = embedNamed.Obj().Pkg().Path() | "." | embedName | "." | sel.Sel.Value
 193  		}
 194  		var embedFn *SSAFunction
 195  		if embedSamePkg {
 196  			embedFn, _ = fb.fn.Pkg.Members[embedMangledName].(*SSAFunction)
 197  		}
 198  		if embedFn == nil {
 199  			for mi := int32(0); mi < int32(embedNamed.NumMethods()); mi++ {
 200  				m := embedNamed.Method(int32(mi))
 201  				if m.Name() == sel.Sel.Value {
 202  					embedFn = fb.fn.Pkg.ExternalFunc(embedMangledName, m.Signature())
 203  					if !embedSamePkg && embedNamed.Obj().Pkg() != nil {
 204  						embedFn.externalSymbol = embedNamed.Obj().Pkg().Path() | "." | embedName | "." | sel.Sel.Value
 205  					}
 206  					break
 207  				}
 208  			}
 209  		}
 210  		if embedFn != nil {
 211  			fieldAddr := &SSAFieldAddr{
 212  				X:     recv,
 213  				Field: i,
 214  			}
 215  			fieldAddr.typ = types.NewPointer(embedType)
 216  			fieldAddr.name = fb.nextName()
 217  			fb.emit(fieldAddr)
 218  			var embedRecv SSAValue = fieldAddr
 219  			if _, isEmbedPtr := types.SafeUnderlying(embedType).(*types.Pointer); isEmbedPtr {
 220  				ld := &SSAUnOp{Op: OpMul, X: fieldAddr}
 221  				ld.typ = embedType
 222  				ld.name = fb.nextName()
 223  				fb.emit(ld)
 224  				embedRecv = ld
 225  			}
 226  			return embedFn, embedRecv
 227  		}
 228  		embedSt, ok5 := types.SafeUnderlying(embedNamed).(*types.TCStruct)
 229  		if !ok5 {
 230  			continue
 231  		}
 232  		for j := 0; j < embedSt.NumFields(); j++ {
 233  			f2 := embedSt.Field(j)
 234  			if !f2.Anonymous() {
 235  				continue
 236  			}
 237  			embed2Type := f2.Type()
 238  			embed2Named, ok6 := embed2Type.(*types.Named)
 239  			if !ok6 {
 240  				if p2, ok7 := embed2Type.(*types.Pointer); ok7 {
 241  					embed2Named, ok6 = p2.Elem().(*types.Named)
 242  				}
 243  			}
 244  			if !ok6 || embed2Named.Obj() == nil {
 245  				continue
 246  			}
 247  			embed2Name := embed2Named.Obj().Name()
 248  			embed2SamePkg := embed2Named.Obj().Pkg() != nil && embed2Named.Obj().Pkg().Path() == fb.fn.Pkg.Pkg.Path()
 249  			embed2Mangled := embed2Name | "." | sel.Sel.Value
 250  			if !embed2SamePkg && embed2Named.Obj().Pkg() != nil {
 251  				embed2Mangled = embed2Named.Obj().Pkg().Path() | "." | embed2Name | "." | sel.Sel.Value
 252  			}
 253  			var embed2Fn *SSAFunction
 254  			if embed2SamePkg {
 255  				embed2Fn, _ = fb.fn.Pkg.Members[embed2Mangled].(*SSAFunction)
 256  			}
 257  			if embed2Fn == nil {
 258  				for mi := int32(0); mi < int32(embed2Named.NumMethods()); mi++ {
 259  					m := embed2Named.Method(int32(mi))
 260  					if m.Name() == sel.Sel.Value {
 261  						embed2Fn = fb.fn.Pkg.ExternalFunc(embed2Mangled, m.Signature())
 262  						if !embed2SamePkg && embed2Named.Obj().Pkg() != nil {
 263  							embed2Fn.externalSymbol = embed2Named.Obj().Pkg().Path() | "." | embed2Name | "." | sel.Sel.Value
 264  						}
 265  						break
 266  					}
 267  				}
 268  			}
 269  			if embed2Fn == nil {
 270  				continue
 271  			}
 272  			fieldAddr1 := &SSAFieldAddr{X: recv, Field: i}
 273  			fieldAddr1.typ = types.NewPointer(embedType)
 274  			fieldAddr1.name = fb.nextName()
 275  			fb.emit(fieldAddr1)
 276  			var cur1 SSAValue = fieldAddr1
 277  			curEmbedType := embedType
 278  			if p5, ok8 := types.SafeUnderlying(embedType).(*types.Pointer); ok8 {
 279  				ld := &SSAUnOp{Op: OpMul, X: fieldAddr1}
 280  				ld.typ = embedType
 281  				ld.name = fb.nextName()
 282  				fb.emit(ld)
 283  				cur1 = ld
 284  				curEmbedType = p5.Elem()
 285  			}
 286  			_ = curEmbedType
 287  			fieldAddr2 := &SSAFieldAddr{X: cur1, Field: j}
 288  			fieldAddr2.typ = types.NewPointer(embed2Type)
 289  			fieldAddr2.name = fb.nextName()
 290  			fb.emit(fieldAddr2)
 291  			var embedRecv2 SSAValue = fieldAddr2
 292  			if _, isEmbedPtr2 := types.SafeUnderlying(embed2Type).(*types.Pointer); isEmbedPtr2 {
 293  				ld2 := &SSAUnOp{Op: OpMul, X: fieldAddr2}
 294  				ld2.typ = embed2Type
 295  				ld2.name = fb.nextName()
 296  				fb.emit(ld2)
 297  				embedRecv2 = ld2
 298  			}
 299  			return embed2Fn, embedRecv2
 300  		}
 301  	}
 302  	return nil, nil
 303  }
 304  
 305  func (fb *ssaFuncBuilder) buildIfaceMethodCall(sel *syntax.SelectorExpr, recv SSAValue, argExprs []syntax.Expr) (s SSAValue) {
 306  	typ := recv.SSAType()
 307  	if p, ok := types.SafeUnderlying(typ).(*types.Pointer); ok {
 308  		typ = p.Elem()
 309  	}
 310  	iface, ok := types.SafeUnderlying(typ).(*types.TCInterface)
 311  	if !ok {
 312  		return nil
 313  	}
 314  	var methodSig *types.Signature
 315  	for i := 0; i < iface.NumMethods(); i++ {
 316  		m := iface.Method(i)
 317  		if m == nil {
 318  			continue
 319  		}
 320  		if m.Name() == sel.Sel.Value {
 321  			methodSig = m.Sig()
 322  			break
 323  		}
 324  	}
 325  	var retType types.Type
 326  	if methodSig != nil && methodSig.Results() != nil {
 327  		if methodSig.Results().Len() == 1 {
 328  			retType = methodSig.Results().At(0).Type()
 329  		} else if methodSig.Results().Len() > 1 {
 330  			retType = methodSig.Results()
 331  		}
 332  	}
 333  	args := fb.buildArgs(argExprs)
 334  	inv := &SSAInvoke{
 335  		X:          recv,
 336  		MethodName: sel.Sel.Value,
 337  		IfaceType:  iface,
 338  		Args:       args,
 339  	}
 340  	inv.typ = retType
 341  	inv.name = fb.nextName()
 342  	fb.emit(inv)
 343  	if retType == nil {
 344  		return nil
 345  	}
 346  	return inv
 347  }
 348  
 349  func (fb *ssaFuncBuilder) resolveType(e syntax.Expr) (t types.Type) {
 350  	if fb.info != nil {
 351  		if tv, ok := fb.info.Types[e]; ok && tv.Type != nil {
 352  			return tv.Type
 353  		}
 354  	}
 355  	t = fb.resolveTypeAST(e)
 356  	return t
 357  }
 358  
 359  func (fb *ssaFuncBuilder) resolveTypeAST(e syntax.Expr) (t types.Type) {
 360  	if e == nil {
 361  		return nil
 362  	}
 363  	switch e := e.(type) {
 364  	case *syntax.Name:
 365  		if fb.typeSubst != nil {
 366  			if t, ok := fb.typeSubst[e.Value]; ok {
 367  				return t
 368  			}
 369  		}
 370  		if t, ok := fb.localTypes[e.Value]; ok {
 371  			return t
 372  		}
 373  		obj := fb.lookupObject(e.Value)
 374  		if tn, ok := obj.(*types.TypeName); ok {
 375  			if tp, ok2 := tn.Type().(*types.TypeParam); ok2 && fb.typeSubst != nil {
 376  				if t, ok3 := fb.typeSubst[tp.String()]; ok3 {
 377  					return t
 378  				}
 379  			}
 380  			return tn.Type()
 381  		}
 382  	case *syntax.Operation:
 383  		if e.Y == nil && e.Op == token.Mul {
 384  			base := fb.resolveTypeAST(e.X)
 385  			if base != nil {
 386  				return types.NewPointer(base)
 387  			}
 388  		}
 389  	case *syntax.SliceType:
 390  		elem := fb.resolveTypeAST(e.Elem)
 391  		if elem != nil {
 392  			if b, ok := elem.(*types.Basic); ok && b.Kind() == types.Uint8 {
 393  				return types.Typ[types.TCString]
 394  			}
 395  			return types.NewSlice(elem)
 396  		}
 397  	case *syntax.ArrayType:
 398  		elem := fb.resolveTypeAST(e.Elem)
 399  		if elem != nil {
 400  			n := int64(-1)
 401  			if lit, ok := e.Len.(*syntax.BasicLit); ok {
 402  				n = ssaParseInt64(lit.Value)
 403  			} else if e.Len != nil {
 404  				cv := tcEvalConstExpr(e.Len, fb.fn.Pkg.Pkg.Scope(), -1)
 405  				if cv == nil && fb.localConsts != nil {
 406  					cv = fb.evalLocalConstExpr(e.Len)
 407  				}
 408  				if ci, ok := cv.(*types.ConstInt); ok {
 409  					n = ci.v
 410  				}
 411  			}
 412  			return types.NewArray(elem, n)
 413  		}
 414  	case *syntax.MapType:
 415  		key := fb.resolveTypeAST(e.Key)
 416  		val := fb.resolveTypeAST(e.Value)
 417  		if key != nil && val != nil {
 418  			return types.NewTCMap(key, val)
 419  		}
 420  	case *syntax.StructType:
 421  		return fb.resolveStructTypeAST(e)
 422  	case *syntax.ChanType:
 423  		elem := fb.resolveTypeAST(e.Elem)
 424  		if elem != nil {
 425  			dir := types.TCSendRecv
 426  			if e.Dir == syntax.SendOnly {
 427  				dir = types.TCSendOnly
 428  			} else if e.Dir == syntax.RecvOnly {
 429  				dir = types.TCRecvOnly
 430  			}
 431  			return types.NewTCChan(dir, elem)
 432  		}
 433  	case *syntax.InterfaceType:
 434  		return fb.resolveInterfaceTypeAST(e)
 435  	case *syntax.FuncType:
 436  		return fb.resolveFuncTypeAST(e)
 437  	case *syntax.SelectorExpr:
 438  		if x, ok := e.X.(*syntax.Name); ok {
 439  			obj := fb.lookupObject(x.Value)
 440  			if pn, ok2 := obj.(*types.PkgName); ok2 && pn.Imported() != nil {
 441  				sel := pn.Imported().Scope().Lookup(e.Sel.Value)
 442  				if tn, ok3 := sel.(*types.TypeName); ok3 {
 443  					return tn.Type()
 444  				}
 445  			}
 446  		}
 447  	case *syntax.ParenExpr:
 448  		return fb.resolveTypeAST(e.X)
 449  	}
 450  	return nil
 451  }
 452  
 453  func (fb *ssaFuncBuilder) resolveInterfaceTypeAST(e *syntax.InterfaceType) (t *types.TCInterface) {
 454  	var methods []*types.IfaceMethod
 455  	for _, f := range e.MethodList {
 456  		if f.Name == nil {
 457  			continue
 458  		}
 459  		ft, ok := f.Type.(*syntax.FuncType)
 460  		if !ok {
 461  			continue
 462  		}
 463  		sig := fb.resolveFuncTypeAST(ft)
 464  		if sig != nil {
 465  			methods = append(methods, types.NewTCIfaceMethod(f.Name.Value, sig))
 466  		}
 467  	}
 468  	iface := types.NewTCInterface(methods, nil)
 469  	iface.Complete()
 470  	return iface
 471  }
 472  
 473  func (fb *ssaFuncBuilder) resolveStructTypeAST(e *syntax.StructType) (t *types.TCStruct) {
 474  	var fields []*types.TCVar
 475  	var tags []string
 476  	for i, f := range e.FieldList {
 477  		typ := fb.resolveTypeAST(f.Type)
 478  		if typ == nil {
 479  			return nil
 480  		}
 481  		name := ""
 482  		if f.Name != nil {
 483  			name = f.Name.Value
 484  		}
 485  		fields = append(fields, types.NewTCField(fb.fn.Pkg.Pkg, name, typ, f.Name == nil))
 486  		tag := ""
 487  		if i < len(e.TagList) && e.TagList[i] != nil {
 488  			tag = e.TagList[i].Value
 489  		}
 490  		tags = append(tags, tag)
 491  	}
 492  	return types.NewTCStruct(fields, tags)
 493  }
 494  
 495  func (fb *ssaFuncBuilder) resolveFuncTypeAST(ft *syntax.FuncType) (s *types.Signature) {
 496  	if ft == nil {
 497  		return nil
 498  	}
 499  	var params []*types.TCVar
 500  	for _, p := range ft.ParamList {
 501  		typ := fb.resolveTypeAST(p.Type)
 502  		pname := ""
 503  		if p.Name != nil {
 504  			pname = p.Name.Value
 505  		}
 506  		params = append(params, types.NewTCVar(nil, pname, typ))
 507  	}
 508  	var results []*types.TCVar
 509  	for _, r := range ft.ResultList {
 510  		typ := fb.resolveTypeAST(r.Type)
 511  		rname := ""
 512  		if r.Name != nil {
 513  			rname = r.Name.Value
 514  		}
 515  		results = append(results, types.NewTCVar(nil, rname, typ))
 516  	}
 517  	var pTuple, rTuple *types.Tuple
 518  	if len(params) > 0 {
 519  		pTuple = types.NewTuple(params...)
 520  	}
 521  	if len(results) > 0 {
 522  		rTuple = types.NewTuple(results...)
 523  	}
 524  	return types.NewSignature(nil, pTuple, rTuple, false)
 525  }
 526  
 527  func (fb *ssaFuncBuilder) fieldIndex(t types.Type, name string) (n int32) {
 528  	if t == nil {
 529  		return -1
 530  	}
 531  	if pt, ok := types.SafeUnderlying(t).(*types.Pointer); ok {
 532  		t = pt.Elem()
 533  	}
 534  	if st, ok := types.SafeUnderlying(t).(*types.TCStruct); ok {
 535  		for i := 0; i < st.NumFields(); i++ {
 536  			if st.Field(i).Name() == name {
 537  				return i
 538  			}
 539  		}
 540  	}
 541  	return -1
 542  }
 543  
 544  func (fb *ssaFuncBuilder) findEmbeddedField(t types.Type, name string) (embedIdx int32, innerIdx int32) {
 545  	path := fb.findEmbeddedFieldPath(t, name)
 546  	if len(path) < 2 {
 547  		return -1, -1
 548  	}
 549  	return path[0], path[1]
 550  }
 551  
 552  func (fb *ssaFuncBuilder) findEmbeddedFieldPath(t types.Type, name string) (ss []int32) {
 553  	if t == nil {
 554  		return nil
 555  	}
 556  	if pt, ok := types.SafeUnderlying(t).(*types.Pointer); ok {
 557  		t = pt.Elem()
 558  	}
 559  	st, ok := types.SafeUnderlying(t).(*types.TCStruct)
 560  	if !ok {
 561  		return nil
 562  	}
 563  	for i := 0; i < st.NumFields(); i++ {
 564  		f := st.Field(i)
 565  		if !f.Anonymous() {
 566  			continue
 567  		}
 568  		embedType := f.Type()
 569  		if pt, ok := types.SafeUnderlying(embedType).(*types.Pointer); ok {
 570  			embedType = pt.Elem()
 571  		}
 572  		inner := fb.fieldIndex(embedType, name)
 573  		if inner >= 0 {
 574  			return []int32{i, inner}
 575  		}
 576  		sub := fb.findEmbeddedFieldPath(embedType, name)
 577  		if len(sub) > 0 {
 578  			return append([]int32{i}, sub...)
 579  		}
 580  	}
 581  	return nil
 582  }
 583  
 584  func (fb *ssaFuncBuilder) fieldType(t Type, idx int32) (tv types.Type) {
 585  	if t == nil {
 586  		return nil
 587  	}
 588  	if pt, ok := types.SafeUnderlying(t).(*types.Pointer); ok {
 589  		t = pt.Elem()
 590  	}
 591  	if st, ok := types.SafeUnderlying(t).(*types.TCStruct); ok {
 592  		if idx >= 0 && idx < st.NumFields() {
 593  			return st.Field(idx).Type()
 594  		}
 595  	}
 596  	return nil
 597  }
 598  
 599  func ssaExtractConst(v SSAValue) (s *SSAConst) {
 600  	if c, ok := v.(*SSAConst); ok {
 601  		return c
 602  	}
 603  	if conv, ok := v.(*SSAConvert); ok {
 604  		if c, ok2 := conv.X.(*SSAConst); ok2 {
 605  			return &SSAConst{typ: conv.SSAType(), val: c.val}
 606  		}
 607  	}
 608  	return nil
 609  }
 610  
 611  func ssaExprNames(e syntax.Expr) (ns []*syntax.Name) {
 612  	if e == nil {
 613  		return nil
 614  	}
 615  	if n, ok := e.(*syntax.Name); ok {
 616  		return []*syntax.Name{n}
 617  	}
 618  	if l, ok := e.(*syntax.ListExpr); ok {
 619  		var names []*syntax.Name
 620  		for _, el := range l.ElemList {
 621  			if n, ok := el.(*syntax.Name); ok {
 622  				names = append(names, n)
 623  			}
 624  		}
 625  		return names
 626  	}
 627  	return nil
 628  }
 629  
 630  func localizeConstVal(val ConstVal, typ types.Type) (c types.ConstVal) {
 631  	if val == nil {
 632  		return nil
 633  	}
 634  	return val
 635  }
 636