1
2
3
4
5 package types2
6
7 import (
8 "cmd/compile/internal/syntax"
9 . "internal/types/errors"
10 "strconv"
11 )
12
13
14
15
16
17 type Struct struct {
18 fields []*Var
19 tags []string
20 }
21
22
23
24
25
26 func NewStruct(fields []*Var, tags []string) *Struct {
27 var fset objset
28 for _, f := range fields {
29 if f.name != "_" && fset.insert(f) != nil {
30 panic("multiple fields with the same name")
31 }
32 }
33 if len(tags) > len(fields) {
34 panic("more tags than fields")
35 }
36 s := &Struct{fields: fields, tags: tags}
37 s.markComplete()
38 return s
39 }
40
41
42 func (s *Struct) NumFields() int { return len(s.fields) }
43
44
45 func (s *Struct) Field(i int) *Var { return s.fields[i] }
46
47
48 func (s *Struct) Tag(i int) string {
49 if i < len(s.tags) {
50 return s.tags[i]
51 }
52 return ""
53 }
54
55 func (s *Struct) Underlying() Type { return s }
56 func (s *Struct) String() string { return TypeString(s, nil) }
57
58
59
60
61 func (s *Struct) markComplete() {
62 if s.fields == nil {
63 s.fields = make([]*Var, 0)
64 }
65 }
66
67 func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
68 if e.FieldList == nil {
69 styp.markComplete()
70 return
71 }
72
73
74 var fields []*Var
75 var tags []string
76
77
78 var fset objset
79
80
81 var typ Type
82 var tag string
83 add := func(ident *syntax.Name, embedded bool, pos syntax.Pos) {
84 if tag != "" && tags == nil {
85 tags = make([]string, len(fields))
86 }
87 if tags != nil {
88 tags = append(tags, tag)
89 }
90
91 name := ident.Value
92 fld := NewField(pos, check.pkg, name, typ, embedded)
93
94 if name == "_" || check.declareInSet(&fset, pos, fld) {
95 fields = append(fields, fld)
96 check.recordDef(ident, fld)
97 }
98 }
99
100
101
102
103
104 addInvalid := func(ident *syntax.Name, pos syntax.Pos) {
105 typ = Typ[Invalid]
106 tag = ""
107 add(ident, true, pos)
108 }
109
110 var prev syntax.Expr
111 for i, f := range e.FieldList {
112
113
114 if i == 0 || f.Type != prev {
115 typ = check.varType(f.Type)
116 prev = f.Type
117 }
118 tag = ""
119 if i < len(e.TagList) {
120 tag = check.tag(e.TagList[i])
121 }
122 if f.Name != nil {
123
124 add(f.Name, false, f.Name.Pos())
125 } else {
126
127
128
129
130 pos := syntax.StartPos(f.Type)
131 name := embeddedFieldIdent(f.Type)
132 if name == nil {
133 check.errorf(pos, InvalidSyntaxTree, "invalid embedded field type %s", f.Type)
134 name = &syntax.Name{Value: "_"}
135 addInvalid(name, pos)
136 continue
137 }
138 add(name, true, name.Pos())
139
140
141
142
143
144 embeddedTyp := typ
145 embeddedPos := pos
146 check.later(func() {
147 t, isPtr := deref(embeddedTyp)
148 switch u := under(t).(type) {
149 case *Basic:
150 if !isValid(t) {
151
152 return
153 }
154
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
163
164
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 syntax.Expr) *syntax.Name {
182 switch e := e.(type) {
183 case *syntax.Name:
184 return e
185 case *syntax.Operation:
186 if base := ptrBase(e); base != nil {
187
188 if op, _ := base.(*syntax.Operation); op == nil || ptrBase(op) == nil {
189 return embeddedFieldIdent(e.X)
190 }
191 }
192 case *syntax.SelectorExpr:
193 return e.Sel
194 case *syntax.IndexExpr:
195 return embeddedFieldIdent(e.X)
196 }
197 return nil
198 }
199
200 func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) bool {
201 if alt := oset.insert(obj); alt != nil {
202 var err error_
203 err.code = DuplicateDecl
204 err.errorf(pos, "%s redeclared", obj.Name())
205 err.recordAltDecl(alt)
206 check.report(&err)
207 return false
208 }
209 return true
210 }
211
212 func (check *Checker) tag(t *syntax.BasicLit) string {
213
214 if t != nil && !t.Bad {
215 if t.Kind == syntax.StringLit {
216 if val, err := strconv.Unquote(t.Value); err == nil {
217 return val
218 }
219 }
220 check.errorf(t, InvalidSyntaxTree, "incorrect tag syntax: %q", t.Value)
221 }
222 return ""
223 }
224
225 func ptrBase(x *syntax.Operation) syntax.Expr {
226 if x.Op == syntax.Mul && x.Y == nil {
227 return x.X
228 }
229 return nil
230 }
231
View as plain text