mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
go/types, types2: implement slice-to-array conversions
For #46505. Change-Id: I9bc9da5dd4b76cb2d8ff41390e1567678e72d88d Reviewed-on: https://go-review.googlesource.com/c/go/+/428938 Run-TryBot: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com> Auto-Submit: Robert Griesemer <gri@google.com> Reviewed-by: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
0e50bf0e40
commit
cd8aa40149
@ -1876,8 +1876,9 @@ func TestConvertibleTo(t *testing.T) {
|
|||||||
{newDefined(new(Struct)), new(Struct), true},
|
{newDefined(new(Struct)), new(Struct), true},
|
||||||
{newDefined(Typ[Int]), new(Struct), false},
|
{newDefined(Typ[Int]), new(Struct), false},
|
||||||
{Typ[UntypedInt], Typ[Int], true},
|
{Typ[UntypedInt], Typ[Int], true},
|
||||||
|
{NewSlice(Typ[Int]), NewArray(Typ[Int], 10), true},
|
||||||
|
{NewSlice(Typ[Int]), NewArray(Typ[Uint], 10), false},
|
||||||
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
|
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
|
||||||
{NewSlice(Typ[Int]), NewArray(Typ[Int], 10), false},
|
|
||||||
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
|
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
|
||||||
// Untyped string values are not permitted by the spec, so the behavior below is undefined.
|
// Untyped string values are not permitted by the spec, so the behavior below is undefined.
|
||||||
{Typ[UntypedString], Typ[String], true},
|
{Typ[UntypedString], Typ[String], true},
|
||||||
|
@ -188,11 +188,27 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// "V a slice, T is a pointer-to-array type,
|
// "V is a slice, T is an array or pointer-to-array type,
|
||||||
// and the slice and array types have identical element types."
|
// and the slice and array types have identical element types."
|
||||||
if s, _ := Vu.(*Slice); s != nil {
|
if s, _ := Vu.(*Slice); s != nil {
|
||||||
if p, _ := Tu.(*Pointer); p != nil {
|
switch a := Tu.(type) {
|
||||||
if a, _ := under(p.Elem()).(*Array); a != nil {
|
case *Array:
|
||||||
|
if Identical(s.Elem(), a.Elem()) {
|
||||||
|
if check == nil || check.allowVersion(check.pkg, 1, 20) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// check != nil
|
||||||
|
if cause != nil {
|
||||||
|
// TODO(gri) consider restructuring versionErrorf so we can use it here and below
|
||||||
|
*cause = "conversion of slices to arrays requires go1.20 or later"
|
||||||
|
if check.conf.CompilerErrorMessages {
|
||||||
|
*cause += fmt.Sprintf(" (-lang was set to %s; check go.mod)", check.conf.GoVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case *Pointer:
|
||||||
|
if a, _ := under(a.Elem()).(*Array); a != nil {
|
||||||
if Identical(s.Elem(), a.Elem()) {
|
if Identical(s.Elem(), a.Elem()) {
|
||||||
if check == nil || check.allowVersion(check.pkg, 1, 17) {
|
if check == nil || check.allowVersion(check.pkg, 1, 17) {
|
||||||
return true
|
return true
|
||||||
|
@ -1873,8 +1873,9 @@ func TestConvertibleTo(t *testing.T) {
|
|||||||
{newDefined(new(Struct)), new(Struct), true},
|
{newDefined(new(Struct)), new(Struct), true},
|
||||||
{newDefined(Typ[Int]), new(Struct), false},
|
{newDefined(Typ[Int]), new(Struct), false},
|
||||||
{Typ[UntypedInt], Typ[Int], true},
|
{Typ[UntypedInt], Typ[Int], true},
|
||||||
|
{NewSlice(Typ[Int]), NewArray(Typ[Int], 10), true},
|
||||||
|
{NewSlice(Typ[Int]), NewArray(Typ[Uint], 10), false},
|
||||||
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
|
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
|
||||||
{NewSlice(Typ[Int]), NewArray(Typ[Int], 10), false},
|
|
||||||
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
|
{NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
|
||||||
// Untyped string values are not permitted by the spec, so the behavior below is undefined.
|
// Untyped string values are not permitted by the spec, so the behavior below is undefined.
|
||||||
{Typ[UntypedString], Typ[String], true},
|
{Typ[UntypedString], Typ[String], true},
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"go/token"
|
"go/token"
|
||||||
"unicode"
|
"unicode"
|
||||||
@ -187,18 +188,39 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// "V a slice, T is a pointer-to-array type,
|
// "V is a slice, T is an array or pointer-to-array type,
|
||||||
// and the slice and array types have identical element types."
|
// and the slice and array types have identical element types."
|
||||||
if s, _ := Vu.(*Slice); s != nil {
|
if s, _ := Vu.(*Slice); s != nil {
|
||||||
if p, _ := Tu.(*Pointer); p != nil {
|
switch a := Tu.(type) {
|
||||||
if a, _ := under(p.Elem()).(*Array); a != nil {
|
case *Array:
|
||||||
|
if Identical(s.Elem(), a.Elem()) {
|
||||||
|
if check == nil || check.allowVersion(check.pkg, 1, 20) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// check != nil
|
||||||
|
if cause != nil {
|
||||||
|
// TODO(gri) consider restructuring versionErrorf so we can use it here and below
|
||||||
|
*cause = "conversion of slices to arrays requires go1.20 or later"
|
||||||
|
if compilerErrorMessages {
|
||||||
|
*cause += fmt.Sprintf(" (-lang was set to %s; check go.mod)", check.conf.GoVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case *Pointer:
|
||||||
|
if a, _ := under(a.Elem()).(*Array); a != nil {
|
||||||
if Identical(s.Elem(), a.Elem()) {
|
if Identical(s.Elem(), a.Elem()) {
|
||||||
if check == nil || check.allowVersion(check.pkg, 1, 17) {
|
if check == nil || check.allowVersion(check.pkg, 1, 17) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// check != nil
|
||||||
if cause != nil {
|
if cause != nil {
|
||||||
*cause = "conversion of slices to array pointers requires go1.17 or later"
|
*cause = "conversion of slices to array pointers requires go1.17 or later"
|
||||||
|
if compilerErrorMessages {
|
||||||
|
*cause += fmt.Sprintf(" (-lang was set to %s; check go.mod)", check.conf.GoVersion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/internal/types/testdata/check/go1_19.go
vendored
Normal file
15
src/internal/types/testdata/check/go1_19.go
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// -lang=go1.19
|
||||||
|
|
||||||
|
// Copyright 2022 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.
|
||||||
|
|
||||||
|
// Check Go language version-specific errors.
|
||||||
|
|
||||||
|
package p
|
||||||
|
|
||||||
|
type Slice []byte
|
||||||
|
type Array [8]byte
|
||||||
|
|
||||||
|
var s Slice
|
||||||
|
var p = (Array)(s /* ERROR requires go1.20 or later */)
|
@ -176,13 +176,11 @@ func _[X unsafe.Pointer](x X) int64 {
|
|||||||
return int64(x /* ERROR cannot convert x \(variable of type X constrained by unsafe\.Pointer\) to int64\n\tcannot convert unsafe\.Pointer \(in X\) to int64 */)
|
return int64(x /* ERROR cannot convert x \(variable of type X constrained by unsafe\.Pointer\) to int64\n\tcannot convert unsafe\.Pointer \(in X\) to int64 */)
|
||||||
}
|
}
|
||||||
|
|
||||||
// "x is a slice, T is a pointer-to-array type,
|
// "x is a slice, T is an array or pointer-to-array type,
|
||||||
// and the slice and array types have identical element types."
|
// and the slice and array types have identical element types."
|
||||||
|
|
||||||
|
func _[X ~[]E, T ~[10]E, E any](x X) T { return T(x) }
|
||||||
func _[X ~[]E, T ~*[10]E, E any](x X) T { return T(x) }
|
func _[X ~[]E, T ~*[10]E, E any](x X) T { return T(x) }
|
||||||
func _[X ~[]E, T ~[10]E, E any](x X) T {
|
|
||||||
return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\[\]E\) to T\n\tcannot convert \[\]E \(in X\) to \[10\]E \(in T\) */)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// The following declarations can be replaced by the exported types of the
|
// The following declarations can be replaced by the exported types of the
|
||||||
|
@ -316,11 +316,11 @@ func _() {
|
|||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
var s []byte
|
var s []byte
|
||||||
_ = ([4]byte)(s) // ERROR "cannot convert"
|
_ = ([4]byte)(s)
|
||||||
_ = (*[4]byte)(s)
|
_ = (*[4]byte)(s)
|
||||||
|
|
||||||
type A [4]byte
|
type A [4]byte
|
||||||
_ = (A)(s) // ERROR "cannot convert"
|
_ = (A)(s)
|
||||||
_ = (*A)(s)
|
_ = (*A)(s)
|
||||||
|
|
||||||
type P *[4]byte
|
type P *[4]byte
|
||||||
|
Loading…
x
Reference in New Issue
Block a user