From 188ddaf79c8114e4fdabb853d109cd072e044619 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 27 May 2020 12:14:44 -0700 Subject: [PATCH] go/types: make "make" work for generic types Passes all.bash. Change-Id: I524878e0299e12633c633540cc8f76deab81ce48 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go2-dev/+/755783 Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 40 +++++++++++++++++----- src/go/types/check_test.go | 1 + src/go/types/expr.go | 2 +- src/go/types/testdata/builtins.go2 | 53 ++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 src/go/types/testdata/builtins.go2 diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index ad8fe15918..6a9ec98a86 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -448,20 +448,42 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return } - var min int // minimum number of arguments - switch T.Under().(type) { - case *Slice: - min = 2 - case *Map, *Chan: - min = 1 - default: + min, max := -1, 10 + var valid func(t Type) bool + valid = func(t Type) bool { + var m int + switch t := t.Under().(type) { + case *Slice: + m = 2 + case *Map, *Chan: + m = 1 + case *TypeParam: + return t.Bound().is(valid) + default: + return false + } + if m > min { + min = m + } + if m+1 < max { + max = m + 1 + } + return true + } + + if !valid(T) { check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0) return } - if nargs < min || min+1 < nargs { - check.errorf(call.Pos(), "%v expects %d or %d arguments; found %d", call, min, min+1, nargs) + if nargs < min || max < nargs { + if min == max { + check.errorf(call.Pos(), "%v expects %d arguments; found %d", call, min, nargs) + } else { + check.errorf(call.Pos(), "%v expects %d or %d arguments; found %d", call, min, max, nargs) + } return } + types := []Type{T} var sizes []int64 // constant integer arguments, if any for _, arg := range call.Args[1:] { diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index aa402b97e5..f6f1142d96 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -82,6 +82,7 @@ var tests = [][]string{ {"testdata/expr3.src"}, {"testdata/methodsets.src"}, {"testdata/shifts.src"}, + {"testdata/builtins.go2"}, {"testdata/builtins.src"}, {"testdata/conversions.src"}, {"testdata/conversions2.src"}, diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 6d35077102..8ba3a25639 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -512,7 +512,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) { } // In case of a type parameter, conversion must succeed against - // all types enumerated by the the type parameter bound. + // all types enumerated by the type parameter bound. if t := target.TypeParam(); t != nil { types := t.Bound().allTypes if len(types) == 0 { diff --git a/src/go/types/testdata/builtins.go2 b/src/go/types/testdata/builtins.go2 new file mode 100644 index 0000000000..e05a3460ab --- /dev/null +++ b/src/go/types/testdata/builtins.go2 @@ -0,0 +1,53 @@ +// Copyright 2020 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. + +// This file tests built-in calls on generic types. + +package builtins + +type Bmc interface { + type map[rune]string, chan int +} + +type Bms interface { + type map[string]int, []int +} + +type Bcs interface { + type chan bool, []float64 +} + +type Bss interface { + type []int, []string +} + +func _(type T) () { + _ = make(T /* ERROR invalid argument */ ) + _ = make(T /* ERROR invalid argument */ , 10) + _ = make(T /* ERROR invalid argument */ , 10, 20) +} + +func _(type T Bmc) () { + _ = make(T) + _ = make(T, 10) + _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20) +} + +func _(type T Bms) () { + _ = make /* ERROR expects 2 arguments */ (T) + _ = make(T, 10) + _ = make /* ERROR expects 2 arguments */ (T, 10, 20) +} + +func _(type T Bcs) () { + _ = make /* ERROR expects 2 arguments */ (T) + _ = make(T, 10) + _ = make /* ERROR expects 2 arguments */ (T, 10, 20) +} + +func _(type T Bss) () { + _ = make /* ERROR expects 2 or 3 arguments */ (T) + _ = make(T, 10) + _ = make(T, 10, 20) +}