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