mirror of
https://github.com/golang/go
synced 2024-11-23 00:30:07 -07:00
[dev.typeparams] cmd/compile/internal/types2: replace optype() with under() in various cases (cleanup)
This makes the behavior for type parameter operands explicit in those cases. Change-Id: I38438af67de4432f1a691dc4947e4576445f031b Reviewed-on: https://go-review.googlesource.com/c/go/+/332555 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
03ec8de24b
commit
d2bf94fb86
@ -332,13 +332,15 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var src Type
|
var src Type
|
||||||
switch t := optype(y.typ).(type) {
|
switch t := under(y.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(y.typ) {
|
if isString(y.typ) {
|
||||||
src = universeByte
|
src = universeByte
|
||||||
}
|
}
|
||||||
case *Slice:
|
case *Slice:
|
||||||
src = t.elem
|
src = t.elem
|
||||||
|
case *TypeParam:
|
||||||
|
check.error(x, "copy on generic operands not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
if dst == nil || src == nil {
|
if dst == nil || src == nil {
|
||||||
@ -455,12 +457,12 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
var valid func(t Type) bool
|
var valid func(t Type) bool
|
||||||
valid = func(t Type) bool {
|
valid = func(t Type) bool {
|
||||||
var m int
|
var m int
|
||||||
switch t := optype(t).(type) {
|
switch t := under(t).(type) {
|
||||||
case *Slice:
|
case *Slice:
|
||||||
m = 2
|
m = 2
|
||||||
case *Map, *Chan:
|
case *Map, *Chan:
|
||||||
m = 1
|
m = 1
|
||||||
case *Union:
|
case *TypeParam:
|
||||||
return t.underIs(valid)
|
return t.underIs(valid)
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -691,7 +691,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
|||||||
return nil, nil, _InvalidUntypedConversion
|
return nil, nil, _InvalidUntypedConversion
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t := optype(target).(type) {
|
switch t := under(target).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if x.mode == constant_ {
|
if x.mode == constant_ {
|
||||||
v, code := check.representation(x, t)
|
v, code := check.representation(x, t)
|
||||||
@ -723,7 +723,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
|
|||||||
default:
|
default:
|
||||||
return nil, nil, _InvalidUntypedConversion
|
return nil, nil, _InvalidUntypedConversion
|
||||||
}
|
}
|
||||||
case *Union:
|
case *TypeParam:
|
||||||
ok := t.underIs(func(t Type) bool {
|
ok := t.underIs(func(t Type) bool {
|
||||||
target, _, _ := check.implicitTypeAndValue(x, t)
|
target, _, _ := check.implicitTypeAndValue(x, t)
|
||||||
return target != nil
|
return target != nil
|
||||||
@ -1197,7 +1197,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
|||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
switch utyp := optype(base).(type) {
|
switch utyp := under(base).(type) {
|
||||||
case *Struct:
|
case *Struct:
|
||||||
if len(e.ElemList) == 0 {
|
if len(e.ElemList) == 0 {
|
||||||
break
|
break
|
||||||
|
@ -199,7 +199,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
|
|||||||
|
|
||||||
valid := false
|
valid := false
|
||||||
length := int64(-1) // valid if >= 0
|
length := int64(-1) // valid if >= 0
|
||||||
switch typ := optype(x.typ).(type) {
|
switch typ := under(x.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
if e.Full {
|
if e.Full {
|
||||||
@ -239,7 +239,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
|
|||||||
valid = true
|
valid = true
|
||||||
// x.typ doesn't change
|
// x.typ doesn't change
|
||||||
|
|
||||||
case *Union, *TypeParam:
|
case *TypeParam:
|
||||||
check.error(x, "generic slice expressions not yet implemented")
|
check.error(x, "generic slice expressions not yet implemented")
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
return
|
return
|
||||||
|
@ -25,10 +25,10 @@ func isGeneric(typ Type) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func is(typ Type, what BasicInfo) bool {
|
func is(typ Type, what BasicInfo) bool {
|
||||||
switch t := optype(typ).(type) {
|
switch t := under(typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
return t.info&what != 0
|
return t.info&what != 0
|
||||||
case *Union:
|
case *TypeParam:
|
||||||
return t.underIs(func(t Type) bool { return is(t, what) })
|
return t.underIs(func(t Type) bool { return is(t, what) })
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -56,7 +56,7 @@ func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
|
|||||||
// are not fully set up.
|
// are not fully set up.
|
||||||
func isTyped(typ Type) bool {
|
func isTyped(typ Type) bool {
|
||||||
// isTyped is called with types that are not fully
|
// isTyped is called with types that are not fully
|
||||||
// set up. Must not call Basic()!
|
// set up. Must not call asBasic()!
|
||||||
// A *Named or *instance type is always typed, so
|
// A *Named or *instance type is always typed, so
|
||||||
// we only need to check if we have a true *Basic
|
// we only need to check if we have a true *Basic
|
||||||
// type.
|
// type.
|
||||||
@ -97,18 +97,19 @@ func comparable(T Type, seen map[Type]bool) bool {
|
|||||||
seen[T] = true
|
seen[T] = true
|
||||||
|
|
||||||
// If T is a type parameter not constrained by any type
|
// If T is a type parameter not constrained by any type
|
||||||
// list (i.e., it's operational type is the top type),
|
// (i.e., it's operational type is the top type),
|
||||||
// T is comparable if it has the == method. Otherwise,
|
// T is comparable if it has the == method. Otherwise,
|
||||||
// the operational type "wins". For instance
|
// the operational type "wins". For instance
|
||||||
//
|
//
|
||||||
// interface{ comparable; type []byte }
|
// interface{ comparable; type []byte }
|
||||||
//
|
//
|
||||||
// is not comparable because []byte is not comparable.
|
// is not comparable because []byte is not comparable.
|
||||||
|
// TODO(gri) this code is not 100% correct (see comment for TypeSet.IsComparable)
|
||||||
if t := asTypeParam(T); t != nil && optype(t) == theTop {
|
if t := asTypeParam(T); t != nil && optype(t) == theTop {
|
||||||
return t.Bound().IsComparable()
|
return t.Bound().IsComparable()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t := optype(T).(type) {
|
switch t := under(T).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
// assume invalid types to be comparable
|
// assume invalid types to be comparable
|
||||||
// to avoid follow-up errors
|
// to avoid follow-up errors
|
||||||
@ -124,24 +125,22 @@ func comparable(T Type, seen map[Type]bool) bool {
|
|||||||
return true
|
return true
|
||||||
case *Array:
|
case *Array:
|
||||||
return comparable(t.elem, seen)
|
return comparable(t.elem, seen)
|
||||||
case *Union:
|
case *TypeParam:
|
||||||
return t.underIs(func(t Type) bool {
|
return t.underIs(func(t Type) bool {
|
||||||
return comparable(t, seen)
|
return comparable(t, seen)
|
||||||
})
|
})
|
||||||
case *TypeParam:
|
|
||||||
return t.Bound().IsComparable()
|
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasNil reports whether a type includes the nil value.
|
// hasNil reports whether a type includes the nil value.
|
||||||
func hasNil(typ Type) bool {
|
func hasNil(typ Type) bool {
|
||||||
switch t := optype(typ).(type) {
|
switch t := under(typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
return t.kind == UnsafePointer
|
return t.kind == UnsafePointer
|
||||||
case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
|
case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
|
||||||
return true
|
return true
|
||||||
case *Union:
|
case *TypeParam:
|
||||||
return t.underIs(hasNil)
|
return t.underIs(hasNil)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -119,7 +119,7 @@ func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[
|
|||||||
// slicing
|
// slicing
|
||||||
// TODO(gri) implement this
|
// TODO(gri) implement this
|
||||||
|
|
||||||
func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] }
|
func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR generic slice expressions not yet implemented */ [i:j:k] }
|
||||||
|
|
||||||
// len/cap built-ins
|
// len/cap built-ins
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ func (s *TypeSet) IsTop() bool { return len(s.methods) == 0 && s.types == nil }
|
|||||||
func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() }
|
func (s *TypeSet) IsMethodSet() bool { return s.types == nil && !s.IsComparable() }
|
||||||
|
|
||||||
// IsComparable reports whether each type in the set is comparable.
|
// IsComparable reports whether each type in the set is comparable.
|
||||||
|
// TODO(gri) this is not correct - there may be s.types values containing non-comparable types
|
||||||
func (s *TypeSet) IsComparable() bool {
|
func (s *TypeSet) IsComparable() bool {
|
||||||
_, m := s.LookupMethod(nil, "==")
|
_, m := s.LookupMethod(nil, "==")
|
||||||
return m != nil
|
return m != nil
|
||||||
|
Loading…
Reference in New Issue
Block a user