...

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  	"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  

View as plain text