]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: add unifyMode to unifier, pass it through
authorRobert Griesemer <gri@golang.org>
Sat, 27 May 2023 21:31:14 +0000 (14:31 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 30 May 2023 20:19:18 +0000 (20:19 +0000)
Pass a mode parameter through all unifier calls but make no use of it.
When unifying type elements (components of composite types), use emode,
which currently is set to mode.

Preparatory step to fix #60460. Factoring out this mechanical change
will make the actual fix smaller and easier to review and understand.
Because this change doesn't affect the behavior of the unifier, it is
safe.

For #60460.

Change-Id: I5b67499d93025be2128c14cc00bcc3b8cc9f44b2
Reviewed-on: https://go-review.googlesource.com/c/go/+/498955
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types2/infer.go
src/cmd/compile/internal/types2/unify.go
src/go/types/infer.go
src/go/types/unify.go

index 097e9c7ddb67229cd70e9985e405ccba4a6d36b8..efa5727681374da90621d343aa1abd8d6e2194a1 100644 (file)
@@ -155,7 +155,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                        // Function parameters are always typed. Arguments may be untyped.
                        // Collect the indices of untyped arguments and handle them later.
                        if isTyped(arg.typ) {
-                               if !u.unify(par.typ, arg.typ) {
+                               if !u.unify(par.typ, arg.typ, 0) {
                                        errorf("type", par.typ, arg.typ, arg)
                                        return nil
                                }
@@ -230,7 +230,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                                        //    core type.
                                        // 2) If the core type doesn't have a tilde, we also must unify tx
                                        //    with the core type.
-                                       if !u.unify(tx, core.typ) {
+                                       if !u.unify(tx, core.typ, 0) {
                                                check.errorf(pos, CannotInferTypeArgs, "%s does not match %s", tpar, core.typ)
                                                return nil
                                        }
@@ -248,7 +248,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                                        // the constraint.
                                        var cause string
                                        constraint := tpar.iface()
-                                       if m, _ := check.missingMethod(tx, constraint, true, u.unify, &cause); m != nil {
+                                       if m, _ := check.missingMethod(tx, constraint, true, func(x, y Type) bool { return u.unify(x, y, 0) }, &cause); m != nil {
                                                check.errorf(pos, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, cause)
                                                return nil
                                        }
@@ -340,7 +340,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                        arg := args[i]
                        typ := Default(arg.typ)
                        assert(isTyped(typ))
-                       if !u.unify(tpar, typ) {
+                       if !u.unify(tpar, typ, 0) {
                                errorf("default type", tpar, typ, arg)
                                return nil
                        }
index fa41ae0798f2006171786a59b7c118ecdf10d92b..1d2b9d14b9dc486f825faf97e179fb4ec7eb91aa 100644 (file)
@@ -106,10 +106,13 @@ func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
        return &unifier{handles, 0}
 }
 
+// unifyMode controls the behavior of the unifier.
+type unifyMode uint
+
 // unify attempts to unify x and y and reports whether it succeeded.
 // As a side-effect, types may be inferred for type parameters.
-func (u *unifier) unify(x, y Type) bool {
-       return u.nify(x, y, nil)
+func (u *unifier) unify(x, y Type, mode unifyMode) bool {
+       return u.nify(x, y, mode, nil)
 }
 
 func (u *unifier) tracef(format string, args ...interface{}) {
@@ -241,10 +244,10 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
 // adapted version of Checker.identical. For changes to that
 // code the corresponding changes should be made here.
 // Must not be called directly from outside the unifier.
-func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
+func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
        u.depth++
        if traceInference {
-               u.tracef("%s ≡ %s", x, y)
+               u.tracef("%s ≡ %s (mode %d)", x, y, mode)
        }
        defer func() {
                if traceInference && !result {
@@ -324,13 +327,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                        return true
                }
                // both x and y have an inferred type - they must match
-               return u.nify(u.at(px), u.at(py), p)
+               return u.nify(u.at(px), u.at(py), mode, p)
 
        case px != nil:
                // x is a type parameter, y is not
                if x := u.at(px); x != nil {
                        // x has an inferred type which must match y
-                       if u.nify(x, y, p) {
+                       if u.nify(x, y, mode, p) {
                                // If we have a match, possibly through underlying types,
                                // and y is a defined type, make sure we record that type
                                // for type parameter x, which may have until now only
@@ -361,6 +364,9 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                x, y = y, x
        }
 
+       // Type elements (array, slice, etc. elements) use emode for unification.
+       emode := mode
+
        // If EnableInterfaceInference is set and both types are interfaces, one
        // interface must have a subset of the methods of the other and corresponding
        // method signatures must unify.
@@ -427,7 +433,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                        }
                        // All xmethods must exist in ymethods and corresponding signatures must unify.
                        for _, xm := range xmethods {
-                               if ym := ymap[xm.Id()]; ym == nil || !u.nify(xm.typ, ym.typ, p) {
+                               if ym := ymap[xm.Id()]; ym == nil || !u.nify(xm.typ, ym.typ, emode, p) {
                                        return false
                                }
                        }
@@ -448,7 +454,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                        xmethods := xi.typeSet().methods
                        for _, xm := range xmethods {
                                obj, _, _ := LookupFieldOrMethod(y, false, xm.pkg, xm.name)
-                               if ym, _ := obj.(*Func); ym == nil || !u.nify(xm.typ, ym.typ, p) {
+                               if ym, _ := obj.(*Func); ym == nil || !u.nify(xm.typ, ym.typ, emode, p) {
                                        return false
                                }
                        }
@@ -474,13 +480,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                if y, ok := y.(*Array); ok {
                        // If one or both array lengths are unknown (< 0) due to some error,
                        // assume they are the same to avoid spurious follow-on errors.
-                       return (x.len < 0 || y.len < 0 || x.len == y.len) && u.nify(x.elem, y.elem, p)
+                       return (x.len < 0 || y.len < 0 || x.len == y.len) && u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Slice:
                // Two slice types unify if their element types unify.
                if y, ok := y.(*Slice); ok {
-                       return u.nify(x.elem, y.elem, p)
+                       return u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Struct:
@@ -495,7 +501,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                        if f.embedded != g.embedded ||
                                                x.Tag(i) != y.Tag(i) ||
                                                !f.sameId(g.pkg, g.name) ||
-                                               !u.nify(f.typ, g.typ, p) {
+                                               !u.nify(f.typ, g.typ, emode, p) {
                                                return false
                                        }
                                }
@@ -506,7 +512,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
        case *Pointer:
                // Two pointer types unify if their base types unify.
                if y, ok := y.(*Pointer); ok {
-                       return u.nify(x.base, y.base, p)
+                       return u.nify(x.base, y.base, emode, p)
                }
 
        case *Tuple:
@@ -517,7 +523,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                if x != nil {
                                        for i, v := range x.vars {
                                                w := y.vars[i]
-                                               if !u.nify(v.typ, w.typ, p) {
+                                               if !u.nify(v.typ, w.typ, mode, p) {
                                                        return false
                                                }
                                        }
@@ -534,8 +540,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                // TODO(gri) handle type parameters or document why we can ignore them.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
-                               u.nify(x.params, y.params, p) &&
-                               u.nify(x.results, y.results, p)
+                               u.nify(x.params, y.params, emode, p) &&
+                               u.nify(x.results, y.results, emode, p)
                }
 
        case *Interface:
@@ -592,7 +598,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                }
                                for i, f := range a {
                                        g := b[i]
-                                       if f.Id() != g.Id() || !u.nify(f.typ, g.typ, q) {
+                                       if f.Id() != g.Id() || !u.nify(f.typ, g.typ, emode, q) {
                                                return false
                                        }
                                }
@@ -603,13 +609,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
        case *Map:
                // Two map types unify if their key and value types unify.
                if y, ok := y.(*Map); ok {
-                       return u.nify(x.key, y.key, p) && u.nify(x.elem, y.elem, p)
+                       return u.nify(x.key, y.key, emode, p) && u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Chan:
                // Two channel types unify if their value types unify.
                if y, ok := y.(*Chan); ok {
-                       return u.nify(x.elem, y.elem, p)
+                       return u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Named:
@@ -625,11 +631,11 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                // If one or both of x and y are interfaces, use interface unification.
                                switch {
                                case xi != nil && yi != nil:
-                                       return u.nify(xi, yi, p)
+                                       return u.nify(xi, yi, mode, p)
                                case xi != nil:
-                                       return u.nify(xi, y, p)
+                                       return u.nify(xi, y, mode, p)
                                case yi != nil:
-                                       return u.nify(x, yi, p)
+                                       return u.nify(x, yi, mode, p)
                                }
                                // In all other cases, the type arguments and origins must match.
                        }
@@ -643,7 +649,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                return false
                        }
                        for i, xarg := range xargs {
-                               if !u.nify(xarg, yargs[i], p) {
+                               if !u.nify(xarg, yargs[i], mode, p) {
                                        return false
                                }
                        }
@@ -678,7 +684,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                if traceInference {
                                        u.tracef("core %s ≡ %s", x, y)
                                }
-                               return u.nify(cx, y, p)
+                               return u.nify(cx, y, mode, p)
                        }
                }
                // x != y and there's nothing to do
@@ -687,7 +693,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                // avoid a crash in case of nil type
 
        default:
-               panic(sprintf(nil, true, "u.nify(%s, %s)", x, y))
+               panic(sprintf(nil, true, "u.nify(%s, %s, %d)", x, y, mode))
        }
 
        return false
index ae1c2af1e424a968d12060202b5d94d33b8b4e14..7032aee7a3cbb4018c43a5b2c65c87c1c6629742 100644 (file)
@@ -157,7 +157,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                        // Function parameters are always typed. Arguments may be untyped.
                        // Collect the indices of untyped arguments and handle them later.
                        if isTyped(arg.typ) {
-                               if !u.unify(par.typ, arg.typ) {
+                               if !u.unify(par.typ, arg.typ, 0) {
                                        errorf("type", par.typ, arg.typ, arg)
                                        return nil
                                }
@@ -232,7 +232,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                                        //    core type.
                                        // 2) If the core type doesn't have a tilde, we also must unify tx
                                        //    with the core type.
-                                       if !u.unify(tx, core.typ) {
+                                       if !u.unify(tx, core.typ, 0) {
                                                check.errorf(posn, CannotInferTypeArgs, "%s does not match %s", tpar, core.typ)
                                                return nil
                                        }
@@ -250,7 +250,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                                        // the constraint.
                                        var cause string
                                        constraint := tpar.iface()
-                                       if m, _ := check.missingMethod(tx, constraint, true, u.unify, &cause); m != nil {
+                                       if m, _ := check.missingMethod(tx, constraint, true, func(x, y Type) bool { return u.unify(x, y, 0) }, &cause); m != nil {
                                                check.errorf(posn, CannotInferTypeArgs, "%s does not satisfy %s %s", tx, constraint, cause)
                                                return nil
                                        }
@@ -342,7 +342,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                        arg := args[i]
                        typ := Default(arg.typ)
                        assert(isTyped(typ))
-                       if !u.unify(tpar, typ) {
+                       if !u.unify(tpar, typ, 0) {
                                errorf("default type", tpar, typ, arg)
                                return nil
                        }
index 0c00329747a30126a95cb207c86bc799ae126a29..1e9efeee82b7b74bceb2f1f102ba8f9980e7cef7 100644 (file)
@@ -108,10 +108,13 @@ func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
        return &unifier{handles, 0}
 }
 
+// unifyMode controls the behavior of the unifier.
+type unifyMode uint
+
 // unify attempts to unify x and y and reports whether it succeeded.
 // As a side-effect, types may be inferred for type parameters.
-func (u *unifier) unify(x, y Type) bool {
-       return u.nify(x, y, nil)
+func (u *unifier) unify(x, y Type, mode unifyMode) bool {
+       return u.nify(x, y, mode, nil)
 }
 
 func (u *unifier) tracef(format string, args ...interface{}) {
@@ -243,10 +246,10 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
 // adapted version of Checker.identical. For changes to that
 // code the corresponding changes should be made here.
 // Must not be called directly from outside the unifier.
-func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
+func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
        u.depth++
        if traceInference {
-               u.tracef("%s ≡ %s", x, y)
+               u.tracef("%s ≡ %s (mode %d)", x, y, mode)
        }
        defer func() {
                if traceInference && !result {
@@ -326,13 +329,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                        return true
                }
                // both x and y have an inferred type - they must match
-               return u.nify(u.at(px), u.at(py), p)
+               return u.nify(u.at(px), u.at(py), mode, p)
 
        case px != nil:
                // x is a type parameter, y is not
                if x := u.at(px); x != nil {
                        // x has an inferred type which must match y
-                       if u.nify(x, y, p) {
+                       if u.nify(x, y, mode, p) {
                                // If we have a match, possibly through underlying types,
                                // and y is a defined type, make sure we record that type
                                // for type parameter x, which may have until now only
@@ -363,6 +366,9 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                x, y = y, x
        }
 
+       // Type elements (array, slice, etc. elements) use emode for unification.
+       emode := mode
+
        // If EnableInterfaceInference is set and both types are interfaces, one
        // interface must have a subset of the methods of the other and corresponding
        // method signatures must unify.
@@ -429,7 +435,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                        }
                        // All xmethods must exist in ymethods and corresponding signatures must unify.
                        for _, xm := range xmethods {
-                               if ym := ymap[xm.Id()]; ym == nil || !u.nify(xm.typ, ym.typ, p) {
+                               if ym := ymap[xm.Id()]; ym == nil || !u.nify(xm.typ, ym.typ, emode, p) {
                                        return false
                                }
                        }
@@ -450,7 +456,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                        xmethods := xi.typeSet().methods
                        for _, xm := range xmethods {
                                obj, _, _ := LookupFieldOrMethod(y, false, xm.pkg, xm.name)
-                               if ym, _ := obj.(*Func); ym == nil || !u.nify(xm.typ, ym.typ, p) {
+                               if ym, _ := obj.(*Func); ym == nil || !u.nify(xm.typ, ym.typ, emode, p) {
                                        return false
                                }
                        }
@@ -476,13 +482,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                if y, ok := y.(*Array); ok {
                        // If one or both array lengths are unknown (< 0) due to some error,
                        // assume they are the same to avoid spurious follow-on errors.
-                       return (x.len < 0 || y.len < 0 || x.len == y.len) && u.nify(x.elem, y.elem, p)
+                       return (x.len < 0 || y.len < 0 || x.len == y.len) && u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Slice:
                // Two slice types unify if their element types unify.
                if y, ok := y.(*Slice); ok {
-                       return u.nify(x.elem, y.elem, p)
+                       return u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Struct:
@@ -497,7 +503,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                        if f.embedded != g.embedded ||
                                                x.Tag(i) != y.Tag(i) ||
                                                !f.sameId(g.pkg, g.name) ||
-                                               !u.nify(f.typ, g.typ, p) {
+                                               !u.nify(f.typ, g.typ, emode, p) {
                                                return false
                                        }
                                }
@@ -508,7 +514,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
        case *Pointer:
                // Two pointer types unify if their base types unify.
                if y, ok := y.(*Pointer); ok {
-                       return u.nify(x.base, y.base, p)
+                       return u.nify(x.base, y.base, emode, p)
                }
 
        case *Tuple:
@@ -519,7 +525,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                if x != nil {
                                        for i, v := range x.vars {
                                                w := y.vars[i]
-                                               if !u.nify(v.typ, w.typ, p) {
+                                               if !u.nify(v.typ, w.typ, mode, p) {
                                                        return false
                                                }
                                        }
@@ -536,8 +542,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                // TODO(gri) handle type parameters or document why we can ignore them.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
-                               u.nify(x.params, y.params, p) &&
-                               u.nify(x.results, y.results, p)
+                               u.nify(x.params, y.params, emode, p) &&
+                               u.nify(x.results, y.results, emode, p)
                }
 
        case *Interface:
@@ -594,7 +600,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                }
                                for i, f := range a {
                                        g := b[i]
-                                       if f.Id() != g.Id() || !u.nify(f.typ, g.typ, q) {
+                                       if f.Id() != g.Id() || !u.nify(f.typ, g.typ, emode, q) {
                                                return false
                                        }
                                }
@@ -605,13 +611,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
        case *Map:
                // Two map types unify if their key and value types unify.
                if y, ok := y.(*Map); ok {
-                       return u.nify(x.key, y.key, p) && u.nify(x.elem, y.elem, p)
+                       return u.nify(x.key, y.key, emode, p) && u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Chan:
                // Two channel types unify if their value types unify.
                if y, ok := y.(*Chan); ok {
-                       return u.nify(x.elem, y.elem, p)
+                       return u.nify(x.elem, y.elem, emode, p)
                }
 
        case *Named:
@@ -627,11 +633,11 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                // If one or both of x and y are interfaces, use interface unification.
                                switch {
                                case xi != nil && yi != nil:
-                                       return u.nify(xi, yi, p)
+                                       return u.nify(xi, yi, mode, p)
                                case xi != nil:
-                                       return u.nify(xi, y, p)
+                                       return u.nify(xi, y, mode, p)
                                case yi != nil:
-                                       return u.nify(x, yi, p)
+                                       return u.nify(x, yi, mode, p)
                                }
                                // In all other cases, the type arguments and origins must match.
                        }
@@ -645,7 +651,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                return false
                        }
                        for i, xarg := range xargs {
-                               if !u.nify(xarg, yargs[i], p) {
+                               if !u.nify(xarg, yargs[i], mode, p) {
                                        return false
                                }
                        }
@@ -680,7 +686,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                                if traceInference {
                                        u.tracef("core %s ≡ %s", x, y)
                                }
-                               return u.nify(cx, y, p)
+                               return u.nify(cx, y, mode, p)
                        }
                }
                // x != y and there's nothing to do
@@ -689,7 +695,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                // avoid a crash in case of nil type
 
        default:
-               panic(sprintf(nil, nil, true, "u.nify(%s, %s)", x, y))
+               panic(sprintf(nil, nil, true, "u.nify(%s, %s, %d)", x, y, mode))
        }
 
        return false