mirror of
https://github.com/golang/go
synced 2024-11-26 02:17:58 -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:
parent
ead4957892
commit
9ee309255a
@ -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
|
||||
}
|
||||
|
@ -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()]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -283,7 +283,7 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
|
||||
|
||||
funcbody()
|
||||
if base.Debug.DclStack != 0 {
|
||||
testdclstack()
|
||||
types.CheckDclstack()
|
||||
}
|
||||
|
||||
typecheckFunc(fn)
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,8 +1476,8 @@ 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 += 4 // skip unused field
|
||||
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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,8 +2494,8 @@ 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
|
||||
wt := types.Types[types.TFLOAT64] // Compute in Float64 to minimize cancellation error
|
||||
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)
|
||||
breal := s.newValue1(ssa.OpComplexReal, pt, b)
|
||||
@ -2560,8 +2538,8 @@ 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
|
||||
wt := types.Types[types.TFLOAT64] // Compute in Float64 to minimize cancellation error
|
||||
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)
|
||||
breal := s.newValue1(ssa.OpComplexReal, pt, b)
|
||||
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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[:]
|
||||
|
@ -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)
|
||||
|
173
src/cmd/compile/internal/types/alg.go
Normal file
173
src/cmd/compile/internal/types/alg.go
Normal 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
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Code generated by "stringer -type AlgKind -trimprefix A"; DO NOT EDIT.
|
||||
|
||||
package gc
|
||||
package types
|
||||
|
||||
import "strconv"
|
||||
|
@ -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])
|
||||
}
|
||||
|
96
src/cmd/compile/internal/types/goversion.go
Normal file
96
src/cmd/compile/internal/types/goversion.go
Normal 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]*)$`)
|
@ -138,3 +138,7 @@ func CleanroomDo(f func()) {
|
||||
f()
|
||||
pkgMap = saved
|
||||
}
|
||||
|
||||
func IsDotAlias(sym *Sym) bool {
|
||||
return sym.Def != nil && sym.Def.Sym() != sym
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
14
src/cmd/compile/internal/types/sort.go
Normal file
14
src/cmd/compile/internal/types/sort.go
Normal 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) }
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user