diff --git a/compiler/ast/lrvalue.go b/compiler/ast/lrvalue.go index 6401cf7..e4a4c83 100644 --- a/compiler/ast/lrvalue.go +++ b/compiler/ast/lrvalue.go @@ -79,6 +79,38 @@ func (lrv *LRValue) BasePtrInfo() *ssa.PtrInfo { return lrv.baseInfo } +// Indirect returns LRValue for the value that lrv points to. If lrv +// is not a pointer, Indirect returns lrv. +func (lrv *LRValue) Indirect() *LRValue { + v := lrv.RValue() + if v.Type.Type != types.TPtr { + return lrv + } + + ret := *lrv + ret.valueType = *lrv.valueType.ElementType + ret.value.PtrInfo = nil + + if lrv.baseInfo.ContainerType.Type == types.TStruct { + ret.value.Type = types.Undefined + + // Lookup struct field. + ret.structField = nil + for _, f := range lrv.baseValue.Type.Struct { + if f.Type.Offset == lrv.baseInfo.Offset { + ret.structField = &f + } + } + if ret.structField == nil { + panic("LRValue.Indirect: could not find struct field") + } + } else { + ret.value.Type = *lrv.value.Type.ElementType + } + + return &ret +} + // Set sets the l-value to rv. func (lrv LRValue) Set(rv ssa.Value) error { if !ssa.CanAssign(lrv.valueType, rv) { @@ -123,7 +155,7 @@ func (lrv LRValue) Set(rv ssa.Value) error { // The l-value and r-value types are now resolved. Let's define // the variable with correct type and value information, // overriding any old values. - lrv.block.Bindings.Define(lValue, &rv) + lrv.baseInfo.Bindings.Define(lValue, &rv) return nil } diff --git a/compiler/ast/ssagen.go b/compiler/ast/ssagen.go index 1901fd4..c1eaffc 100644 --- a/compiler/ast/ssagen.go +++ b/compiler/ast/ssagen.go @@ -1833,7 +1833,7 @@ func (ast *Slice) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( return nil, nil, ctx.Errorf(ast, "invalid expression") } expr := exprs[0] - elementType := expr.Deref() + elementType := expr.IndirectType() if !elementType.Type.Array() { return nil, nil, ctx.Errorf(ast, "invalid operation: cannot slice %v", expr.Type.Type) @@ -2182,6 +2182,7 @@ func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( if err != nil { return nil, nil, ctx.Error(ast.Dst, err.Error()) } + lrv = lrv.Indirect() dst = lrv.RValue() if !dst.Type.Type.Array() { return nil, nil, ast.errf(ctx, ast.Dst, "got %v", dst.Type) @@ -2200,6 +2201,7 @@ func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( if err != nil { return nil, nil, ctx.Error(ast.Dst, err.Error()) } + lrv = lrv.Indirect() dst = lrv.RValue() if !dst.Type.Type.Array() { return nil, nil, ast.errf(ctx, ast.Dst, "got %v", dst.Type) @@ -2225,12 +2227,7 @@ func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( return nil, nil, ast.errf(ctx, ast.Src, "got multivalue %T", ast.Src) } src := v[0] - var srcType types.Info - if src.Type.Type == types.TPtr { - srcType = *src.Type.ElementType - } else { - srcType = src.Type - } + srcType := src.IndirectType() if !srcType.Type.Array() { return nil, nil, ast.errf(ctx, ast.Src, "got %v", src.Type) } @@ -2262,7 +2259,7 @@ func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( block.AddInstr(ssa.NewSliceInstr(src, fromConst, toConst, tmp)) err := lrv.Set(tmp) if err != nil { - return nil, nil, err + return nil, nil, ctx.Error(ast, err.Error()) } } else { // Src overwrites part of dst. @@ -2285,7 +2282,7 @@ func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( err := lrv.Set(tmp2) if err != nil { - return nil, nil, err + return nil, nil, ctx.Error(ast, err.Error()) } } diff --git a/compiler/ssa/value.go b/compiler/ssa/value.go index 78191c2..f402974 100644 --- a/compiler/ssa/value.go +++ b/compiler/ssa/value.go @@ -75,9 +75,9 @@ func (v Value) Check() { } } -// Deref returns the pointer element type of the value. For -// non-pointer values, this returns the value type itself. -func (v Value) Deref() types.Info { +// IndirectType returns the type that v points to. If v is not a +// pointer, IndirectType returns the type of v. +func (v Value) IndirectType() types.Info { if v.Type.Type == types.TPtr { return *v.Type.ElementType }