case _Copy:
// copy(x, y []T) int
- dst, _ := coreType(x.typ).(*Slice)
+ dst, _ := commonUnder(check, x.typ, nil).(*Slice)
y := args[1]
src0 := coreString(y.typ)
case *Map, *Chan:
min = 1
case nil:
- check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s: no core type", arg0)
+ check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s: no common underlying type", arg0)
return
default:
check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0)
// unsafe.Slice(ptr *T, len IntegerType) []T
check.verifyVersionf(call.Fun, go1_17, "unsafe.Slice")
- ptr, _ := coreType(x.typ).(*Pointer)
+ ptr, _ := commonUnder(check, x.typ, nil).(*Pointer)
if ptr == nil {
check.errorf(x, InvalidUnsafeSlice, invalidArg+"%s is not a pointer", x)
return
// unsafe.SliceData(slice []T) *T
check.verifyVersionf(call.Fun, go1_20, "unsafe.SliceData")
- slice, _ := coreType(x.typ).(*Slice)
+ slice, _ := commonUnder(check, x.typ, nil).(*Slice)
if slice == nil {
check.errorf(x, InvalidUnsafeSliceData, invalidArg+"%s is not a slice", x)
return
cgocall := x.mode == cgofunc
// If the operand type is a type parameter, all types in its type set
- // must have a shared underlying type, which must be a signature.
+ // must have a common underlying type, which must be a signature.
var cause string
- sig, _ := sharedUnder(check, x.typ, &cause).(*Signature)
+ sig, _ := commonUnder(check, x.typ, &cause).(*Signature)
if sig == nil {
if cause != "" {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, cause)
obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, foldCase)
- // If we didn't find anything and if we have a type parameter with a shared underlying
+ // If we didn't find anything and if we have a type parameter with a common underlying
// type, see if there is a matching field (but not a method, those need to be declared
// explicitly in the constraint). If the constraint is a named pointer type (see above),
// we are ok here because only fields are accepted as results.
const enableTParamFieldLookup = false // see go.dev/issue/51576
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
- if t := sharedUnder(nil, T, nil); t != nil {
+ if t := commonUnder(nil, T, nil); t != nil {
obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, foldCase)
if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only
}
var cause1 string
- rtyp := sharedUnderOrChan(check, orig, &cause1)
+ rtyp := commonUnderOrChan(check, orig, &cause1)
if rtyp == nil {
return bad(cause1)
}
assert(typ.Recv() == nil)
// check iterator argument type
var cause2 string
- cb, _ := sharedUnder(check, typ.Params().At(0).Type(), &cause2).(*Signature)
+ cb, _ := commonUnder(check, typ.Params().At(0).Type(), &cause2).(*Signature)
switch {
case cb == nil:
if cause2 != "" {
yield(t, under(t))
}
-// If t is not a type parameter, sharedUnder returns the underlying type.
-// If t is a type parameter, sharedUnder returns the single underlying
+// TODO(gri) commonUnder, commonUnderOrChan, and Checker.chanElem (expr.go)
+// have a lot of similarities. Maybe we can find common ground
+// between them and distill a better factorization.
+
+// If t is not a type parameter, commonUnder returns the underlying type.
+// If t is a type parameter, commonUnder returns the common underlying
// type of all types in its type set if it exists.
// Otherwise the result is nil, and *cause reports the error if a non-nil
// cause is provided.
// The check parameter is only used if *cause reports an error; it may be nil.
-func sharedUnder(check *Checker, t Type, cause *string) Type {
+func commonUnder(check *Checker, t Type, cause *string) Type {
var s, su Type
bad := func(s string) bool {
return su
}
-// If t is not a type parameter, sharedUnderOrChan returns the underlying type;
+// If t is not a type parameter, commonUnderOrChan returns the underlying type;
// if that type is a channel type it must permit receive operations.
-// If t is a type parameter, sharedUnderOrChan returns the single underlying
+// If t is a type parameter, commonUnderOrChan returns the common underlying
// type of all types in its type set if it exists, or, if the type set contains
// only channel types permitting receive operations and with identical element
-// types, sharedUnderOrChan returns one of those channel types.
+// types, commonUnderOrChan returns one of those channel types.
// Otherwise the result is nil, and *cause reports the error if a non-nil cause
// is provided.
// The check parameter is only used if *cause reports an error; it may be nil.
-func sharedUnderOrChan(check *Checker, t Type, cause *string) Type {
+func commonUnderOrChan(check *Checker, t Type, cause *string) Type {
var s, su Type
var sc *Chan
case _Copy:
// copy(x, y []T) int
- dst, _ := coreType(x.typ).(*Slice)
+ dst, _ := commonUnder(check, x.typ, nil).(*Slice)
y := args[1]
src0 := coreString(y.typ)
case *Map, *Chan:
min = 1
case nil:
- check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s: no core type", arg0)
+ check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s: no common underlying type", arg0)
return
default:
check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0)
// unsafe.Slice(ptr *T, len IntegerType) []T
check.verifyVersionf(call.Fun, go1_17, "unsafe.Slice")
- ptr, _ := coreType(x.typ).(*Pointer)
+ ptr, _ := commonUnder(check, x.typ, nil).(*Pointer)
if ptr == nil {
check.errorf(x, InvalidUnsafeSlice, invalidArg+"%s is not a pointer", x)
return
// unsafe.SliceData(slice []T) *T
check.verifyVersionf(call.Fun, go1_20, "unsafe.SliceData")
- slice, _ := coreType(x.typ).(*Slice)
+ slice, _ := commonUnder(check, x.typ, nil).(*Slice)
if slice == nil {
check.errorf(x, InvalidUnsafeSliceData, invalidArg+"%s is not a slice", x)
return
cgocall := x.mode == cgofunc
// If the operand type is a type parameter, all types in its type set
- // must have a shared underlying type, which must be a signature.
+ // must have a common underlying type, which must be a signature.
var cause string
- sig, _ := sharedUnder(check, x.typ, &cause).(*Signature)
+ sig, _ := commonUnder(check, x.typ, &cause).(*Signature)
if sig == nil {
if cause != "" {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, cause)
obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, foldCase)
- // If we didn't find anything and if we have a type parameter with a shared underlying
+ // If we didn't find anything and if we have a type parameter with a common underlying
// type, see if there is a matching field (but not a method, those need to be declared
// explicitly in the constraint). If the constraint is a named pointer type (see above),
// we are ok here because only fields are accepted as results.
const enableTParamFieldLookup = false // see go.dev/issue/51576
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
- if t := sharedUnder(nil, T, nil); t != nil {
+ if t := commonUnder(nil, T, nil); t != nil {
obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, foldCase)
if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only
}
var cause1 string
- rtyp := sharedUnderOrChan(check, orig, &cause1)
+ rtyp := commonUnderOrChan(check, orig, &cause1)
if rtyp == nil {
return bad(cause1)
}
assert(typ.Recv() == nil)
// check iterator argument type
var cause2 string
- cb, _ := sharedUnder(check, typ.Params().At(0).Type(), &cause2).(*Signature)
+ cb, _ := commonUnder(check, typ.Params().At(0).Type(), &cause2).(*Signature)
switch {
case cb == nil:
if cause2 != "" {
yield(t, under(t))
}
-// If t is not a type parameter, sharedUnder returns the underlying type.
-// If t is a type parameter, sharedUnder returns the single underlying
+// TODO(gri) commonUnder, commonUnderOrChan, and Checker.chanElem (expr.go)
+// have a lot of similarities. Maybe we can find common ground
+// between them and distill a better factorization.
+
+// If t is not a type parameter, commonUnder returns the underlying type.
+// If t is a type parameter, commonUnder returns the common underlying
// type of all types in its type set if it exists.
// Otherwise the result is nil, and *cause reports the error if a non-nil
// cause is provided.
// The check parameter is only used if *cause reports an error; it may be nil.
-func sharedUnder(check *Checker, t Type, cause *string) Type {
+func commonUnder(check *Checker, t Type, cause *string) Type {
var s, su Type
bad := func(s string) bool {
return su
}
-// If t is not a type parameter, sharedUnderOrChan returns the underlying type;
+// If t is not a type parameter, commonUnderOrChan returns the underlying type;
// if that type is a channel type it must permit receive operations.
-// If t is a type parameter, sharedUnderOrChan returns the single underlying
+// If t is a type parameter, commonUnderOrChan returns the common underlying
// type of all types in its type set if it exists, or, if the type set contains
// only channel types permitting receive operations and with identical element
-// types, sharedUnderOrChan returns one of those channel types.
+// types, commonUnderOrChan returns one of those channel types.
// Otherwise the result is nil, and *cause reports the error if a non-nil cause
// is provided.
// The check parameter is only used if *cause reports an error; it may be nil.
-func sharedUnderOrChan(check *Checker, t Type, cause *string) Type {
+func commonUnderOrChan(check *Checker, t Type, cause *string) Type {
var s, su Type
var sc *Chan
C1 ~chan int,
C2 ~chan int | ~chan string,
- C3 chan int | myChan, // single underlying type
+ C3 chan int | myChan, // single underlying type
+ C4 chan int | chan<- int, // channels may have different (non-conflicting) directions
+ C5 <-chan int | chan<- int,
]() {
type S0 []int
_ = make([]int, 10)
_ = make /* ERROR "expects 2 or 3 arguments" */ (S1)
_ = make(S1, 10, 20)
_ = make /* ERROR "expects 2 or 3 arguments" */ (S1, 10, 20, 30)
- _ = make(S2 /* ERROR "cannot make S2: no core type" */ , 10)
+ _ = make(S2 /* ERROR "cannot make S2: no common underlying type" */ , 10)
type M0 map[string]int
_ = make(map[string]int)
_ = make(M1)
_ = make(M1, 10)
_ = make/* ERROR "expects 1 or 2 arguments" */(M1, 10, 20)
- _ = make(M2 /* ERROR "cannot make M2: no core type" */ )
+ _ = make(M2 /* ERROR "cannot make M2: no common underlying type" */ )
type C0 chan int
_ = make(chan int)
_ = make(C1)
_ = make(C1, 10)
_ = make/* ERROR "expects 1 or 2 arguments" */(C1, 10, 20)
- _ = make(C2 /* ERROR "cannot make C2: no core type" */ )
+ _ = make(C2 /* ERROR "cannot make C2: no common underlying type" */ )
_ = make(C3)
+ _ = make(C4)
+ _ = make(C5 /* ERROR "cannot make C5: no common underlying type" */ )
}
// max