[dev.typeparams] cmd/compile/internal/types2: factor out constraint satisfaction check

This is a simple move of a block of inlined code into a function
to make instantiation more manageable and easier to understand.
There is no change in functionality or behavior.

Change-Id: I46e7a9ea03527731e1f0219b3402eb03949627c5
Reviewed-on: https://go-review.googlesource.com/c/go/+/322070
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-05-21 19:46:45 -07:00
parent 5770d7a637
commit 155dc0e541

View file

@ -119,19 +119,28 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
// check bounds // check bounds
for i, tname := range tparams { for i, tname := range tparams {
tpar := tname.typ.(*TypeParam)
iface := tpar.Bound()
if iface.Empty() {
continue // no type bound
}
targ := targs[i]
// best position for error reporting // best position for error reporting
pos := pos pos := pos
if i < len(poslist) { if i < len(poslist) {
pos = poslist[i] pos = poslist[i]
} }
// stop checking bounds after the first failure
if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) {
break
}
}
return check.subst(pos, typ, smap)
}
// satisfies reports whether the type argument targ satisfies the constraint of type parameter
// parameter tpar (after any of its type parameters have been substituted through smap).
// A suitable error is reported if the result is false.
func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap *substMap) bool {
iface := tpar.Bound()
if iface.Empty() {
return true // no type bound
}
// The type parameter bound is parameterized with the same type parameters // The type parameter bound is parameterized with the same type parameters
// as the instantiated type; before we can use it for bounds checking we // as the instantiated type; before we can use it for bounds checking we
@ -148,7 +157,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
// TODO(gri) is this what we want? (spec question) // TODO(gri) is this what we want? (spec question)
if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil { if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
check.errorf(pos, "%s has no methods", targ) check.errorf(pos, "%s has no methods", targ)
break return false
} }
if m, wrong := check.missingMethod(targ, iface, true); m != nil { if m, wrong := check.missingMethod(targ, iface, true); m != nil {
// TODO(gri) needs to print updated name to avoid major confusion in error message! // TODO(gri) needs to print updated name to avoid major confusion in error message!
@ -168,13 +177,13 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
} else { } else {
check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name) check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
} }
break return false
} }
} }
// targ's underlying type must also be one of the interface types listed, if any // targ's underlying type must also be one of the interface types listed, if any
if iface.allTypes == nil { if iface.allTypes == nil {
continue // nothing to do return true // nothing to do
} }
// If targ is itself a type parameter, each of its possible types, but at least one, must be in the // If targ is itself a type parameter, each of its possible types, but at least one, must be in the
@ -183,26 +192,25 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
targBound := targ.Bound() targBound := targ.Bound()
if targBound.allTypes == nil { if targBound.allTypes == nil {
check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
break return false
} }
for _, t := range unpack(targBound.allTypes) { for _, t := range unpack(targBound.allTypes) {
if !iface.isSatisfiedBy(t) { if !iface.isSatisfiedBy(t) {
// TODO(gri) match this error message with the one below (or vice versa) // TODO(gri) match this error message with the one below (or vice versa)
check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
break return false
} }
} }
break return false
} }
// Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
if !iface.isSatisfiedBy(targ) { if !iface.isSatisfiedBy(targ) {
check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes) check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes)
break return false
}
} }
return check.subst(pos, typ, smap) return true
} }
// subst returns the type typ with its type parameters tpars replaced by // subst returns the type typ with its type parameters tpars replaced by