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