// signature may be generic
cgocall := x.mode == cgofunc
- // a type parameter may be "called" if all types have the same signature
- sig, _ := coreType(x.typ).(*Signature)
+ // 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.
+ var cause string
+ sig, _ := sharedUnder(check, x.typ, &cause).(*Signature)
if sig == nil {
- check.errorf(x, InvalidCall, invalidOp+"cannot call non-function %s", x)
+ if cause != "" {
+ check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, cause)
+ } else {
+ check.errorf(x, InvalidCall, invalidOp+"cannot call non-function %s", x)
+ }
x.mode = invalid
x.expr = call
return statement
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
+// 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 {
+ var s, su Type
+
+ bad := func(s string) bool {
+ if cause != nil {
+ *cause = s
+ }
+ su = nil
+ return false
+ }
+
+ typeset(t, func(t, u Type) bool {
+ if u == nil {
+ return bad("no specific type")
+ }
+ if su != nil && !Identical(su, u) {
+ return bad(check.sprintf("%s and %s have different underlying types", s, t))
+ }
+ // su == nil || Identical(su, u)
+ s, su = t, u
+ return true
+ })
+
+ return su
+}
+
// If t is not a type parameter, sharedUnderOrChan 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
// signature may be generic
cgocall := x.mode == cgofunc
- // a type parameter may be "called" if all types have the same signature
- sig, _ := coreType(x.typ).(*Signature)
+ // 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.
+ var cause string
+ sig, _ := sharedUnder(check, x.typ, &cause).(*Signature)
if sig == nil {
- check.errorf(x, InvalidCall, invalidOp+"cannot call non-function %s", x)
+ if cause != "" {
+ check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, cause)
+ } else {
+ check.errorf(x, InvalidCall, invalidOp+"cannot call non-function %s", x)
+ }
x.mode = invalid
x.expr = call
return statement
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
+// 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 {
+ var s, su Type
+
+ bad := func(s string) bool {
+ if cause != nil {
+ *cause = s
+ }
+ su = nil
+ return false
+ }
+
+ typeset(t, func(t, u Type) bool {
+ if u == nil {
+ return bad("no specific type")
+ }
+ if su != nil && !Identical(su, u) {
+ return bad(check.sprintf("%s and %s have different underlying types", s, t))
+ }
+ // su == nil || Identical(su, u)
+ s, su = t, u
+ return true
+ })
+
+ return su
+}
+
// If t is not a type parameter, sharedUnderOrChan 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
_ = x.Form // ERROR "x.Form undefined (type big.Float has no field or method Form, but does have unexported field form)"
_ = x.FOrm // ERROR "x.FOrm undefined (type big.Float has no field or method FOrm)"
}
+
+func _[P any](x P) {
+ x /* ERROR "cannot call x (variable of type P constrained by any): no specific type" */ ()
+}
+
+func _[P int](x P) {
+ x /* ERROR "cannot call non-function x (variable of type P constrained by int)" */ ()
+}
+
+func _[P int | string](x P) {
+ x /* ERROR "cannot call x (variable of type P constrained by int | string): int and string have different underlying types" */ ()
+}