func visitFieldAddr(instr *ssa.FieldAddr, infer *TypeInfer, ctx *Context) { field, struc, index := instr, instr.X, instr.Field if sType, ok := derefType(struc.Type()).Underlying().(*types.Struct); ok { sInst, ok := ctx.F.locals[struc] if !ok { sInst, ok = ctx.F.Prog.globals[struc] if !ok { infer.Logger.Fatalf("field-addr: %s: %+v", ErrUnknownValue, struc) return } } // Check status of instance. switch inst := sInst.(type) { case *Value: // Continue case *External: // Continue infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"field-addr: %+v is external", sInst)) ctx.F.locals[field] = inst return case *Const: infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"field-addr: %+v is a constant", sInst)) if inst.Const.IsNil() { ctx.F.locals[field] = inst } return default: infer.Logger.Fatalf("field-addr: %s: not instance %+v", ErrUnknownValue, sInst) return } // Find the struct. fields, ok := ctx.F.structs[sInst] if !ok { fields, ok = ctx.F.Prog.structs[sInst] if !ok { infer.Logger.Fatalf("field-addr: %s: struct uninitialised %+v", ErrUnknownValue, sInst) return } } infer.Logger.Print(ctx.F.Sprintf(ValSymbol+"%s = %s"+FieldSymbol+"{%d} of type %s", instr.Name(), sInst, index, sType.String())) if fields[index] != nil { infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"accessed as %s", fields[index])) } else { fields[index] = &Value{field, ctx.F.InstanceID(), ctx.L.Index} infer.Logger.Print(ctx.F.Sprintf(SubSymbol+"field uninitialised, set to %s", field.Name())) } initNestedRefVar(infer, ctx, fields[index], false) ctx.F.locals[field] = fields[index] return } infer.Logger.Fatalf("field-addr: %s: field is not struct: %+v", ErrInvalidVarRead, struc) }