mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00:00
[dev.typeparams] cmd/compile/internal/types2: remove unused *Checker arguments (cleanup)
Simplified names and unnecessary function indirections where possible. Change-Id: I1c7a386393d086fd7ad29f892e03f048781f3547 Reviewed-on: https://go-review.googlesource.com/c/go/+/331512 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
4b5fdb0b7a
commit
1ff43d1b17
|
@ -430,11 +430,11 @@ func Implements(V Type, T *Interface) bool {
|
||||||
// Identical reports whether x and y are identical types.
|
// Identical reports whether x and y are identical types.
|
||||||
// Receivers of Signature types are ignored.
|
// Receivers of Signature types are ignored.
|
||||||
func Identical(x, y Type) bool {
|
func Identical(x, y Type) bool {
|
||||||
return (*Checker)(nil).identical(x, y)
|
return identical(x, y, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored.
|
// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored.
|
||||||
// Receivers of Signature types are ignored.
|
// Receivers of Signature types are ignored.
|
||||||
func IdenticalIgnoreTags(x, y Type) bool {
|
func IdenticalIgnoreTags(x, y Type) bool {
|
||||||
return (*Checker)(nil).identicalIgnoreTags(x, y)
|
return identical(x, y, false, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,7 +281,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// both argument types must be identical
|
// both argument types must be identical
|
||||||
if !check.identical(x.typ, y.typ) {
|
if !Identical(x.typ, y.typ) {
|
||||||
check.errorf(x, invalidOp+"%v (mismatched types %s and %s)", call, x.typ, y.typ)
|
check.errorf(x, invalidOp+"%v (mismatched types %s and %s)", call, x.typ, y.typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !check.identical(dst, src) {
|
if !Identical(dst, src) {
|
||||||
check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
|
check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -635,7 +635,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
|
|
||||||
base := derefStructPtr(x.typ)
|
base := derefStructPtr(x.typ)
|
||||||
sel := selx.Sel.Value
|
sel := selx.Sel.Value
|
||||||
obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel)
|
obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
check.errorf(x, invalidArg+"%s has no single field %s", base, sel)
|
check.errorf(x, invalidArg+"%s has no single field %s", base, sel)
|
||||||
|
|
|
@ -467,7 +467,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
||||||
|
|
||||||
check.instantiatedOperand(x)
|
check.instantiatedOperand(x)
|
||||||
|
|
||||||
obj, index, indirect = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
switch {
|
switch {
|
||||||
case index != nil:
|
case index != nil:
|
||||||
|
@ -497,7 +497,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
||||||
} else {
|
} else {
|
||||||
changeCase = string(unicode.ToUpper(r)) + sel[1:]
|
changeCase = string(unicode.ToUpper(r)) + sel[1:]
|
||||||
}
|
}
|
||||||
if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
|
if obj, _, _ = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
|
||||||
why += ", but does have " + changeCase
|
why += ", but does have " + changeCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
V := x.typ
|
V := x.typ
|
||||||
Vu := under(V)
|
Vu := under(V)
|
||||||
Tu := under(T)
|
Tu := under(T)
|
||||||
if check.identicalIgnoreTags(Vu, Tu) {
|
if IdenticalIgnoreTags(Vu, Tu) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
// have identical underlying types if tags are ignored"
|
// have identical underlying types if tags are ignored"
|
||||||
if V, ok := V.(*Pointer); ok {
|
if V, ok := V.(*Pointer); ok {
|
||||||
if T, ok := T.(*Pointer); ok {
|
if T, ok := T.(*Pointer); ok {
|
||||||
if check.identicalIgnoreTags(under(V.base), under(T.base)) {
|
if IdenticalIgnoreTags(under(V.base), under(T.base)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
if s := asSlice(V); s != nil {
|
if s := asSlice(V); s != nil {
|
||||||
if p := asPointer(T); p != nil {
|
if p := asPointer(T); p != nil {
|
||||||
if a := asArray(p.Elem()); a != nil {
|
if a := asArray(p.Elem()); a != nil {
|
||||||
if check.identical(s.Elem(), a.Elem()) {
|
if Identical(s.Elem(), a.Elem()) {
|
||||||
if check == nil || check.allowVersion(check.pkg, 1, 17) {
|
if check == nil || check.allowVersion(check.pkg, 1, 17) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1000,7 +1000,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !check.identical(x.typ, y.typ) {
|
if !Identical(x.typ, y.typ) {
|
||||||
// only report an error if we have valid types
|
// only report an error if we have valid types
|
||||||
// (otherwise we had an error reported elsewhere already)
|
// (otherwise we had an error reported elsewhere already)
|
||||||
if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
|
if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
|
||||||
|
@ -1329,7 +1329,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
xkey := keyVal(x.val)
|
xkey := keyVal(x.val)
|
||||||
if asInterface(utyp.key) != nil {
|
if asInterface(utyp.key) != nil {
|
||||||
for _, vtyp := range visited[xkey] {
|
for _, vtyp := range visited[xkey] {
|
||||||
if check.identical(vtyp, x.typ) {
|
if Identical(vtyp, x.typ) {
|
||||||
duplicate = true
|
duplicate = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1550,7 +1550,7 @@ func (check *Checker) typeAssertion(pos syntax.Pos, x *operand, xtyp *Interface,
|
||||||
}
|
}
|
||||||
var msg string
|
var msg string
|
||||||
if wrongType != nil {
|
if wrongType != nil {
|
||||||
if check.identical(method.typ, wrongType.typ) {
|
if Identical(method.typ, wrongType.typ) {
|
||||||
msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name)
|
msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name)
|
||||||
} else {
|
} else {
|
||||||
msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
|
msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
|
||||||
// Unify parameter and argument types for generic parameters with typed arguments
|
// Unify parameter and argument types for generic parameters with typed arguments
|
||||||
// and collect the indices of generic parameters with untyped arguments.
|
// and collect the indices of generic parameters with untyped arguments.
|
||||||
// Terminology: generic parameter = function parameter with a type-parameterized type
|
// Terminology: generic parameter = function parameter with a type-parameterized type
|
||||||
u := newUnifier(check, false)
|
u := newUnifier(false)
|
||||||
u.x.init(tparams)
|
u.x.init(tparams)
|
||||||
|
|
||||||
// Set the type arguments which we know already.
|
// Set the type arguments which we know already.
|
||||||
|
@ -374,7 +374,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
|
||||||
|
|
||||||
// Setup bidirectional unification between those structural bounds
|
// Setup bidirectional unification between those structural bounds
|
||||||
// and the corresponding type arguments (which may be nil!).
|
// and the corresponding type arguments (which may be nil!).
|
||||||
u := newUnifier(check, false)
|
u := newUnifier(false)
|
||||||
u.x.init(tparams)
|
u.x.init(tparams)
|
||||||
u.y = u.x // type parameters between LHS and RHS of unification are identical
|
u.y = u.x // type parameters between LHS and RHS of unification are identical
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet {
|
||||||
}
|
}
|
||||||
// check != nil
|
// check != nil
|
||||||
check.later(func() {
|
check.later(func() {
|
||||||
if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) {
|
if !check.allowVersion(m.pkg, 1, 14) || !Identical(m.typ, other.Type()) {
|
||||||
var err error_
|
var err error_
|
||||||
err.errorf(pos, "duplicate method %s", m.name)
|
err.errorf(pos, "duplicate method %s", m.name)
|
||||||
err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name)
|
err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name)
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
|
|
||||||
package types2
|
package types2
|
||||||
|
|
||||||
|
// Internal use of LookupFieldOrMethod: If the obj result is a method
|
||||||
|
// associated with a concrete (non-interface) type, the method's signature
|
||||||
|
// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing
|
||||||
|
// the method's type.
|
||||||
|
|
||||||
// LookupFieldOrMethod looks up a field or method with given package and name
|
// LookupFieldOrMethod looks up a field or method with given package and name
|
||||||
// in T and returns the corresponding *Var or *Func, an index sequence, and a
|
// in T and returns the corresponding *Var or *Func, an index sequence, and a
|
||||||
// bool indicating if there were any pointer indirections on the path to the
|
// bool indicating if there were any pointer indirections on the path to the
|
||||||
|
@ -33,19 +38,6 @@ package types2
|
||||||
// the method's formal receiver base type, nor was the receiver addressable.
|
// the method's formal receiver base type, nor was the receiver addressable.
|
||||||
//
|
//
|
||||||
func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
||||||
return (*Checker)(nil).lookupFieldOrMethod(T, addressable, pkg, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal use of Checker.lookupFieldOrMethod: If the obj result is a method
|
|
||||||
// associated with a concrete (non-interface) type, the method's signature
|
|
||||||
// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing
|
|
||||||
// the method's type.
|
|
||||||
// TODO(gri) Now that we provide the *Checker, we can probably remove this
|
|
||||||
// caveat by calling Checker.objDecl from lookupFieldOrMethod. Investigate.
|
|
||||||
|
|
||||||
// lookupFieldOrMethod is like the external version but completes interfaces
|
|
||||||
// as necessary.
|
|
||||||
func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
|
||||||
// Methods cannot be associated to a named pointer type
|
// Methods cannot be associated to a named pointer type
|
||||||
// (spec: "The type denoted by T is called the receiver base type;
|
// (spec: "The type denoted by T is called the receiver base type;
|
||||||
// it must not be a pointer or interface type and it must be declared
|
// it must not be a pointer or interface type and it must be declared
|
||||||
|
@ -55,7 +47,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
|
||||||
// not have found it for T (see also issue 8590).
|
// not have found it for T (see also issue 8590).
|
||||||
if t := asNamed(T); t != nil {
|
if t := asNamed(T); t != nil {
|
||||||
if p, _ := t.Underlying().(*Pointer); p != nil {
|
if p, _ := t.Underlying().(*Pointer); p != nil {
|
||||||
obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name)
|
obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
|
||||||
if _, ok := obj.(*Func); ok {
|
if _, ok := obj.(*Func); ok {
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
|
@ -63,7 +55,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return check.rawLookupFieldOrMethod(T, addressable, pkg, name)
|
return lookupFieldOrMethod(T, addressable, pkg, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri) The named type consolidation and seen maps below must be
|
// TODO(gri) The named type consolidation and seen maps below must be
|
||||||
|
@ -71,10 +63,9 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
|
||||||
// types always have only one representation (even when imported
|
// types always have only one representation (even when imported
|
||||||
// indirectly via different packages.)
|
// indirectly via different packages.)
|
||||||
|
|
||||||
// rawLookupFieldOrMethod should only be called by lookupFieldOrMethod and missingMethod.
|
// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod.
|
||||||
func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
||||||
// WARNING: The code in this function is extremely subtle - do not modify casually!
|
// WARNING: The code in this function is extremely subtle - do not modify casually!
|
||||||
// This function and NewMethodSet should be kept in sync.
|
|
||||||
|
|
||||||
if name == "_" {
|
if name == "_" {
|
||||||
return // blank fields/methods are never found
|
return // blank fields/methods are never found
|
||||||
|
@ -228,7 +219,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
current = check.consolidateMultiples(next)
|
current = consolidateMultiples(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, false // not found
|
return nil, nil, false // not found
|
||||||
|
@ -245,7 +236,7 @@ type embeddedType struct {
|
||||||
// consolidateMultiples collects multiple list entries with the same type
|
// consolidateMultiples collects multiple list entries with the same type
|
||||||
// into a single entry marked as containing multiples. The result is the
|
// into a single entry marked as containing multiples. The result is the
|
||||||
// consolidated list.
|
// consolidated list.
|
||||||
func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType {
|
func consolidateMultiples(list []embeddedType) []embeddedType {
|
||||||
if len(list) <= 1 {
|
if len(list) <= 1 {
|
||||||
return list // at most one entry - nothing to do
|
return list // at most one entry - nothing to do
|
||||||
}
|
}
|
||||||
|
@ -253,7 +244,7 @@ func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType {
|
||||||
n := 0 // number of entries w/ unique type
|
n := 0 // number of entries w/ unique type
|
||||||
prev := make(map[Type]int) // index at which type was previously seen
|
prev := make(map[Type]int) // index at which type was previously seen
|
||||||
for _, e := range list {
|
for _, e := range list {
|
||||||
if i, found := check.lookupType(prev, e.typ); found {
|
if i, found := lookupType(prev, e.typ); found {
|
||||||
list[i].multiples = true
|
list[i].multiples = true
|
||||||
// ignore this entry
|
// ignore this entry
|
||||||
} else {
|
} else {
|
||||||
|
@ -265,14 +256,14 @@ func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType {
|
||||||
return list[:n]
|
return list[:n]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) lookupType(m map[Type]int, typ Type) (int, bool) {
|
func lookupType(m map[Type]int, typ Type) (int, bool) {
|
||||||
// fast path: maybe the types are equal
|
// fast path: maybe the types are equal
|
||||||
if i, found := m[typ]; found {
|
if i, found := m[typ]; found {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
|
|
||||||
for t, i := range m {
|
for t, i := range m {
|
||||||
if check.identical(t, typ) {
|
if Identical(t, typ) {
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,7 +329,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||||
// to see if they can be made to match.
|
// to see if they can be made to match.
|
||||||
// TODO(gri) is this always correct? what about type bounds?
|
// TODO(gri) is this always correct? what about type bounds?
|
||||||
// (Alternative is to rename/subst type parameters and compare.)
|
// (Alternative is to rename/subst type parameters and compare.)
|
||||||
u := newUnifier(check, true)
|
u := newUnifier(true)
|
||||||
u.x.init(ftyp.tparams)
|
u.x.init(ftyp.tparams)
|
||||||
if !u.unify(ftyp, mtyp) {
|
if !u.unify(ftyp, mtyp) {
|
||||||
return m, f
|
return m, f
|
||||||
|
@ -353,12 +344,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||||
Vn := asNamed(Vd)
|
Vn := asNamed(Vd)
|
||||||
for _, m := range T.typeSet().methods {
|
for _, m := range T.typeSet().methods {
|
||||||
// TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
|
// TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
|
||||||
obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name)
|
obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
|
||||||
|
|
||||||
// Check if *V implements this method of T.
|
// Check if *V implements this method of T.
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
ptr := NewPointer(V)
|
ptr := NewPointer(V)
|
||||||
obj, _, _ = check.rawLookupFieldOrMethod(ptr, false, m.pkg, m.name)
|
obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name)
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
return m, obj.(*Func)
|
return m, obj.(*Func)
|
||||||
}
|
}
|
||||||
|
@ -414,7 +405,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
||||||
// to see if they can be made to match.
|
// to see if they can be made to match.
|
||||||
// TODO(gri) is this always correct? what about type bounds?
|
// TODO(gri) is this always correct? what about type bounds?
|
||||||
// (Alternative is to rename/subst type parameters and compare.)
|
// (Alternative is to rename/subst type parameters and compare.)
|
||||||
u := newUnifier(check, true)
|
u := newUnifier(true)
|
||||||
if len(ftyp.tparams) > 0 {
|
if len(ftyp.tparams) > 0 {
|
||||||
// We reach here only if we accept method type parameters.
|
// We reach here only if we accept method type parameters.
|
||||||
// In this case, unification must consider any receiver
|
// In this case, unification must consider any receiver
|
||||||
|
|
|
@ -255,7 +255,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// x's type is identical to T
|
// x's type is identical to T
|
||||||
if check.identical(V, T) {
|
if Identical(V, T) {
|
||||||
return true, 0
|
return true, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
||||||
|
|
||||||
// x's type V and T have identical underlying types
|
// x's type V and T have identical underlying types
|
||||||
// and at least one of V or T is not a named type
|
// and at least one of V or T is not a named type
|
||||||
if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
|
if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
|
||||||
return true, 0
|
return true, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
||||||
if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
|
if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
|
||||||
if reason != nil {
|
if reason != nil {
|
||||||
if wrongType != nil {
|
if wrongType != nil {
|
||||||
if check.identical(m.typ, wrongType.typ) {
|
if Identical(m.typ, wrongType.typ) {
|
||||||
*reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
|
*reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
|
||||||
} else {
|
} else {
|
||||||
*reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
|
*reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
|
||||||
|
@ -315,7 +315,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
||||||
// type, x's type V and T have identical element types,
|
// type, x's type V and T have identical element types,
|
||||||
// and at least one of V or T is not a named type
|
// and at least one of V or T is not a named type
|
||||||
if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
|
if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
|
||||||
if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
|
if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
|
||||||
return !isNamed(V) || !isNamed(T), _InvalidChanAssign
|
return !isNamed(V) || !isNamed(T), _InvalidChanAssign
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,18 +147,6 @@ func hasNil(typ Type) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// identical reports whether x and y are identical types.
|
|
||||||
// Receivers of Signature types are ignored.
|
|
||||||
func (check *Checker) identical(x, y Type) bool {
|
|
||||||
return check.identical0(x, y, true, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// identicalIgnoreTags reports whether x and y are identical types if tags are ignored.
|
|
||||||
// Receivers of Signature types are ignored.
|
|
||||||
func (check *Checker) identicalIgnoreTags(x, y Type) bool {
|
|
||||||
return check.identical0(x, y, false, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// An ifacePair is a node in a stack of interface type pairs compared for identity.
|
// An ifacePair is a node in a stack of interface type pairs compared for identity.
|
||||||
type ifacePair struct {
|
type ifacePair struct {
|
||||||
x, y *Interface
|
x, y *Interface
|
||||||
|
@ -170,7 +158,7 @@ func (p *ifacePair) identical(q *ifacePair) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For changes to this code the corresponding changes should be made to unifier.nify.
|
// For changes to this code the corresponding changes should be made to unifier.nify.
|
||||||
func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
// types must be expanded for comparison
|
// types must be expanded for comparison
|
||||||
x = expandf(x)
|
x = expandf(x)
|
||||||
y = expandf(y)
|
y = expandf(y)
|
||||||
|
@ -194,13 +182,13 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
if y, ok := y.(*Array); ok {
|
if y, ok := y.(*Array); ok {
|
||||||
// If one or both array lengths are unknown (< 0) due to some error,
|
// If one or both array lengths are unknown (< 0) due to some error,
|
||||||
// assume they are the same to avoid spurious follow-on errors.
|
// assume they are the same to avoid spurious follow-on errors.
|
||||||
return (x.len < 0 || y.len < 0 || x.len == y.len) && check.identical0(x.elem, y.elem, cmpTags, p)
|
return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Slice:
|
case *Slice:
|
||||||
// Two slice types are identical if they have identical element types.
|
// Two slice types are identical if they have identical element types.
|
||||||
if y, ok := y.(*Slice); ok {
|
if y, ok := y.(*Slice); ok {
|
||||||
return check.identical0(x.elem, y.elem, cmpTags, p)
|
return identical(x.elem, y.elem, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Struct:
|
case *Struct:
|
||||||
|
@ -215,7 +203,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
if f.embedded != g.embedded ||
|
if f.embedded != g.embedded ||
|
||||||
cmpTags && x.Tag(i) != y.Tag(i) ||
|
cmpTags && x.Tag(i) != y.Tag(i) ||
|
||||||
!f.sameId(g.pkg, g.name) ||
|
!f.sameId(g.pkg, g.name) ||
|
||||||
!check.identical0(f.typ, g.typ, cmpTags, p) {
|
!identical(f.typ, g.typ, cmpTags, p) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,7 +214,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
// Two pointer types are identical if they have identical base types.
|
// Two pointer types are identical if they have identical base types.
|
||||||
if y, ok := y.(*Pointer); ok {
|
if y, ok := y.(*Pointer); ok {
|
||||||
return check.identical0(x.base, y.base, cmpTags, p)
|
return identical(x.base, y.base, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Tuple:
|
case *Tuple:
|
||||||
|
@ -237,7 +225,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
for i, v := range x.vars {
|
for i, v := range x.vars {
|
||||||
w := y.vars[i]
|
w := y.vars[i]
|
||||||
if !check.identical0(v.typ, w.typ, cmpTags, p) {
|
if !identical(v.typ, w.typ, cmpTags, p) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,9 +243,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
// parameter names.
|
// parameter names.
|
||||||
if y, ok := y.(*Signature); ok {
|
if y, ok := y.(*Signature); ok {
|
||||||
return x.variadic == y.variadic &&
|
return x.variadic == y.variadic &&
|
||||||
check.identicalTParams(x.tparams, y.tparams, cmpTags, p) &&
|
identicalTParams(x.tparams, y.tparams, cmpTags, p) &&
|
||||||
check.identical0(x.params, y.params, cmpTags, p) &&
|
identical(x.params, y.params, cmpTags, p) &&
|
||||||
check.identical0(x.results, y.results, cmpTags, p)
|
identical(x.results, y.results, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Union:
|
case *Union:
|
||||||
|
@ -325,7 +313,7 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
}
|
}
|
||||||
for i, f := range a {
|
for i, f := range a {
|
||||||
g := b[i]
|
g := b[i]
|
||||||
if f.Id() != g.Id() || !check.identical0(f.typ, g.typ, cmpTags, q) {
|
if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,14 +324,14 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
case *Map:
|
case *Map:
|
||||||
// Two map types are identical if they have identical key and value types.
|
// Two map types are identical if they have identical key and value types.
|
||||||
if y, ok := y.(*Map); ok {
|
if y, ok := y.(*Map); ok {
|
||||||
return check.identical0(x.key, y.key, cmpTags, p) && check.identical0(x.elem, y.elem, cmpTags, p)
|
return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Chan:
|
case *Chan:
|
||||||
// Two channel types are identical if they have identical value types
|
// Two channel types are identical if they have identical value types
|
||||||
// and the same direction.
|
// and the same direction.
|
||||||
if y, ok := y.(*Chan); ok {
|
if y, ok := y.(*Chan); ok {
|
||||||
return x.dir == y.dir && check.identical0(x.elem, y.elem, cmpTags, p)
|
return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Named:
|
case *Named:
|
||||||
|
@ -376,13 +364,13 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
|
func identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
|
||||||
if len(x) != len(y) {
|
if len(x) != len(y) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i, x := range x {
|
for i, x := range x {
|
||||||
y := y[i]
|
y := y[i]
|
||||||
if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
|
if !identical(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ L:
|
||||||
// look for duplicate types for a given value
|
// look for duplicate types for a given value
|
||||||
// (quadratic algorithm, but these lists tend to be very short)
|
// (quadratic algorithm, but these lists tend to be very short)
|
||||||
for _, vt := range seen[val] {
|
for _, vt := range seen[val] {
|
||||||
if check.identical(v.typ, vt.typ) {
|
if Identical(v.typ, vt.typ) {
|
||||||
var err error_
|
var err error_
|
||||||
err.errorf(&v, "duplicate case %s in expression switch", &v)
|
err.errorf(&v, "duplicate case %s in expression switch", &v)
|
||||||
err.errorf(vt.pos, "previous case")
|
err.errorf(vt.pos, "previous case")
|
||||||
|
@ -282,7 +282,7 @@ L:
|
||||||
// look for duplicate types
|
// look for duplicate types
|
||||||
// (quadratic algorithm, but type switches tend to be reasonably small)
|
// (quadratic algorithm, but type switches tend to be reasonably small)
|
||||||
for t, other := range seen {
|
for t, other := range seen {
|
||||||
if T == nil && t == nil || T != nil && t != nil && check.identical(T, t) {
|
if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
|
||||||
// talk about "case" rather than "type" because of nil case
|
// talk about "case" rather than "type" because of nil case
|
||||||
Ts := "nil"
|
Ts := "nil"
|
||||||
if T != nil {
|
if T != nil {
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
|
|
||||||
package types2
|
package types2
|
||||||
|
|
||||||
import "bytes"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// The unifier maintains two separate sets of type parameters x and y
|
// The unifier maintains two separate sets of type parameters x and y
|
||||||
// which are used to resolve type parameters in the x and y arguments
|
// which are used to resolve type parameters in the x and y arguments
|
||||||
|
@ -34,7 +37,6 @@ import "bytes"
|
||||||
// and the respective types inferred for each type parameter.
|
// and the respective types inferred for each type parameter.
|
||||||
// A unifier is created by calling newUnifier.
|
// A unifier is created by calling newUnifier.
|
||||||
type unifier struct {
|
type unifier struct {
|
||||||
check *Checker
|
|
||||||
exact bool
|
exact bool
|
||||||
x, y tparamsList // x and y must initialized via tparamsList.init
|
x, y tparamsList // x and y must initialized via tparamsList.init
|
||||||
types []Type // inferred types, shared by x and y
|
types []Type // inferred types, shared by x and y
|
||||||
|
@ -45,8 +47,8 @@ type unifier struct {
|
||||||
// exactly. If exact is not set, a named type's underlying type
|
// exactly. If exact is not set, a named type's underlying type
|
||||||
// is considered if unification would fail otherwise, and the
|
// is considered if unification would fail otherwise, and the
|
||||||
// direction of channels is ignored.
|
// direction of channels is ignored.
|
||||||
func newUnifier(check *Checker, exact bool) *unifier {
|
func newUnifier(exact bool) *unifier {
|
||||||
u := &unifier{check: check, exact: exact}
|
u := &unifier{exact: exact}
|
||||||
u.x.unifier = u
|
u.x.unifier = u
|
||||||
u.y.unifier = u
|
u.y.unifier = u
|
||||||
return u
|
return u
|
||||||
|
@ -453,8 +455,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
|
||||||
// avoid a crash in case of nil type
|
// avoid a crash in case of nil type
|
||||||
|
|
||||||
default:
|
default:
|
||||||
u.check.dump("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams)
|
panic(fmt.Sprintf("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams))
|
||||||
unreachable()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
Loading…
Reference in a new issue