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 EnableAlias: true,
60 }
61 if base.Flag.ErrorURL {
62 conf.ErrorURL = " [go.dev/e/%s]"
63 }
64 info := &types2.Info{
65 StoreTypesInSyntax: true,
66 Defs: make(map[*syntax.Name]types2.Object),
67 Uses: make(map[*syntax.Name]types2.Object),
68 Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
69 Implicits: make(map[syntax.Node]types2.Object),
70 Scopes: make(map[syntax.Node]*types2.Scope),
71 Instances: make(map[*syntax.Name]types2.Instance),
72 FileVersions: make(map[*syntax.PosBase]string),
73
74 }
75 conf.Error = func(err error) {
76 terr := err.(types2.Error)
77 msg := terr.Msg
78 if versionErrorRx.MatchString(msg) {
79 fileBase := terr.Pos.FileBase()
80 fileVersion := info.FileVersions[fileBase]
81 file := fileBaseMap[fileBase]
82 if file == nil {
83
84 } else if file.GoVersion == fileVersion {
85
86 msg = fmt.Sprintf("%s (file declares //go:build %s)", msg, fileVersion)
87 } else {
88
89 msg = fmt.Sprintf("%s (-lang was set to %s; check go.mod)", msg, base.Flag.Lang)
90 }
91 }
92 base.ErrorfAt(m.makeXPos(terr.Pos), terr.Code, "%s", msg)
93 }
94
95 pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info)
96 base.ExitIfErrors()
97 if err != nil {
98 base.FatalfAt(src.NoXPos, "conf.Check error: %v", err)
99 }
100
101
102
103 var f cycleFinder
104 for _, file := range files {
105 syntax.Inspect(file, func(n syntax.Node) bool {
106 if n, ok := n.(*syntax.InterfaceType); ok {
107 if f.hasCycle(types2.Unalias(n.GetTypeInfo().Type).(*types2.Interface)) {
108 base.ErrorfAt(m.makeXPos(n.Pos()), errors.InvalidTypeCycle, "invalid recursive type: anonymous interface refers to itself (see https://go.dev/issue/56103)")
109
110 for typ := range f.cyclic {
111 f.cyclic[typ] = false
112 }
113 }
114 return false
115 }
116 return true
117 })
118 }
119 base.ExitIfErrors()
120
121
122
123 {
124 type nihTarg struct {
125 pos src.XPos
126 typ types2.Type
127 }
128 var nihTargs []nihTarg
129
130 for name, inst := range info.Instances {
131 for i := 0; i < inst.TypeArgs.Len(); i++ {
132 if targ := inst.TypeArgs.At(i); isNotInHeap(targ) {
133 nihTargs = append(nihTargs, nihTarg{m.makeXPos(name.Pos()), targ})
134 }
135 }
136 }
137 sort.Slice(nihTargs, func(i, j int) bool {
138 ti, tj := nihTargs[i], nihTargs[j]
139 return ti.pos.Before(tj.pos)
140 })
141 for _, targ := range nihTargs {
142 base.ErrorfAt(targ.pos, 0, "cannot use incomplete (or unallocatable) type as a type argument: %v", targ.typ)
143 }
144 }
145 base.ExitIfErrors()
146
147
148
149
150
151
152
153
154 rangeInfo := rangefunc.Rewrite(pkg, info, files)
155
156 return pkg, info, rangeInfo
157 }
158
159
160 type cycleFinder struct {
161 cyclic map[*types2.Interface]bool
162 }
163
164
165 func (f *cycleFinder) hasCycle(typ *types2.Interface) bool {
166
167
168
169
170 for i := 0; i < typ.NumMethods(); i++ {
171 if f.visit(typ.Method(i).Type()) {
172 return true
173 }
174 }
175 return false
176 }
177
178
179 func (f *cycleFinder) visit(typ0 types2.Type) bool {
180 for {
181 switch typ := types2.Unalias(typ0).(type) {
182 default:
183 base.Fatalf("unexpected type: %T", typ)
184
185 case *types2.Basic, *types2.Named, *types2.TypeParam:
186 return false
187 case *types2.Pointer:
188 typ0 = typ.Elem()
189 case *types2.Array:
190 typ0 = typ.Elem()
191 case *types2.Chan:
192 typ0 = typ.Elem()
193 case *types2.Map:
194 if f.visit(typ.Key()) {
195 return true
196 }
197 typ0 = typ.Elem()
198 case *types2.Slice:
199 typ0 = typ.Elem()
200
201 case *types2.Struct:
202 for i := 0; i < typ.NumFields(); i++ {
203 if f.visit(typ.Field(i).Type()) {
204 return true
205 }
206 }
207 return false
208
209 case *types2.Interface:
210
211 if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 0 {
212 return false
213 }
214
215
216
217
218
219
220
221 if x, ok := f.cyclic[typ]; ok {
222 return x
223 }
224 if f.cyclic == nil {
225 f.cyclic = make(map[*types2.Interface]bool)
226 }
227 f.cyclic[typ] = true
228 if f.hasCycle(typ) {
229 return true
230 }
231 f.cyclic[typ] = false
232 return false
233
234 case *types2.Signature:
235 return f.visit(typ.Params()) || f.visit(typ.Results())
236 case *types2.Tuple:
237 for i := 0; i < typ.Len(); i++ {
238 if f.visit(typ.At(i).Type()) {
239 return true
240 }
241 }
242 return false
243 }
244 }
245 }
246
View as plain text