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  }