struct.go raw

   1  // Copyright 2021 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 types
   6  
   7  import (
   8  	"go/ast"
   9  	"go/token"
  10  	. "internal/types/errors"
  11  	"strconv"
  12  )
  13  
  14  // ----------------------------------------------------------------------------
  15  // API
  16  
  17  // A Struct represents a struct type.
  18  type Struct struct {
  19  	fields []*Var   // fields != nil indicates the struct is set up (possibly with len(fields) == 0)
  20  	tags   []string // field tags; nil if there are no tags
  21  }
  22  
  23  // NewStruct returns a new struct with the given fields and corresponding field tags.
  24  // If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
  25  // only as long as required to hold the tag with the largest index i. Consequently,
  26  // if no field has a tag, tags may be nil.
  27  func NewStruct(fields []*Var, tags []string) *Struct {
  28  	var fset objset
  29  	for _, f := range fields {
  30  		if f.name != "_" && fset.insert(f) != nil {
  31  			panic("multiple fields with the same name")
  32  		}
  33  	}
  34  	if len(tags) > len(fields) {
  35  		panic("more tags than fields")
  36  	}
  37  	s := &Struct{fields: fields, tags: tags}
  38  	s.markComplete()
  39  	return s
  40  }
  41  
  42  // NumFields returns the number of fields in the struct (including blank and embedded fields).
  43  func (s *Struct) NumFields() int { return len(s.fields) }
  44  
  45  // Field returns the i'th field for 0 <= i < NumFields().
  46  func (s *Struct) Field(i int) *Var { return s.fields[i] }
  47  
  48  // Tag returns the i'th field tag for 0 <= i < NumFields().
  49  func (s *Struct) Tag(i int) string {
  50  	if i < len(s.tags) {
  51  		return s.tags[i]
  52  	}
  53  	return ""
  54  }
  55  
  56  func (t *Struct) Underlying() Type { return t }
  57  func (t *Struct) String() string   { return TypeString(t, nil) }
  58  
  59  // ----------------------------------------------------------------------------
  60  // Implementation
  61  
  62  func (s *Struct) markComplete() {
  63  	if s.fields == nil {
  64  		s.fields = make([]*Var, 0)
  65  	}
  66  }
  67  
  68  func (check *Checker) structType(styp *Struct, e *ast.StructType) {
  69  	list := e.Fields
  70  	if list == nil {
  71  		styp.markComplete()
  72  		return
  73  	}
  74  
  75  	// struct fields and tags
  76  	var fields []*Var
  77  	var tags []string
  78  
  79  	// for double-declaration checks
  80  	var fset objset
  81  
  82  	// current field typ and tag
  83  	var typ Type
  84  	var tag string
  85  	add := func(ident *ast.Ident, embedded bool) {
  86  		if tag != "" && tags == nil {
  87  			tags = make([]string, len(fields))
  88  		}
  89  		if tags != nil {
  90  			tags = append(tags, tag)
  91  		}
  92  
  93  		pos := ident.Pos()
  94  		name := ident.Name
  95  		fld := NewField(pos, check.pkg, name, typ, embedded)
  96  		// spec: "Within a struct, non-blank field names must be unique."
  97  		if name == "_" || check.declareInSet(&fset, pos, fld) {
  98  			fields = append(fields, fld)
  99  			check.recordDef(ident, fld)
 100  		}
 101  	}
 102  
 103  	// addInvalid adds an embedded field of invalid type to the struct for
 104  	// fields with errors; this keeps the number of struct fields in sync
 105  	// with the source as long as the fields are _ or have different names
 106  	// (go.dev/issue/25627).
 107  	addInvalid := func(ident *ast.Ident) {
 108  		typ = Typ[Invalid]
 109  		tag = ""
 110  		add(ident, true)
 111  	}
 112  
 113  	for _, f := range list.List {
 114  		typ = check.varType(f.Type)
 115  		tag = check.tag(f.Tag)
 116  		if len(f.Names) > 0 {
 117  			// named fields
 118  			for _, name := range f.Names {
 119  				add(name, false)
 120  			}
 121  		} else {
 122  			// embedded field
 123  			// spec: "An embedded type must be specified as a type name T or as a
 124  			// pointer to a non-interface type name *T, and T itself may not be a
 125  			// pointer type."
 126  			pos := f.Type.Pos() // position of type, for errors
 127  			name := embeddedFieldIdent(f.Type)
 128  			if name == nil {
 129  				check.errorf(f.Type, InvalidSyntaxTree, "embedded field type %s has no name", f.Type)
 130  				name = ast.NewIdent("_")
 131  				name.NamePos = pos
 132  				addInvalid(name)
 133  				continue
 134  			}
 135  			add(name, true) // struct{p.T} field has position of T
 136  
 137  			// Because we have a name, typ must be of the form T or *T, where T is the name
 138  			// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
 139  			// We must delay this check to the end because we don't want to instantiate
 140  			// (via under(t)) a possibly incomplete type.
 141  
 142  			// for use in the closure below
 143  			embeddedTyp := typ
 144  			embeddedPos := f.Type
 145  
 146  			check.later(func() {
 147  				t, isPtr := deref(embeddedTyp)
 148  				switch u := under(t).(type) {
 149  				case *Basic:
 150  					if !isValid(t) {
 151  						// error was reported before
 152  						return
 153  					}
 154  					// unsafe.Pointer is treated like a regular pointer
 155  					if u.kind == UnsafePointer {
 156  						check.error(embeddedPos, InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer")
 157  					}
 158  				case *Pointer:
 159  					check.error(embeddedPos, InvalidPtrEmbed, "embedded field type cannot be a pointer")
 160  				case *Interface:
 161  					if isTypeParam(t) {
 162  						// The error code here is inconsistent with other error codes for
 163  						// invalid embedding, because this restriction may be relaxed in the
 164  						// future, and so it did not warrant a new error code.
 165  						check.error(embeddedPos, MisplacedTypeParam, "embedded field type cannot be a (pointer to a) type parameter")
 166  						break
 167  					}
 168  					if isPtr {
 169  						check.error(embeddedPos, InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
 170  					}
 171  				}
 172  			}).describef(embeddedPos, "check embedded type %s", embeddedTyp)
 173  		}
 174  	}
 175  
 176  	styp.fields = fields
 177  	styp.tags = tags
 178  	styp.markComplete()
 179  }
 180  
 181  func embeddedFieldIdent(e ast.Expr) *ast.Ident {
 182  	switch e := e.(type) {
 183  	case *ast.Ident:
 184  		return e
 185  	case *ast.StarExpr:
 186  		// *T is valid, but **T is not
 187  		if _, ok := e.X.(*ast.StarExpr); !ok {
 188  			return embeddedFieldIdent(e.X)
 189  		}
 190  	case *ast.SelectorExpr:
 191  		return e.Sel
 192  	case *ast.IndexExpr:
 193  		return embeddedFieldIdent(e.X)
 194  	case *ast.IndexListExpr:
 195  		return embeddedFieldIdent(e.X)
 196  	}
 197  	return nil // invalid embedded field
 198  }
 199  
 200  func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
 201  	if alt := oset.insert(obj); alt != nil {
 202  		err := check.newError(DuplicateDecl)
 203  		err.addf(atPos(pos), "%s redeclared", obj.Name())
 204  		err.addAltDecl(alt)
 205  		err.report()
 206  		return false
 207  	}
 208  	return true
 209  }
 210  
 211  func (check *Checker) tag(t *ast.BasicLit) string {
 212  	if t != nil {
 213  		if t.Kind == token.STRING {
 214  			if val, err := strconv.Unquote(t.Value); err == nil {
 215  				return val
 216  			}
 217  		}
 218  		check.errorf(t, InvalidSyntaxTree, "incorrect tag syntax: %q", t.Value)
 219  	}
 220  	return ""
 221  }
 222