1
2
3
4
5 package noder
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "internal/types/errors"
11 "regexp"
12 "sort"
13
14 "cmd/compile/internal/base"
15 "cmd/compile/internal/rangefunc"
16 "cmd/compile/internal/syntax"
17 "cmd/compile/internal/types2"
18 "cmd/internal/src"
19 )
20
21 var versionErrorRx = regexp.MustCompile(`requires go[0-9]+\.[0-9]+ or later`)
22
23
24
25
26 func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info, map[*syntax.FuncLit]bool) {
27 if base.SyntaxErrors() != 0 {
28 base.ErrorExit()
29 }
30
31
32 files := make([]*syntax.File, len(noders))
33
34
35 fileBaseMap := make(map[*syntax.PosBase]*syntax.File)
36 for i, p := range noders {
37 files[i] = p.file
38
39
40
41
42
43
44 fileBaseMap[p.file.Pos().FileBase()] = p.file
45 }
46
47
48 ctxt := types2.NewContext()
49 importer := gcimports{
50 ctxt: ctxt,
51 packages: make(map[string]*types2.Package),
52 }
53 conf := types2.Config{
54 Context: ctxt,
55 GoVersion: base.Flag.Lang,
56 IgnoreBranchErrors: true,
57 Importer: &importer,
58 Sizes: types2.SizesFor("gc", buildcfg.GOARCH),
59 }
60 if base.Flag.ErrorURL {
61 conf.ErrorURL = " [go.dev/e/%s]"
62 }
63 info := &types2.Info{
64 StoreTypesInSyntax: true,
65 Defs: make(map[*syntax.Name]types2.Object),
66 Uses: make(map[*syntax.Name]types2.Object),
67 Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
68 Implicits: make(map[syntax.Node]types2.Object),
69 Scopes: make(map[syntax.Node]*types2.Scope),
70 Instances: make(map[*syntax.Name]types2.Instance),
71 FileVersions: make(map[*syntax.PosBase]string),
72
73 }
74 conf.Error = func(err error) {
75 terr := err.(types2.Error)
76 msg := terr.Msg
77 if versionErrorRx.MatchString(msg) {
78 fileBase := terr.Pos.FileBase()
79 fileVersion := info.FileVersions[fileBase]
80 file := fileBaseMap[fileBase]
81 if file == nil {
82
83 } else if file.GoVersion == fileVersion {
84
85 msg = fmt.Sprintf("%s (file declares //go:build %s)", msg, fileVersion)
86 } else {
87
88 msg = fmt.Sprintf("%s (-lang was set to %s; check go.mod)", msg, base.Flag.Lang)
89 }
90 }
91 base.ErrorfAt(m.makeXPos(terr.Pos), terr.Code, "%s", msg)
92 }
93
94 pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info)
95 base.ExitIfErrors()
96 if err != nil {
97 base.FatalfAt(src.NoXPos, "conf.Check error: %v", err)
98 }
99
100
101
102 var f cycleFinder
103 for _, file := range files {
104 syntax.Inspect(file, func(n syntax.Node) bool {
105 if n, ok := n.(*syntax.InterfaceType); ok {
106 if f.hasCycle(types2.Unalias(n.GetTypeInfo().Type).(*types2.Interface)) {
107 base.ErrorfAt(m.makeXPos(n.Pos()), errors.InvalidTypeCycle, "invalid recursive type: anonymous interface refers to itself (see https://go.dev/issue/56103)")
108
109 for typ := range f.cyclic {
110 f.cyclic[typ] = false
111 }
112 }
113 return false
114 }
115 return true
116 })
117 }
118 base.ExitIfErrors()
119
120
121
122 {
123 type nihTarg struct {
124 pos src.XPos
125 typ types2.Type
126 }
127 var nihTargs []nihTarg
128
129 for name, inst := range info.Instances {
130 for i := 0; i < inst.TypeArgs.Len(); i++ {
131 if targ := inst.TypeArgs.At(i); isNotInHeap(targ) {
132 nihTargs = append(nihTargs, nihTarg{m.makeXPos(name.Pos()), targ})
133 }
134 }
135 }
136 sort.Slice(nihTargs, func(i, j int) bool {
137 ti, tj := nihTargs[i], nihTargs[j]
138 return ti.pos.Before(tj.pos)
139 })
140 for _, targ := range nihTargs {
141 base.ErrorfAt(targ.pos, 0, "cannot use incomplete (or unallocatable) type as a type argument: %v", targ.typ)
142 }
143 }
144 base.ExitIfErrors()
145
146
147
148 {
149 for _, file := range files {
150 syntax.Inspect(file, func(n syntax.Node) bool {
151 if n, ok := n.(*syntax.TypeDecl); ok {
152 switch n := n.Type.(type) {
153 case *syntax.MapType:
154 typ := n.GetTypeInfo().Type.Underlying().(*types2.Map)
155 if isNotInHeap(typ.Key()) {
156 base.ErrorfAt(m.makeXPos(n.Pos()), 0, "incomplete (or unallocatable) map key not allowed")
157 }
158 if isNotInHeap(typ.Elem()) {
159 base.ErrorfAt(m.makeXPos(n.Pos()), 0, "incomplete (or unallocatable) map value not allowed")
160 }
161 case *syntax.ChanType:
162 typ := n.GetTypeInfo().Type.Underlying().(*types2.Chan)
163 if isNotInHeap(typ.Elem()) {
164 base.ErrorfAt(m.makeXPos(n.Pos()), 0, "chan of incomplete (or unallocatable) type not allowed")
165 }
166 }
167 }
168 return true
169 })
170 }
171 }
172 base.ExitIfErrors()
173
174
175
176
177
178
179
180
181 rangeInfo := rangefunc.Rewrite(pkg, info, files)
182
183 return pkg, info, rangeInfo
184 }
185
186
187 type cycleFinder struct {
188 cyclic map[*types2.Interface]bool
189 }
190
191
192 func (f *cycleFinder) hasCycle(typ *types2.Interface) bool {
193
194
195
196
197 for i := 0; i < typ.NumMethods(); i++ {
198 if f.visit(typ.Method(i).Type()) {
199 return true
200 }
201 }
202 return false
203 }
204
205
206 func (f *cycleFinder) visit(typ0 types2.Type) bool {
207 for {
208 switch typ := types2.Unalias(typ0).(type) {
209 default:
210 base.Fatalf("unexpected type: %T", typ)
211
212 case *types2.Basic, *types2.Named, *types2.TypeParam:
213 return false
214 case *types2.Pointer:
215 typ0 = typ.Elem()
216 case *types2.Array:
217 typ0 = typ.Elem()
218 case *types2.Chan:
219 typ0 = typ.Elem()
220 case *types2.Map:
221 if f.visit(typ.Key()) {
222 return true
223 }
224 typ0 = typ.Elem()
225 case *types2.Slice:
226 typ0 = typ.Elem()
227
228 case *types2.Struct:
229 for i := 0; i < typ.NumFields(); i++ {
230 if f.visit(typ.Field(i).Type()) {
231 return true
232 }
233 }
234 return false
235
236 case *types2.Interface:
237
238 if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 0 {
239 return false
240 }
241
242
243
244
245
246
247
248 if x, ok := f.cyclic[typ]; ok {
249 return x
250 }
251 if f.cyclic == nil {
252 f.cyclic = make(map[*types2.Interface]bool)
253 }
254 f.cyclic[typ] = true
255 if f.hasCycle(typ) {
256 return true
257 }
258 f.cyclic[typ] = false
259 return false
260
261 case *types2.Signature:
262 return f.visit(typ.Params()) || f.visit(typ.Results())
263 case *types2.Tuple:
264 for i := 0; i < typ.Len(); i++ {
265 if f.visit(typ.At(i).Type()) {
266 return true
267 }
268 }
269 return false
270 }
271 }
272 }
273
View as plain text