diff options
| author | Cherry Mui <cherryyz@google.com> | 2025-09-25 13:33:58 -0400 |
|---|---|---|
| committer | Cherry Mui <cherryyz@google.com> | 2025-09-25 13:33:59 -0400 |
| commit | a693ae1e9aebac896f6634583dbdd1cd319f3983 (patch) | |
| tree | 44ef04e84afe5ef8652222c5500ab6c779d09650 /src/cmd/compile | |
| parent | 5a78e1a4a1c79185e86b5c18efffba2a9b9d3739 (diff) | |
| parent | d70ad4e740e24b4b76961c4b56d698fa23668aa2 (diff) | |
| download | go-a693ae1e9aebac896f6634583dbdd1cd319f3983.tar.xz | |
[dev.simd] all: merge master (d70ad4e) into dev.simd
Conflicts:
- src/cmd/compile/internal/types2/stdlib_test.go
- src/go/types/stdlib_test.go
Merge List:
+ 2025-09-25 d70ad4e740 sync/atomic: correct Uintptr.Or return doc
+ 2025-09-25 d7abfe4f0d runtime: acquire/release C TSAN lock when calling cgo symbolizer/tracebacker
+ 2025-09-25 393d91aea0 cmd/fix: remove all functionality
+ 2025-09-25 6dceff8bad cmd/link: handle -w flag in external linking mode
+ 2025-09-25 76d088eb74 cmd/internal/obj/riscv: remove ACFLWSP/ACFSWSP and ACFLW/ACFSW
+ 2025-09-25 5225e9dc49 doc/next: document new image/jpeg DCT in release notes
+ 2025-09-25 81a83bba21 cmd: update x/tools@4df13e3
+ 2025-09-25 6b32c613ca go/types: make typeset return an iterator
+ 2025-09-25 fbba930271 image/jpeg: replace fdct.go and idct.go with new implementation in dct.go
+ 2025-09-25 92e093467f image/jpeg: correct and test reference slowFDCT and slowIDCT
+ 2025-09-25 27c7bbc51c image/jpeg: prepare for new FDCT/IDCT implementations
+ 2025-09-24 f15cd63ec4 cmd/compile: don't rely on loop info when there are irreducible loops
+ 2025-09-24 371c1d2fcb cmd/internal/obj/riscv: add support for vector unit-stride fault-only-first load instructions
+ 2025-09-23 411c250d64 runtime: add specialized malloc functions for sizes up to 512 bytes
+ 2025-09-23 d7a38adf4c runtime: eliminate global span queue [green tea]
+ 2025-09-23 7bc1935db5 cmd/compile/internal: support new(expr)
+ 2025-09-23 eb78f13c9f doc/go_spec.html: document new(expr)
+ 2025-09-23 74cc463f9e go/token: add TestRemovedFileFileReturnsNil test
+ 2025-09-23 902dc27ae9 go/token: clear cache after grabbing the mutex in RemoveFile
+ 2025-09-23 a13d085a5b cmd/cgo: don't hardcode section name in TestNumberOfExportedFunctions
+ 2025-09-23 61bf26a9ee cmd/link: fix Macho-O X86_64_RELOC_SUBTRACTOR in internal linking
+ 2025-09-23 4b787c8c2b reflect: remove stale comment in unpackEface
+ 2025-09-23 3df27cd21a cmd/compile: fix typo in comment
+ 2025-09-23 684e8d3363 reflect: allocate memory in TypeAssert[I] only when the assertion succeeds
+ 2025-09-23 a5866ebe40 cmd/compile: prevent shapifying of pointer shape type
+ 2025-09-23 a27261c42f go/types,types2: allow new(expr)
+ 2025-09-23 e93f439ac4 runtime/cgo: retry when CreateThread fails with ERROR_ACCESS_DENIED
+ 2025-09-23 69e74b0aac runtime: deduplicate pMask resize code
+ 2025-09-23 fde10c4ce7 runtime: split gcMarkWorkAvailable into two separate conditions
+ 2025-09-23 5d040df092 runtime: use scan kernels in scanSpan [green tea]
+ 2025-09-23 7e0251bf58 runtime: don't report non-blocked goroutines as "(durable)" in stacks
+ 2025-09-23 22ac328856 cmd/link: make -w behavior consistent on Windows
Change-Id: Id76b5a30a3b6f6669437f97e3320c9bca65a1e96
Diffstat (limited to 'src/cmd/compile')
| -rw-r--r-- | src/cmd/compile/internal/ir/node.go | 2 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ir/type.go | 4 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/doc.go | 6 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/reader.go | 59 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/writer.go | 8 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/tighten.go | 27 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/builtins.go | 74 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/index.go | 12 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/signature.go | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/stdlib_test.go | 1 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/typeparam.go | 10 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/typeset.go | 16 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/under.go | 57 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/version.go | 1 | ||||
| -rw-r--r-- | src/cmd/compile/testdata/script/issue75461.txt | 78 |
15 files changed, 223 insertions, 139 deletions
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 003ec15de1..8c61bb6ed5 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -215,7 +215,7 @@ const ( ORSH // X >> Y OAND // X & Y OANDNOT // X &^ Y - ONEW // new(X); corresponds to calls to new in source code + ONEW // new(X); corresponds to calls to new(T) in source code ONOT // !X OBITNOT // ^X OPLUS // +X diff --git a/src/cmd/compile/internal/ir/type.go b/src/cmd/compile/internal/ir/type.go index 6daca856a6..0f44cf8d04 100644 --- a/src/cmd/compile/internal/ir/type.go +++ b/src/cmd/compile/internal/ir/type.go @@ -42,6 +42,10 @@ func TypeNode(t *types.Type) Node { // A DynamicType represents a type expression whose exact type must be // computed dynamically. +// +// TODO(adonovan): I think "dynamic" is a misnomer here; it's really a +// type with free type parameters that needs to be instantiated to obtain +// a ground type for which an rtype can exist. type DynamicType struct { miniExpr diff --git a/src/cmd/compile/internal/noder/doc.go b/src/cmd/compile/internal/noder/doc.go index a5d5533168..8eb67e92f0 100644 --- a/src/cmd/compile/internal/noder/doc.go +++ b/src/cmd/compile/internal/noder/doc.go @@ -87,7 +87,7 @@ constant for file bases and hence not encoded. [ Sync ] StringRef // the (absolute) file name for the base Bool // true if a file base, else a line base - // The below is ommitted for file bases. + // The below is omitted for file bases. [ Pos Uint64 // line Uint64 ] // column @@ -99,7 +99,7 @@ without a PosBase have no line or column. Pos = [ Sync ] Bool // true if the position has a base - // The below is ommitted if the position has no base. + // The below is omitted if the position has no base. [ Ref[PosBase] Uint64 // line Uint64 ] // column @@ -125,7 +125,7 @@ packages. The below package paths have special meaning. Pkg = RefTable [ Sync ] StringRef // path - // The below is ommitted for the special package paths + // The below is omitted for the special package paths // "builtin" and "unsafe". [ StringRef // name Imports ] diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 3cbc7989a7..ca7c6bf151 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -49,9 +49,6 @@ type pkgReader struct { // but bitwise inverted so we can detect if we're missing the entry // or not. newindex []index - - // indicates whether the data is reading during reshaping. - reshaping bool } func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader { @@ -119,10 +116,6 @@ type reader struct { // find parameters/results. funarghack bool - // reshaping is used during reading exprReshape code, preventing - // the reader from shapifying the re-shaped type. - reshaping bool - // methodSym is the name of method's name, if reading a method. // It's nil if reading a normal function or closure body. methodSym *types.Sym @@ -937,8 +930,19 @@ func shapify(targ *types.Type, basic bool) *types.Type { // types, and discarding struct field names and tags. However, we'll // need to start tracking how type parameters are actually used to // implement some of these optimizations. + pointerShaping := basic && targ.IsPtr() && !targ.Elem().NotInHeap() + // The exception is when the type parameter is a pointer to a type + // which `Type.HasShape()` returns true, but `Type.IsShape()` returns + // false, like `*[]go.shape.T`. This is because the type parameter is + // used to instantiate a generic function inside another generic function. + // In this case, we want to keep the targ as-is, otherwise, we may lose the + // original type after `*[]go.shape.T` is shapified to `*go.shape.uint8`. + // See issue #54535, #71184. + if pointerShaping && !targ.Elem().IsShape() && targ.Elem().HasShape() { + return targ + } under := targ.Underlying() - if basic && targ.IsPtr() && !targ.Elem().NotInHeap() { + if pointerShaping { under = types.NewPtr(types.Types[types.TUINT8]) } @@ -1014,25 +1018,7 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx index, implicits, explicits // arguments. for i, targ := range dict.targs { basic := r.Bool() - isPointerShape := basic && targ.IsPtr() && !targ.Elem().NotInHeap() - // We should not do shapify during the reshaping process, see #71184. - // However, this only matters for shapify a pointer type, which will - // lose the original underlying type. - // - // Example with a pointer type: - // - // - First, shapifying *[]T -> *uint8 - // - During the reshaping process, *uint8 is shapified to *go.shape.uint8 - // - This ends up with a different type with the original *[]T - // - // For a non-pointer type: - // - // - int -> go.shape.int - // - go.shape.int -> go.shape.int - // - // We always end up with the identical type. - canShapify := !pr.reshaping || !isPointerShape - if dict.shaped && canShapify { + if dict.shaped { dict.targs[i] = shapify(targ, basic) } } @@ -2445,8 +2431,16 @@ func (r *reader) expr() (res ir.Node) { case exprNew: pos := r.pos() - typ := r.exprType() - return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ)) + if r.Bool() { + // new(expr) -> tmp := expr; &tmp + x := r.expr() + var init ir.Nodes + addr := ir.NewAddrExpr(pos, r.tempCopy(pos, x, &init)) + addr.SetInit(init) + return typecheck.Expr(addr) + } + // new(T) + return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, r.exprType())) case exprSizeof: return ir.NewUintptr(r.pos(), r.typ().Size()) @@ -2470,10 +2464,7 @@ func (r *reader) expr() (res ir.Node) { case exprReshape: typ := r.typ() - old := r.reshaping - r.reshaping = true x := r.expr() - r.reshaping = old if types.IdenticalStrict(x.Type(), typ) { return x @@ -2596,10 +2587,7 @@ func (r *reader) funcInst(pos src.XPos) (wrapperFn, baseFn, dictPtr ir.Node) { info := r.dict.subdicts[idx] explicits := r.p.typListIdx(info.explicits, r.dict) - old := r.p.reshaping - r.p.reshaping = r.reshaping baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) - r.p.reshaping = old // TODO(mdempsky): Is there a more robust way to get the // dictionary pointer type here? @@ -3259,6 +3247,7 @@ func (r *reader) exprType() ir.Node { var rtype, itab ir.Node if r.Bool() { + // non-empty interface typ, rtype, _, _, itab = r.itab(pos) if !typ.IsInterface() { rtype = nil // TODO(mdempsky): Leave set? diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 54e5f1ea5f..9c90d221c2 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -2035,10 +2035,16 @@ func (w *writer) expr(expr syntax.Expr) { case "new": assert(len(expr.ArgList) == 1) assert(!expr.HasDots) + arg := expr.ArgList[0] w.Code(exprNew) w.pos(expr) - w.exprType(nil, expr.ArgList[0]) + tv := w.p.typeAndValue(arg) + if w.Bool(!tv.IsType()) { + w.expr(arg) // new(expr), go1.26 + } else { + w.exprType(nil, arg) // new(T) + } return case "Sizeof": diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index 48efdb5609..b1f787e03b 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -123,18 +123,21 @@ func tighten(f *Func) { // If the target location is inside a loop, // move the target location up to just before the loop head. - for _, b := range f.Blocks { - origloop := loops.b2l[b.ID] - for _, v := range b.Values { - t := target[v.ID] - if t == nil { - continue - } - targetloop := loops.b2l[t.ID] - for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) { - t = idom[targetloop.header.ID] - target[v.ID] = t - targetloop = loops.b2l[t.ID] + if !loops.hasIrreducible { + // Loop info might not be correct for irreducible loops. See issue 75569. + for _, b := range f.Blocks { + origloop := loops.b2l[b.ID] + for _, v := range b.Values { + t := target[v.ID] + if t == nil { + continue + } + targetloop := loops.b2l[t.ID] + for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) { + t = idom[targetloop.header.ID] + target[v.ID] = t + targetloop = loops.b2l[t.ID] + } } } } diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 4bb2135755..df207a2746 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -98,17 +98,17 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok { y := args[1] hasString := false - typeset(y.typ, func(_, u Type) bool { + for _, u := range typeset(y.typ) { if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) { - return true - } - if isString(u) { + // typeset ⊇ {[]byte} + } else if isString(u) { + // typeset ⊇ {string} hasString = true - return true + } else { + y = nil + break } - y = nil - return false - }) + } if y != nil && hasString { // setting the signature also signals that we're done sig = makeSig(x.typ, x.typ, y.typ) @@ -368,16 +368,16 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( var special bool if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok { special = true - typeset(y.typ, func(_, u Type) bool { + for _, u := range typeset(y.typ) { if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) { - return true - } - if isString(u) { - return true + // typeset ⊇ {[]byte} + } else if isString(u) { + // typeset ⊇ {string} + } else { + special = false + break } - special = false - return false - }) + } } // general case @@ -636,11 +636,30 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } case _New: - // new(T) + // new(T) or new(expr) // (no argument evaluated yet) - T := check.varType(argList[0]) - if !isValid(T) { - return + arg := argList[0] + check.exprOrType(x, arg, true) + var T Type + switch x.mode { + case builtin: + check.errorf(x, UncalledBuiltin, "%s must be called", x) + x.mode = invalid + case typexpr: + // new(T) + T = x.typ + if !isValid(T) { + return + } + default: + // new(expr) + check.verifyVersionf(call.Fun, go1_26, "new(expr)") + T = Default(x.typ) + if T != x.typ { + // untyped constant: check for overflow. + check.assignment(x, T, "argument to new") + } + check.validVarType(arg, T) } x.mode = value @@ -961,29 +980,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // or a type error if x is not a slice (or a type set of slices). func sliceElem(x *operand) (Type, *typeError) { var E Type - var err *typeError - typeset(x.typ, func(_, u Type) bool { + for _, u := range typeset(x.typ) { s, _ := u.(*Slice) if s == nil { if x.isNil() { // Printing x in this case would just print "nil". // Special case this so we can emphasize "untyped". - err = typeErrorf("argument must be a slice; have untyped nil") + return nil, typeErrorf("argument must be a slice; have untyped nil") } else { - err = typeErrorf("argument must be a slice; have %s", x) + return nil, typeErrorf("argument must be a slice; have %s", x) } - return false } if E == nil { E = s.elem } else if !Identical(E, s.elem) { - err = typeErrorf("mismatched slice element types %s and %s in %s", E, s.elem, x) - return false + return nil, typeErrorf("mismatched slice element types %s and %s in %s", E, s.elem, x) } - return true - }) - if err != nil { - return nil, err } return E, nil } diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 80e8514168..7e16a87332 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -216,11 +216,11 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) { // determine common underlying type cu var ct, cu Type // type and respective common underlying type var hasString bool - typeset(x.typ, func(t, u Type) bool { + for t, u := range typeset(x.typ) { if u == nil { check.errorf(x, NonSliceableOperand, "cannot slice %s: no specific type in %s", x, x.typ) cu = nil - return false + break } // Treat strings like byte slices but remember that we saw a string. @@ -232,18 +232,16 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) { // If this is the first type we're seeing, we're done. if cu == nil { ct, cu = t, u - return true + continue } // Otherwise, the current type must have the same underlying type as all previous types. if !Identical(cu, u) { check.errorf(x, NonSliceableOperand, "cannot slice %s: %s and %s have different underlying types", x, ct, t) cu = nil - return false + break } - - return true - }) + } if hasString { // If we saw a string, proceed with string type, // but don't go from untyped string to string. diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index eaecb77af5..ea1cfd88cc 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -49,7 +49,7 @@ func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params } last := params.At(n - 1).typ var S *Slice - typeset(last, func(t, _ Type) bool { + for t := range typeset(last) { var s *Slice if isString(t) { s = NewSlice(universeByte) @@ -60,10 +60,9 @@ func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params S = s } else if !Identical(S, s) { S = nil - return false + break } - return true - }) + } if S == nil { panic(fmt.Sprintf("got %s, want variadic parameter of unnamed slice or string type", last)) } diff --git a/src/cmd/compile/internal/types2/stdlib_test.go b/src/cmd/compile/internal/types2/stdlib_test.go index fc67397503..26d2eb23ab 100644 --- a/src/cmd/compile/internal/types2/stdlib_test.go +++ b/src/cmd/compile/internal/types2/stdlib_test.go @@ -360,6 +360,7 @@ func TestStdKen(t *testing.T) { var excluded = map[string]bool{ "builtin": true, "cmd/compile/internal/ssa/_gen": true, + "runtime/_mkmalloc": true, "simd/_gen/simdgen": true, "simd/_gen/unify": true, } diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index a04f928908..c60b5eb417 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -155,10 +155,10 @@ func (t *TypeParam) is(f func(*term) bool) bool { return t.iface().typeSet().is(f) } -// typeset is an iterator over the (type/underlying type) pairs of the +// typeset reports whether f(t, y) is true for all (type/underlying type) pairs of the // specific type terms of t's constraint. -// If there are no specific terms, typeset calls yield with (nil, nil). -// In any case, typeset is guaranteed to call yield at least once. -func (t *TypeParam) typeset(yield func(t, u Type) bool) { - t.iface().typeSet().typeset(yield) +// If there are no specific terms, typeset returns f(nil, nil). +// In any case, typeset is guaranteed to call f at least once. +func (t *TypeParam) typeset(f func(t, u Type) bool) bool { + return t.iface().typeSet().all(f) } diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 74436952f2..ce487e74f7 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -104,13 +104,12 @@ func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll // subsetOf reports whether s1 ⊆ s2. func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) } -// typeset is an iterator over the (type/underlying type) pairs in s. -// If s has no specific terms, typeset calls yield with (nil, nil). -// In any case, typeset is guaranteed to call yield at least once. -func (s *_TypeSet) typeset(yield func(t, u Type) bool) { +// all reports whether f(t, u) is true for each (type/underlying type) pairs in s. +// If s has no specific terms, all calls f(nil, nil). +// In any case, all is guaranteed to call f at least once. +func (s *_TypeSet) all(f func(t, u Type) bool) bool { if !s.hasTerms() { - yield(nil, nil) - return + return f(nil, nil) } for _, t := range s.terms { @@ -123,10 +122,11 @@ func (s *_TypeSet) typeset(yield func(t, u Type) bool) { if debug { assert(Identical(u, under(u))) } - if !yield(t.typ, u) { - break + if !f(t.typ, u) { + return false } } + return true } // is calls f with the specific type terms of s and reports whether diff --git a/src/cmd/compile/internal/types2/under.go b/src/cmd/compile/internal/types2/under.go index 9e5334b724..078ba9ab17 100644 --- a/src/cmd/compile/internal/types2/under.go +++ b/src/cmd/compile/internal/types2/under.go @@ -4,6 +4,8 @@ package types2 +import "iter" + // under returns the true expanded underlying type. // If it doesn't exist, the result is Typ[Invalid]. // under must only be called when a type is known @@ -18,12 +20,18 @@ func under(t Type) Type { // If typ is a type parameter, underIs returns the result of typ.underIs(f). // Otherwise, underIs returns the result of f(under(typ)). func underIs(typ Type, f func(Type) bool) bool { - var ok bool - typeset(typ, func(_, u Type) bool { - ok = f(u) - return ok + return all(typ, func(_, u Type) bool { + return f(u) }) - return ok +} + +// all reports whether f(t, u) is true for all (type/underlying type) +// pairs in the typeset of t. See [typeset] for details of sequence. +func all(t Type, f func(t, u Type) bool) bool { + if p, _ := Unalias(t).(*TypeParam); p != nil { + return p.typeset(f) + } + return f(t, under(t)) } // typeset is an iterator over the (type/underlying type) pairs of the @@ -32,12 +40,10 @@ func underIs(typ Type, f func(Type) bool) bool { // In that case, if there are no specific terms, typeset calls yield with (nil, nil). // If t is not a type parameter, the implied type set consists of just t. // In any case, typeset is guaranteed to call yield at least once. -func typeset(t Type, yield func(t, u Type) bool) { - if p, _ := Unalias(t).(*TypeParam); p != nil { - p.typeset(yield) - return +func typeset(t Type) iter.Seq2[Type, Type] { + return func(yield func(t, u Type) bool) { + _ = all(t, yield) } - yield(t, under(t)) } // A typeError describes a type error. @@ -80,35 +86,28 @@ func (err *typeError) format(check *Checker) string { // with the single type t in its type set. func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) { var ct, cu Type // type and respective common underlying type - var err *typeError - - bad := func(format string, args ...any) bool { - err = typeErrorf(format, args...) - return false - } - - typeset(t, func(t, u Type) bool { + for t, u := range typeset(t) { if cond != nil { - if err = cond(t, u); err != nil { - return false + if err := cond(t, u); err != nil { + return nil, err } } if u == nil { - return bad("no specific type") + return nil, typeErrorf("no specific type") } // If this is the first type we're seeing, we're done. if cu == nil { ct, cu = t, u - return true + continue } // If we've seen a channel before, and we have a channel now, they must be compatible. if chu, _ := cu.(*Chan); chu != nil { if ch, _ := u.(*Chan); ch != nil { if !Identical(chu.elem, ch.elem) { - return bad("channels %s and %s have different element types", ct, t) + return nil, typeErrorf("channels %s and %s have different element types", ct, t) } // If we have different channel directions, keep the restricted one // and complain if they conflict. @@ -118,22 +117,16 @@ func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) { case chu.dir == SendRecv: ct, cu = t, u // switch to restricted channel case ch.dir != SendRecv: - return bad("channels %s and %s have conflicting directions", ct, t) + return nil, typeErrorf("channels %s and %s have conflicting directions", ct, t) } - return true + continue } } // Otherwise, the current type must have the same underlying type as all previous types. if !Identical(cu, u) { - return bad("%s and %s have different underlying types", ct, t) + return nil, typeErrorf("%s and %s have different underlying types", ct, t) } - - return true - }) - - if err != nil { - return nil, err } return cu, nil } diff --git a/src/cmd/compile/internal/types2/version.go b/src/cmd/compile/internal/types2/version.go index b555f398da..765b0f7e9a 100644 --- a/src/cmd/compile/internal/types2/version.go +++ b/src/cmd/compile/internal/types2/version.go @@ -43,6 +43,7 @@ var ( go1_21 = asGoVersion("go1.21") go1_22 = asGoVersion("go1.22") go1_23 = asGoVersion("go1.23") + go1_26 = asGoVersion("go1.26") // current (deployed) Go version go_current = asGoVersion(fmt.Sprintf("go1.%d", goversion.Version)) diff --git a/src/cmd/compile/testdata/script/issue75461.txt b/src/cmd/compile/testdata/script/issue75461.txt new file mode 100644 index 0000000000..05f0fd4cfa --- /dev/null +++ b/src/cmd/compile/testdata/script/issue75461.txt @@ -0,0 +1,78 @@ +go build main.go +! stdout . +! stderr . + +-- main.go -- +package main + +import ( + "demo/registry" +) + +func main() { + _ = registry.NewUserRegistry() +} + +-- go.mod -- +module demo + +go 1.24 + +-- model/user.go -- +package model + +type User struct { + ID int +} + +func (c *User) String() string { + return "" +} + +-- ordered/map.go -- +package ordered + +type OrderedMap[K comparable, V any] struct { + m map[K]V +} + +func New[K comparable, V any](options ...any) *OrderedMap[K, V] { + orderedMap := &OrderedMap[K, V]{} + return orderedMap +} + +-- registry/user.go -- +package registry + +import ( + "demo/model" + "demo/ordered" +) + +type baseRegistry = Registry[model.User, *model.User] + +type UserRegistry struct { + *baseRegistry +} + +type Registry[T any, P PStringer[T]] struct { + m *ordered.OrderedMap[string, P] +} + +type PStringer[T any] interface { + *T + String() string +} + +func NewRegistry[T any, P PStringer[T]]() *Registry[T, P] { + r := &Registry[T, P]{ + m: ordered.New[string, P](), + } + return r +} + +func NewUserRegistry() *UserRegistry { + return &UserRegistry{ + baseRegistry: NewRegistry[model.User](), + } +} |
