...

Source file src/golang.org/x/tools/go/ssa/lvalue.go

Documentation: golang.org/x/tools/go/ssa

     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  }
   154  

View as plain text