github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/ssa/lvalue.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 // lvalues are the union of addressable expressions and map-index 8 // expressions. 9 10 import ( 11 "go/ast" 12 "go/token" 13 "go/types" 14 ) 15 16 // An lvalue represents an assignable location that may appear on the 17 // left-hand side of an assignment. This is a generalization of a 18 // pointer to permit updates to elements of maps. 19 type lvalue interface { 20 store(fn *Function, v Value) // stores v into the location 21 load(fn *Function) Value // loads the contents of the location 22 address(fn *Function) Value // address of the location 23 typ() types.Type // returns the type of the location 24 } 25 26 // An address is an lvalue represented by a true pointer. 27 type address struct { 28 addr Value 29 pos token.Pos // source position 30 expr ast.Expr // source syntax of the value (not address) [debug mode] 31 } 32 33 func (a *address) load(fn *Function) Value { 34 load := emitLoad(fn, a.addr) 35 load.pos = a.pos 36 return load 37 } 38 39 func (a *address) store(fn *Function, v Value) { 40 store := emitStore(fn, a.addr, v, a.pos) 41 if a.expr != nil { 42 // store.Val is v, converted for assignability. 43 emitDebugRef(fn, a.expr, store.Val, false) 44 } 45 } 46 47 func (a *address) address(fn *Function) Value { 48 if a.expr != nil { 49 emitDebugRef(fn, a.expr, a.addr, true) 50 } 51 return a.addr 52 } 53 54 func (a *address) typ() types.Type { 55 return deref(a.addr.Type()) 56 } 57 58 // An element is an lvalue represented by m[k], the location of an 59 // element of a map. These locations are not addressable 60 // since pointers cannot be formed from them, but they do support 61 // load() and store(). 62 type element struct { 63 m, k Value // map 64 t types.Type // map element type 65 pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v) 66 } 67 68 func (e *element) load(fn *Function) Value { 69 l := &Lookup{ 70 X: e.m, 71 Index: e.k, 72 } 73 l.setPos(e.pos) 74 l.setType(e.t) 75 return fn.emit(l) 76 } 77 78 func (e *element) store(fn *Function, v Value) { 79 up := &MapUpdate{ 80 Map: e.m, 81 Key: e.k, 82 Value: emitConv(fn, v, e.t), 83 } 84 up.pos = e.pos 85 fn.emit(up) 86 } 87 88 func (e *element) address(fn *Function) Value { 89 panic("map elements are not addressable") 90 } 91 92 func (e *element) typ() types.Type { 93 return e.t 94 } 95 96 // A lazyAddress is an lvalue whose address is the result of an instruction. 97 // These work like an *address except a new address.address() Value 98 // is created on each load, store and address call. 99 // A lazyAddress can be used to control when a side effect (nil pointer 100 // dereference, index out of bounds) of using a location happens. 101 type lazyAddress struct { 102 addr func(fn *Function) Value // emit to fn the computation of the address 103 t types.Type // type of the location 104 pos token.Pos // source position 105 expr ast.Expr // source syntax of the value (not address) [debug mode] 106 } 107 108 func (l *lazyAddress) load(fn *Function) Value { 109 load := emitLoad(fn, l.addr(fn)) 110 load.pos = l.pos 111 return load 112 } 113 114 func (l *lazyAddress) store(fn *Function, v Value) { 115 store := emitStore(fn, l.addr(fn), v, l.pos) 116 if l.expr != nil { 117 // store.Val is v, converted for assignability. 118 emitDebugRef(fn, l.expr, store.Val, false) 119 } 120 } 121 122 func (l *lazyAddress) address(fn *Function) Value { 123 addr := l.addr(fn) 124 if l.expr != nil { 125 emitDebugRef(fn, l.expr, addr, true) 126 } 127 return addr 128 } 129 130 func (l *lazyAddress) typ() types.Type { return l.t } 131 132 // A blank is a dummy variable whose name is "_". 133 // It is not reified: loads are illegal and stores are ignored. 134 type blank struct{} 135 136 func (bl blank) load(fn *Function) Value { 137 panic("blank.load is illegal") 138 } 139 140 func (bl blank) store(fn *Function, v Value) { 141 // no-op 142 } 143 144 func (bl blank) address(fn *Function) Value { 145 panic("blank var is not addressable") 146 } 147 148 func (bl blank) typ() types.Type { 149 // This should be the type of the blank Ident; the typechecker 150 // doesn't provide this yet, but fortunately, we don't need it 151 // yet either. 152 panic("blank.typ is unimplemented") 153 }