1
0
mirror of https://github.com/golang/go synced 2024-11-26 04:17:59 -07:00

[dev.regabi] cmd/compile: move helpers into package types [generated]

[git-generate]
cd src/cmd/compile/internal/gc
rf '
	# Type hash (formatting).
	mv typehash TypeHash
	mv TypeHash fmt.go

	# Method sorting.
	mv methcmp MethodsByName
	mv MethodsByName MethodsByName.Len MethodsByName.Swap \
		MethodsByName.Less sort.go

	# Move version check into types.
	# A little surprising, but its keyed off the types.Pkg.
	ex {
		import "cmd/compile/internal/types"
		var p *types.Pkg
		var major, minor int
		langSupported(major, minor, p) -> AllowsGoVersion(p, major, minor)
	}
	rm langSupported
	mv checkLang ParseLangFlag
	mv lang langWant AllowsGoVersion ParseLangFlag \
		parseLang currentLang goVersionRE goversion.go

	mv testdclstack CheckDclstack
	mv CheckDclstack scope.go

	mv algtype1 AlgType
	mv isComplex IsComplex
	mv isFloat IsFloat
	mv isInt IsInt
	mv issimple IsSimple
	mv okforcmp IsOrdered
	mv floatForComplex FloatForComplex
	mv complexForFloat ComplexForFloat
	mv isdirectiface IsDirectIface
	mv isifacemethod IsInterfaceMethod
	mv isMethodApplicable IsMethodApplicable
	mv ispaddedfield IsPaddedField
	mv isRuntimePkg IsRuntimePkg
	mv isReflectPkg IsReflectPkg
	mv methtype ReceiverBaseType
	mv typesymname TypeSymName
	mv typesym TypeSym
	mv typeLookup TypeSymLookup
	mv IsAlias IsDotAlias
	mv isreflexive IsReflexive
	mv simtype SimType

	# The type1.go here is to avoid an undiagnosed bug in rf
	# that does not get the follow-up typechecking right if we
	# move directly to type.go during the mv into package types below.
	mv \
		IsInt IsOrdered IsReflexive \
		IsDirectIface IsInterfaceMethod IsMethodApplicable IsPaddedField \
		IsRuntimePkg IsReflectPkg ReceiverBaseType \
		FloatForComplex ComplexForFloat \
		TypeSym TypeSymLookup TypeSymName \
		typepkg SimType \
		type1.go

	# The alg1.go here is because we are only moving part of alg.go.
	mv typeHasNoAlg TypeHasNoAlg
	mv AlgKind ANOEQ AlgType TypeHasNoAlg IsComparable IncomparableField IsPaddedField alg1.go

	mv IsDotAlias pkg.go

	mv alg1.go algkind_string.go fmt.go goversion.go pkg.go \
		CheckDclstack \ # scope.go
		sort.go type1.go \
		cmd/compile/internal/types
'
cd ../types
rf '
	mv IsDclstackValid isDclstackValid
	mv alg1.go alg.go
	mv type1.go type.go
'

Change-Id: I8bd53b21c7bdd1770e1b525de32f136833e84c9d
Reviewed-on: https://go-review.googlesource.com/c/go/+/279307
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-12-23 00:08:03 -05:00
parent ead4957892
commit 9ee309255a
31 changed files with 691 additions and 666 deletions

View File

@ -13,56 +13,10 @@ import (
"sort"
)
// AlgKind describes the kind of algorithms used for comparing and
// hashing a Type.
type AlgKind int
//go:generate stringer -type AlgKind -trimprefix A
const (
// These values are known by runtime.
ANOEQ AlgKind = iota
AMEM0
AMEM8
AMEM16
AMEM32
AMEM64
AMEM128
ASTRING
AINTER
ANILINTER
AFLOAT32
AFLOAT64
ACPLX64
ACPLX128
// Type can be compared/hashed as regular memory.
AMEM AlgKind = 100
// Type needs special comparison/hashing functions.
ASPECIAL AlgKind = -1
)
// IsComparable reports whether t is a comparable type.
func IsComparable(t *types.Type) bool {
a, _ := algtype1(t)
return a != ANOEQ
}
// IsRegularMemory reports whether t can be compared/hashed as regular memory.
func IsRegularMemory(t *types.Type) bool {
a, _ := algtype1(t)
return a == AMEM
}
// IncomparableField returns an incomparable Field of struct Type t, if any.
func IncomparableField(t *types.Type) *types.Field {
for _, f := range t.FieldSlice() {
if !IsComparable(f.Type) {
return f
}
}
return nil
a, _ := types.AlgType(t)
return a == types.AMEM
}
// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
@ -87,128 +41,28 @@ func EqCanPanic(t *types.Type) bool {
// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
// instead of the general AMEM kind when possible.
func algtype(t *types.Type) AlgKind {
a, _ := algtype1(t)
if a == AMEM {
func algtype(t *types.Type) types.AlgKind {
a, _ := types.AlgType(t)
if a == types.AMEM {
switch t.Width {
case 0:
return AMEM0
return types.AMEM0
case 1:
return AMEM8
return types.AMEM8
case 2:
return AMEM16
return types.AMEM16
case 4:
return AMEM32
return types.AMEM32
case 8:
return AMEM64
return types.AMEM64
case 16:
return AMEM128
return types.AMEM128
}
}
return a
}
// algtype1 returns the AlgKind used for comparing and hashing Type t.
// If it returns ANOEQ, it also returns the component type of t that
// makes it incomparable.
func algtype1(t *types.Type) (AlgKind, *types.Type) {
if t.Broke() {
return AMEM, nil
}
if t.Noalg() {
return ANOEQ, t
}
switch t.Kind() {
case types.TANY, types.TFORW:
// will be defined later.
return ANOEQ, t
case types.TINT8, types.TUINT8, types.TINT16, types.TUINT16,
types.TINT32, types.TUINT32, types.TINT64, types.TUINT64,
types.TINT, types.TUINT, types.TUINTPTR,
types.TBOOL, types.TPTR,
types.TCHAN, types.TUNSAFEPTR:
return AMEM, nil
case types.TFUNC, types.TMAP:
return ANOEQ, t
case types.TFLOAT32:
return AFLOAT32, nil
case types.TFLOAT64:
return AFLOAT64, nil
case types.TCOMPLEX64:
return ACPLX64, nil
case types.TCOMPLEX128:
return ACPLX128, nil
case types.TSTRING:
return ASTRING, nil
case types.TINTER:
if t.IsEmptyInterface() {
return ANILINTER, nil
}
return AINTER, nil
case types.TSLICE:
return ANOEQ, t
case types.TARRAY:
a, bad := algtype1(t.Elem())
switch a {
case AMEM:
return AMEM, nil
case ANOEQ:
return ANOEQ, bad
}
switch t.NumElem() {
case 0:
// We checked above that the element type is comparable.
return AMEM, nil
case 1:
// Single-element array is same as its lone element.
return a, nil
}
return ASPECIAL, nil
case types.TSTRUCT:
fields := t.FieldSlice()
// One-field struct is same as that one field alone.
if len(fields) == 1 && !fields[0].Sym.IsBlank() {
return algtype1(fields[0].Type)
}
ret := AMEM
for i, f := range fields {
// All fields must be comparable.
a, bad := algtype1(f.Type)
if a == ANOEQ {
return ANOEQ, bad
}
// Blank fields, padded fields, fields with non-memory
// equality need special compare.
if a != AMEM || f.Sym.IsBlank() || ispaddedfield(t, i) {
ret = ASPECIAL
}
}
return ret, nil
}
base.Fatalf("algtype1: unexpected type %v", t)
return 0, nil
}
// genhash returns a symbol which is the closure used to compute
// the hash of a value of type t.
// Note: the generated function must match runtime.typehash exactly.
@ -217,37 +71,37 @@ func genhash(t *types.Type) *obj.LSym {
default:
// genhash is only called for types that have equality
base.Fatalf("genhash %v", t)
case AMEM0:
case types.AMEM0:
return sysClosure("memhash0")
case AMEM8:
case types.AMEM8:
return sysClosure("memhash8")
case AMEM16:
case types.AMEM16:
return sysClosure("memhash16")
case AMEM32:
case types.AMEM32:
return sysClosure("memhash32")
case AMEM64:
case types.AMEM64:
return sysClosure("memhash64")
case AMEM128:
case types.AMEM128:
return sysClosure("memhash128")
case ASTRING:
case types.ASTRING:
return sysClosure("strhash")
case AINTER:
case types.AINTER:
return sysClosure("interhash")
case ANILINTER:
case types.ANILINTER:
return sysClosure("nilinterhash")
case AFLOAT32:
case types.AFLOAT32:
return sysClosure("f32hash")
case AFLOAT64:
case types.AFLOAT64:
return sysClosure("f64hash")
case ACPLX64:
case types.ACPLX64:
return sysClosure("c64hash")
case ACPLX128:
case types.ACPLX128:
return sysClosure("c128hash")
case AMEM:
case types.AMEM:
// For other sizes of plain memory, we build a closure
// that calls memhash_varlen. The size of the memory is
// encoded in the first slot of the closure.
closure := typeLookup(fmt.Sprintf(".hashfunc%d", t.Width)).Linksym()
closure := types.TypeSymLookup(fmt.Sprintf(".hashfunc%d", t.Width)).Linksym()
if len(closure.P) > 0 { // already generated
return closure
}
@ -259,7 +113,7 @@ func genhash(t *types.Type) *obj.LSym {
ot = duintptr(closure, ot, uint64(t.Width)) // size encoded in closure
ggloblsym(closure, int32(ot), obj.DUPOK|obj.RODATA)
return closure
case ASPECIAL:
case types.ASPECIAL:
break
}
@ -390,7 +244,7 @@ func genhash(t *types.Type) *obj.LSym {
Curfn = nil
if base.Debug.DclStack != 0 {
testdclstack()
types.CheckDclstack()
}
fn.SetNilCheckDisabled(true)
@ -407,22 +261,22 @@ func genhash(t *types.Type) *obj.LSym {
func hashfor(t *types.Type) ir.Node {
var sym *types.Sym
switch a, _ := algtype1(t); a {
case AMEM:
switch a, _ := types.AlgType(t); a {
case types.AMEM:
base.Fatalf("hashfor with AMEM type")
case AINTER:
case types.AINTER:
sym = Runtimepkg.Lookup("interhash")
case ANILINTER:
case types.ANILINTER:
sym = Runtimepkg.Lookup("nilinterhash")
case ASTRING:
case types.ASTRING:
sym = Runtimepkg.Lookup("strhash")
case AFLOAT32:
case types.AFLOAT32:
sym = Runtimepkg.Lookup("f32hash")
case AFLOAT64:
case types.AFLOAT64:
sym = Runtimepkg.Lookup("f64hash")
case ACPLX64:
case types.ACPLX64:
sym = Runtimepkg.Lookup("c64hash")
case ACPLX128:
case types.ACPLX128:
sym = Runtimepkg.Lookup("c128hash")
default:
// Note: the caller of hashfor ensured that this symbol
@ -457,40 +311,40 @@ func sysClosure(name string) *obj.LSym {
// equality for two objects of type t.
func geneq(t *types.Type) *obj.LSym {
switch algtype(t) {
case ANOEQ:
case types.ANOEQ:
// The runtime will panic if it tries to compare
// a type with a nil equality function.
return nil
case AMEM0:
case types.AMEM0:
return sysClosure("memequal0")
case AMEM8:
case types.AMEM8:
return sysClosure("memequal8")
case AMEM16:
case types.AMEM16:
return sysClosure("memequal16")
case AMEM32:
case types.AMEM32:
return sysClosure("memequal32")
case AMEM64:
case types.AMEM64:
return sysClosure("memequal64")
case AMEM128:
case types.AMEM128:
return sysClosure("memequal128")
case ASTRING:
case types.ASTRING:
return sysClosure("strequal")
case AINTER:
case types.AINTER:
return sysClosure("interequal")
case ANILINTER:
case types.ANILINTER:
return sysClosure("nilinterequal")
case AFLOAT32:
case types.AFLOAT32:
return sysClosure("f32equal")
case AFLOAT64:
case types.AFLOAT64:
return sysClosure("f64equal")
case ACPLX64:
case types.ACPLX64:
return sysClosure("c64equal")
case ACPLX128:
case types.ACPLX128:
return sysClosure("c128equal")
case AMEM:
case types.AMEM:
// make equality closure. The size of the type
// is encoded in the closure.
closure := typeLookup(fmt.Sprintf(".eqfunc%d", t.Width)).Linksym()
closure := types.TypeSymLookup(fmt.Sprintf(".eqfunc%d", t.Width)).Linksym()
if len(closure.P) != 0 {
return closure
}
@ -502,7 +356,7 @@ func geneq(t *types.Type) *obj.LSym {
ot = duintptr(closure, ot, uint64(t.Width))
ggloblsym(closure, int32(ot), obj.DUPOK|obj.RODATA)
return closure
case ASPECIAL:
case types.ASPECIAL:
break
}
@ -766,7 +620,7 @@ func geneq(t *types.Type) *obj.LSym {
Curfn = nil
if base.Debug.DclStack != 0 {
testdclstack()
types.CheckDclstack()
}
// Disable checknils while compiling this code.
@ -904,7 +758,7 @@ func memrun(t *types.Type, start int) (size int64, next int) {
break
}
// Stop run after a padded field.
if ispaddedfield(t, next-1) {
if types.IsPaddedField(t, next-1) {
break
}
// Also, stop before a blank or non-memory field.
@ -914,16 +768,3 @@ func memrun(t *types.Type, start int) (size int64, next int) {
}
return t.Field(next-1).End() - t.Field(start).Offset, next
}
// ispaddedfield reports whether the i'th field of struct type t is followed
// by padding.
func ispaddedfield(t *types.Type, i int) bool {
if !t.IsStruct() {
base.Fatalf("ispaddedfield called non-struct %v", t)
}
end := t.Width
if i+1 < t.NumFields() {
end = t.Field(i + 1).Offset
}
return t.Field(i).End() != end
}

View File

@ -40,7 +40,7 @@ func expandiface(t *types.Type) {
switch prev := seen[m.Sym]; {
case prev == nil:
seen[m.Sym] = m
case langSupported(1, 14, t.Pkg()) && !explicit && types.Identical(m.Type, prev.Type):
case types.AllowsGoVersion(t.Pkg(), 1, 14) && !explicit && types.Identical(m.Type, prev.Type):
return
default:
base.ErrorfAt(m.Pos, "duplicate method %s", m.Sym.Name)
@ -84,7 +84,7 @@ func expandiface(t *types.Type) {
}
}
sort.Sort(methcmp(methods))
sort.Sort(types.MethodsByName(methods))
if int64(len(methods)) >= MaxWidth/int64(Widthptr) {
base.ErrorfAt(typePos(t), "interface too large")
@ -325,8 +325,8 @@ func dowidth(t *types.Type) {
// simtype == 0 during bootstrap
default:
if simtype[t.Kind()] != 0 {
et = simtype[t.Kind()]
if types.SimType[t.Kind()] != 0 {
et = types.SimType[t.Kind()]
}
}

View File

@ -242,11 +242,11 @@ func operandType(op ir.Op, t *types.Type) *types.Type {
switch op {
case ir.OCOMPLEX:
if t.IsComplex() {
return floatForComplex(t)
return types.FloatForComplex(t)
}
case ir.OREAL, ir.OIMAG:
if t.IsFloat() {
return complexForFloat(t)
return types.ComplexForFloat(t)
}
default:
if okfor[op][t.Kind()] {
@ -377,7 +377,7 @@ func doesoverflow(v constant.Value, t *types.Type) bool {
return math.IsInf(f, 0)
}
case t.IsComplex():
ft := floatForComplex(t)
ft := types.FloatForComplex(t)
return doesoverflow(constant.Real(v), ft) || doesoverflow(constant.Imag(v), ft)
}
base.Fatalf("doesoverflow: %v, %v", v, t)

View File

@ -28,12 +28,6 @@ func NoWriteBarrierRecCheck() {
var nowritebarrierrecCheck *nowritebarrierrecChecker
func testdclstack() {
if !types.IsDclstackValid() {
base.Fatalf("mark left on the dclstack")
}
}
// redeclare emits a diagnostic about symbol s being redeclared at pos.
func redeclare(pos src.XPos, s *types.Sym, where string) {
if !s.Lastlineno.IsKnown() {
@ -555,13 +549,6 @@ func fakeRecvField() *types.Field {
return types.NewField(src.NoXPos, nil, types.FakeRecvType())
}
// isifacemethod reports whether (field) m is
// an interface method. Such methods have the
// special receiver type types.FakeRecvType().
func isifacemethod(f *types.Type) bool {
return f.Recv().Type == types.FakeRecvType()
}
// turn a parsed function declaration into a type
func functype(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
funarg := func(n *ir.Field) *types.Field {
@ -685,7 +672,7 @@ func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bo
return nil
}
mt := methtype(rf.Type)
mt := types.ReceiverBaseType(rf.Type)
if mt == nil || mt.Sym() == nil {
pa := rf.Type
t := pa
@ -883,7 +870,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
if fn.Class_ != ir.PFUNC || fn.Name().Defn == nil {
return
}
if !isRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
if !types.IsRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
return
}

View File

@ -579,7 +579,7 @@ func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
}
case ir.OCONVIFACE:
n := n.(*ir.ConvExpr)
if !n.X.Type().IsInterface() && !isdirectiface(n.X.Type()) {
if !n.X.Type().IsInterface() && !types.IsDirectIface(n.X.Type()) {
k = e.spill(k, n)
}
e.expr(k.note(n, "interface-converted"), n.X)
@ -1064,7 +1064,7 @@ func (k EscHole) deref(where ir.Node, why string) EscHole { return k.shift(1).no
func (k EscHole) addr(where ir.Node, why string) EscHole { return k.shift(-1).note(where, why) }
func (k EscHole) dotType(t *types.Type, where ir.Node, why string) EscHole {
if !t.IsInterface() && !isdirectiface(t) {
if !t.IsInterface() && !types.IsDirectIface(t) {
k = k.shift(1)
}
return k.note(where, why)

View File

@ -5,7 +5,6 @@
package gc
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
@ -34,22 +33,6 @@ var (
smallArrayBytes = int64(256)
)
// isRuntimePkg reports whether p is package runtime.
func isRuntimePkg(p *types.Pkg) bool {
if base.Flag.CompilingRuntime && p == types.LocalPkg {
return true
}
return p.Path == "runtime"
}
// isReflectPkg reports whether p is package reflect.
func isReflectPkg(p *types.Pkg) bool {
if p == types.LocalPkg {
return base.Ctxt.Pkgpath == "reflect"
}
return p.Path == "reflect"
}
// Slices in the runtime are represented by three components:
//
// type slice struct {
@ -101,15 +84,6 @@ var gopkg *types.Pkg // pseudo-package for method symbols on anonymous receiver
var zerosize int64
var simtype [types.NTYPE]types.Kind
var (
isInt [types.NTYPE]bool
isFloat [types.NTYPE]bool
isComplex [types.NTYPE]bool
issimple [types.NTYPE]bool
)
var (
okforeq [types.NTYPE]bool
okforadd [types.NTYPE]bool
@ -121,8 +95,6 @@ var (
okforarith [types.NTYPE]bool
)
var okforcmp [types.NTYPE]bool
var (
okfor [ir.OEND][]bool
iscmp [ir.OEND]bool

View File

@ -283,7 +283,7 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
funcbody()
if base.Debug.DclStack != 0 {
testdclstack()
types.CheckDclstack()
}
typecheckFunc(fn)

View File

@ -461,7 +461,7 @@ func (p *iexporter) doDecl(n *ir.Name) {
w.value(n.Type(), n.Val())
case ir.OTYPE:
if IsAlias(n.Sym()) {
if types.IsDotAlias(n.Sym()) {
// Alias.
w.tag('A')
w.pos(n.Pos())
@ -1028,8 +1028,8 @@ func (w *exportWriter) typeExt(t *types.Type) {
w.int64(i[1])
return
}
w.symIdx(typesym(t))
w.symIdx(typesym(t.PtrTo()))
w.symIdx(types.TypeSym(t))
w.symIdx(types.TypeSym(t.PtrTo()))
}
// Inline bodies.

View File

@ -350,7 +350,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
// runtime.throw is a "cheap call" like panic in normal code.
if n.X.Op() == ir.ONAME {
name := n.X.(*ir.Name)
if name.Class_ == ir.PFUNC && isRuntimePkg(name.Sym().Pkg) {
if name.Class_ == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
fn := name.Sym().Name
if fn == "getcallerpc" || fn == "getcallersp" {
return errors.New("call to " + fn)
@ -382,7 +382,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
if t == nil {
base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
}
if isRuntimePkg(n.X.Sym().Pkg) {
if types.IsRuntimePkg(n.X.Sym().Pkg) {
fn := n.X.Sym().Name
if fn == "heapBits.nextArena" {
// Special case: explicitly allow
@ -589,7 +589,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
// Prevent inlining some reflect.Value methods when using checkptr,
// even when package reflect was compiled without it (#35073).
n := n.(*ir.CallExpr)
if s := n.X.Sym(); base.Debug.Checkptr != 0 && isReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
if s := n.X.Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
return n
}
}
@ -844,7 +844,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
return n
}
if base.Flag.Cfg.Instrumenting && isRuntimePkg(fn.Sym().Pkg) {
if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
// Runtime package must not be instrumented.
// Instrument skips runtime package. However, some runtime code can be
// inlined into other packages and instrumented there. To avoid this,

View File

@ -23,13 +23,11 @@ import (
"flag"
"fmt"
"go/constant"
"internal/goversion"
"io"
"io/ioutil"
"log"
"os"
"path"
"regexp"
"runtime"
"sort"
"strconv"
@ -153,7 +151,7 @@ func Main(archInit func(*Arch)) {
log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
}
checkLang()
types.ParseLangFlag()
if base.Flag.SymABIs != "" {
readSymABIs(base.Flag.SymABIs, base.Ctxt.Pkgpath)
@ -858,7 +856,7 @@ func clearImports() {
s.Def = nil
continue
}
if IsAlias(s) {
if types.IsDotAlias(s) {
// throw away top-level name left over
// from previous import . "x"
// We'll report errors after type checking in checkDotImports.
@ -873,10 +871,6 @@ func clearImports() {
}
}
func IsAlias(sym *types.Sym) bool {
return sym.Def != nil && sym.Def.Sym() != sym
}
// recordFlags records the specified command-line flags to be placed
// in the DWARF info.
func recordFlags(flags ...string) {
@ -944,89 +938,6 @@ func recordPackageName() {
s.P = []byte(types.LocalPkg.Name)
}
// currentLang returns the current language version.
func currentLang() string {
return fmt.Sprintf("go1.%d", goversion.Version)
}
// goVersionRE is a regular expression that matches the valid
// arguments to the -lang flag.
var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
// A lang is a language version broken into major and minor numbers.
type lang struct {
major, minor int
}
// langWant is the desired language version set by the -lang flag.
// If the -lang flag is not set, this is the zero value, meaning that
// any language version is supported.
var langWant lang
// AllowsGoVersion reports whether a particular package
// is allowed to use Go version major.minor.
// We assume the imported packages have all been checked,
// so we only have to check the local package against the -lang flag.
func AllowsGoVersion(pkg *types.Pkg, major, minor int) bool {
if pkg == nil {
// TODO(mdempsky): Set Pkg for local types earlier.
pkg = types.LocalPkg
}
if pkg != types.LocalPkg {
// Assume imported packages passed type-checking.
return true
}
if langWant.major == 0 && langWant.minor == 0 {
return true
}
return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
}
func langSupported(major, minor int, pkg *types.Pkg) bool {
return AllowsGoVersion(pkg, major, minor)
}
// checkLang verifies that the -lang flag holds a valid value, and
// exits if not. It initializes data used by langSupported.
func checkLang() {
if base.Flag.Lang == "" {
return
}
var err error
langWant, err = parseLang(base.Flag.Lang)
if err != nil {
log.Fatalf("invalid value %q for -lang: %v", base.Flag.Lang, err)
}
if def := currentLang(); base.Flag.Lang != def {
defVers, err := parseLang(def)
if err != nil {
log.Fatalf("internal error parsing default lang %q: %v", def, err)
}
if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
log.Fatalf("invalid value %q for -lang: max known version is %q", base.Flag.Lang, def)
}
}
}
// parseLang parses a -lang option into a langVer.
func parseLang(s string) (lang, error) {
matches := goVersionRE.FindStringSubmatch(s)
if matches == nil {
return lang{}, fmt.Errorf(`should be something like "go1.12"`)
}
major, err := strconv.Atoi(matches[1])
if err != nil {
return lang{}, err
}
minor, err := strconv.Atoi(matches[2])
if err != nil {
return lang{}, err
}
return lang{major: major, minor: minor}, nil
}
// useNewABIWrapGen returns TRUE if the compiler should generate an
// ABI wrapper for the function 'f'.
func useABIWrapGen(f *ir.Func) bool {

View File

@ -72,7 +72,7 @@ func parseFiles(filenames []string) uint {
base.ErrorExit()
}
// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
testdclstack()
types.CheckDclstack()
}
for _, p := range noders {
@ -485,7 +485,7 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) ir.Node {
}
nod := ir.NewDecl(p.pos(decl), ir.ODCLTYPE, n)
if n.Alias() && !langSupported(1, 9, types.LocalPkg) {
if n.Alias() && !types.AllowsGoVersion(types.LocalPkg, 1, 9) {
base.ErrorfAt(nod.Pos(), "type aliases only supported as of -lang=go1.9")
}
return nod
@ -1401,7 +1401,7 @@ func (p *noder) binOp(op syntax.Operator) ir.Op {
// literal is not compatible with the current language version.
func checkLangCompat(lit *syntax.BasicLit) {
s := lit.Value
if len(s) <= 2 || langSupported(1, 13, types.LocalPkg) {
if len(s) <= 2 || types.AllowsGoVersion(types.LocalPkg, 1, 13) {
return
}
// len(s) > 2

View File

@ -259,7 +259,7 @@ func dumpGlobalConst(n ir.Node) {
return
}
}
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, typesymname(t), ir.IntVal(t, v))
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
}
func dumpglobls(externs []ir.Node) {

View File

@ -1332,7 +1332,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
case ir.ODOTTYPE, ir.ODOTTYPE2:
n := n.(*ir.TypeAssertExpr)
n.X = o.expr(n.X, nil)
if !isdirectiface(n.Type()) || base.Flag.Cfg.Instrumenting {
if !types.IsDirectIface(n.Type()) || base.Flag.Cfg.Instrumenting {
return o.copyExprClear(n)
}
return n

View File

@ -552,7 +552,7 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class_, n)
}
typename := dwarf.InfoPrefix + typesymname(n.Type())
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
delete(fnsym.Func().Autot, ngotype(n).Linksym())
inlIndex := 0
if base.Flag.GenDwarfInl > 1 {
@ -655,7 +655,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
decls = append(decls, n)
continue
}
typename := dwarf.InfoPrefix + typesymname(n.Type())
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
decls = append(decls, n)
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
isReturnValue := (n.Class_ == ir.PPARAMOUT)

View File

@ -493,7 +493,7 @@ func isMapClear(n *ir.RangeStmt) bool {
}
// Keys where equality is not reflexive can not be deleted from maps.
if !isreflexive(m.Type().Key()) {
if !types.IsReflexive(m.Type().Key()) {
return false
}

View File

@ -135,7 +135,7 @@ func bmap(t *types.Type) *types.Type {
dowidth(bucket)
// Check invariants that map code depends on.
if !IsComparable(t.Key()) {
if !types.IsComparable(t.Key()) {
base.Fatalf("unsupported map key type for %v", t)
}
if BUCKETSIZE < 8 {
@ -373,7 +373,7 @@ func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
// Generates stub functions as needed.
func methods(t *types.Type) []*Sig {
// method type
mt := methtype(t)
mt := types.ReceiverBaseType(t)
if mt == nil {
return nil
@ -383,7 +383,7 @@ func methods(t *types.Type) []*Sig {
// type stored in interface word
it := t
if !isdirectiface(it) {
if !types.IsDirectIface(it) {
it = types.NewPtr(t)
}
@ -410,7 +410,7 @@ func methods(t *types.Type) []*Sig {
// if pointer receiver but non-pointer t and
// this is not an embedded pointer inside a struct,
// method does not apply.
if !isMethodApplicable(t, f) {
if !types.IsMethodApplicable(t, f) {
continue
}
@ -848,7 +848,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
ot := 0
ot = duintptr(lsym, ot, uint64(t.Width))
ot = duintptr(lsym, ot, uint64(ptrdata))
ot = duint32(lsym, ot, typehash(t))
ot = duint32(lsym, ot, types.TypeHash(t))
var tflag uint8
if uncommonSize(t) != 0 {
@ -895,7 +895,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
ot = duint8(lsym, ot, t.Align) // fieldAlign
i = kinds[t.Kind()]
if isdirectiface(t) {
if types.IsDirectIface(t) {
i |= objabi.KindDirectIface
}
if useGCProg {
@ -923,40 +923,6 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
return ot
}
// typeHasNoAlg reports whether t does not have any associated hash/eq
// algorithms because t, or some component of t, is marked Noalg.
func typeHasNoAlg(t *types.Type) bool {
a, bad := algtype1(t)
return a == ANOEQ && bad.Noalg()
}
func typesymname(t *types.Type) string {
name := t.ShortString()
// Use a separate symbol name for Noalg types for #17752.
if typeHasNoAlg(t) {
name = "noalg." + name
}
return name
}
// Fake package for runtime type info (headers)
// Don't access directly, use typeLookup below.
var (
typepkgmu sync.Mutex // protects typepkg lookups
typepkg = types.NewPkg("type", "type")
)
func typeLookup(name string) *types.Sym {
typepkgmu.Lock()
s := typepkg.Lookup(name)
typepkgmu.Unlock()
return s
}
func typesym(t *types.Type) *types.Sym {
return typeLookup(typesymname(t))
}
// tracksym returns the symbol for tracking use of field/method f, assumed
// to be a member of struct/interface type t.
func tracksym(t *types.Type, f *types.Field) *types.Sym {
@ -965,7 +931,7 @@ func tracksym(t *types.Type, f *types.Field) *types.Sym {
func typesymprefix(prefix string, t *types.Type) *types.Sym {
p := prefix + "." + t.ShortString()
s := typeLookup(p)
s := types.TypeSymLookup(p)
// This function is for looking up type-related generated functions
// (e.g. eq and hash). Make sure they are indeed generated.
@ -982,7 +948,7 @@ func typenamesym(t *types.Type) *types.Sym {
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
base.Fatalf("typenamesym %v", t)
}
s := typesym(t)
s := types.TypeSym(t)
signatmu.Lock()
addsignat(t)
signatmu.Unlock()
@ -1025,52 +991,6 @@ func itabname(t, itype *types.Type) *ir.AddrExpr {
return n
}
// isreflexive reports whether t has a reflexive equality operator.
// That is, if x==x for all x of type t.
func isreflexive(t *types.Type) bool {
switch t.Kind() {
case types.TBOOL,
types.TINT,
types.TUINT,
types.TINT8,
types.TUINT8,
types.TINT16,
types.TUINT16,
types.TINT32,
types.TUINT32,
types.TINT64,
types.TUINT64,
types.TUINTPTR,
types.TPTR,
types.TUNSAFEPTR,
types.TSTRING,
types.TCHAN:
return true
case types.TFLOAT32,
types.TFLOAT64,
types.TCOMPLEX64,
types.TCOMPLEX128,
types.TINTER:
return false
case types.TARRAY:
return isreflexive(t.Elem())
case types.TSTRUCT:
for _, t1 := range t.Fields().Slice() {
if !isreflexive(t1.Type) {
return false
}
}
return true
default:
base.Fatalf("bad type for map key: %v", t)
return false
}
}
// needkeyupdate reports whether map updates with t as a key
// need the key to be updated.
func needkeyupdate(t *types.Type) bool {
@ -1139,7 +1059,7 @@ func dtypesym(t *types.Type) *obj.LSym {
base.Fatalf("dtypesym %v", t)
}
s := typesym(t)
s := types.TypeSym(t)
lsym := s.Linksym()
if s.Siggen() {
return lsym
@ -1310,7 +1230,7 @@ func dtypesym(t *types.Type) *obj.LSym {
ot = duint8(lsym, ot, uint8(t.Elem().Width))
}
ot = duint16(lsym, ot, uint16(bmap(t).Width))
if isreflexive(t.Key()) {
if types.IsReflexive(t.Key()) {
flags |= 4 // reflexive key
}
if needkeyupdate(t.Key()) {
@ -1404,7 +1324,7 @@ func dtypesym(t *types.Type) *obj.LSym {
}
}
// Do not put Noalg types in typelinks. See issue #22605.
if typeHasNoAlg(t) {
if types.TypeHasNoAlg(t) {
keep = false
}
lsym.Set(obj.AttrMakeTypelink, keep)
@ -1528,7 +1448,7 @@ func dumpsignats() {
signats = signats[:0]
// Transfer entries to a slice and sort, for reproducible builds.
for _, t := range signatslice {
signats = append(signats, typeAndStr{t: t, short: typesymname(t), regular: t.String()})
signats = append(signats, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
delete(signatset, t)
}
signatslice = signatslice[:0]
@ -1556,7 +1476,7 @@ func dumptabs() {
// }
o := dsymptr(i.lsym, 0, dtypesym(i.itype), 0)
o = dsymptr(i.lsym, o, dtypesym(i.t), 0)
o = duint32(i.lsym, o, typehash(i.t)) // copy of type hash
o = duint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash
o += 4 // skip unused field
for _, fn := range genfun(i.t, i.itype) {
o = dsymptr(i.lsym, o, fn, 0) // method pointer for each method

View File

@ -324,7 +324,7 @@ func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *type
addrsym(l, loff, itab.X.(*ir.Name), 0)
// Emit data.
if isdirectiface(val.Type()) {
if types.IsDirectIface(val.Type()) {
if val.Op() == ir.ONIL {
// Nil is zero, nothing to do.
return true
@ -506,7 +506,7 @@ func isStaticCompositeLiteral(n ir.Node) bool {
if val.Type().IsInterface() {
return val.Op() == ir.ONIL
}
if isdirectiface(val.Type()) && val.Op() == ir.ONIL {
if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
return true
}
return isStaticCompositeLiteral(val)

View File

@ -1916,28 +1916,6 @@ func (s *state) ssaOp(op ir.Op, t *types.Type) ssa.Op {
return x
}
func floatForComplex(t *types.Type) *types.Type {
switch t.Kind() {
case types.TCOMPLEX64:
return types.Types[types.TFLOAT32]
case types.TCOMPLEX128:
return types.Types[types.TFLOAT64]
}
base.Fatalf("unexpected type: %v", t)
return nil
}
func complexForFloat(t *types.Type) *types.Type {
switch t.Kind() {
case types.TFLOAT32:
return types.Types[types.TCOMPLEX64]
case types.TFLOAT64:
return types.Types[types.TCOMPLEX128]
}
base.Fatalf("unexpected type: %v", t)
return nil
}
type opAndTwoTypes struct {
op ir.Op
etype1 types.Kind
@ -2458,8 +2436,8 @@ func (s *state) expr(n ir.Node) *ssa.Value {
} else {
s.Fatalf("weird complex conversion %v -> %v", ft, tt)
}
ftp := floatForComplex(ft)
ttp := floatForComplex(tt)
ftp := types.FloatForComplex(ft)
ttp := types.FloatForComplex(tt)
return s.newValue2(ssa.OpComplexMake, tt,
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
@ -2479,7 +2457,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
a := s.expr(n.X)
b := s.expr(n.Y)
if n.X.Type().IsComplex() {
pt := floatForComplex(n.X.Type())
pt := types.FloatForComplex(n.X.Type())
op := s.ssaOp(ir.OEQ, pt)
r := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
i := s.newValueOrSfCall2(op, types.Types[types.TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
@ -2516,7 +2494,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
mulop := ssa.OpMul64F
addop := ssa.OpAdd64F
subop := ssa.OpSub64F
pt := floatForComplex(n.Type()) // Could be Float32 or Float64
pt := types.FloatForComplex(n.Type()) // Could be Float32 or Float64
wt := types.Types[types.TFLOAT64] // Compute in Float64 to minimize cancellation error
areal := s.newValue1(ssa.OpComplexReal, pt, a)
@ -2560,7 +2538,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
addop := ssa.OpAdd64F
subop := ssa.OpSub64F
divop := ssa.OpDiv64F
pt := floatForComplex(n.Type()) // Could be Float32 or Float64
pt := types.FloatForComplex(n.Type()) // Could be Float32 or Float64
wt := types.Types[types.TFLOAT64] // Compute in Float64 to minimize cancellation error
areal := s.newValue1(ssa.OpComplexReal, pt, a)
@ -2606,7 +2584,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
a := s.expr(n.X)
b := s.expr(n.Y)
if n.Type().IsComplex() {
pt := floatForComplex(n.Type())
pt := types.FloatForComplex(n.Type())
op := s.ssaOp(n.Op(), pt)
return s.newValue2(ssa.OpComplexMake, n.Type(),
s.newValueOrSfCall2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
@ -2694,7 +2672,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
n := n.(*ir.UnaryExpr)
a := s.expr(n.X)
if n.Type().IsComplex() {
tp := floatForComplex(n.Type())
tp := types.FloatForComplex(n.Type())
negop := s.ssaOp(n.Op(), tp)
return s.newValue2(ssa.OpComplexMake, n.Type(),
s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
@ -6147,7 +6125,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
}
// Converting to a concrete type.
direct := isdirectiface(n.Type())
direct := types.IsDirectIface(n.Type())
itab := s.newValue1(ssa.OpITab, byteptr, iface) // type word of interface
if base.Debug.TypeAssert > 0 {
base.WarnfAt(n.Pos(), "type assertion inlined")
@ -6442,7 +6420,7 @@ func emitStackObjects(e *ssafn, pp *Progs) {
// in which case the offset is relative to argp.
// Locals have a negative Xoffset, in which case the offset is relative to varp.
off = duintptr(x, off, uint64(v.FrameOffset()))
if !typesym(v.Type()).Siggen() {
if !types.TypeSym(v.Type()).Siggen() {
e.Fatalf(v.Pos(), "stack object's type symbol not generated for type %s", v.Type())
}
off = dsymptr(x, off, dtypesym(v.Type()), 0)

View File

@ -9,8 +9,6 @@ import (
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"crypto/md5"
"encoding/binary"
"fmt"
"go/constant"
"sort"
@ -170,13 +168,6 @@ func NewName(s *types.Sym) *ir.Name {
return n
}
// methcmp sorts methods by symbol.
type methcmp []*types.Field
func (x methcmp) Len() int { return len(x) }
func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }
func nodintconst(v int64) ir.Node {
return ir.NewLiteral(constant.MakeInt64(v))
}
@ -212,41 +203,6 @@ func isptrto(t *types.Type, et types.Kind) bool {
return true
}
// methtype returns the underlying type, if any,
// that owns methods with receiver parameter t.
// The result is either a named type or an anonymous struct.
func methtype(t *types.Type) *types.Type {
if t == nil {
return nil
}
// Strip away pointer if it's there.
if t.IsPtr() {
if t.Sym() != nil {
return nil
}
t = t.Elem()
if t == nil {
return nil
}
}
// Must be a named type or anonymous struct.
if t.Sym() == nil && !t.IsStruct() {
return nil
}
// Check types.
if issimple[t.Kind()] {
return t
}
switch t.Kind() {
case types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRING, types.TSTRUCT:
return t
}
return nil
}
// Is type src assignment compatible to type dst?
// If so, return op code to use in conversion.
// If not, return OXXX. In this case, the string return parameter may
@ -294,7 +250,7 @@ func assignop(src, dst *types.Type) (ir.Op, string) {
// gets added to itabs early, which allows
// us to de-virtualize calls through this
// type/interface pair later. See peekitabs in reflect.go
if isdirectiface(src) && !dst.IsEmptyInterface() {
if types.IsDirectIface(src) && !dst.IsEmptyInterface() {
NeedITab(src, dst)
}
@ -429,7 +385,7 @@ func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
// 4. src and dst are both integer or floating point types.
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
if simtype[src.Kind()] == simtype[dst.Kind()] {
if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
return ir.OCONVNOP, ""
}
return ir.OCONV, ""
@ -437,7 +393,7 @@ func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
// 5. src and dst are both complex types.
if src.IsComplex() && dst.IsComplex() {
if simtype[src.Kind()] == simtype[dst.Kind()] {
if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
return ir.OCONVNOP, ""
}
return ir.OCONV, ""
@ -574,15 +530,6 @@ func syslook(name string) *ir.Name {
return ir.AsNode(s.Def).(*ir.Name)
}
// typehash computes a hash value for type t to use in type switch statements.
func typehash(t *types.Type) uint32 {
p := t.LongString()
// Using MD5 is overkill, but reduces accidental collisions.
h := md5.Sum([]byte(p))
return binary.LittleEndian.Uint32(h[:4])
}
// updateHasCall checks whether expression n contains any function
// calls and sets the n.HasCall flag if so.
func updateHasCall(n ir.Node) {
@ -627,25 +574,25 @@ func calcHasCall(n ir.Node) bool {
// so we ensure they are evaluated first.
case ir.OADD, ir.OSUB, ir.OMUL:
n := n.(*ir.BinaryExpr)
if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) {
if thearch.SoftFloat && (types.IsFloat[n.Type().Kind()] || types.IsComplex[n.Type().Kind()]) {
return true
}
return n.X.HasCall() || n.Y.HasCall()
case ir.ONEG:
n := n.(*ir.UnaryExpr)
if thearch.SoftFloat && (isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) {
if thearch.SoftFloat && (types.IsFloat[n.Type().Kind()] || types.IsComplex[n.Type().Kind()]) {
return true
}
return n.X.HasCall()
case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
n := n.(*ir.BinaryExpr)
if thearch.SoftFloat && (isFloat[n.X.Type().Kind()] || isComplex[n.X.Type().Kind()]) {
if thearch.SoftFloat && (types.IsFloat[n.X.Type().Kind()] || types.IsComplex[n.X.Type().Kind()]) {
return true
}
return n.X.HasCall() || n.Y.HasCall()
case ir.OCONV:
n := n.(*ir.ConvExpr)
if thearch.SoftFloat && ((isFloat[n.Type().Kind()] || isComplex[n.Type().Kind()]) || (isFloat[n.X.Type().Kind()] || isComplex[n.X.Type().Kind()])) {
if thearch.SoftFloat && ((types.IsFloat[n.Type().Kind()] || types.IsComplex[n.Type().Kind()]) || (types.IsFloat[n.X.Type().Kind()] || types.IsComplex[n.X.Type().Kind()])) {
return true
}
return n.X.HasCall()
@ -893,7 +840,7 @@ func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool)
// If t is a defined pointer type, then x.m is shorthand for (*x).m.
u = t.Elem()
}
u = methtype(u)
u = types.ReceiverBaseType(u)
if u != nil {
for _, f := range u.Methods().Slice() {
if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
@ -1056,7 +1003,7 @@ func expand0(t *types.Type) {
return
}
u = methtype(t)
u = types.ReceiverBaseType(t)
if u != nil {
for _, f := range u.Methods().Slice() {
if f.Sym.Uniq() {
@ -1147,7 +1094,7 @@ func expandmeth(t *types.Type) {
}
ms = append(ms, t.Methods().Slice()...)
sort.Sort(methcmp(ms))
sort.Sort(types.MethodsByName(ms))
t.AllMethods().Set(ms)
}
@ -1243,7 +1190,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
// the TOC to the appropriate value for that module. But if it returns
// directly to the wrapper's caller, nothing will reset it to the correct
// value for that function.
if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
// generate tail call: adjust pointer receiver and jump to embedded method.
left := dot.X // skip final .M
if !left.Type().IsPtr() {
@ -1272,7 +1219,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
funcbody()
if base.Debug.DclStack != 0 {
testdclstack()
types.CheckDclstack()
}
typecheckFunc(fn)
@ -1373,7 +1320,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
return true
}
t = methtype(t)
t = types.ReceiverBaseType(t)
var tms []*types.Field
if t != nil {
expandmeth(t)
@ -1405,7 +1352,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
// if pointer receiver in method,
// the method does not exist for value types.
rcvr := tm.Type.Recv().Type
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) {
if false && base.Flag.LowerR != 0 {
base.Errorf("interface pointer mismatch")
}
@ -1508,35 +1455,6 @@ func isbadimport(path string, allowSpace bool) bool {
return false
}
// Can this type be stored directly in an interface word?
// Yes, if the representation is a single pointer.
func isdirectiface(t *types.Type) bool {
if t.Broke() {
return false
}
switch t.Kind() {
case types.TPTR:
// Pointers to notinheap types must be stored indirectly. See issue 42076.
return !t.Elem().NotInHeap()
case types.TCHAN,
types.TMAP,
types.TFUNC,
types.TUNSAFEPTR:
return true
case types.TARRAY:
// Array of 1 direct iface type can be direct.
return t.NumElem() == 1 && isdirectiface(t.Elem())
case types.TSTRUCT:
// Struct with 1 field of direct iface type can be direct.
return t.NumFields() == 1 && isdirectiface(t.Field(0).Type)
}
return false
}
// itabType loads the _type field from a runtime.itab struct.
func itabType(itab ir.Node) ir.Node {
typ := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil)
@ -1555,7 +1473,7 @@ func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node {
base.Fatalf("ifaceData interface: %v", t)
}
ptr := ir.NewUnaryExpr(pos, ir.OIDATA, n)
if isdirectiface(t) {
if types.IsDirectIface(t) {
ptr.SetType(t)
ptr.SetTypecheck(1)
return ptr

View File

@ -166,9 +166,9 @@ func typecheckExprSwitch(n *ir.SwitchStmt) {
case t.IsSlice():
nilonly = "slice"
case !IsComparable(t):
case !types.IsComparable(t):
if t.IsStruct() {
base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, IncomparableField(t).Type)
base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
} else {
base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
}
@ -200,7 +200,7 @@ func typecheckExprSwitch(n *ir.SwitchStmt) {
if nilonly != "" && !ir.IsNil(n1) {
base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
} else if t.IsInterface() && !n1.Type().IsInterface() && !IsComparable(n1.Type()) {
} else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
} else {
op1, _ := assignop(n1.Type(), t)
@ -339,7 +339,7 @@ type exprClause struct {
func (s *exprSwitch) Add(pos src.XPos, expr, jmp ir.Node) {
c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp}
if okforcmp[s.exprname.Type().Kind()] && expr.Op() == ir.OLITERAL {
if types.IsOrdered[s.exprname.Type().Kind()] && expr.Op() == ir.OLITERAL {
s.clauses = append(s.clauses, c)
return
}
@ -670,7 +670,7 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp ir.Node) {
if !typ.IsInterface() {
s.clauses = append(s.clauses, typeClause{
hash: typehash(typ),
hash: types.TypeHash(typ),
body: body,
})
return

View File

@ -837,7 +837,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil)
return n
}
if t.IsSigned() && !langSupported(1, 13, curpkg()) {
if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) {
base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type())
n.SetType(nil)
return n
@ -904,7 +904,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if r.Type().Kind() != types.TBLANK {
aop, _ = assignop(l.Type(), r.Type())
if aop != ir.OXXX {
if r.Type().IsInterface() && !l.Type().IsInterface() && !IsComparable(l.Type()) {
if r.Type().IsInterface() && !l.Type().IsInterface() && !types.IsComparable(l.Type()) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type()))
n.SetType(nil)
return n
@ -925,7 +925,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if !converted && l.Type().Kind() != types.TBLANK {
aop, _ = assignop(r.Type(), l.Type())
if aop != ir.OXXX {
if l.Type().IsInterface() && !r.Type().IsInterface() && !IsComparable(r.Type()) {
if l.Type().IsInterface() && !r.Type().IsInterface() && !types.IsComparable(r.Type()) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type()))
n.SetType(nil)
return n
@ -969,7 +969,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// okfor allows any array == array, map == map, func == func.
// restrict to slice/map/func == nil and nil == slice/map/func.
if l.Type().IsArray() && !IsComparable(l.Type()) {
if l.Type().IsArray() && !types.IsComparable(l.Type()) {
base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
n.SetType(nil)
return n
@ -994,7 +994,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
}
if l.Type().IsStruct() {
if f := IncomparableField(l.Type()); f != nil {
if f := types.IncomparableField(l.Type()); f != nil {
base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
n.SetType(nil)
return n
@ -1627,7 +1627,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(l.Type().Results().Field(0).Type)
if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
if sym := n.X.(*ir.Name).Sym(); isRuntimePkg(sym.Pkg) && sym.Name == "getg" {
if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
// Emit code for runtime.getg() directly instead of calling function.
// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
// so that the ordering pass can make sure to preserve the semantics of the original code
@ -2560,7 +2560,7 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
if t.IsInterface() {
ms = t.Fields()
} else {
mt := methtype(t)
mt := types.ReceiverBaseType(t)
if mt == nil {
base.Errorf("%v undefined (type %v has no method %v)", n, t, n.Sel)
n.SetType(nil)
@ -2595,7 +2595,7 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
return n
}
if !isMethodApplicable(t, m) {
if !types.IsMethodApplicable(t, m) {
base.Errorf("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s)
n.SetType(nil)
return n
@ -2616,14 +2616,6 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
return me
}
// isMethodApplicable reports whether method m can be called on a
// value of type t. This is necessary because we compute a single
// method set for both T and *T, but some *T methods are not
// applicable to T receivers.
func isMethodApplicable(t *types.Type, m *types.Field) bool {
return t.IsPtr() || !m.Type.Recv().Type.IsPtr() || isifacemethod(m.Type) || m.Embedded == 2
}
func derefall(t *types.Type) *types.Type {
for t != nil && t.IsPtr() {
t = t.Elem()
@ -2642,7 +2634,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
var f2 *types.Field
if n.X.Type() == t || n.X.Type().Sym() == nil {
mt := methtype(t)
mt := types.ReceiverBaseType(t)
if mt != nil {
f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
}
@ -3406,7 +3398,7 @@ func samesafeexpr(l ir.Node, r ir.Node) bool {
r := r.(*ir.ConvExpr)
// Some conversions can't be reused, such as []byte(str).
// Allow only numeric-ish types. This is a bit conservative.
return issimple[l.Type().Kind()] && samesafeexpr(l.X, r.X)
return types.IsSimple[l.Type().Kind()] && samesafeexpr(l.X, r.X)
case ir.OINDEX, ir.OINDEXMAP:
l := l.(*ir.IndexExpr)
@ -3680,7 +3672,7 @@ var mapqueue []*ir.MapType
func checkMapKeys() {
for _, n := range mapqueue {
k := n.Type().MapType().Key
if !k.Broke() && !IsComparable(k) {
if !k.Broke() && !types.IsComparable(k) {
base.ErrorfAt(n.Pos(), "invalid map key type %v", k)
}
}

View File

@ -90,7 +90,7 @@ func initUniverse() {
sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
for et := types.Kind(0); et < types.NTYPE; et++ {
simtype[et] = et
types.SimType[et] = et
}
types.Types[types.TANY] = types.New(types.TANY)
@ -117,7 +117,7 @@ func initUniverse() {
if Widthptr == 8 {
sameas = s.sameas64
}
simtype[s.etype] = sameas
types.SimType[s.etype] = sameas
types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
}
@ -144,10 +144,10 @@ func initUniverse() {
types.Types[types.TUNSAFEPTR] = defBasic(types.TUNSAFEPTR, unsafepkg, "Pointer")
// simple aliases
simtype[types.TMAP] = types.TPTR
simtype[types.TCHAN] = types.TPTR
simtype[types.TFUNC] = types.TPTR
simtype[types.TUNSAFEPTR] = types.TPTR
types.SimType[types.TMAP] = types.TPTR
types.SimType[types.TCHAN] = types.TPTR
types.SimType[types.TFUNC] = types.TPTR
types.SimType[types.TUNSAFEPTR] = types.TPTR
for _, s := range &builtinFuncs {
s2 := types.BuiltinPkg.Lookup(s.name)
@ -194,49 +194,49 @@ func initUniverse() {
s.Def = ir.NewIota(base.Pos, s)
for et := types.TINT8; et <= types.TUINT64; et++ {
isInt[et] = true
types.IsInt[et] = true
}
isInt[types.TINT] = true
isInt[types.TUINT] = true
isInt[types.TUINTPTR] = true
types.IsInt[types.TINT] = true
types.IsInt[types.TUINT] = true
types.IsInt[types.TUINTPTR] = true
isFloat[types.TFLOAT32] = true
isFloat[types.TFLOAT64] = true
types.IsFloat[types.TFLOAT32] = true
types.IsFloat[types.TFLOAT64] = true
isComplex[types.TCOMPLEX64] = true
isComplex[types.TCOMPLEX128] = true
types.IsComplex[types.TCOMPLEX64] = true
types.IsComplex[types.TCOMPLEX128] = true
// initialize okfor
for et := types.Kind(0); et < types.NTYPE; et++ {
if isInt[et] || et == types.TIDEAL {
if types.IsInt[et] || et == types.TIDEAL {
okforeq[et] = true
okforcmp[et] = true
types.IsOrdered[et] = true
okforarith[et] = true
okforadd[et] = true
okforand[et] = true
ir.OKForConst[et] = true
issimple[et] = true
types.IsSimple[et] = true
}
if isFloat[et] {
if types.IsFloat[et] {
okforeq[et] = true
okforcmp[et] = true
types.IsOrdered[et] = true
okforadd[et] = true
okforarith[et] = true
ir.OKForConst[et] = true
issimple[et] = true
types.IsSimple[et] = true
}
if isComplex[et] {
if types.IsComplex[et] {
okforeq[et] = true
okforadd[et] = true
okforarith[et] = true
ir.OKForConst[et] = true
issimple[et] = true
types.IsSimple[et] = true
}
}
issimple[types.TBOOL] = true
types.IsSimple[types.TBOOL] = true
okforadd[types.TSTRING] = true
@ -267,7 +267,7 @@ func initUniverse() {
okforeq[types.TARRAY] = true // only if element type is comparable; refined in typecheck
okforeq[types.TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
okforcmp[types.TSTRING] = true
types.IsOrdered[types.TSTRING] = true
for i := range okfor {
okfor[i] = okfornone[:]
@ -280,10 +280,10 @@ func initUniverse() {
okfor[ir.OANDNOT] = okforand[:]
okfor[ir.ODIV] = okforarith[:]
okfor[ir.OEQ] = okforeq[:]
okfor[ir.OGE] = okforcmp[:]
okfor[ir.OGT] = okforcmp[:]
okfor[ir.OLE] = okforcmp[:]
okfor[ir.OLT] = okforcmp[:]
okfor[ir.OGE] = types.IsOrdered[:]
okfor[ir.OGT] = types.IsOrdered[:]
okfor[ir.OLE] = types.IsOrdered[:]
okfor[ir.OLT] = types.IsOrdered[:]
okfor[ir.OMOD] = okforand[:]
okfor[ir.OMUL] = okforarith[:]
okfor[ir.ONE] = okforeq[:]

View File

@ -939,7 +939,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
}
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
if isdirectiface(fromType) {
if types.IsDirectIface(fromType) {
l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), n.X)
l.SetType(toType)
l.SetTypecheck(n.Typecheck())
@ -1101,14 +1101,14 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
// rewrite complex div into function call.
et := n.X.Type().Kind()
if isComplex[et] && n.Op() == ir.ODIV {
if types.IsComplex[et] && n.Op() == ir.ODIV {
t := n.Type()
call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, conv(n.X, types.Types[types.TCOMPLEX128]), conv(n.Y, types.Types[types.TCOMPLEX128]))
return conv(call, t)
}
// Nothing to do for float divisions.
if isFloat[et] {
if types.IsFloat[et] {
return n
}
@ -2078,7 +2078,7 @@ func walkprint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
on = syslook("printslice")
on = substArgTypes(on, n.Type()) // any-1
case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
if isRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
if types.IsRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
on = syslook("printhex")
} else {
on = syslook("printuint")
@ -2706,7 +2706,7 @@ func mapfast(t *types.Type) int {
return mapslow
}
switch algtype(t.Key()) {
case AMEM32:
case types.AMEM32:
if !t.Key().HasPointers() {
return mapfast32
}
@ -2714,7 +2714,7 @@ func mapfast(t *types.Type) int {
return mapfast32ptr
}
base.Fatalf("small pointer %v", t.Key())
case AMEM64:
case types.AMEM64:
if !t.Key().HasPointers() {
return mapfast64
}
@ -2723,7 +2723,7 @@ func mapfast(t *types.Type) int {
}
// Two-word object, at least one of which is a pointer.
// Use the slow path.
case ASTRING:
case types.ASTRING:
return mapfaststr
}
return mapslow
@ -3256,12 +3256,12 @@ func eqfor(t *types.Type) (n ir.Node, needsize bool) {
// a struct/array containing a non-memory field/element.
// Small memory is handled inline, and single non-memory
// is handled by walkcompare.
switch a, _ := algtype1(t); a {
case AMEM:
switch a, _ := types.AlgType(t); a {
case types.AMEM:
n := syslook("memequal")
n = substArgTypes(n, t, t)
return n, true
case ASPECIAL:
case types.ASPECIAL:
sym := typesymprefix(".eq", t)
n := NewName(sym)
setNodeNameFunc(n)
@ -3398,7 +3398,7 @@ func walkcompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
return n
case types.TARRAY:
// We can compare several elements at once with 2/4/8 byte integer compares
inline = t.NumElem() <= 1 || (issimple[t.Elem().Kind()] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize))
inline = t.NumElem() <= 1 || (types.IsSimple[t.Elem().Kind()] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize))
case types.TSTRUCT:
inline = t.NumComponents(types.IgnoreBlankFields) <= 4
}
@ -3793,7 +3793,7 @@ func usemethod(n *ir.CallExpr) {
// Note: Don't rely on res0.Type.String() since its formatting depends on multiple factors
// (including global variables such as numImports - was issue #19028).
// Also need to check for reflect package itself (see Issue #38515).
if s := res0.Type.Sym(); s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) {
if s := res0.Type.Sym(); s != nil && s.Name == "Method" && types.IsReflectPkg(s.Pkg) {
Curfn.SetReflectMethod(true)
// The LSym is initialized at this point. We need to set the attribute on the LSym.
Curfn.LSym.Set(obj.AttrReflectMethod, true)

View File

@ -0,0 +1,173 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import "cmd/compile/internal/base"
// AlgKind describes the kind of algorithms used for comparing and
// hashing a Type.
type AlgKind int
//go:generate stringer -type AlgKind -trimprefix A
const (
// These values are known by runtime.
ANOEQ AlgKind = iota
AMEM0
AMEM8
AMEM16
AMEM32
AMEM64
AMEM128
ASTRING
AINTER
ANILINTER
AFLOAT32
AFLOAT64
ACPLX64
ACPLX128
// Type can be compared/hashed as regular memory.
AMEM AlgKind = 100
// Type needs special comparison/hashing functions.
ASPECIAL AlgKind = -1
)
// AlgType returns the AlgKind used for comparing and hashing Type t.
// If it returns ANOEQ, it also returns the component type of t that
// makes it incomparable.
func AlgType(t *Type) (AlgKind, *Type) {
if t.Broke() {
return AMEM, nil
}
if t.Noalg() {
return ANOEQ, t
}
switch t.Kind() {
case TANY, TFORW:
// will be defined later.
return ANOEQ, t
case TINT8, TUINT8, TINT16, TUINT16,
TINT32, TUINT32, TINT64, TUINT64,
TINT, TUINT, TUINTPTR,
TBOOL, TPTR,
TCHAN, TUNSAFEPTR:
return AMEM, nil
case TFUNC, TMAP:
return ANOEQ, t
case TFLOAT32:
return AFLOAT32, nil
case TFLOAT64:
return AFLOAT64, nil
case TCOMPLEX64:
return ACPLX64, nil
case TCOMPLEX128:
return ACPLX128, nil
case TSTRING:
return ASTRING, nil
case TINTER:
if t.IsEmptyInterface() {
return ANILINTER, nil
}
return AINTER, nil
case TSLICE:
return ANOEQ, t
case TARRAY:
a, bad := AlgType(t.Elem())
switch a {
case AMEM:
return AMEM, nil
case ANOEQ:
return ANOEQ, bad
}
switch t.NumElem() {
case 0:
// We checked above that the element type is comparable.
return AMEM, nil
case 1:
// Single-element array is same as its lone element.
return a, nil
}
return ASPECIAL, nil
case TSTRUCT:
fields := t.FieldSlice()
// One-field struct is same as that one field alone.
if len(fields) == 1 && !fields[0].Sym.IsBlank() {
return AlgType(fields[0].Type)
}
ret := AMEM
for i, f := range fields {
// All fields must be comparable.
a, bad := AlgType(f.Type)
if a == ANOEQ {
return ANOEQ, bad
}
// Blank fields, padded fields, fields with non-memory
// equality need special compare.
if a != AMEM || f.Sym.IsBlank() || IsPaddedField(t, i) {
ret = ASPECIAL
}
}
return ret, nil
}
base.Fatalf("algtype1: unexpected type %v", t)
return 0, nil
}
// TypeHasNoAlg reports whether t does not have any associated hash/eq
// algorithms because t, or some component of t, is marked Noalg.
func TypeHasNoAlg(t *Type) bool {
a, bad := AlgType(t)
return a == ANOEQ && bad.Noalg()
}
// IsComparable reports whether t is a comparable type.
func IsComparable(t *Type) bool {
a, _ := AlgType(t)
return a != ANOEQ
}
// IncomparableField returns an incomparable Field of struct Type t, if any.
func IncomparableField(t *Type) *Field {
for _, f := range t.FieldSlice() {
if !IsComparable(f.Type) {
return f
}
}
return nil
}
// IsPaddedField reports whether the i'th field of struct type t is followed
// by padding.
func IsPaddedField(t *Type, i int) bool {
if !t.IsStruct() {
base.Fatalf("ispaddedfield called non-struct %v", t)
}
end := t.Width
if i+1 < t.NumFields() {
end = t.Field(i + 1).Offset
}
return t.Field(i).End() != end
}

View File

@ -1,6 +1,6 @@
// Code generated by "stringer -type AlgKind -trimprefix A"; DO NOT EDIT.
package gc
package types
import "strconv"

View File

@ -6,6 +6,8 @@ package types
import (
"bytes"
"crypto/md5"
"encoding/binary"
"fmt"
"go/constant"
"strconv"
@ -659,3 +661,12 @@ func FmtConst(v constant.Value, sharp bool) string {
return v.String()
}
// TypeHash computes a hash value for type t to use in type switch statements.
func TypeHash(t *Type) uint32 {
p := t.LongString()
// Using MD5 is overkill, but reduces accidental collisions.
h := md5.Sum([]byte(p))
return binary.LittleEndian.Uint32(h[:4])
}

View File

@ -0,0 +1,96 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run mkbuiltin.go
package types
import (
"fmt"
"internal/goversion"
"log"
"regexp"
"strconv"
"cmd/compile/internal/base"
)
// A lang is a language version broken into major and minor numbers.
type lang struct {
major, minor int
}
// langWant is the desired language version set by the -lang flag.
// If the -lang flag is not set, this is the zero value, meaning that
// any language version is supported.
var langWant lang
// AllowsGoVersion reports whether a particular package
// is allowed to use Go version major.minor.
// We assume the imported packages have all been checked,
// so we only have to check the local package against the -lang flag.
func AllowsGoVersion(pkg *Pkg, major, minor int) bool {
if pkg == nil {
// TODO(mdempsky): Set Pkg for local types earlier.
pkg = LocalPkg
}
if pkg != LocalPkg {
// Assume imported packages passed type-checking.
return true
}
if langWant.major == 0 && langWant.minor == 0 {
return true
}
return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
}
// ParseLangFlag verifies that the -lang flag holds a valid value, and
// exits if not. It initializes data used by langSupported.
func ParseLangFlag() {
if base.Flag.Lang == "" {
return
}
var err error
langWant, err = parseLang(base.Flag.Lang)
if err != nil {
log.Fatalf("invalid value %q for -lang: %v", base.Flag.Lang, err)
}
if def := currentLang(); base.Flag.Lang != def {
defVers, err := parseLang(def)
if err != nil {
log.Fatalf("internal error parsing default lang %q: %v", def, err)
}
if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
log.Fatalf("invalid value %q for -lang: max known version is %q", base.Flag.Lang, def)
}
}
}
// parseLang parses a -lang option into a langVer.
func parseLang(s string) (lang, error) {
matches := goVersionRE.FindStringSubmatch(s)
if matches == nil {
return lang{}, fmt.Errorf(`should be something like "go1.12"`)
}
major, err := strconv.Atoi(matches[1])
if err != nil {
return lang{}, err
}
minor, err := strconv.Atoi(matches[2])
if err != nil {
return lang{}, err
}
return lang{major: major, minor: minor}, nil
}
// currentLang returns the current language version.
func currentLang() string {
return fmt.Sprintf("go1.%d", goversion.Version)
}
// goVersionRE is a regular expression that matches the valid
// arguments to the -lang flag.
var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)

View File

@ -138,3 +138,7 @@ func CleanroomDo(f func()) {
f()
pkgMap = saved
}
func IsDotAlias(sym *Sym) bool {
return sym.Def != nil && sym.Def.Sym() != sym
}

View File

@ -72,7 +72,7 @@ func Markdcl() {
Block = blockgen
}
func IsDclstackValid() bool {
func isDclstackValid() bool {
for _, d := range dclstack {
if d.sym == nil {
return false
@ -105,3 +105,9 @@ func (s *Sym) pkgDefPtr() *Object {
// function scope.
return &s.Def
}
func CheckDclstack() {
if !isDclstackValid() {
base.Fatalf("mark left on the dclstack")
}
}

View File

@ -0,0 +1,14 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
// MethodsByName sorts methods by symbol.
type MethodsByName []*Field
func (x MethodsByName) Len() int { return len(x) }
func (x MethodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x MethodsByName) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }

View File

@ -9,6 +9,7 @@ import (
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
"sync"
)
// IRNode represents an ir.Node, but without needing to import cmd/compile/internal/ir,
@ -1695,3 +1696,204 @@ func anyBroke(fields []*Field) bool {
}
return false
}
var (
IsInt [NTYPE]bool
IsFloat [NTYPE]bool
IsComplex [NTYPE]bool
IsSimple [NTYPE]bool
)
var IsOrdered [NTYPE]bool
// IsReflexive reports whether t has a reflexive equality operator.
// That is, if x==x for all x of type t.
func IsReflexive(t *Type) bool {
switch t.Kind() {
case TBOOL,
TINT,
TUINT,
TINT8,
TUINT8,
TINT16,
TUINT16,
TINT32,
TUINT32,
TINT64,
TUINT64,
TUINTPTR,
TPTR,
TUNSAFEPTR,
TSTRING,
TCHAN:
return true
case TFLOAT32,
TFLOAT64,
TCOMPLEX64,
TCOMPLEX128,
TINTER:
return false
case TARRAY:
return IsReflexive(t.Elem())
case TSTRUCT:
for _, t1 := range t.Fields().Slice() {
if !IsReflexive(t1.Type) {
return false
}
}
return true
default:
base.Fatalf("bad type for map key: %v", t)
return false
}
}
// Can this type be stored directly in an interface word?
// Yes, if the representation is a single pointer.
func IsDirectIface(t *Type) bool {
if t.Broke() {
return false
}
switch t.Kind() {
case TPTR:
// Pointers to notinheap types must be stored indirectly. See issue 42076.
return !t.Elem().NotInHeap()
case TCHAN,
TMAP,
TFUNC,
TUNSAFEPTR:
return true
case TARRAY:
// Array of 1 direct iface type can be direct.
return t.NumElem() == 1 && IsDirectIface(t.Elem())
case TSTRUCT:
// Struct with 1 field of direct iface type can be direct.
return t.NumFields() == 1 && IsDirectIface(t.Field(0).Type)
}
return false
}
// IsInterfaceMethod reports whether (field) m is
// an interface method. Such methods have the
// special receiver type types.FakeRecvType().
func IsInterfaceMethod(f *Type) bool {
return f.Recv().Type == FakeRecvType()
}
// IsMethodApplicable reports whether method m can be called on a
// value of type t. This is necessary because we compute a single
// method set for both T and *T, but some *T methods are not
// applicable to T receivers.
func IsMethodApplicable(t *Type, m *Field) bool {
return t.IsPtr() || !m.Type.Recv().Type.IsPtr() || IsInterfaceMethod(m.Type) || m.Embedded == 2
}
// IsRuntimePkg reports whether p is package runtime.
func IsRuntimePkg(p *Pkg) bool {
if base.Flag.CompilingRuntime && p == LocalPkg {
return true
}
return p.Path == "runtime"
}
// IsReflectPkg reports whether p is package reflect.
func IsReflectPkg(p *Pkg) bool {
if p == LocalPkg {
return base.Ctxt.Pkgpath == "reflect"
}
return p.Path == "reflect"
}
// ReceiverBaseType returns the underlying type, if any,
// that owns methods with receiver parameter t.
// The result is either a named type or an anonymous struct.
func ReceiverBaseType(t *Type) *Type {
if t == nil {
return nil
}
// Strip away pointer if it's there.
if t.IsPtr() {
if t.Sym() != nil {
return nil
}
t = t.Elem()
if t == nil {
return nil
}
}
// Must be a named type or anonymous struct.
if t.Sym() == nil && !t.IsStruct() {
return nil
}
// Check types.
if IsSimple[t.Kind()] {
return t
}
switch t.Kind() {
case TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRING, TSTRUCT:
return t
}
return nil
}
func FloatForComplex(t *Type) *Type {
switch t.Kind() {
case TCOMPLEX64:
return Types[TFLOAT32]
case TCOMPLEX128:
return Types[TFLOAT64]
}
base.Fatalf("unexpected type: %v", t)
return nil
}
func ComplexForFloat(t *Type) *Type {
switch t.Kind() {
case TFLOAT32:
return Types[TCOMPLEX64]
case TFLOAT64:
return Types[TCOMPLEX128]
}
base.Fatalf("unexpected type: %v", t)
return nil
}
func TypeSym(t *Type) *Sym {
return TypeSymLookup(TypeSymName(t))
}
func TypeSymLookup(name string) *Sym {
typepkgmu.Lock()
s := typepkg.Lookup(name)
typepkgmu.Unlock()
return s
}
func TypeSymName(t *Type) string {
name := t.ShortString()
// Use a separate symbol name for Noalg types for #17752.
if TypeHasNoAlg(t) {
name = "noalg." + name
}
return name
}
// Fake package for runtime type info (headers)
// Don't access directly, use typeLookup below.
var (
typepkgmu sync.Mutex // protects typepkg lookups
typepkg = NewPkg("type", "type")
)
var SimType [NTYPE]Kind