Skip to content

Commit

Permalink
feat: go1.20 introduces slice to array convertibility
Browse files Browse the repository at this point in the history
Signed-off-by: Maxime Soulé <btik-git@scoubidou.com>
  • Loading branch information
maxatome committed Oct 17, 2022
1 parent e1156b8 commit 11a6bc3
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 7 deletions.
18 changes: 14 additions & 4 deletions internal/types/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,23 @@ func IsTypeOrConvertible(v reflect.Value, target reflect.Type) (bool, bool) {
// It handles go 1.17 slice to array pointer convertibility.
func IsConvertible(v reflect.Value, target reflect.Type) bool {
if v.Type().ConvertibleTo(target) {
if v.Kind() != reflect.Slice {
return true
}

switch target.Kind() {
// Since go 1.17, a slice can be convertible to a pointer to an
// array, but Convert() may still panic if the slice length is lesser
// than array pointed one
if v.Kind() != reflect.Slice ||
target.Kind() != reflect.Ptr ||
target.Elem().Kind() != reflect.Array ||
v.Len() >= target.Elem().Len() {
case reflect.Ptr:
return target.Elem().Kind() != reflect.Array ||
v.Len() >= target.Elem().Len()
// Since go 1.20, a slice can also be convertible to an array, but
// Convert() may still panic if the slice length is lesser than
// array one
case reflect.Array:
return v.Len() >= target.Len()
default:
return true
}
}
Expand Down
6 changes: 3 additions & 3 deletions internal/types/reflect_go117_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Copyright (c) 2021, Maxime Soulé
// Copyright (c) 2021, 2022, Maxime Soulé
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

//go:build go1.17
// +build go1.17
//go:build go1.17 && !go1.20
// +build go1.17,!go1.20

package types_test

Expand Down
58 changes: 58 additions & 0 deletions internal/types/reflect_go120_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2022, Maxime Soulé
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

//go:build go1.20
// +build go1.20

package types_test

import (
"reflect"
"testing"

"github.com/maxatome/go-testdeep/internal/test"
"github.com/maxatome/go-testdeep/internal/types"
)

// go1.17 allows to convert []T to *[n]T.
// go1.20 allows to convert []T to [n]T.
func TestIsTypeOrConvertible_go117(t *testing.T) {
type ArrP *[5]int
type Arr [5]int

// 1.17
ok, convertible := types.IsTypeOrConvertible(
reflect.ValueOf([]int{1, 2, 3, 4, 5}),
reflect.TypeOf((ArrP)(nil)))
test.IsTrue(t, ok)
test.IsTrue(t, convertible)

// 1.20
ok, convertible = types.IsTypeOrConvertible(
reflect.ValueOf([]int{1, 2, 3, 4, 5}),
reflect.TypeOf([5]int{}))
test.IsTrue(t, ok)
test.IsTrue(t, convertible)

// 1.20
ok, convertible = types.IsTypeOrConvertible(
reflect.ValueOf([]int{1, 2, 3, 4, 5}),
reflect.TypeOf(Arr{}))
test.IsTrue(t, ok)
test.IsTrue(t, convertible)

ok, convertible = types.IsTypeOrConvertible(
reflect.ValueOf([]int{1, 2, 3, 4}), // not enough items
reflect.TypeOf((ArrP)(nil)))
test.IsFalse(t, ok)
test.IsFalse(t, convertible)

ok, convertible = types.IsTypeOrConvertible(
reflect.ValueOf([]int{1, 2, 3, 4, 5}),
reflect.TypeOf(&struct{}{}))
test.IsFalse(t, ok)
test.IsFalse(t, convertible)
}

0 comments on commit 11a6bc3

Please sign in to comment.