From: Robert Griesemer Date: Wed, 26 Feb 2025 17:57:31 +0000 (-0800) Subject: go/types, types2: remove references to core type in append X-Git-Tag: go1.25rc1~859 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=4b1ac7bbfe3e8e4872b1a4651c527ea8be4a045f;p=gostls13.git go/types, types2: remove references to core type in append Writing explicit code for this case turned out to be simpler and easier to reason about then relying on a helper functions (except for typeset). While at it, make append error messages more consistent. For #70128. Change-Id: I3dc79774249929de5061b4301ab2506d4b3da0d0 Reviewed-on: https://go-review.googlesource.com/c/go/+/653095 Reviewed-by: Robert Findley LUCI-TryBot-Result: Go LUCI Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 1d5b67946b..e7d5f56c81 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -82,41 +82,61 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( switch id { case _Append: - // append(s S, x ...T) S, where T is the element type of S - // spec: "The variadic function append appends zero or more values x to s of type - // S, which must be a slice type, and returns the resulting slice, also of type S. - // The values x are passed to a parameter of type ...T where T is the element type + // append(s S, x ...E) S, where E is the element type of S + // spec: "The variadic function append appends zero or more values x to a slice s + // of type S and returns the resulting slice, also of type S. + // The values x are passed to a parameter of type ...E where E is the element type // of S and the respective parameter passing rules apply." S := x.typ - var T Type - if s, _ := coreType(S).(*Slice); s != nil { - T = s.elem - } else { - var cause string - switch { - case x.isNil(): - cause = "have untyped nil" - case isTypeParam(S): - if u := coreType(S); u != nil { - cause = check.sprintf("%s has core type %s", x, u) + + // determine E + var E Type + typeset(S, func(_, u Type) bool { + s, _ := u.(*Slice) + if s == nil { + var cause string + if x.isNil() { + // Printing x in this case would just print "nil". + // Special case this so we can emphasize "untyped". + cause = "untyped nil" } else { - cause = check.sprintf("%s has no core type", x) + cause = check.sprintf("%s", x) } - default: - cause = check.sprintf("have %s", x) + check.errorf(x, InvalidAppend, "invalid append: first argument must be a slice; have %s", cause) + E = nil + return false } - // don't use invalidArg prefix here as it would repeat "argument" in the error message - check.errorf(x, InvalidAppend, "first argument to append must be a slice; %s", cause) + if E == nil { + E = s.elem + } else if !Identical(E, s.elem) { + check.errorf(x, InvalidAppend, "invalid append: mismatched slice element types %s and %s in %s", E, s.elem, x) + E = nil + return false + } + return true + }) + if E == nil { return } // spec: "As a special case, append also accepts a first argument assignable // to type []byte with a second argument of string type followed by ... . - // This form appends the bytes of the string. + // This form appends the bytes of the string." if nargs == 2 && hasDots(call) { if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok { - y := args[1] - if t := coreString(y.typ); t != nil && isString(t) { + y := args[1] // valid if != nil + typeset(y.typ, func(_, u Type) bool { + if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) { + return true + } + if isString(u) { + return true + } + y = nil + return false + }) + + if y != nil { if check.recordTypes() { sig := makeSig(S, S, y.typ) sig.variadic = true @@ -130,7 +150,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( } // check general case by creating custom signature - sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature + sig := makeSig(S, S, NewSlice(E)) // []E required for variadic signature sig.variadic = true check.arguments(call, sig, nil, nil, args, nil) // discard result (we know the result type) // ok to continue even if check.arguments reported errors diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 4a6dcedb54..786c0d5ea4 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -85,41 +85,61 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b switch id { case _Append: - // append(s S, x ...T) S, where T is the element type of S - // spec: "The variadic function append appends zero or more values x to s of type - // S, which must be a slice type, and returns the resulting slice, also of type S. - // The values x are passed to a parameter of type ...T where T is the element type + // append(s S, x ...E) S, where E is the element type of S + // spec: "The variadic function append appends zero or more values x to a slice s + // of type S and returns the resulting slice, also of type S. + // The values x are passed to a parameter of type ...E where E is the element type // of S and the respective parameter passing rules apply." S := x.typ - var T Type - if s, _ := coreType(S).(*Slice); s != nil { - T = s.elem - } else { - var cause string - switch { - case x.isNil(): - cause = "have untyped nil" - case isTypeParam(S): - if u := coreType(S); u != nil { - cause = check.sprintf("%s has core type %s", x, u) + + // determine E + var E Type + typeset(S, func(_, u Type) bool { + s, _ := u.(*Slice) + if s == nil { + var cause string + if x.isNil() { + // Printing x in this case would just print "nil". + // Special case this so we can emphasize "untyped". + cause = "untyped nil" } else { - cause = check.sprintf("%s has no core type", x) + cause = check.sprintf("%s", x) } - default: - cause = check.sprintf("have %s", x) + check.errorf(x, InvalidAppend, "invalid append: first argument must be a slice; have %s", cause) + E = nil + return false } - // don't use invalidArg prefix here as it would repeat "argument" in the error message - check.errorf(x, InvalidAppend, "first argument to append must be a slice; %s", cause) + if E == nil { + E = s.elem + } else if !Identical(E, s.elem) { + check.errorf(x, InvalidAppend, "invalid append: mismatched slice element types %s and %s in %s", E, s.elem, x) + E = nil + return false + } + return true + }) + if E == nil { return } // spec: "As a special case, append also accepts a first argument assignable // to type []byte with a second argument of string type followed by ... . - // This form appends the bytes of the string. + // This form appends the bytes of the string." if nargs == 2 && hasDots(call) { if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok { - y := args[1] - if t := coreString(y.typ); t != nil && isString(t) { + y := args[1] // valid if != nil + typeset(y.typ, func(_, u Type) bool { + if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) { + return true + } + if isString(u) { + return true + } + y = nil + return false + }) + + if y != nil { if check.recordTypes() { sig := makeSig(S, S, y.typ) sig.variadic = true @@ -133,7 +153,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b } // check general case by creating custom signature - sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature + sig := makeSig(S, S, NewSlice(E)) // []E required for variadic signature sig.variadic = true check.arguments(call, sig, nil, nil, args, nil) // discard result (we know the result type) // ok to continue even if check.arguments reported errors diff --git a/src/internal/types/testdata/fixedbugs/issue49735.go b/src/internal/types/testdata/fixedbugs/issue49735.go index 0fcc778a06..07603b712c 100644 --- a/src/internal/types/testdata/fixedbugs/issue49735.go +++ b/src/internal/types/testdata/fixedbugs/issue49735.go @@ -4,8 +4,9 @@ package p -func _[P1 any, P2 ~byte](s1 P1, s2 P2) { - _ = append(nil /* ERROR "first argument to append must be a slice; have untyped nil" */ , 0) - _ = append(s1 /* ERRORx `s1 .* has no core type` */ , 0) - _ = append(s2 /* ERRORx `s2 .* has core type byte` */ , 0) +func _[P1 any, P2 ~byte, P3 []int | []byte](s1 P1, s2 P2, s3 P3) { + _ = append(nil /* ERROR "invalid append: first argument must be a slice; have untyped nil" */, 0) + _ = append(s1 /* ERROR "invalid append: first argument must be a slice; have s1 (variable of type P1 constrained by any)" */, 0) + _ = append(s2 /* ERROR "invalid append: first argument must be a slice; have s2 (variable of type P2 constrained by ~byte)" */, 0) + _ = append(s3 /* ERROR "invalid append: mismatched slice element types int and byte in s3 (variable of type P3 constrained by []int | []byte)" */, 0) }