Source file src/cmd/compile/internal/types2/recording.go

     1  // Copyright 2024 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  // This file implements recording of type information
     6  // in the types2.Info maps.
     7  
     8  package types2
     9  
    10  import (
    11  	"cmd/compile/internal/syntax"
    12  	"go/constant"
    13  )
    14  
    15  func (check *Checker) record(x *operand) {
    16  	// convert x into a user-friendly set of values
    17  	// TODO(gri) this code can be simplified
    18  	var typ Type
    19  	var val constant.Value
    20  	switch x.mode {
    21  	case invalid:
    22  		typ = Typ[Invalid]
    23  	case novalue:
    24  		typ = (*Tuple)(nil)
    25  	case constant_:
    26  		typ = x.typ
    27  		val = x.val
    28  	default:
    29  		typ = x.typ
    30  	}
    31  	assert(x.expr != nil && typ != nil)
    32  
    33  	if isUntyped(typ) {
    34  		// delay type and value recording until we know the type
    35  		// or until the end of type checking
    36  		check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
    37  	} else {
    38  		check.recordTypeAndValue(x.expr, x.mode, typ, val)
    39  	}
    40  }
    41  
    42  func (check *Checker) recordUntyped() {
    43  	if !debug && !check.recordTypes() {
    44  		return // nothing to do
    45  	}
    46  
    47  	for x, info := range check.untyped {
    48  		if debug && isTyped(info.typ) {
    49  			check.dump("%v: %s (type %s) is typed", atPos(x), x, info.typ)
    50  			panic("unreachable")
    51  		}
    52  		check.recordTypeAndValue(x, info.mode, info.typ, info.val)
    53  	}
    54  }
    55  
    56  func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
    57  	assert(x != nil)
    58  	assert(typ != nil)
    59  	if mode == invalid {
    60  		return // omit
    61  	}
    62  	if mode == constant_ {
    63  		assert(val != nil)
    64  		// We check allBasic(typ, IsConstType) here as constant expressions may be
    65  		// recorded as type parameters.
    66  		assert(!isValid(typ) || allBasic(typ, IsConstType))
    67  	}
    68  	if m := check.Types; m != nil {
    69  		m[x] = TypeAndValue{mode, typ, val}
    70  	}
    71  	check.recordTypeAndValueInSyntax(x, mode, typ, val)
    72  }
    73  
    74  func (check *Checker) recordBuiltinType(f syntax.Expr, sig *Signature) {
    75  	// f must be a (possibly parenthesized, possibly qualified)
    76  	// identifier denoting a built-in (including unsafe's non-constant
    77  	// functions Add and Slice): record the signature for f and possible
    78  	// children.
    79  	for {
    80  		check.recordTypeAndValue(f, builtin, sig, nil)
    81  		switch p := f.(type) {
    82  		case *syntax.Name, *syntax.SelectorExpr:
    83  			return // we're done
    84  		case *syntax.ParenExpr:
    85  			f = p.X
    86  		default:
    87  			panic("unreachable")
    88  		}
    89  	}
    90  }
    91  
    92  // recordCommaOkTypes updates recorded types to reflect that x is used in a commaOk context
    93  // (and therefore has tuple type).
    94  func (check *Checker) recordCommaOkTypes(x syntax.Expr, a []*operand) {
    95  	assert(x != nil)
    96  	assert(len(a) == 2)
    97  	if a[0].mode == invalid {
    98  		return
    99  	}
   100  	t0, t1 := a[0].typ, a[1].typ
   101  	assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError))
   102  	if m := check.Types; m != nil {
   103  		for {
   104  			tv := m[x]
   105  			assert(tv.Type != nil) // should have been recorded already
   106  			pos := x.Pos()
   107  			tv.Type = NewTuple(
   108  				NewVar(pos, check.pkg, "", t0),
   109  				NewVar(pos, check.pkg, "", t1),
   110  			)
   111  			m[x] = tv
   112  			// if x is a parenthesized expression (p.X), update p.X
   113  			p, _ := x.(*syntax.ParenExpr)
   114  			if p == nil {
   115  				break
   116  			}
   117  			x = p.X
   118  		}
   119  	}
   120  	check.recordCommaOkTypesInSyntax(x, t0, t1)
   121  }
   122  
   123  // recordInstance records instantiation information into check.Info, if the
   124  // Instances map is non-nil. The given expr must be an ident, selector, or
   125  // index (list) expr with ident or selector operand.
   126  //
   127  // TODO(rfindley): the expr parameter is fragile. See if we can access the
   128  // instantiated identifier in some other way.
   129  func (check *Checker) recordInstance(expr syntax.Expr, targs []Type, typ Type) {
   130  	ident := instantiatedIdent(expr)
   131  	assert(ident != nil)
   132  	assert(typ != nil)
   133  	if m := check.Instances; m != nil {
   134  		m[ident] = Instance{newTypeList(targs), typ}
   135  	}
   136  }
   137  
   138  func (check *Checker) recordDef(id *syntax.Name, obj Object) {
   139  	assert(id != nil)
   140  	if m := check.Defs; m != nil {
   141  		m[id] = obj
   142  	}
   143  }
   144  
   145  func (check *Checker) recordUse(id *syntax.Name, obj Object) {
   146  	assert(id != nil)
   147  	assert(obj != nil)
   148  	if m := check.Uses; m != nil {
   149  		m[id] = obj
   150  	}
   151  }
   152  
   153  func (check *Checker) recordImplicit(node syntax.Node, obj Object) {
   154  	assert(node != nil)
   155  	assert(obj != nil)
   156  	if m := check.Implicits; m != nil {
   157  		m[node] = obj
   158  	}
   159  }
   160  
   161  func (check *Checker) recordSelection(x *syntax.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
   162  	assert(obj != nil && (recv == nil || len(index) > 0))
   163  	check.recordUse(x.Sel, obj)
   164  	if m := check.Selections; m != nil {
   165  		m[x] = &Selection{kind, recv, obj, index, indirect}
   166  	}
   167  }
   168  
   169  func (check *Checker) recordScope(node syntax.Node, scope *Scope) {
   170  	assert(node != nil)
   171  	assert(scope != nil)
   172  	if m := check.Scopes; m != nil {
   173  		m[node] = scope
   174  	}
   175  }
   176  

View as plain text