]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/noder/irgen.go
cmd/compile: update types2.Info.FileVersions API to match go/types
[gostls13.git] / src / cmd / compile / internal / noder / irgen.go
1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
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 // checkFiles configures and runs the types2 checker on the given
24 // parsed source files and then returns the result.
25 func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
26         if base.SyntaxErrors() != 0 {
27                 base.ErrorExit()
28         }
29
30         // setup and syntax error reporting
31         files := make([]*syntax.File, len(noders))
32         // posBaseMap maps all file pos bases back to *syntax.File
33         // for checking Go version mismatched.
34         posBaseMap := make(map[*syntax.PosBase]*syntax.File)
35         for i, p := range noders {
36                 files[i] = p.file
37                 posBaseMap[p.file.Pos().Base()] = p.file
38         }
39
40         // typechecking
41         ctxt := types2.NewContext()
42         importer := gcimports{
43                 ctxt:     ctxt,
44                 packages: make(map[string]*types2.Package),
45         }
46         conf := types2.Config{
47                 Context:            ctxt,
48                 GoVersion:          base.Flag.Lang,
49                 IgnoreBranchErrors: true, // parser already checked via syntax.CheckBranches mode
50                 Importer:           &importer,
51                 Sizes:              types2.SizesFor("gc", buildcfg.GOARCH),
52         }
53         if base.Flag.ErrorURL {
54                 conf.ErrorURL = " [go.dev/e/%s]"
55         }
56         info := &types2.Info{
57                 StoreTypesInSyntax: true,
58                 Defs:               make(map[*syntax.Name]types2.Object),
59                 Uses:               make(map[*syntax.Name]types2.Object),
60                 Selections:         make(map[*syntax.SelectorExpr]*types2.Selection),
61                 Implicits:          make(map[syntax.Node]types2.Object),
62                 Scopes:             make(map[syntax.Node]*types2.Scope),
63                 Instances:          make(map[*syntax.Name]types2.Instance),
64                 FileVersions:       make(map[*syntax.PosBase]string),
65                 // expand as needed
66         }
67         conf.Error = func(err error) {
68                 terr := err.(types2.Error)
69                 msg := terr.Msg
70                 if versionErrorRx.MatchString(msg) {
71                         posBase := terr.Pos.Base()
72                         for !posBase.IsFileBase() { // line directive base
73                                 posBase = posBase.Pos().Base()
74                         }
75                         fileVersion := info.FileVersions[posBase]
76                         file := posBaseMap[posBase]
77                         if file.GoVersion == fileVersion {
78                                 // If we have a version error caused by //go:build, report it.
79                                 msg = fmt.Sprintf("%s (file declares //go:build %s)", msg, fileVersion)
80                         } else {
81                                 // Otherwise, hint at the -lang setting.
82                                 msg = fmt.Sprintf("%s (-lang was set to %s; check go.mod)", msg, base.Flag.Lang)
83                         }
84                 }
85                 base.ErrorfAt(m.makeXPos(terr.Pos), terr.Code, "%s", msg)
86         }
87
88         pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info)
89         base.ExitIfErrors()
90         if err != nil {
91                 base.FatalfAt(src.NoXPos, "conf.Check error: %v", err)
92         }
93
94         // Check for anonymous interface cycles (#56103).
95         if base.Debug.InterfaceCycles == 0 {
96                 var f cycleFinder
97                 for _, file := range files {
98                         syntax.Inspect(file, func(n syntax.Node) bool {
99                                 if n, ok := n.(*syntax.InterfaceType); ok {
100                                         if f.hasCycle(n.GetTypeInfo().Type.(*types2.Interface)) {
101                                                 base.ErrorfAt(m.makeXPos(n.Pos()), errors.InvalidTypeCycle, "invalid recursive type: anonymous interface refers to itself (see https://go.dev/issue/56103)")
102
103                                                 for typ := range f.cyclic {
104                                                         f.cyclic[typ] = false // suppress duplicate errors
105                                                 }
106                                         }
107                                         return false
108                                 }
109                                 return true
110                         })
111                 }
112         }
113         base.ExitIfErrors()
114
115         // Implementation restriction: we don't allow not-in-heap types to
116         // be used as type arguments (#54765).
117         {
118                 type nihTarg struct {
119                         pos src.XPos
120                         typ types2.Type
121                 }
122                 var nihTargs []nihTarg
123
124                 for name, inst := range info.Instances {
125                         for i := 0; i < inst.TypeArgs.Len(); i++ {
126                                 if targ := inst.TypeArgs.At(i); isNotInHeap(targ) {
127                                         nihTargs = append(nihTargs, nihTarg{m.makeXPos(name.Pos()), targ})
128                                 }
129                         }
130                 }
131                 sort.Slice(nihTargs, func(i, j int) bool {
132                         ti, tj := nihTargs[i], nihTargs[j]
133                         return ti.pos.Before(tj.pos)
134                 })
135                 for _, targ := range nihTargs {
136                         base.ErrorfAt(targ.pos, 0, "cannot use incomplete (or unallocatable) type as a type argument: %v", targ.typ)
137                 }
138         }
139         base.ExitIfErrors()
140
141         // Rewrite range over function to explicit function calls
142         // with the loop bodies converted into new implicit closures.
143         // We do this now, before serialization to unified IR, so that if the
144         // implicit closures are inlined, we will have the unified IR form.
145         // If we do the rewrite in the back end, like between typecheck and walk,
146         // then the new implicit closure will not have a unified IR inline body,
147         // and bodyReaderFor will fail.
148         rangefunc.Rewrite(pkg, info, files)
149
150         return pkg, info
151 }
152
153 // A cycleFinder detects anonymous interface cycles (go.dev/issue/56103).
154 type cycleFinder struct {
155         cyclic map[*types2.Interface]bool
156 }
157
158 // hasCycle reports whether typ is part of an anonymous interface cycle.
159 func (f *cycleFinder) hasCycle(typ *types2.Interface) bool {
160         // We use Method instead of ExplicitMethod to implicitly expand any
161         // embedded interfaces. Then we just need to walk any anonymous
162         // types, keeping track of *types2.Interface types we visit along
163         // the way.
164         for i := 0; i < typ.NumMethods(); i++ {
165                 if f.visit(typ.Method(i).Type()) {
166                         return true
167                 }
168         }
169         return false
170 }
171
172 // visit recursively walks typ0 to check any referenced interface types.
173 func (f *cycleFinder) visit(typ0 types2.Type) bool {
174         for { // loop for tail recursion
175                 switch typ := typ0.(type) {
176                 default:
177                         base.Fatalf("unexpected type: %T", typ)
178
179                 case *types2.Basic, *types2.Named, *types2.TypeParam:
180                         return false // named types cannot be part of an anonymous cycle
181                 case *types2.Pointer:
182                         typ0 = typ.Elem()
183                 case *types2.Array:
184                         typ0 = typ.Elem()
185                 case *types2.Chan:
186                         typ0 = typ.Elem()
187                 case *types2.Map:
188                         if f.visit(typ.Key()) {
189                                 return true
190                         }
191                         typ0 = typ.Elem()
192                 case *types2.Slice:
193                         typ0 = typ.Elem()
194
195                 case *types2.Struct:
196                         for i := 0; i < typ.NumFields(); i++ {
197                                 if f.visit(typ.Field(i).Type()) {
198                                         return true
199                                 }
200                         }
201                         return false
202
203                 case *types2.Interface:
204                         // The empty interface (e.g., "any") cannot be part of a cycle.
205                         if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 0 {
206                                 return false
207                         }
208
209                         // As an optimization, we wait to allocate cyclic here, after
210                         // we've found at least one other (non-empty) anonymous
211                         // interface. This means when a cycle is present, we need to
212                         // make an extra recursive call to actually detect it. But for
213                         // most packages, it allows skipping the map allocation
214                         // entirely.
215                         if x, ok := f.cyclic[typ]; ok {
216                                 return x
217                         }
218                         if f.cyclic == nil {
219                                 f.cyclic = make(map[*types2.Interface]bool)
220                         }
221                         f.cyclic[typ] = true
222                         if f.hasCycle(typ) {
223                                 return true
224                         }
225                         f.cyclic[typ] = false
226                         return false
227
228                 case *types2.Signature:
229                         return f.visit(typ.Params()) || f.visit(typ.Results())
230                 case *types2.Tuple:
231                         for i := 0; i < typ.Len(); i++ {
232                                 if f.visit(typ.At(i).Type()) {
233                                         return true
234                                 }
235                         }
236                         return false
237                 }
238         }
239 }