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