From: Robert Griesemer Date: Sat, 27 May 2023 21:31:14 +0000 (-0700) Subject: go/types, types2: add unifyMode to unifier, pass it through X-Git-Tag: go1.21rc1~181 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f78483eaac3a678ef242cc04e05a330c8a92a992;p=gostls13.git go/types, types2: add unifyMode to unifier, pass it through 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 Reviewed-by: Robert Findley Run-TryBot: Robert Griesemer Reviewed-by: Robert Griesemer TryBot-Result: Gopher Robot --- diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 097e9c7ddb..efa5727681 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -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 } diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index fa41ae0798..1d2b9d14b9 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -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 diff --git a/src/go/types/infer.go b/src/go/types/infer.go index ae1c2af1e4..7032aee7a3 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -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 } diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 0c00329747..1e9efeee82 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -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