Example #1
0
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)
}