]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: implement slice-to-array conversions
authorRobert Griesemer <gri@golang.org>
Wed, 7 Sep 2022 18:57:26 +0000 (11:57 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 8 Sep 2022 15:55:44 +0000 (15:55 +0000)
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>

src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/conversions.go
src/go/types/api_test.go
src/go/types/conversions.go
src/internal/types/testdata/check/go1_19.go [new file with mode: 0644]
src/internal/types/testdata/spec/conversions.go
test/convert2.go

index ac81d31fb2222ed5d7661cfb06da24653ac25770..9a3e76a07dc1ff1cd5ad6e062f6e9d2ec7ba829d 100644 (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},
index a86645a547790c80be5452317d8daa708a12d56b..d15645499b33f67e4f00a905a96894fc0f08d9a7 100644 (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
index 2367f3ab9304e3b2f2aaacade773a6009a3e0407..b204025b5448d71342b9e5ff6b3118a56d739d7e 100644 (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},
index 3ad94c8eff5ab807c42d18102a5c64d158b688d0..926a79cf5e24cc3f41923eea5a925bb989f0680e 100644 (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
                                }
                        }
                }
diff --git a/src/internal/types/testdata/check/go1_19.go b/src/internal/types/testdata/check/go1_19.go
new file mode 100644 (file)
index 0000000..f899d93
--- /dev/null
@@ -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 */)
index f20705c4b2d625ac00138cb91086a05df56561b4..e8fa4c5300b28357ca113fc14d0f32a039609719 100644 (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
index 8e43967aaaea5796b5e4ffe725e639013594957f..ef93fe1f9bda37941071aa3c8c1217d2a367a150 100644 (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