src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

lvalue.go (4166B)


      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 }