github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/noder/irgen.go (about) 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 "github.com/bir3/gocompiler/src/internal/buildcfg" 10 "github.com/bir3/gocompiler/src/internal/types/errors" 11 "regexp" 12 "sort" 13 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 15 "github.com/bir3/gocompiler/src/cmd/compile/internal/rangefunc" 16 "github.com/bir3/gocompiler/src/cmd/compile/internal/syntax" 17 "github.com/bir3/gocompiler/src/cmd/compile/internal/types2" 18 "github.com/bir3/gocompiler/src/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 // TODO(gri) move this code into the type checkers (types2 and go/types) 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(types2.Unalias(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 base.ExitIfErrors() 113 114 // Implementation restriction: we don't allow not-in-heap types to 115 // be used as type arguments (#54765). 116 { 117 type nihTarg struct { 118 pos src.XPos 119 typ types2.Type 120 } 121 var nihTargs []nihTarg 122 123 for name, inst := range info.Instances { 124 for i := 0; i < inst.TypeArgs.Len(); i++ { 125 if targ := inst.TypeArgs.At(i); isNotInHeap(targ) { 126 nihTargs = append(nihTargs, nihTarg{m.makeXPos(name.Pos()), targ}) 127 } 128 } 129 } 130 sort.Slice(nihTargs, func(i, j int) bool { 131 ti, tj := nihTargs[i], nihTargs[j] 132 return ti.pos.Before(tj.pos) 133 }) 134 for _, targ := range nihTargs { 135 base.ErrorfAt(targ.pos, 0, "cannot use incomplete (or unallocatable) type as a type argument: %v", targ.typ) 136 } 137 } 138 base.ExitIfErrors() 139 140 // Rewrite range over function to explicit function calls 141 // with the loop bodies converted into new implicit closures. 142 // We do this now, before serialization to unified IR, so that if the 143 // implicit closures are inlined, we will have the unified IR form. 144 // If we do the rewrite in the back end, like between typecheck and walk, 145 // then the new implicit closure will not have a unified IR inline body, 146 // and bodyReaderFor will fail. 147 rangefunc.Rewrite(pkg, info, files) 148 149 return pkg, info 150 } 151 152 // A cycleFinder detects anonymous interface cycles (go.dev/issue/56103). 153 type cycleFinder struct { 154 cyclic map[*types2.Interface]bool 155 } 156 157 // hasCycle reports whether typ is part of an anonymous interface cycle. 158 func (f *cycleFinder) hasCycle(typ *types2.Interface) bool { 159 // We use Method instead of ExplicitMethod to implicitly expand any 160 // embedded interfaces. Then we just need to walk any anonymous 161 // types, keeping track of *types2.Interface types we visit along 162 // the way. 163 for i := 0; i < typ.NumMethods(); i++ { 164 if f.visit(typ.Method(i).Type()) { 165 return true 166 } 167 } 168 return false 169 } 170 171 // visit recursively walks typ0 to check any referenced interface types. 172 func (f *cycleFinder) visit(typ0 types2.Type) bool { 173 for { // loop for tail recursion 174 switch typ := types2.Unalias(typ0).(type) { 175 default: 176 base.Fatalf("unexpected type: %T", typ) 177 178 case *types2.Basic, *types2.Named, *types2.TypeParam: 179 return false // named types cannot be part of an anonymous cycle 180 case *types2.Pointer: 181 typ0 = typ.Elem() 182 case *types2.Array: 183 typ0 = typ.Elem() 184 case *types2.Chan: 185 typ0 = typ.Elem() 186 case *types2.Map: 187 if f.visit(typ.Key()) { 188 return true 189 } 190 typ0 = typ.Elem() 191 case *types2.Slice: 192 typ0 = typ.Elem() 193 194 case *types2.Struct: 195 for i := 0; i < typ.NumFields(); i++ { 196 if f.visit(typ.Field(i).Type()) { 197 return true 198 } 199 } 200 return false 201 202 case *types2.Interface: 203 // The empty interface (e.g., "any") cannot be part of a cycle. 204 if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 0 { 205 return false 206 } 207 208 // As an optimization, we wait to allocate cyclic here, after 209 // we've found at least one other (non-empty) anonymous 210 // interface. This means when a cycle is present, we need to 211 // make an extra recursive call to actually detect it. But for 212 // most packages, it allows skipping the map allocation 213 // entirely. 214 if x, ok := f.cyclic[typ]; ok { 215 return x 216 } 217 if f.cyclic == nil { 218 f.cyclic = make(map[*types2.Interface]bool) 219 } 220 f.cyclic[typ] = true 221 if f.hasCycle(typ) { 222 return true 223 } 224 f.cyclic[typ] = false 225 return false 226 227 case *types2.Signature: 228 return f.visit(typ.Params()) || f.visit(typ.Results()) 229 case *types2.Tuple: 230 for i := 0; i < typ.Len(); i++ { 231 if f.visit(typ.At(i).Type()) { 232 return true 233 } 234 } 235 return false 236 } 237 } 238 }