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