lvalue.go raw

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