func visitField(instr *ssa.Field, infer *TypeInfer, ctx *Context) { field, struc, index := instr, instr.X, instr.Field if sType, ok := struc.Type().Underlying().(*types.Struct); ok { sInst, ok := ctx.F.locals[struc] if !ok { infer.Logger.Fatalf("field: %s :%+v", ErrUnknownValue, struc) return } fields, ok := ctx.F.structs[sInst] if !ok { fields, ok = ctx.F.Prog.structs[sInst] if !ok { infer.Logger.Fatalf("field: %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, ctx.F.locals[field], false) ctx.F.locals[field] = fields[index] return } infer.Logger.Fatalf("field: %s: field is not struct: %+v", ErrInvalidVarRead, struc) }
func visitField(inst *ssa.Field, fr *frame) { field := inst struc := inst.X index := inst.Field if stype, ok := struc.Type().Underlying().(*types.Struct); ok { switch vd, kind := fr.get(struc); kind { case Struct: fmt.Fprintf(os.Stderr, " %s = %s(=%s).[%d] of type %s\n", cyan(reg(field)), struc.Name(), vd.String(), index, field.Type().String()) if fr.env.structs[vd][index] == nil { // First use vdField := utils.NewDef(field) fr.env.structs[vd][index] = vdField fmt.Fprintf(os.Stderr, " ^ accessed for the first time: use %s as field definition\n", field.Name()) // If field is struct if fieldType, ok := field.Type().Underlying().(*types.Struct); ok { fr.env.structs[vdField] = make(Fields, fieldType.NumFields()) fmt.Fprintf(os.Stderr, " ^ field %s is a struct (allocating)\n", field.Name()) } } else if fr.env.structs[vd][index].Var != field { // Previously defined fmt.Fprintf(os.Stderr, " ^ field %s previously defined as %s\n", field.Name(), reg(fr.env.structs[vd][index].Var)) } // else Accessed before (and unchanged) fr.locals[field] = fr.env.structs[vd][index] case LocalStruct: fmt.Fprintf(os.Stderr, " %s = %s(=%s).[%d] (local) of type %s\n", cyan(reg(field)), struc.Name(), vd.String(), index, field.Type().String()) if fr.structs[vd][index] == nil { // First use vdField := utils.NewDef(field) fr.structs[vd][index] = vdField fmt.Fprintf(os.Stderr, " ^ accessed for the first time: use %s as field definition\n", field.Name()) // If field is struct if fieldType, ok := field.Type().Underlying().(*types.Struct); ok { fr.structs[vdField] = make(Fields, fieldType.NumFields()) fmt.Fprintf(os.Stderr, " ^ field %s is a struct (allocating locally)\n", field.Name()) } } else if fr.structs[vd][index].Var != field { // Previously defined fmt.Fprintf(os.Stderr, " ^ field %s previously defined as %s\n", field.Name(), reg(fr.structs[vd][index].Var)) } // else Accessed before (and unchanged) fr.locals[field] = fr.structs[vd][index] case Nothing, Untracked: // Nothing: Very likely external struct. // Untracked: likely branches of return values (e.g. returning nil) fmt.Fprintf(os.Stderr, " %s = %s(=%s).[%d] (external) of type %s\n", cyan(reg(field)), inst.X.Name(), vd.String(), index, field.Type().String()) vd := utils.NewDef(struc) // New external struct fr.locals[struc] = vd fr.env.structs[vd] = make(Fields, stype.NumFields()) vdField := utils.NewDef(field) // New external field fr.env.structs[vd][index] = vdField fr.locals[field] = vdField fmt.Fprintf(os.Stderr, " ^ accessed for the first time: use %s as field definition of type %s\n", field.Name(), inst.Type().Underlying().String()) // If field is struct if fieldType, ok := field.Type().Underlying().(*types.Struct); ok { fr.env.structs[vdField] = make(Fields, fieldType.NumFields()) fmt.Fprintf(os.Stderr, " ^ field %s previously defined as %s\n", field.Name(), reg(fr.env.structs[vd][index].Var)) } default: panic(fmt.Sprintf("Field: Cannot access non-struct %s %T %d", reg(struc), struc.Type(), kind)) } } else { panic(fmt.Sprintf("Field: Cannot access field - %s not a struct\n", reg(struc))) } }