1
0
mirror of https://github.com/golang/go synced 2024-11-25 07:07:57 -07: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:
Robert Griesemer 2022-09-07 11:57:26 -07:00 committed by Gopher Robot
parent 0e50bf0e40
commit cd8aa40149
7 changed files with 67 additions and 14 deletions

View File

@ -1876,8 +1876,9 @@ func TestConvertibleTo(t *testing.T) {
{newDefined(new(Struct)), new(Struct), true},
{newDefined(Typ[Int]), new(Struct), false},
{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]), NewArray(Typ[Int], 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.
{Typ[UntypedString], Typ[String], true},

View File

@ -188,11 +188,27 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
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."
if s, _ := Vu.(*Slice); s != nil {
if p, _ := Tu.(*Pointer); p != nil {
if a, _ := under(p.Elem()).(*Array); a != nil {
switch a := Tu.(type) {
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 check == nil || check.allowVersion(check.pkg, 1, 17) {
return true

View File

@ -1873,8 +1873,9 @@ func TestConvertibleTo(t *testing.T) {
{newDefined(new(Struct)), new(Struct), true},
{newDefined(Typ[Int]), new(Struct), false},
{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]), NewArray(Typ[Int], 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.
{Typ[UntypedString], Typ[String], true},

View File

@ -7,6 +7,7 @@
package types
import (
"fmt"
"go/constant"
"go/token"
"unicode"
@ -187,18 +188,39 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
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."
if s, _ := Vu.(*Slice); s != nil {
if p, _ := Tu.(*Pointer); p != nil {
if a, _ := under(p.Elem()).(*Array); a != nil {
switch a := Tu.(type) {
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 check == nil || check.allowVersion(check.pkg, 1, 17) {
return true
}
// check != nil
if cause != nil {
*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
}
}
}

View 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 */)

View File

@ -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 */)
}
// "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."
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

View File

@ -316,11 +316,11 @@ func _() {
func _() {
var s []byte
_ = ([4]byte)(s) // ERROR "cannot convert"
_ = ([4]byte)(s)
_ = (*[4]byte)(s)
type A [4]byte
_ = (A)(s) // ERROR "cannot convert"
_ = (A)(s)
_ = (*A)(s)
type P *[4]byte