mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.cmdgo] all: merge master (5e6a7e9) into dev.cmdgo
Merge List: + 2021-08-26 5e6a7e9b86 embed: remove reference to global variables in docs + 2021-08-26 166b691b65 cmd/compile/internal/types2: remove need for instance (struct) + 2021-08-26 d6bdae33e9 cmd/compile/internal/types2: address some TODOs (cleanup) + 2021-08-26 770df2e18d crypto/tls: fix typo in PreferServerCipherSuites comment + 2021-08-26 a6ff433d6a cmd/go: pass -gcflags after other flags generated by the go command + 2021-08-25 4f2620285d cmd/compile/internal/types2: fix type set printing and add test + 2021-08-25 0ac64f6d70 cmd/compile/internal/types2: rename IsMethodSet to IsConstraint (cleanup) + 2021-08-25 4068fb6c21 cmd/compile: always accept 1.18 syntax but complain if not 1.18 + 2021-08-25 bf0bc4122f go/types, types2: don't re-evaluate context string for each function argument (optimization) + 2021-08-25 4158e88f64 cmd/compile/internal/syntax: fix position of type parameter field + 2021-08-25 647bef6c59 go/types: implement NewTypeList and use it instead of composite literals + 2021-08-25 6cf1d5d0fa cmd/compile: generic SSA rules for simplifying 2 and 3 operand integer arithmetic expressions + 2021-08-25 5baf60d472 bytes, strings: optimize Trim for single byte cutsets + 2021-08-25 3d667671ad cmd/compile: fix function contains no TParam in generic function + 2021-08-25 4f2ebfe34b cmd/compile: allow embed into any byte slice type + 2021-08-25 d2f002cb39 time/format: avoid growslice in time.String()/time.GoString() + 2021-08-25 08d4cc20ca cmd/compile: fix stencil call expression. + 2021-08-25 099b819085 cmd/compile: fix CheckSize() calculation for -G=3 and stencils + 2021-08-25 e1fcf8857e test: add test that caused gofrontend compiler crash + 2021-08-25 d37b8dedf7 test: add test case that gofrontend miscompiled + 2021-08-25 41b99dab0f os/user: don't skip TestLookupGroup if supported + 2021-08-25 de1c934b97 cmd/compile: fix checkptr false positive for (*[Big]T)(ptr)[:n:n] pattern + 2021-08-24 54cdef1f10 reflect: add MapIter.SetKey and MapIter.SetValue + 2021-08-24 5d863f89fe cmd/compile: simplify bad conversion check Change-Id: I29ab927f0e47f44d82f9307c642900f75f4f678f
This commit is contained in:
commit
de83ef67ac
@ -888,11 +888,6 @@ func (as *asciiSet) contains(c byte) bool {
|
||||
}
|
||||
|
||||
func makeCutsetFunc(cutset string) func(r rune) bool {
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return func(r rune) bool {
|
||||
return r == rune(cutset[0])
|
||||
}
|
||||
}
|
||||
if as, isASCII := makeASCIISet(cutset); isASCII {
|
||||
return func(r rune) bool {
|
||||
return r < utf8.RuneSelf && as.contains(byte(r))
|
||||
@ -911,21 +906,44 @@ func makeCutsetFunc(cutset string) func(r rune) bool {
|
||||
// Trim returns a subslice of s by slicing off all leading and
|
||||
// trailing UTF-8-encoded code points contained in cutset.
|
||||
func Trim(s []byte, cutset string) []byte {
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
|
||||
}
|
||||
return TrimFunc(s, makeCutsetFunc(cutset))
|
||||
}
|
||||
|
||||
// TrimLeft returns a subslice of s by slicing off all leading
|
||||
// UTF-8-encoded code points contained in cutset.
|
||||
func TrimLeft(s []byte, cutset string) []byte {
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return trimLeftByte(s, cutset[0])
|
||||
}
|
||||
return TrimLeftFunc(s, makeCutsetFunc(cutset))
|
||||
}
|
||||
|
||||
func trimLeftByte(s []byte, c byte) []byte {
|
||||
for len(s) > 0 && s[0] == c {
|
||||
s = s[1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// TrimRight returns a subslice of s by slicing off all trailing
|
||||
// UTF-8-encoded code points that are contained in cutset.
|
||||
func TrimRight(s []byte, cutset string) []byte {
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return trimRightByte(s, cutset[0])
|
||||
}
|
||||
return TrimRightFunc(s, makeCutsetFunc(cutset))
|
||||
}
|
||||
|
||||
func trimRightByte(s []byte, c byte) []byte {
|
||||
for len(s) > 0 && s[len(s)-1] == c {
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// TrimSpace returns a subslice of s by slicing off all leading and
|
||||
// trailing white space, as defined by Unicode.
|
||||
func TrimSpace(s []byte) []byte {
|
||||
|
@ -1251,7 +1251,9 @@ var trimTests = []TrimTest{
|
||||
{"TrimLeft", "abba", "ab", ""},
|
||||
{"TrimRight", "abba", "ab", ""},
|
||||
{"TrimLeft", "abba", "a", "bba"},
|
||||
{"TrimLeft", "abba", "b", "abba"},
|
||||
{"TrimRight", "abba", "a", "abb"},
|
||||
{"TrimRight", "abba", "b", "abba"},
|
||||
{"Trim", "<tag>", "<>", "tag"},
|
||||
{"Trim", "* listitem", " *", "listitem"},
|
||||
{"Trim", `"quote"`, `"`, "quote"},
|
||||
@ -1963,6 +1965,13 @@ func BenchmarkTrimASCII(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTrimByte(b *testing.B) {
|
||||
x := []byte(" the quick brown fox ")
|
||||
for i := 0; i < b.N; i++ {
|
||||
Trim(x, " ")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIndexPeriodic(b *testing.B) {
|
||||
key := []byte{1, 1}
|
||||
for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
|
||||
|
@ -570,10 +570,11 @@ func (*SelectorExpr) CanBeNtype() {}
|
||||
// A SliceExpr is a slice expression X[Low:High] or X[Low:High:Max].
|
||||
type SliceExpr struct {
|
||||
miniExpr
|
||||
X Node
|
||||
Low Node
|
||||
High Node
|
||||
Max Node
|
||||
X Node
|
||||
Low Node
|
||||
High Node
|
||||
Max Node
|
||||
CheckPtrCall *CallExpr
|
||||
}
|
||||
|
||||
func NewSliceExpr(pos src.XPos, op Op, x, low, high, max Node) *SliceExpr {
|
||||
|
@ -35,7 +35,7 @@ func LoadPackage(filenames []string) {
|
||||
supportsGenerics := base.Flag.G != 0 || buildcfg.Experiment.Unified
|
||||
|
||||
mode := syntax.CheckBranches
|
||||
if supportsGenerics && types.AllowsGoVersion(types.LocalPkg, 1, 18) {
|
||||
if supportsGenerics {
|
||||
mode |= syntax.AllowGenerics
|
||||
}
|
||||
|
||||
|
@ -732,21 +732,15 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*typ
|
||||
g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...)
|
||||
|
||||
if doubleCheck {
|
||||
okConvs := map[ir.Node]bool{}
|
||||
ir.Visit(newf, func(n ir.Node) {
|
||||
if n.Op() == ir.OIDATA {
|
||||
// IDATA(OCONVIFACE(x)) is ok, as we don't use the type of x.
|
||||
// TODO: use some other op besides OCONVIFACE. ONEW might work
|
||||
// (with appropriate direct vs. indirect interface cases).
|
||||
okConvs[n.(*ir.UnaryExpr).X] = true
|
||||
if n.Op() != ir.OCONVIFACE {
|
||||
return
|
||||
}
|
||||
if n.Op() == ir.OCONVIFACE && !okConvs[n] {
|
||||
c := n.(*ir.ConvExpr)
|
||||
if c.X.Type().HasShape() {
|
||||
ir.Dump("BAD FUNCTION", newf)
|
||||
ir.Dump("BAD CONVERSION", c)
|
||||
base.Fatalf("converting shape type to interface")
|
||||
}
|
||||
c := n.(*ir.ConvExpr)
|
||||
if c.X.Type().HasShape() {
|
||||
ir.Dump("BAD FUNCTION", newf)
|
||||
ir.Dump("BAD CONVERSION", c)
|
||||
base.Fatalf("converting shape type to interface")
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1054,6 +1048,13 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
case ir.OCLOSURE:
|
||||
transformCall(call)
|
||||
|
||||
case ir.ODEREF, ir.OINDEX, ir.OINDEXMAP, ir.ORECV:
|
||||
// Transform a call that was delayed because of the
|
||||
// use of typeparam inside an expression that required
|
||||
// a pointer dereference, array indexing, map indexing,
|
||||
// or channel receive to compute function value.
|
||||
transformCall(call)
|
||||
|
||||
case ir.OFUNCINST:
|
||||
// A call with an OFUNCINST will get transformed
|
||||
// in stencil() once we have created & attached the
|
||||
|
@ -30,21 +30,11 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
|
||||
// typ converts a types2.Type to a types.Type, including caching of previously
|
||||
// translated types.
|
||||
func (g *irgen) typ(typ types2.Type) *types.Type {
|
||||
// Defer the CheckSize calls until we have fully-defined a
|
||||
// (possibly-recursive) top-level type.
|
||||
types.DeferCheckSize()
|
||||
res := g.typ1(typ)
|
||||
|
||||
// Calculate the size for all concrete types seen by the frontend. The old
|
||||
// typechecker calls CheckSize() a lot, and we want to eliminate calling
|
||||
// it eventually, so we should do it here instead. We only call it for
|
||||
// top-level types (i.e. we do it here rather in typ1), to make sure that
|
||||
// recursive types have been fully constructed before we call CheckSize.
|
||||
if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
|
||||
types.CheckSize(res)
|
||||
if res.IsPtr() {
|
||||
// Pointers always have their size set, even though their element
|
||||
// may not have its size set.
|
||||
types.CheckSize(res.Elem())
|
||||
}
|
||||
}
|
||||
types.ResumeCheckSize()
|
||||
return res
|
||||
}
|
||||
|
||||
@ -59,6 +49,12 @@ func (g *irgen) typ1(typ types2.Type) *types.Type {
|
||||
res, ok := g.typs[typ]
|
||||
if !ok {
|
||||
res = g.typ0(typ)
|
||||
// Calculate the size for all concrete types seen by the frontend.
|
||||
// This is the replacement for the CheckSize() calls in the types1
|
||||
// typechecker. These will be deferred until the top-level g.typ().
|
||||
if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
|
||||
types.CheckSize(res)
|
||||
}
|
||||
g.typs[typ] = res
|
||||
}
|
||||
return res
|
||||
|
@ -590,6 +590,10 @@
|
||||
// simplifications often used for lengths. e.g. len(s[i:i+5])==5
|
||||
(Sub(64|32|16|8) (Add(64|32|16|8) x y) x) => y
|
||||
(Sub(64|32|16|8) (Add(64|32|16|8) x y) y) => x
|
||||
(Sub(64|32|16|8) (Sub(64|32|16|8) x y) x) => (Neg(64|32|16|8) y)
|
||||
(Sub(64|32|16|8) x (Add(64|32|16|8) x y)) => (Neg(64|32|16|8) y)
|
||||
(Add(64|32|16|8) x (Sub(64|32|16|8) y x)) => y
|
||||
(Add(64|32|16|8) x (Add(64|32|16|8) y (Sub(64|32|16|8) z x))) => (Add(64|32|16|8) y z)
|
||||
|
||||
// basic phi simplifications
|
||||
(Phi (Const8 [c]) (Const8 [c])) => (Const8 [c])
|
||||
|
@ -533,6 +533,52 @@ func rewriteValuegeneric_OpAdd16(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add16 x (Sub16 y x))
|
||||
// result: y
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpSub16 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
y := v_1.Args[0]
|
||||
if x != v_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.copyOf(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add16 x (Add16 y (Sub16 z x)))
|
||||
// result: (Add16 y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd16 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
|
||||
y := v_1_0
|
||||
if v_1_1.Op != OpSub16 {
|
||||
continue
|
||||
}
|
||||
_ = v_1_1.Args[1]
|
||||
z := v_1_1.Args[0]
|
||||
if x != v_1_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAdd16)
|
||||
v.AddArg2(y, z)
|
||||
return true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add16 (Add16 i:(Const16 <t>) z) x)
|
||||
// cond: (z.Op != OpConst16 && x.Op != OpConst16)
|
||||
// result: (Add16 i (Add16 <t> z x))
|
||||
@ -732,6 +778,52 @@ func rewriteValuegeneric_OpAdd32(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add32 x (Sub32 y x))
|
||||
// result: y
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpSub32 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
y := v_1.Args[0]
|
||||
if x != v_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.copyOf(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add32 x (Add32 y (Sub32 z x)))
|
||||
// result: (Add32 y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd32 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
|
||||
y := v_1_0
|
||||
if v_1_1.Op != OpSub32 {
|
||||
continue
|
||||
}
|
||||
_ = v_1_1.Args[1]
|
||||
z := v_1_1.Args[0]
|
||||
if x != v_1_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAdd32)
|
||||
v.AddArg2(y, z)
|
||||
return true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add32 (Add32 i:(Const32 <t>) z) x)
|
||||
// cond: (z.Op != OpConst32 && x.Op != OpConst32)
|
||||
// result: (Add32 i (Add32 <t> z x))
|
||||
@ -958,6 +1050,52 @@ func rewriteValuegeneric_OpAdd64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add64 x (Sub64 y x))
|
||||
// result: y
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpSub64 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
y := v_1.Args[0]
|
||||
if x != v_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.copyOf(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add64 x (Add64 y (Sub64 z x)))
|
||||
// result: (Add64 y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd64 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
|
||||
y := v_1_0
|
||||
if v_1_1.Op != OpSub64 {
|
||||
continue
|
||||
}
|
||||
_ = v_1_1.Args[1]
|
||||
z := v_1_1.Args[0]
|
||||
if x != v_1_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAdd64)
|
||||
v.AddArg2(y, z)
|
||||
return true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add64 (Add64 i:(Const64 <t>) z) x)
|
||||
// cond: (z.Op != OpConst64 && x.Op != OpConst64)
|
||||
// result: (Add64 i (Add64 <t> z x))
|
||||
@ -1184,6 +1322,52 @@ func rewriteValuegeneric_OpAdd8(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add8 x (Sub8 y x))
|
||||
// result: y
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpSub8 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
y := v_1.Args[0]
|
||||
if x != v_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.copyOf(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add8 x (Add8 y (Sub8 z x)))
|
||||
// result: (Add8 y z)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd8 {
|
||||
continue
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
|
||||
y := v_1_0
|
||||
if v_1_1.Op != OpSub8 {
|
||||
continue
|
||||
}
|
||||
_ = v_1_1.Args[1]
|
||||
z := v_1_1.Args[0]
|
||||
if x != v_1_1.Args[1] {
|
||||
continue
|
||||
}
|
||||
v.reset(OpAdd8)
|
||||
v.AddArg2(y, z)
|
||||
return true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Add8 (Add8 i:(Const8 <t>) z) x)
|
||||
// cond: (z.Op != OpConst8 && x.Op != OpConst8)
|
||||
// result: (Add8 i (Add8 <t> z x))
|
||||
@ -22590,6 +22774,42 @@ func rewriteValuegeneric_OpSub16(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub16 (Sub16 x y) x)
|
||||
// result: (Neg16 y)
|
||||
for {
|
||||
if v_0.Op != OpSub16 {
|
||||
break
|
||||
}
|
||||
y := v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpNeg16)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
// match: (Sub16 x (Add16 x y))
|
||||
// result: (Neg16 y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd16 {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpNeg16)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub16 x (Sub16 i:(Const16 <t>) z))
|
||||
// cond: (z.Op != OpConst16 && x.Op != OpConst16)
|
||||
// result: (Sub16 (Add16 <t> x z) i)
|
||||
@ -22869,6 +23089,42 @@ func rewriteValuegeneric_OpSub32(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub32 (Sub32 x y) x)
|
||||
// result: (Neg32 y)
|
||||
for {
|
||||
if v_0.Op != OpSub32 {
|
||||
break
|
||||
}
|
||||
y := v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpNeg32)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
// match: (Sub32 x (Add32 x y))
|
||||
// result: (Neg32 y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd32 {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpNeg32)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub32 x (Sub32 i:(Const32 <t>) z))
|
||||
// cond: (z.Op != OpConst32 && x.Op != OpConst32)
|
||||
// result: (Sub32 (Add32 <t> x z) i)
|
||||
@ -23172,6 +23428,42 @@ func rewriteValuegeneric_OpSub64(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub64 (Sub64 x y) x)
|
||||
// result: (Neg64 y)
|
||||
for {
|
||||
if v_0.Op != OpSub64 {
|
||||
break
|
||||
}
|
||||
y := v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpNeg64)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
// match: (Sub64 x (Add64 x y))
|
||||
// result: (Neg64 y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd64 {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpNeg64)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub64 x (Sub64 i:(Const64 <t>) z))
|
||||
// cond: (z.Op != OpConst64 && x.Op != OpConst64)
|
||||
// result: (Sub64 (Add64 <t> x z) i)
|
||||
@ -23475,6 +23767,42 @@ func rewriteValuegeneric_OpSub8(v *Value) bool {
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub8 (Sub8 x y) x)
|
||||
// result: (Neg8 y)
|
||||
for {
|
||||
if v_0.Op != OpSub8 {
|
||||
break
|
||||
}
|
||||
y := v_0.Args[1]
|
||||
x := v_0.Args[0]
|
||||
if x != v_1 {
|
||||
break
|
||||
}
|
||||
v.reset(OpNeg8)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
// match: (Sub8 x (Add8 x y))
|
||||
// result: (Neg8 y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpAdd8 {
|
||||
break
|
||||
}
|
||||
_ = v_1.Args[1]
|
||||
v_1_0 := v_1.Args[0]
|
||||
v_1_1 := v_1.Args[1]
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
|
||||
if x != v_1_0 {
|
||||
continue
|
||||
}
|
||||
y := v_1_1
|
||||
v.reset(OpNeg8)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
// match: (Sub8 x (Sub8 i:(Const8 <t>) z))
|
||||
// cond: (z.Op != OpConst8 && x.Op != OpConst8)
|
||||
// result: (Sub8 (Add8 <t> x z) i)
|
||||
|
@ -3090,6 +3090,9 @@ func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
k = s.expr(n.Max)
|
||||
}
|
||||
p, l, c := s.slice(v, i, j, k, n.Bounded())
|
||||
if n.CheckPtrCall != nil {
|
||||
s.stmt(n.CheckPtrCall)
|
||||
}
|
||||
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
|
||||
|
||||
case ir.OSLICESTR:
|
||||
|
@ -73,7 +73,7 @@ func embedKind(typ *types.Type) int {
|
||||
if typ.Kind() == types.TSTRING {
|
||||
return embedString
|
||||
}
|
||||
if typ.Sym() == nil && typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
|
||||
if typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
|
||||
return embedBytes
|
||||
}
|
||||
return embedUnknown
|
||||
|
@ -1840,7 +1840,11 @@ func (p *parser) paramDeclOrNil(name *Name) *Field {
|
||||
}
|
||||
|
||||
f := new(Field)
|
||||
f.pos = p.pos()
|
||||
if name != nil {
|
||||
f.pos = name.pos
|
||||
} else {
|
||||
f.pos = p.pos()
|
||||
}
|
||||
|
||||
if p.tok == _Name || name != nil {
|
||||
if name == nil {
|
||||
|
@ -1003,6 +1003,15 @@ type Tsubster struct {
|
||||
// result is t; otherwise the result is a new type. It deals with recursive types
|
||||
// by using TFORW types and finding partially or fully created types via sym.Def.
|
||||
func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||
// Defer the CheckSize calls until we have fully-defined
|
||||
// (possibly-recursive) top-level type.
|
||||
types.DeferCheckSize()
|
||||
r := ts.typ1(t)
|
||||
types.ResumeCheckSize()
|
||||
return r
|
||||
}
|
||||
|
||||
func (ts *Tsubster) typ1(t *types.Type) *types.Type {
|
||||
if !t.HasTParam() && t.Kind() != types.TFUNC {
|
||||
// Note: function types need to be copied regardless, as the
|
||||
// types of closures may contain declarations that need
|
||||
@ -1042,12 +1051,13 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||
var targsChanged bool
|
||||
var forw *types.Type
|
||||
|
||||
if t.Sym() != nil {
|
||||
if t.Sym() != nil && t.HasTParam() {
|
||||
// Need to test for t.HasTParam() again because of special TFUNC case above.
|
||||
// Translate the type params for this type according to
|
||||
// the tparam/targs mapping from subst.
|
||||
neededTargs = make([]*types.Type, len(t.RParams()))
|
||||
for i, rparam := range t.RParams() {
|
||||
neededTargs[i] = ts.Typ(rparam)
|
||||
neededTargs[i] = ts.typ1(rparam)
|
||||
if !types.Identical(neededTargs[i], rparam) {
|
||||
targsChanged = true
|
||||
}
|
||||
@ -1085,26 +1095,26 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||
}
|
||||
// Substitute the underlying typeparam (e.g. T in P[T], see
|
||||
// the example describing type P[T] above).
|
||||
newt = ts.Typ(t.Underlying())
|
||||
newt = ts.typ1(t.Underlying())
|
||||
assert(newt != t)
|
||||
|
||||
case types.TARRAY:
|
||||
elem := t.Elem()
|
||||
newelem := ts.Typ(elem)
|
||||
newelem := ts.typ1(elem)
|
||||
if newelem != elem || targsChanged {
|
||||
newt = types.NewArray(newelem, t.NumElem())
|
||||
}
|
||||
|
||||
case types.TPTR:
|
||||
elem := t.Elem()
|
||||
newelem := ts.Typ(elem)
|
||||
newelem := ts.typ1(elem)
|
||||
if newelem != elem || targsChanged {
|
||||
newt = types.NewPtr(newelem)
|
||||
}
|
||||
|
||||
case types.TSLICE:
|
||||
elem := t.Elem()
|
||||
newelem := ts.Typ(elem)
|
||||
newelem := ts.typ1(elem)
|
||||
if newelem != elem || targsChanged {
|
||||
newt = types.NewSlice(newelem)
|
||||
}
|
||||
@ -1159,22 +1169,17 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||
}
|
||||
|
||||
case types.TMAP:
|
||||
newkey := ts.Typ(t.Key())
|
||||
newval := ts.Typ(t.Elem())
|
||||
newkey := ts.typ1(t.Key())
|
||||
newval := ts.typ1(t.Elem())
|
||||
if newkey != t.Key() || newval != t.Elem() || targsChanged {
|
||||
newt = types.NewMap(newkey, newval)
|
||||
}
|
||||
|
||||
case types.TCHAN:
|
||||
elem := t.Elem()
|
||||
newelem := ts.Typ(elem)
|
||||
newelem := ts.typ1(elem)
|
||||
if newelem != elem || targsChanged {
|
||||
newt = types.NewChan(newelem, t.ChanDir())
|
||||
if !newt.HasTParam() {
|
||||
// TODO(danscales): not sure why I have to do this
|
||||
// only for channels.....
|
||||
types.CheckSize(newt)
|
||||
}
|
||||
}
|
||||
case types.TFORW:
|
||||
if ts.SubstForwFunc != nil {
|
||||
@ -1194,7 +1199,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||
for i := 0; i < nt; i++ {
|
||||
term, tilde := t.Term(i)
|
||||
tildes[i] = tilde
|
||||
newterms[i] = ts.Typ(term)
|
||||
newterms[i] = ts.typ1(term)
|
||||
if newterms[i] != term {
|
||||
changed = true
|
||||
}
|
||||
@ -1212,24 +1217,24 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
|
||||
return t
|
||||
}
|
||||
|
||||
if t.Sym() == nil && t.Kind() != types.TINTER {
|
||||
// Not a named type or interface type, so there was no forwarding type
|
||||
// and there are no methods to substitute.
|
||||
assert(t.Methods().Len() == 0)
|
||||
return newt
|
||||
}
|
||||
|
||||
if forw != nil {
|
||||
forw.SetUnderlying(newt)
|
||||
newt = forw
|
||||
}
|
||||
|
||||
if !newt.HasTParam() {
|
||||
// Calculate the size of any new types created. These will be
|
||||
// deferred until the top-level ts.Typ() or g.typ() (if this is
|
||||
// called from g.fillinMethods()).
|
||||
types.CheckSize(newt)
|
||||
}
|
||||
|
||||
if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
|
||||
// Fill in the method info for the new type.
|
||||
var newfields []*types.Field
|
||||
newfields = make([]*types.Field, t.Methods().Len())
|
||||
for i, f := range t.Methods().Slice() {
|
||||
t2 := ts.Typ(f.Type)
|
||||
t2 := ts.typ1(f.Type)
|
||||
oldsym := f.Nname.Sym()
|
||||
newsym := MakeFuncInstSym(oldsym, ts.Targs, true)
|
||||
var nname *ir.Name
|
||||
@ -1272,7 +1277,7 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
|
||||
newfields = make([]*types.Field, t.NumFields())
|
||||
}
|
||||
for i, f := range t.Fields().Slice() {
|
||||
t2 := ts.Typ(f.Type)
|
||||
t2 := ts.typ1(f.Type)
|
||||
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
|
||||
newfields = make([]*types.Field, t.NumFields())
|
||||
for j := 0; j < i; j++ {
|
||||
@ -1325,7 +1330,7 @@ func (ts *Tsubster) tinter(t *types.Type) *types.Type {
|
||||
}
|
||||
var newfields []*types.Field
|
||||
for i, f := range t.Methods().Slice() {
|
||||
t2 := ts.Typ(f.Type)
|
||||
t2 := ts.typ1(f.Type)
|
||||
if (t2 != f.Type || f.Nname != nil) && newfields == nil {
|
||||
newfields = make([]*types.Field, t.Methods().Len())
|
||||
for j := 0; j < i; j++ {
|
||||
|
@ -15,6 +15,10 @@ import (
|
||||
// funcInst type-checks a function instantiation inst and returns the result in x.
|
||||
// The operand x must be the evaluation of inst.X and its type must be a signature.
|
||||
func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
|
||||
if !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.softErrorf(inst.Pos(), "function instantiation requires go1.18 or later")
|
||||
}
|
||||
|
||||
xlist := unpackExpr(inst.Index)
|
||||
targs := check.typeList(xlist)
|
||||
if targs == nil {
|
||||
@ -318,6 +322,13 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
|
||||
|
||||
// infer type arguments and instantiate signature if necessary
|
||||
if sig.TParams().Len() > 0 {
|
||||
if !check.allowVersion(check.pkg, 1, 18) {
|
||||
if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
|
||||
check.softErrorf(iexpr.Pos(), "function instantiation requires go1.18 or later")
|
||||
} else {
|
||||
check.softErrorf(call.Pos(), "implicit function instantiation requires go1.18 or later")
|
||||
}
|
||||
}
|
||||
// TODO(gri) provide position information for targs so we can feed
|
||||
// it to the instantiate call for better error reporting
|
||||
targs := check.infer(call.Pos(), sig.TParams().list(), targs, sigParams, args, true)
|
||||
@ -341,8 +352,11 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
|
||||
}
|
||||
|
||||
// check arguments
|
||||
for i, a := range args {
|
||||
check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun))
|
||||
if len(args) > 0 {
|
||||
context := check.sprintf("argument to %s", call.Fun)
|
||||
for i, a := range args {
|
||||
check.assignment(a, sigParams.vars[i].typ, context)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -20,9 +20,6 @@
|
||||
// _ = x /* ERROR "not declared" */ + 1
|
||||
// }
|
||||
|
||||
// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
|
||||
// and test against strict mode.
|
||||
|
||||
package types2_test
|
||||
|
||||
import (
|
||||
|
@ -514,11 +514,26 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
|
||||
check.initVars(lhs, []syntax.Expr{init}, nopos)
|
||||
}
|
||||
|
||||
// isImportedConstraint reports whether typ is an imported type constraint.
|
||||
func (check *Checker) isImportedConstraint(typ Type) bool {
|
||||
named, _ := typ.(*Named)
|
||||
if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
|
||||
return false
|
||||
}
|
||||
u, _ := named.under().(*Interface)
|
||||
return u != nil && u.IsConstraint()
|
||||
}
|
||||
|
||||
func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
|
||||
assert(obj.typ == nil)
|
||||
|
||||
var rhs Type
|
||||
check.later(func() {
|
||||
check.validType(obj.typ, nil)
|
||||
// If typ is local, an error was already reported where typ is specified/defined.
|
||||
if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.errorf(tdecl.Type.Pos(), "using type constraint %s requires go1.18 or later", rhs)
|
||||
}
|
||||
})
|
||||
|
||||
alias := tdecl.Alias
|
||||
@ -540,7 +555,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
|
||||
}
|
||||
|
||||
obj.typ = Typ[Invalid]
|
||||
obj.typ = check.anyType(tdecl.Type)
|
||||
rhs = check.anyType(tdecl.Type)
|
||||
obj.typ = rhs
|
||||
return
|
||||
}
|
||||
|
||||
@ -555,8 +571,9 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
|
||||
}
|
||||
|
||||
// determine underlying type of named
|
||||
named.fromRHS = check.definedType(tdecl.Type, named)
|
||||
assert(named.fromRHS != nil)
|
||||
rhs = check.definedType(tdecl.Type, named)
|
||||
assert(rhs != nil)
|
||||
named.fromRHS = rhs
|
||||
// The underlying type of named may be itself a named type that is
|
||||
// incomplete:
|
||||
//
|
||||
|
@ -127,9 +127,7 @@ func (check *Checker) overflow(x *operand) {
|
||||
}
|
||||
|
||||
// opName returns the name of an operation, or the empty string.
|
||||
// For now, only operations that might overflow are handled.
|
||||
// TODO(gri) Expand this to a general mechanism giving names to
|
||||
// nodes?
|
||||
// Only operations that might overflow are handled.
|
||||
func opName(e *syntax.Operation) string {
|
||||
op := int(e.Op)
|
||||
if e.Y == nil {
|
||||
|
@ -29,8 +29,7 @@ func TestHilbert(t *testing.T) {
|
||||
}
|
||||
|
||||
// parse source
|
||||
// TODO(gri) get rid of []bytes to string conversion below
|
||||
f, err := parseSrc("hilbert.go", string(src))
|
||||
f, err := syntax.Parse(syntax.NewFileBase("hilbert.go"), bytes.NewReader(src), nil, nil, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -122,27 +122,26 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
|
||||
// instance creates a type or function instance using the given original type
|
||||
// typ and arguments targs. For Named types the resulting instance will be
|
||||
// unexpanded.
|
||||
func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) (res Type) {
|
||||
// TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
|
||||
func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) Type {
|
||||
switch t := typ.(type) {
|
||||
case *Named:
|
||||
h := instantiatedHash(t, targs)
|
||||
if check != nil {
|
||||
// typ may already have been instantiated with identical type arguments. In
|
||||
// that case, re-use the existing instance.
|
||||
// typ may already have been instantiated with identical type arguments.
|
||||
// In that case, re-use the existing instance.
|
||||
if named := check.typMap[h]; named != nil {
|
||||
return named
|
||||
}
|
||||
}
|
||||
|
||||
tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
|
||||
named := check.newNamed(tname, t, nil, nil, nil) // methods and tparams are set when named is loaded
|
||||
named.targs = NewTypeList(targs)
|
||||
named.instance = &instance{pos}
|
||||
named.instPos = &pos
|
||||
if check != nil {
|
||||
check.typMap[h] = named
|
||||
}
|
||||
res = named
|
||||
return named
|
||||
|
||||
case *Signature:
|
||||
tparams := t.TParams()
|
||||
if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
|
||||
@ -151,30 +150,22 @@ func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) (res Type
|
||||
if tparams.Len() == 0 {
|
||||
return typ // nothing to do (minor optimization)
|
||||
}
|
||||
defer func() {
|
||||
// If we had an unexpected failure somewhere don't panic below when
|
||||
// asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
|
||||
// is returned.
|
||||
if _, ok := res.(*Signature); !ok {
|
||||
return
|
||||
}
|
||||
// If the signature doesn't use its type parameters, subst
|
||||
// will not make a copy. In that case, make a copy now (so
|
||||
// we can set tparams to nil w/o causing side-effects).
|
||||
if t == res {
|
||||
copy := *t
|
||||
res = ©
|
||||
}
|
||||
// After instantiating a generic signature, it is not generic
|
||||
// anymore; we need to set tparams to nil.
|
||||
res.(*Signature).tparams = nil
|
||||
}()
|
||||
res = check.subst(pos, typ, makeSubstMap(tparams.list(), targs), nil)
|
||||
default:
|
||||
// only types and functions can be generic
|
||||
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||
sig := check.subst(pos, typ, makeSubstMap(tparams.list(), targs), nil).(*Signature)
|
||||
// If the signature doesn't use its type parameters, subst
|
||||
// will not make a copy. In that case, make a copy now (so
|
||||
// we can set tparams to nil w/o causing side-effects).
|
||||
if sig == t {
|
||||
copy := *sig
|
||||
sig = ©
|
||||
}
|
||||
// After instantiating a generic signature, it is not generic
|
||||
// anymore; we need to set tparams to nil.
|
||||
sig.tparams = nil
|
||||
return sig
|
||||
}
|
||||
return res
|
||||
|
||||
// only types and functions can be generic
|
||||
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||
}
|
||||
|
||||
// validateTArgLen verifies that the length of targs and tparams matches,
|
||||
|
@ -98,7 +98,7 @@ func (t *Interface) Empty() bool { return t.typeSet().IsAll() }
|
||||
func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() }
|
||||
|
||||
// IsConstraint reports whether interface t is not just a method set.
|
||||
func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() }
|
||||
func (t *Interface) IsConstraint() bool { return t.typeSet().IsConstraint() }
|
||||
|
||||
func (t *Interface) Underlying() Type { return t }
|
||||
func (t *Interface) String() string { return TypeString(t, nil) }
|
||||
|
@ -9,8 +9,6 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TODO(gri) Clean up Named struct below; specifically the fromRHS field (can we use underlying?).
|
||||
|
||||
// A Named represents a named (defined) type.
|
||||
type Named struct {
|
||||
check *Checker
|
||||
@ -19,7 +17,7 @@ type Named struct {
|
||||
orig *Named // original, uninstantiated type
|
||||
fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)
|
||||
underlying Type // possibly a *Named during setup; never a *Named once set up completely
|
||||
instance *instance // position information for lazy instantiation, or nil
|
||||
instPos *syntax.Pos // position information for lazy instantiation, or nil
|
||||
tparams *TParamList // type parameters, or nil
|
||||
targs *TypeList // type arguments (after instantiation), or nil
|
||||
methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
|
||||
@ -242,24 +240,16 @@ func (n *Named) setUnderlying(typ Type) {
|
||||
}
|
||||
}
|
||||
|
||||
// instance holds position information for use in lazy instantiation.
|
||||
//
|
||||
// TODO(rfindley): instance is probably unnecessary now. See if it can be
|
||||
// eliminated.
|
||||
type instance struct {
|
||||
pos syntax.Pos // position of type instantiation; for error reporting only
|
||||
}
|
||||
|
||||
// expand ensures that the underlying type of n is instantiated.
|
||||
// The underlying type will be Typ[Invalid] if there was an error.
|
||||
func (n *Named) expand(typMap map[string]*Named) *Named {
|
||||
if n.instance != nil {
|
||||
if n.instPos != nil {
|
||||
// n must be loaded before instantiation, in order to have accurate
|
||||
// tparams. This is done implicitly by the call to n.TParams, but making it
|
||||
// explicit is harmless: load is idempotent.
|
||||
n.load()
|
||||
var u Type
|
||||
if n.check.validateTArgLen(n.instance.pos, n.tparams.Len(), n.targs.Len()) {
|
||||
if n.check.validateTArgLen(*n.instPos, n.tparams.Len(), n.targs.Len()) {
|
||||
if typMap == nil {
|
||||
if n.check != nil {
|
||||
typMap = n.check.typMap
|
||||
@ -272,13 +262,13 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
|
||||
typMap = map[string]*Named{h: n}
|
||||
}
|
||||
}
|
||||
u = n.check.subst(n.instance.pos, n.orig.underlying, makeSubstMap(n.TParams().list(), n.targs.list()), typMap)
|
||||
u = n.check.subst(*n.instPos, n.orig.underlying, makeSubstMap(n.TParams().list(), n.targs.list()), typMap)
|
||||
} else {
|
||||
u = Typ[Invalid]
|
||||
}
|
||||
n.underlying = u
|
||||
n.fromRHS = u
|
||||
n.instance = nil
|
||||
n.instPos = nil
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
@ -412,52 +412,60 @@ func (check *Checker) collectObjects() {
|
||||
}
|
||||
|
||||
case *syntax.TypeDecl:
|
||||
if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) {
|
||||
check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
|
||||
}
|
||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
|
||||
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
|
||||
|
||||
case *syntax.FuncDecl:
|
||||
d := s // TODO(gri) get rid of this
|
||||
name := d.Name.Value
|
||||
obj := NewFunc(d.Name.Pos(), pkg, name, nil)
|
||||
if d.Recv == nil {
|
||||
name := s.Name.Value
|
||||
obj := NewFunc(s.Name.Pos(), pkg, name, nil)
|
||||
hasTParamError := false // avoid duplicate type parameter errors
|
||||
if s.Recv == nil {
|
||||
// regular function
|
||||
if name == "init" || name == "main" && pkg.name == "main" {
|
||||
if d.TParamList != nil {
|
||||
check.softErrorf(d, "func %s must have no type parameters", name)
|
||||
if len(s.TParamList) != 0 {
|
||||
check.softErrorf(s.TParamList[0], "func %s must have no type parameters", name)
|
||||
hasTParamError = true
|
||||
}
|
||||
if t := d.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
|
||||
check.softErrorf(d, "func %s must have no arguments and no return values", name)
|
||||
if t := s.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
|
||||
check.softErrorf(s, "func %s must have no arguments and no return values", name)
|
||||
}
|
||||
}
|
||||
// don't declare init functions in the package scope - they are invisible
|
||||
if name == "init" {
|
||||
obj.parent = pkg.scope
|
||||
check.recordDef(d.Name, obj)
|
||||
check.recordDef(s.Name, obj)
|
||||
// init functions must have a body
|
||||
if d.Body == nil {
|
||||
if s.Body == nil {
|
||||
// TODO(gri) make this error message consistent with the others above
|
||||
check.softErrorf(obj.pos, "missing function body")
|
||||
}
|
||||
} else {
|
||||
check.declare(pkg.scope, d.Name, obj, nopos)
|
||||
check.declare(pkg.scope, s.Name, obj, nopos)
|
||||
}
|
||||
} else {
|
||||
// method
|
||||
// d.Recv != nil
|
||||
if !acceptMethodTypeParams && len(d.TParamList) != 0 {
|
||||
if !acceptMethodTypeParams && len(s.TParamList) != 0 {
|
||||
//check.error(d.TParamList.Pos(), invalidAST + "method must have no type parameters")
|
||||
check.error(d, invalidAST+"method must have no type parameters")
|
||||
check.error(s.TParamList[0], invalidAST+"method must have no type parameters")
|
||||
hasTParamError = true
|
||||
}
|
||||
ptr, recv, _ := check.unpackRecv(d.Recv.Type, false)
|
||||
ptr, recv, _ := check.unpackRecv(s.Recv.Type, false)
|
||||
// (Methods with invalid receiver cannot be associated to a type, and
|
||||
// methods with blank _ names are never found; no need to collect any
|
||||
// of them. They will still be type-checked with all the other functions.)
|
||||
if recv != nil && name != "_" {
|
||||
methods = append(methods, methodInfo{obj, ptr, recv})
|
||||
}
|
||||
check.recordDef(d.Name, obj)
|
||||
check.recordDef(s.Name, obj)
|
||||
}
|
||||
info := &declInfo{file: fileScope, fdecl: d}
|
||||
if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
|
||||
check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
|
||||
}
|
||||
info := &declInfo{file: fileScope, fdecl: s}
|
||||
// Methods are not package-level objects but we still track them in the
|
||||
// object map so that we can handle them like regular functions (if the
|
||||
// receiver is invalid); also we need their fdecl info when associating
|
||||
|
@ -24,12 +24,7 @@ func TestSelf(t *testing.T) {
|
||||
conf := Config{Importer: defaultImporter()}
|
||||
_, err = conf.Check("cmd/compile/internal/types2", files, nil)
|
||||
if err != nil {
|
||||
// Importing go/constant doesn't work in the
|
||||
// build dashboard environment. Don't report an error
|
||||
// for now so that the build remains green.
|
||||
// TODO(gri) fix this
|
||||
t.Log(err) // replace w/ t.Fatal eventually
|
||||
return
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,12 +150,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
// TODO(gri) should we assume now that bounds always exist?
|
||||
// (no bound == empty interface)
|
||||
if bound != nil {
|
||||
bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
tpar.bound = bound
|
||||
}
|
||||
tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,11 +52,6 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
|
||||
check.error(body.Rbrace, "missing return")
|
||||
}
|
||||
|
||||
// TODO(gri) Should we make it an error to declare generic functions
|
||||
// where the type parameters are not used?
|
||||
// 12/19/2018: Probably not - it can make sense to have an API with
|
||||
// all functions uniformly sharing the same type parameters.
|
||||
|
||||
// spec: "Implementation restriction: A compiler may make it illegal to
|
||||
// declare a variable inside a function body if the variable is never used."
|
||||
check.usage(sig.scope)
|
||||
@ -422,7 +417,6 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
||||
check.assignVar(lhs[0], &x)
|
||||
|
||||
case *syntax.CallStmt:
|
||||
// TODO(gri) get rid of this conversion to string
|
||||
kind := "go"
|
||||
if s.Tok == syntax.Defer {
|
||||
kind = "defer"
|
||||
|
@ -38,7 +38,7 @@ func (m substMap) lookup(tpar *TypeParam) Type {
|
||||
// subst returns the type typ with its type parameters tpars replaced by the
|
||||
// corresponding type arguments targs, recursively. subst doesn't modify the
|
||||
// incoming type. If a substitution took place, the result type is different
|
||||
// from from the incoming type.
|
||||
// from the incoming type.
|
||||
//
|
||||
// If the given typMap is non-nil, it is used in lieu of check.typMap.
|
||||
func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[string]*Named) Type {
|
||||
|
@ -146,7 +146,7 @@ type (
|
||||
m1(I5)
|
||||
}
|
||||
I6 interface {
|
||||
S0 /* ERROR "not an interface" */
|
||||
S0 /* ERROR "non-interface type S0" */
|
||||
}
|
||||
I7 interface {
|
||||
I1
|
||||
|
@ -79,11 +79,11 @@ func issue9473(a []int, b ...int) {
|
||||
// Check that embedding a non-interface type in an interface results in a good error message.
|
||||
func issue10979() {
|
||||
type _ interface {
|
||||
int /* ERROR int is not an interface */
|
||||
int /* ERROR non-interface type int */
|
||||
}
|
||||
type T struct{}
|
||||
type _ interface {
|
||||
T /* ERROR T is not an interface */
|
||||
T /* ERROR non-interface type T */
|
||||
}
|
||||
type _ interface {
|
||||
nosuchtype /* ERROR undeclared name: nosuchtype */
|
||||
@ -280,7 +280,7 @@ type issue25301b /* ERROR cycle */ = interface {
|
||||
}
|
||||
|
||||
type issue25301c interface {
|
||||
notE // ERROR struct\{\} is not an interface
|
||||
notE // ERROR non-interface type struct\{\}
|
||||
}
|
||||
|
||||
type notE = struct{}
|
||||
|
@ -4,4 +4,4 @@
|
||||
|
||||
package main
|
||||
|
||||
func /* ERROR "func main must have no type parameters" */ main[T any]() {}
|
||||
func main [T /* ERROR "func main must have no type parameters" */ any]() {}
|
||||
|
@ -15,7 +15,7 @@ type any interface{}
|
||||
// f("a", "b", "c", "d")
|
||||
// f0("a", "b", "c", "d")
|
||||
// }
|
||||
//
|
||||
//
|
||||
// func f1[A any, B interface{~A}](A, B)
|
||||
// func _() {
|
||||
// f := f1[int]
|
||||
@ -60,9 +60,7 @@ func _() {
|
||||
var _ string = x
|
||||
}
|
||||
|
||||
// TODO(gri) Need to flag invalid recursive constraints. At the
|
||||
// moment these cause infinite recursions and stack overflow.
|
||||
// func f7[A interface{type B}, B interface{~A}]()
|
||||
func f7[A interface{*B}, B interface{~*A}]() {}
|
||||
|
||||
// More realistic examples
|
||||
|
||||
|
@ -304,8 +304,8 @@ var _ = f8[int, float64](0, 0, nil...) // test case for #18268
|
||||
// init functions cannot have type parameters
|
||||
|
||||
func init() {}
|
||||
func init[/* ERROR func init must have no type parameters */ _ any]() {}
|
||||
func init[/* ERROR func init must have no type parameters */ P any]() {}
|
||||
func init[_ /* ERROR func init must have no type parameters */ any]() {}
|
||||
func init[P /* ERROR func init must have no type parameters */ any]() {}
|
||||
|
||||
type T struct {}
|
||||
|
||||
|
59
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2
vendored
Normal file
59
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
// Parser accepts type parameters but the type checker
|
||||
// needs to report any operations that are not permitted
|
||||
// before Go 1.18.
|
||||
|
||||
package go1_17
|
||||
|
||||
type T[P /* ERROR type parameters require go1\.18 or later */ any] struct{}
|
||||
|
||||
// for init (and main, but we're not in package main) we should only get one error
|
||||
func init[P /* ERROR func init must have no type parameters */ any]() {}
|
||||
func main[P /* ERROR type parameters require go1\.18 or later */ any]() {}
|
||||
|
||||
func f[P /* ERROR type parameters require go1\.18 or later */ any](x P) {
|
||||
var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
|
||||
var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
|
||||
_ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
|
||||
_ = T[ /* ERROR type instantiation requires go1\.18 or later */ int](struct{}{})
|
||||
}
|
||||
|
||||
func (T[ /* ERROR type instantiation requires go1\.18 or later */ P]) g(x int) {
|
||||
f[ /* ERROR function instantiation requires go1\.18 or later */ int](0) // explicit instantiation
|
||||
(f[ /* ERROR function instantiation requires go1\.18 or later */ int])(0) // parentheses (different code path)
|
||||
f( /* ERROR implicit function instantiation requires go1\.18 or later */ x) // implicit instantiation
|
||||
}
|
||||
|
||||
type C1 interface {
|
||||
comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
|
||||
}
|
||||
|
||||
type C2 interface {
|
||||
comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
|
||||
int // ERROR embedding non-interface type int requires go1\.18 or later
|
||||
~ /* ERROR embedding interface element ~int requires go1\.18 or later */ int
|
||||
int /* ERROR embedding interface element int\|~string requires go1\.18 or later */ | ~string
|
||||
}
|
||||
|
||||
type _ interface {
|
||||
// errors for these were reported with their declaration
|
||||
C1
|
||||
C2
|
||||
}
|
||||
|
||||
type (
|
||||
_ comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
|
||||
// errors for these were reported with their declaration
|
||||
_ C1
|
||||
_ C2
|
||||
|
||||
_ = comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
|
||||
// errors for these were reported with their declaration
|
||||
_ = C1
|
||||
_ = C2
|
||||
)
|
||||
|
||||
// TODO(gri) need test cases for imported constraint types (see also issue #47967)
|
@ -16,8 +16,6 @@ func NewTuple(x ...*Var) *Tuple {
|
||||
if len(x) > 0 {
|
||||
return &Tuple{vars: x}
|
||||
}
|
||||
// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
|
||||
// it's too subtle and causes problems.
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ func (t *top) String() string { return TypeString(t, nil) }
|
||||
// under must only be called when a type is known
|
||||
// to be fully set up.
|
||||
func under(t Type) Type {
|
||||
// TODO(gri) is this correct for *Union?
|
||||
if n := asNamed(t); n != nil {
|
||||
return n.under()
|
||||
}
|
||||
|
@ -30,10 +30,8 @@ func (s *_TypeSet) IsAll() bool {
|
||||
return !s.comparable && len(s.methods) == 0 && s.terms.isAll()
|
||||
}
|
||||
|
||||
// TODO(gri) IsMethodSet is not a great name for this predicate. Find a better one.
|
||||
|
||||
// IsMethodSet reports whether the type set s is described by a single set of methods.
|
||||
func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() }
|
||||
// IsConstraint reports whether type set s is not just a set of methods.
|
||||
func (s *_TypeSet) IsConstraint() bool { return s.comparable || !s.terms.isAll() }
|
||||
|
||||
// IsComparable reports whether each type in the set is comparable.
|
||||
func (s *_TypeSet) IsComparable() bool {
|
||||
@ -79,26 +77,24 @@ func (s *_TypeSet) String() string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('{')
|
||||
if s.comparable {
|
||||
buf.WriteString(" comparable")
|
||||
buf.WriteString("comparable")
|
||||
if hasMethods || hasTerms {
|
||||
buf.WriteByte(';')
|
||||
buf.WriteString("; ")
|
||||
}
|
||||
}
|
||||
for i, m := range s.methods {
|
||||
if i > 0 {
|
||||
buf.WriteByte(';')
|
||||
buf.WriteString("; ")
|
||||
}
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(m.String())
|
||||
}
|
||||
if hasMethods && hasTerms {
|
||||
buf.WriteByte(';')
|
||||
buf.WriteString("; ")
|
||||
}
|
||||
if hasTerms {
|
||||
buf.WriteString(s.terms.String())
|
||||
}
|
||||
buf.WriteString(" }") // there was at least one method or term
|
||||
|
||||
buf.WriteString("}")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
@ -271,6 +267,11 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
switch u := under(typ).(type) {
|
||||
case *Interface:
|
||||
tset := computeInterfaceTypeSet(check, pos, u)
|
||||
// If typ is local, an error was already reported where typ is specified/defined.
|
||||
if check != nil && check.isImportedConstraint(typ) && !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.errorf(pos, "embedding constraint interface %s requires go1.18 or later", typ)
|
||||
continue
|
||||
}
|
||||
if tset.comparable {
|
||||
ityp.tset.comparable = true
|
||||
}
|
||||
@ -279,6 +280,10 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
}
|
||||
terms = tset.terms
|
||||
case *Union:
|
||||
if check != nil && !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.errorf(pos, "embedding interface element %s requires go1.18 or later", u)
|
||||
continue
|
||||
}
|
||||
tset := computeUnionTypeSet(check, pos, u)
|
||||
if tset == &invalidTypeSet {
|
||||
continue // ignore invalid unions
|
||||
@ -293,7 +298,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
continue
|
||||
}
|
||||
if check != nil && !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.errorf(pos, "%s is not an interface", typ)
|
||||
check.errorf(pos, "embedding non-interface type %s requires go1.18 or later", typ)
|
||||
continue
|
||||
}
|
||||
terms = termlist{{false, typ}}
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
package types2
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInvalidTypeSet(t *testing.T) {
|
||||
if !invalidTypeSet.IsEmpty() {
|
||||
@ -12,4 +16,65 @@ func TestInvalidTypeSet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeSetString(t *testing.T) {
|
||||
for body, want := range map[string]string{
|
||||
"{}": "𝓤",
|
||||
"{int}": "{int}",
|
||||
"{~int}": "{~int}",
|
||||
"{int|string}": "{int ∪ string}",
|
||||
"{int; string}": "∅",
|
||||
|
||||
"{comparable}": "{comparable}",
|
||||
"{comparable; int}": "{comparable; int}",
|
||||
"{~int; comparable}": "{comparable; ~int}",
|
||||
"{int|string; comparable}": "{comparable; int ∪ string}",
|
||||
"{comparable; int; string}": "∅",
|
||||
|
||||
"{m()}": "{func (p.T).m()}",
|
||||
"{m1(); m2() int }": "{func (p.T).m1(); func (p.T).m2() int}",
|
||||
"{error}": "{func (error).Error() string}",
|
||||
"{m(); comparable}": "{comparable; func (p.T).m()}",
|
||||
"{m1(); comparable; m2() int }": "{comparable; func (p.T).m1(); func (p.T).m2() int}",
|
||||
"{comparable; error}": "{comparable; func (error).Error() string}",
|
||||
|
||||
"{m(); comparable; int|float32|string}": "{comparable; func (p.T).m(); int ∪ float32 ∪ string}",
|
||||
"{m1(); int; m2(); comparable }": "{comparable; func (p.T).m1(); func (p.T).m2(); int}",
|
||||
|
||||
"{E}; type E interface{}": "𝓤",
|
||||
"{E}; type E interface{int;string}": "∅",
|
||||
"{E}; type E interface{comparable}": "{comparable}",
|
||||
} {
|
||||
// parse
|
||||
errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
|
||||
src := "package p; type T interface" + body
|
||||
file, err := syntax.Parse(nil, strings.NewReader(src), errh, nil, syntax.AllowGenerics)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v (invalid test case)", body, err)
|
||||
}
|
||||
|
||||
// type check
|
||||
var conf Config
|
||||
pkg, err := conf.Check(file.PkgName.Value, []*syntax.File{file}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v (invalid test case)", body, err)
|
||||
}
|
||||
|
||||
// lookup T
|
||||
obj := pkg.scope.Lookup("T")
|
||||
if obj == nil {
|
||||
t.Fatalf("%s: T not found (invalid test case)", body)
|
||||
}
|
||||
T, ok := under(obj.Type()).(*Interface)
|
||||
if !ok {
|
||||
t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
|
||||
}
|
||||
|
||||
// verify test case
|
||||
got := T.typeSet().String()
|
||||
if got != want {
|
||||
t.Errorf("%s: got %s; want %s", body, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gri) add more tests
|
||||
|
@ -195,7 +195,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
||||
}
|
||||
|
||||
case *Named:
|
||||
if t.instance != nil {
|
||||
if t.instPos != nil {
|
||||
buf.WriteByte(instanceMarker)
|
||||
}
|
||||
writeTypeName(buf, t.obj, qf)
|
||||
@ -279,6 +279,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeParam, qf Qualifier, visited
|
||||
|
||||
func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
|
||||
if obj == nil {
|
||||
assert(instanceHashing == 0) // we need an object for instance hashing
|
||||
buf.WriteString("<Named w/o object>")
|
||||
return
|
||||
}
|
||||
|
@ -38,14 +38,12 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
|
||||
}
|
||||
return
|
||||
case universeAny, universeComparable:
|
||||
// complain if necessary but keep going
|
||||
if !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.errorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
|
||||
return
|
||||
}
|
||||
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
|
||||
if obj == universeAny {
|
||||
check.error(e, "cannot use any outside constraint position")
|
||||
return
|
||||
check.softErrorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
|
||||
} else if obj == universeAny {
|
||||
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
|
||||
check.softErrorf(e, "cannot use any outside constraint position")
|
||||
}
|
||||
}
|
||||
check.recordUse(e, obj)
|
||||
@ -153,7 +151,7 @@ func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
|
||||
check.later(func() {
|
||||
if t := asInterface(typ); t != nil {
|
||||
tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position?
|
||||
if !tset.IsMethodSet() {
|
||||
if tset.IsConstraint() {
|
||||
if tset.comparable {
|
||||
check.softErrorf(pos, "interface is (or embeds) comparable")
|
||||
} else {
|
||||
@ -274,6 +272,9 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
|
||||
}
|
||||
|
||||
case *syntax.IndexExpr:
|
||||
if !check.allowVersion(check.pkg, 1, 18) {
|
||||
check.softErrorf(e.Pos(), "type instantiation requires go1.18 or later")
|
||||
}
|
||||
return check.instantiatedType(e.X, unpackExpr(e.Index), def)
|
||||
|
||||
case *syntax.ParenExpr:
|
||||
|
@ -433,9 +433,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
|
||||
xargs := x.targs.list()
|
||||
yargs := y.targs.list()
|
||||
|
||||
// TODO(gri) This is not always correct: two types may have the same names
|
||||
// in the same package if one of them is nested in a function.
|
||||
// Extremely unlikely but we need an always correct solution.
|
||||
if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
|
||||
assert(len(xargs) == len(yargs))
|
||||
for i, x := range xargs {
|
||||
|
@ -413,11 +413,15 @@ func byteindex(n ir.Node) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
func walkCheckPtrAlignment(n *ir.ConvExpr, init *ir.Nodes, count ir.Node) ir.Node {
|
||||
func walkCheckPtrAlignment(n *ir.ConvExpr, init *ir.Nodes, se *ir.SliceExpr) ir.Node {
|
||||
if !n.Type().IsPtr() {
|
||||
base.Fatalf("expected pointer type: %v", n.Type())
|
||||
}
|
||||
elem := n.Type().Elem()
|
||||
var count ir.Node
|
||||
if se != nil {
|
||||
count = se.Max
|
||||
}
|
||||
if count != nil {
|
||||
if !elem.IsArray() {
|
||||
base.Fatalf("expected array type: %v", elem)
|
||||
@ -435,7 +439,12 @@ func walkCheckPtrAlignment(n *ir.ConvExpr, init *ir.Nodes, count ir.Node) ir.Nod
|
||||
}
|
||||
|
||||
n.X = cheapExpr(n.X, init)
|
||||
init.Append(mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), reflectdata.TypePtr(elem), typecheck.Conv(count, types.Types[types.TUINTPTR])))
|
||||
checkPtrCall := mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), reflectdata.TypePtr(elem), typecheck.Conv(count, types.Types[types.TUINTPTR]))
|
||||
if se != nil {
|
||||
se.CheckPtrCall = checkPtrCall
|
||||
} else {
|
||||
init.Append(checkPtrCall)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -824,7 +824,7 @@ func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
|
||||
n.High = walkExpr(n.High, init)
|
||||
n.Max = walkExpr(n.Max, init)
|
||||
if checkSlice {
|
||||
n.X = walkCheckPtrAlignment(n.X.(*ir.ConvExpr), init, n.Max)
|
||||
n.X = walkCheckPtrAlignment(n.X.(*ir.ConvExpr), init, n)
|
||||
}
|
||||
|
||||
if n.Op().IsSlice3() {
|
||||
|
@ -75,7 +75,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
|
||||
}
|
||||
|
||||
pkgpath := pkgPath(a)
|
||||
gcargs := []string{"-p", pkgpath}
|
||||
gcflags := []string{"-p", pkgpath}
|
||||
if p.Module != nil {
|
||||
v := p.Module.GoVersion
|
||||
if v == "" {
|
||||
@ -94,11 +94,11 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
|
||||
v = "1.16"
|
||||
}
|
||||
if allowedVersion(v) {
|
||||
gcargs = append(gcargs, "-lang=go"+v)
|
||||
gcflags = append(gcflags, "-lang=go"+v)
|
||||
}
|
||||
}
|
||||
if p.Standard {
|
||||
gcargs = append(gcargs, "-std")
|
||||
gcflags = append(gcflags, "-std")
|
||||
}
|
||||
_, compilingRuntime := runtimePackages[p.ImportPath]
|
||||
compilingRuntime = compilingRuntime && p.Standard
|
||||
@ -106,7 +106,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
|
||||
// runtime compiles with a special gc flag to check for
|
||||
// memory allocations that are invalid in the runtime package,
|
||||
// and to implement some special compiler pragmas.
|
||||
gcargs = append(gcargs, "-+")
|
||||
gcflags = append(gcflags, "-+")
|
||||
}
|
||||
|
||||
// If we're giving the compiler the entire package (no C etc files), tell it that,
|
||||
@ -125,25 +125,25 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
|
||||
}
|
||||
}
|
||||
if extFiles == 0 {
|
||||
gcargs = append(gcargs, "-complete")
|
||||
gcflags = append(gcflags, "-complete")
|
||||
}
|
||||
if cfg.BuildContext.InstallSuffix != "" {
|
||||
gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
|
||||
gcflags = append(gcflags, "-installsuffix", cfg.BuildContext.InstallSuffix)
|
||||
}
|
||||
if a.buildID != "" {
|
||||
gcargs = append(gcargs, "-buildid", a.buildID)
|
||||
gcflags = append(gcflags, "-buildid", a.buildID)
|
||||
}
|
||||
if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" {
|
||||
gcargs = append(gcargs, "-dwarf=false")
|
||||
gcflags = append(gcflags, "-dwarf=false")
|
||||
}
|
||||
if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
|
||||
gcargs = append(gcargs, "-goversion", runtimeVersion)
|
||||
gcflags = append(gcflags, "-goversion", runtimeVersion)
|
||||
}
|
||||
if symabis != "" {
|
||||
gcargs = append(gcargs, "-symabis", symabis)
|
||||
gcflags = append(gcflags, "-symabis", symabis)
|
||||
}
|
||||
|
||||
gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags)
|
||||
gcflags = append(gcflags, str.StringList(forcedGcflags, p.Internal.Gcflags)...)
|
||||
if compilingRuntime {
|
||||
// Remove -N, if present.
|
||||
// It is not possible to build the runtime with no optimizations,
|
||||
@ -157,7 +157,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
|
||||
}
|
||||
}
|
||||
|
||||
args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), gcflags, gcargs}
|
||||
args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), gcflags}
|
||||
if p.Internal.LocalPrefix != "" {
|
||||
// Workaround #43883.
|
||||
args = append(args, "-D", p.Internal.LocalPrefix)
|
||||
|
20
src/cmd/go/testdata/script/build_gcflags_order.txt
vendored
Normal file
20
src/cmd/go/testdata/script/build_gcflags_order.txt
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Tests golang.org/issue/47682
|
||||
# Flags specified with -gcflags should appear after other flags generated by cmd/go.
|
||||
|
||||
cd m
|
||||
go build -n -gcflags=-lang=go1.17
|
||||
stderr ' -lang=go1.16.* -lang=go1.17'
|
||||
|
||||
-- m/go.mod --
|
||||
module example.com
|
||||
|
||||
go 1.16
|
||||
|
||||
-- m/main.go --
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var s = []int{1, 2, 3}
|
||||
var pa = (*[2]int)(s[1:])
|
||||
println(pa[1])
|
||||
}
|
@ -8,4 +8,4 @@ mkdir $GOCACHE
|
||||
# Verify the standard library (specifically runtime/internal/atomic) can be
|
||||
# built with -gcflags when -n is given. See golang.org/issue/29346.
|
||||
go build -n -gcflags=all='-l' std
|
||||
stderr 'compile.* -l .* runtime/internal/atomic'
|
||||
stderr 'compile.* runtime/internal/atomic .* -l'
|
||||
|
22
src/cmd/go/testdata/script/gcflags_patterns.txt
vendored
22
src/cmd/go/testdata/script/gcflags_patterns.txt
vendored
@ -7,28 +7,28 @@ env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache
|
||||
|
||||
# -gcflags=-e applies to named packages, not dependencies
|
||||
go build -n -v -gcflags=-e z1 z2
|
||||
stderr 'compile.* -e.* -p z1'
|
||||
stderr 'compile.* -e.* -p z2'
|
||||
stderr 'compile.* -p z1.* -e'
|
||||
stderr 'compile.* -p z2.* -e'
|
||||
stderr 'compile.* -p y'
|
||||
! stderr 'compile.* -e.* -p [^z]'
|
||||
! stderr 'compile.* -p [^z].* -e'
|
||||
|
||||
# -gcflags can specify package=flags, and can be repeated; last match wins
|
||||
go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2
|
||||
stderr 'compile.* -N.* -p z1'
|
||||
! stderr 'compile.* -e.* -p z1'
|
||||
! stderr 'compile.* -N.* -p z2'
|
||||
stderr 'compile.* -e.* -p z2'
|
||||
stderr 'compile.* -p z1.* -N'
|
||||
! stderr 'compile.* -p z1.* -e'
|
||||
! stderr 'compile.* -p z2.* -N'
|
||||
stderr 'compile.* -p z2.* -e'
|
||||
stderr 'compile.* -p y'
|
||||
! stderr 'compile.* -e.* -p [^z]'
|
||||
! stderr 'compile.* -N.* -p [^z]'
|
||||
! stderr 'compile.* -p [^z].* -e'
|
||||
! stderr 'compile.* -p [^z].* -N'
|
||||
|
||||
# -gcflags can have arbitrary spaces around the flags
|
||||
go build -n -v -gcflags=' z1 = -e ' z1
|
||||
stderr 'compile.* -e.* -p z1'
|
||||
stderr 'compile.* -p z1.* -e'
|
||||
|
||||
# -gcflags='all=-e' should apply to all packages, even with go test
|
||||
go test -c -n -gcflags='all=-e' z1
|
||||
stderr 'compile.* -e.* -p z3 '
|
||||
stderr 'compile.* -p z3.* -e '
|
||||
|
||||
# this particular -gcflags argument made the compiler crash
|
||||
! go build -gcflags=-d=ssa/ z1
|
||||
|
@ -659,7 +659,7 @@ type Config struct {
|
||||
// cipher suite based on logic that takes into account inferred client
|
||||
// hardware, server hardware, and security.
|
||||
//
|
||||
// Deprected: PreferServerCipherSuites is ignored.
|
||||
// Deprecated: PreferServerCipherSuites is ignored.
|
||||
PreferServerCipherSuites bool
|
||||
|
||||
// SessionTicketsDisabled may be set to true to disable session ticket and
|
||||
|
@ -83,8 +83,7 @@
|
||||
//
|
||||
// The //go:embed directive can be used with both exported and unexported variables,
|
||||
// depending on whether the package wants to make the data available to other packages.
|
||||
// It can only be used with global variables at package scope,
|
||||
// not with local variables.
|
||||
// It can only be used with variables at package scope, not with local variables.
|
||||
//
|
||||
// Patterns must not match files outside the package's module, such as ‘.git/*’ or symbolic links.
|
||||
// Matches for empty directories are ignored. After that, each pattern in a //go:embed line
|
||||
|
@ -129,3 +129,43 @@ func TestUninitialized(t *testing.T) {
|
||||
t.Errorf("in uninitialized embed.FS, . is not a directory")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloT []T
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloUint8 []uint8
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloEUint8 []EmbedUint8
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloBytes EmbedBytes
|
||||
//go:embed "testdata/hello.txt"
|
||||
helloString EmbedString
|
||||
)
|
||||
|
||||
type T byte
|
||||
type EmbedUint8 uint8
|
||||
type EmbedBytes []byte
|
||||
type EmbedString string
|
||||
|
||||
// golang.org/issue/47735
|
||||
func TestAliases(t *testing.T) {
|
||||
all := testDirAll
|
||||
want, e := all.ReadFile("testdata/hello.txt")
|
||||
if e != nil {
|
||||
t.Fatal("ReadFile:", e)
|
||||
}
|
||||
check := func(g interface{}) {
|
||||
got := reflect.ValueOf(g)
|
||||
for i := 0; i < got.Len(); i++ {
|
||||
if byte(got.Index(i).Uint()) != want[i] {
|
||||
t.Fatalf("got %v want %v", got.Bytes(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
check(helloT)
|
||||
check(helloUint8)
|
||||
check(helloEUint8)
|
||||
check(helloBytes)
|
||||
check(helloString)
|
||||
}
|
||||
|
@ -347,8 +347,11 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
|
||||
}
|
||||
|
||||
// check arguments
|
||||
for i, a := range args {
|
||||
check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun))
|
||||
if len(args) > 0 {
|
||||
context := check.sprintf("argument to %s", call.Fun)
|
||||
for i, a := range args {
|
||||
check.assignment(a, sigParams.vars[i].typ, context)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -407,7 +407,7 @@ func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature
|
||||
assert(call != nil)
|
||||
assert(sig != nil)
|
||||
if m := check.Inferred; m != nil {
|
||||
m[call] = Inferred{&TypeList{targs}, sig}
|
||||
m[call] = Inferred{NewTypeList(targs), sig}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ func (check *Checker) instance(pos token.Pos, typ Type, targs []Type) (res Type)
|
||||
|
||||
tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
|
||||
named := check.newNamed(tname, t, nil, nil, nil) // methods and tparams are set when named is loaded
|
||||
named.targs = &TypeList{targs}
|
||||
named.targs = NewTypeList(targs)
|
||||
named.instance = &instance{pos}
|
||||
if check != nil {
|
||||
check.typMap[h] = named
|
||||
|
@ -312,16 +312,14 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if nargs := len(xargs); nargs > 0 {
|
||||
if len(xargs) > 0 {
|
||||
// Instances are identical if their original type and type arguments
|
||||
// are identical.
|
||||
if !Identical(x.orig, y.orig) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < nargs; i++ {
|
||||
xa := xargs[i]
|
||||
ya := yargs[i]
|
||||
if !Identical(xa, ya) {
|
||||
for i, xa := range xargs {
|
||||
if !Identical(xa, yargs[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ func (subst *subster) typ(typ Type) Type {
|
||||
// It's ok to provide a nil *Checker because the newly created type
|
||||
// doesn't need to be (lazily) expanded; it's expanded below.
|
||||
named := (*Checker)(nil).newNamed(tname, t.orig, nil, t.tparams, t.methods) // t is loaded, so tparams and methods are available
|
||||
named.targs = &TypeList{newTArgs}
|
||||
named.targs = NewTypeList(newTArgs)
|
||||
subst.typMap[h] = named
|
||||
t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion
|
||||
|
||||
|
@ -27,6 +27,14 @@ func (l *TParamList) list() []*TypeParam {
|
||||
// TypeList holds a list of types.
|
||||
type TypeList struct{ types []Type }
|
||||
|
||||
// NewTypeList returns a new TypeList with the types in list.
|
||||
func NewTypeList(list []Type) *TypeList {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &TypeList{list}
|
||||
}
|
||||
|
||||
// Len returns the number of types in the list.
|
||||
// It is safe to call on a nil receiver.
|
||||
func (l *TypeList) Len() int { return len(l.list()) }
|
||||
|
@ -20,6 +20,7 @@ const (
|
||||
func init() {
|
||||
userImplemented = false
|
||||
groupImplemented = false
|
||||
groupListImplemented = false
|
||||
}
|
||||
|
||||
func current() (*User, error) {
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
groupImplemented = false
|
||||
groupListImplemented = false
|
||||
}
|
||||
|
||||
func current() (*User, error) {
|
||||
|
@ -18,13 +18,15 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const groupFile = "/etc/group"
|
||||
const userFile = "/etc/passwd"
|
||||
const (
|
||||
groupFile = "/etc/group"
|
||||
userFile = "/etc/passwd"
|
||||
)
|
||||
|
||||
var colon = []byte{':'}
|
||||
|
||||
func init() {
|
||||
groupImplemented = false
|
||||
groupListImplemented = false
|
||||
}
|
||||
|
||||
// lineFunc returns a value, an error, or (nil, nil) to skip the row.
|
||||
|
@ -20,9 +20,12 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// These may be set to false in init() for a particular platform and/or
|
||||
// build flags to let the tests know to skip tests of some features.
|
||||
var (
|
||||
userImplemented = true // set to false by lookup_stubs.go's init
|
||||
groupImplemented = true // set to false by lookup_stubs.go's init
|
||||
userImplemented = true
|
||||
groupImplemented = true
|
||||
groupListImplemented = true
|
||||
)
|
||||
|
||||
// User represents a user account.
|
||||
|
@ -119,8 +119,15 @@ func TestLookupGroup(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func checkGroupList(t *testing.T) {
|
||||
t.Helper()
|
||||
if !groupListImplemented {
|
||||
t.Skip("user: group list not implemented; skipping test")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupIds(t *testing.T) {
|
||||
checkGroup(t)
|
||||
checkGroupList(t)
|
||||
if runtime.GOOS == "aix" {
|
||||
t.Skip("skipping GroupIds, see golang.org/issue/30563")
|
||||
}
|
||||
|
@ -336,6 +336,47 @@ func TestSetValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapIterSet(t *testing.T) {
|
||||
m := make(map[string]interface{}, len(valueTests))
|
||||
for _, tt := range valueTests {
|
||||
m[tt.s] = tt.i
|
||||
}
|
||||
v := ValueOf(m)
|
||||
|
||||
k := New(v.Type().Key()).Elem()
|
||||
e := New(v.Type().Elem()).Elem()
|
||||
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
iter.SetKey(k)
|
||||
iter.SetValue(e)
|
||||
want := m[k.String()]
|
||||
got := e.Interface()
|
||||
if got != want {
|
||||
t.Errorf("%q: want (%T) %v, got (%T) %v", k.String(), want, want, got, got)
|
||||
}
|
||||
if setkey, key := valueToString(k), valueToString(iter.Key()); setkey != key {
|
||||
t.Errorf("MapIter.Key() = %q, MapIter.SetKey() = %q", key, setkey)
|
||||
}
|
||||
if setval, val := valueToString(e), valueToString(iter.Value()); setval != val {
|
||||
t.Errorf("MapIter.Value() = %q, MapIter.SetValue() = %q", val, setval)
|
||||
}
|
||||
}
|
||||
|
||||
got := int(testing.AllocsPerRun(10, func() {
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
iter.SetKey(k)
|
||||
iter.SetValue(e)
|
||||
}
|
||||
}))
|
||||
// Making a *MapIter and making an hiter both allocate.
|
||||
// Those should be the only two allocations.
|
||||
if got != 2 {
|
||||
t.Errorf("wanted 2 allocs, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanSetField(t *testing.T) {
|
||||
type embed struct{ x, X int }
|
||||
type Embed struct{ x, X int }
|
||||
|
@ -1578,13 +1578,40 @@ func (it *MapIter) Key() Value {
|
||||
if it.it == nil {
|
||||
panic("MapIter.Key called before Next")
|
||||
}
|
||||
if mapiterkey(it.it) == nil {
|
||||
iterkey := mapiterkey(it.it)
|
||||
if iterkey == nil {
|
||||
panic("MapIter.Key called on exhausted iterator")
|
||||
}
|
||||
|
||||
t := (*mapType)(unsafe.Pointer(it.m.typ))
|
||||
ktype := t.key
|
||||
return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), mapiterkey(it.it))
|
||||
return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), iterkey)
|
||||
}
|
||||
|
||||
// SetKey assigns dst to the key of the iterator's current map entry.
|
||||
// It is equivalent to dst.Set(it.Key()), but it avoids allocating a new Value.
|
||||
// As in Go, the key must be assignable to dst's type.
|
||||
func (it *MapIter) SetKey(dst Value) {
|
||||
if it.it == nil {
|
||||
panic("MapIter.SetKey called before Next")
|
||||
}
|
||||
iterkey := mapiterkey(it.it)
|
||||
if iterkey == nil {
|
||||
panic("MapIter.SetKey called on exhausted iterator")
|
||||
}
|
||||
|
||||
dst.mustBeAssignable()
|
||||
var target unsafe.Pointer
|
||||
if dst.kind() == Interface {
|
||||
target = dst.ptr
|
||||
}
|
||||
|
||||
t := (*mapType)(unsafe.Pointer(it.m.typ))
|
||||
ktype := t.key
|
||||
|
||||
key := Value{ktype, iterkey, it.m.flag | flag(ktype.Kind())}
|
||||
key = key.assignTo("reflect.MapIter.SetKey", dst.typ, target)
|
||||
typedmemmove(dst.typ, dst.ptr, key.ptr)
|
||||
}
|
||||
|
||||
// Value returns the value of the iterator's current map entry.
|
||||
@ -1592,13 +1619,40 @@ func (it *MapIter) Value() Value {
|
||||
if it.it == nil {
|
||||
panic("MapIter.Value called before Next")
|
||||
}
|
||||
if mapiterkey(it.it) == nil {
|
||||
iterelem := mapiterelem(it.it)
|
||||
if iterelem == nil {
|
||||
panic("MapIter.Value called on exhausted iterator")
|
||||
}
|
||||
|
||||
t := (*mapType)(unsafe.Pointer(it.m.typ))
|
||||
vtype := t.elem
|
||||
return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapiterelem(it.it))
|
||||
return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), iterelem)
|
||||
}
|
||||
|
||||
// SetValue assigns dst to the value of the iterator's current map entry.
|
||||
// It is equivalent to dst.Set(it.Value()), but it avoids allocating a new Value.
|
||||
// As in Go, the value must be assignable to dst's type.
|
||||
func (it *MapIter) SetValue(dst Value) {
|
||||
if it.it == nil {
|
||||
panic("MapIter.SetValue called before Next")
|
||||
}
|
||||
iterelem := mapiterelem(it.it)
|
||||
if iterelem == nil {
|
||||
panic("MapIter.SetValue called on exhausted iterator")
|
||||
}
|
||||
|
||||
dst.mustBeAssignable()
|
||||
var target unsafe.Pointer
|
||||
if dst.kind() == Interface {
|
||||
target = dst.ptr
|
||||
}
|
||||
|
||||
t := (*mapType)(unsafe.Pointer(it.m.typ))
|
||||
vtype := t.elem
|
||||
|
||||
elem := Value{vtype, iterelem, it.m.flag | flag(vtype.Kind())}
|
||||
elem = elem.assignTo("reflect.MapIter.SetValue", dst.typ, target)
|
||||
typedmemmove(dst.typ, dst.ptr, elem.ptr)
|
||||
}
|
||||
|
||||
// Next advances the map iterator and reports whether there is another
|
||||
|
@ -818,11 +818,6 @@ func (as *asciiSet) contains(c byte) bool {
|
||||
}
|
||||
|
||||
func makeCutsetFunc(cutset string) func(rune) bool {
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return func(r rune) bool {
|
||||
return r == rune(cutset[0])
|
||||
}
|
||||
}
|
||||
if as, isASCII := makeASCIISet(cutset); isASCII {
|
||||
return func(r rune) bool {
|
||||
return r < utf8.RuneSelf && as.contains(byte(r))
|
||||
@ -837,6 +832,9 @@ func Trim(s, cutset string) string {
|
||||
if s == "" || cutset == "" {
|
||||
return s
|
||||
}
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
|
||||
}
|
||||
return TrimFunc(s, makeCutsetFunc(cutset))
|
||||
}
|
||||
|
||||
@ -848,9 +846,19 @@ func TrimLeft(s, cutset string) string {
|
||||
if s == "" || cutset == "" {
|
||||
return s
|
||||
}
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return trimLeftByte(s, cutset[0])
|
||||
}
|
||||
return TrimLeftFunc(s, makeCutsetFunc(cutset))
|
||||
}
|
||||
|
||||
func trimLeftByte(s string, c byte) string {
|
||||
for len(s) > 0 && s[0] == c {
|
||||
s = s[1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// TrimRight returns a slice of the string s, with all trailing
|
||||
// Unicode code points contained in cutset removed.
|
||||
//
|
||||
@ -859,9 +867,19 @@ func TrimRight(s, cutset string) string {
|
||||
if s == "" || cutset == "" {
|
||||
return s
|
||||
}
|
||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
||||
return trimRightByte(s, cutset[0])
|
||||
}
|
||||
return TrimRightFunc(s, makeCutsetFunc(cutset))
|
||||
}
|
||||
|
||||
func trimRightByte(s string, c byte) string {
|
||||
for len(s) > 0 && s[len(s)-1] == c {
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// TrimSpace returns a slice of the string s, with all leading
|
||||
// and trailing white space removed, as defined by Unicode.
|
||||
func TrimSpace(s string) string {
|
||||
|
@ -808,7 +808,9 @@ var trimTests = []struct {
|
||||
{"TrimLeft", "abba", "ab", ""},
|
||||
{"TrimRight", "abba", "ab", ""},
|
||||
{"TrimLeft", "abba", "a", "bba"},
|
||||
{"TrimLeft", "abba", "b", "abba"},
|
||||
{"TrimRight", "abba", "a", "abb"},
|
||||
{"TrimRight", "abba", "b", "abba"},
|
||||
{"Trim", "<tag>", "<>", "tag"},
|
||||
{"Trim", "* listitem", " *", "listitem"},
|
||||
{"Trim", `"quote"`, `"`, "quote"},
|
||||
@ -1860,6 +1862,13 @@ func BenchmarkTrimASCII(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTrimByte(b *testing.B) {
|
||||
x := " the quick brown fox "
|
||||
for i := 0; i < b.N; i++ {
|
||||
Trim(x, " ")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIndexPeriodic(b *testing.B) {
|
||||
key := "aa"
|
||||
for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
|
||||
|
@ -479,7 +479,7 @@ func (t Time) String() string {
|
||||
}
|
||||
m1, m2 := m2/1e9, m2%1e9
|
||||
m0, m1 := m1/1e9, m1%1e9
|
||||
var buf []byte
|
||||
buf := make([]byte, 0, 24)
|
||||
buf = append(buf, " m="...)
|
||||
buf = append(buf, sign)
|
||||
wid := 0
|
||||
@ -498,7 +498,8 @@ func (t Time) String() string {
|
||||
// GoString implements fmt.GoStringer and formats t to be printed in Go source
|
||||
// code.
|
||||
func (t Time) GoString() string {
|
||||
buf := []byte("time.Date(")
|
||||
buf := make([]byte, 0, 70)
|
||||
buf = append(buf, "time.Date("...)
|
||||
buf = appendInt(buf, t.Year(), 0)
|
||||
month := t.Month()
|
||||
if January <= month && month <= December {
|
||||
|
@ -84,6 +84,30 @@ func NegAddFromConstNeg(a int) int {
|
||||
return c
|
||||
}
|
||||
|
||||
func SubSubNegSimplify(a, b int) int {
|
||||
// amd64:"NEGQ"
|
||||
r := (a - b) - a
|
||||
return r
|
||||
}
|
||||
|
||||
func SubAddSimplify(a, b int) int {
|
||||
// amd64:-"SUBQ",-"ADDQ"
|
||||
r := a + (b - a)
|
||||
return r
|
||||
}
|
||||
|
||||
func SubAddNegSimplify(a, b int) int {
|
||||
// amd64:"NEGQ",-"ADDQ",-"SUBQ"
|
||||
r := a - (b + a)
|
||||
return r
|
||||
}
|
||||
|
||||
func AddAddSubSimplify(a, b, c int) int {
|
||||
// amd64:-"SUBQ"
|
||||
r := a + (b + (c - a))
|
||||
return r
|
||||
}
|
||||
|
||||
// -------------------- //
|
||||
// Multiplication //
|
||||
// -------------------- //
|
||||
|
16
test/fixedbugs/gcc101994.go
Normal file
16
test/fixedbugs/gcc101994.go
Normal file
@ -0,0 +1,16 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2021 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.
|
||||
|
||||
// https://gcc.gnu.org/PR101994
|
||||
// gccgo compiler crash with zero-sized result.
|
||||
|
||||
package p
|
||||
|
||||
type Empty struct{}
|
||||
|
||||
func F() (int, Empty) {
|
||||
return 0, Empty{}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
package main
|
||||
|
||||
type I interface {
|
||||
int // ERROR "interface contains embedded non-interface|not an interface"
|
||||
int // ERROR "interface contains embedded non-interface|embedding non-interface type"
|
||||
}
|
||||
|
||||
func New() I {
|
||||
|
29
test/fixedbugs/issue46938.go
Normal file
29
test/fixedbugs/issue46938.go
Normal file
@ -0,0 +1,29 @@
|
||||
// run -gcflags="-d=checkptr"
|
||||
|
||||
// Copyright 2021 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 main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
panic("expected panic")
|
||||
}
|
||||
if got := err.(error).Error(); !strings.Contains(got, "slice bounds out of range") {
|
||||
panic("expected panic slice out of bound, got " + got)
|
||||
}
|
||||
}()
|
||||
s := make([]int64, 100)
|
||||
p := unsafe.Pointer(&s[0])
|
||||
n := 1000
|
||||
|
||||
_ = (*[10]int64)(p)[:n:n]
|
||||
}
|
19
test/fixedbugs/issue47771.go
Normal file
19
test/fixedbugs/issue47771.go
Normal file
@ -0,0 +1,19 @@
|
||||
// run
|
||||
|
||||
// Copyright 2021 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.
|
||||
|
||||
// gofrontend miscompiled some cases of append(s, make(typ, ln)...).
|
||||
|
||||
package main
|
||||
|
||||
var g int
|
||||
|
||||
func main() {
|
||||
a := []*int{&g, &g, &g, &g}
|
||||
a = append(a[:0], make([]*int, len(a) - 1)...)
|
||||
if len(a) != 3 || a[0] != nil || a[1] != nil || a[2] != nil {
|
||||
panic(a)
|
||||
}
|
||||
}
|
46
test/typeparam/issue47878.go
Normal file
46
test/typeparam/issue47878.go
Normal file
@ -0,0 +1,46 @@
|
||||
// compile -G=3
|
||||
|
||||
// Copyright 2021 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 main
|
||||
|
||||
type Src1[T any] func() Src1[T]
|
||||
|
||||
func (s *Src1[T]) Next() {
|
||||
*s = (*s)()
|
||||
}
|
||||
|
||||
type Src2[T any] []func() Src2[T]
|
||||
|
||||
func (s Src2[T]) Next() {
|
||||
_ = s[0]()
|
||||
}
|
||||
|
||||
type Src3[T comparable] map[T]func() Src3[T]
|
||||
|
||||
func (s Src3[T]) Next() {
|
||||
var a T
|
||||
_ = s[a]()
|
||||
}
|
||||
|
||||
type Src4[T any] chan func() T
|
||||
|
||||
func (s Src4[T]) Next() {
|
||||
_ = (<-s)()
|
||||
}
|
||||
|
||||
func main() {
|
||||
var src1 Src1[int]
|
||||
src1.Next()
|
||||
|
||||
var src2 Src2[int]
|
||||
src2.Next()
|
||||
|
||||
var src3 Src3[string]
|
||||
src3.Next()
|
||||
|
||||
var src4 Src4[int]
|
||||
src4.Next()
|
||||
}
|
21
test/typeparam/issue47901.go
Normal file
21
test/typeparam/issue47901.go
Normal file
@ -0,0 +1,21 @@
|
||||
// run -gcflags=-G=3
|
||||
|
||||
// Copyright 2021 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 main
|
||||
|
||||
type Chan[T any] chan Chan[T]
|
||||
|
||||
func (ch Chan[T]) recv() Chan[T] {
|
||||
return <-ch
|
||||
}
|
||||
|
||||
func main() {
|
||||
ch := Chan[int](make(chan Chan[int]))
|
||||
go func() {
|
||||
ch <- make(Chan[int])
|
||||
}()
|
||||
ch.recv()
|
||||
}
|
29
test/typeparam/issue47929.go
Normal file
29
test/typeparam/issue47929.go
Normal file
@ -0,0 +1,29 @@
|
||||
// compile -G=3 -p=p
|
||||
|
||||
// Copyright 2021 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 v4
|
||||
|
||||
var sink interface{}
|
||||
|
||||
//go:noinline
|
||||
func Do(result, body interface{}) {
|
||||
sink = &result
|
||||
}
|
||||
|
||||
func DataAction(result DataActionResponse, body DataActionRequest) {
|
||||
Do(&result, body)
|
||||
}
|
||||
|
||||
type DataActionRequest struct {
|
||||
Action *interface{}
|
||||
}
|
||||
|
||||
type DataActionResponse struct {
|
||||
ValidationErrors *ValidationError
|
||||
}
|
||||
|
||||
type ValidationError struct {
|
||||
}
|
18
test/typeparam/issue47948.go
Normal file
18
test/typeparam/issue47948.go
Normal file
@ -0,0 +1,18 @@
|
||||
// compile -G=3
|
||||
|
||||
// Copyright 2021 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 main
|
||||
|
||||
type fun func()
|
||||
|
||||
func F[T any]() {
|
||||
_ = fun(func() {
|
||||
|
||||
})
|
||||
}
|
||||
func main() {
|
||||
F[int]()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user