mirror of https://github.com/golang/go.git
[dev.typeparams] cmd/compile/internal/types2: trigger verification while resolving instance
This is a straight port of CL 335978 with minor adjustements to white space and an error message. Change-Id: Icfcb562f75802a119ce5d02427bffecf7e279b2f Reviewed-on: https://go-review.googlesource.com/c/go/+/338097 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
ff0c0dbca6
commit
c079b6baaa
|
|
@ -26,7 +26,7 @@ func (n *Named) expand() {
|
||||||
// tparams. This is done implicitly by the call to n.TParams, but making it
|
// tparams. This is done implicitly by the call to n.TParams, but making it
|
||||||
// explicit is harmless: load is idempotent.
|
// explicit is harmless: load is idempotent.
|
||||||
n.load()
|
n.load()
|
||||||
inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams(), n.targs, n.instance.posList, n.instance.verify)
|
inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams(), n.targs, n.instance.posList)
|
||||||
n.underlying = inst
|
n.underlying = inst
|
||||||
n.fromRHS = inst
|
n.fromRHS = inst
|
||||||
n.instance = nil
|
n.instance = nil
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,15 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
|
||||||
// only types and functions can be generic
|
// only types and functions can be generic
|
||||||
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||||
}
|
}
|
||||||
return check.instantiate(pos, typ, tparams, targs, posList, verify)
|
|
||||||
|
inst := check.instantiate(pos, typ, tparams, targs, posList)
|
||||||
|
if verify && len(tparams) == len(targs) {
|
||||||
|
check.verify(pos, tparams, targs, posList)
|
||||||
|
}
|
||||||
|
return inst
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos, verify bool) (res Type) {
|
func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos) (res Type) {
|
||||||
// the number of supplied types must match the number of type parameters
|
// the number of supplied types must match the number of type parameters
|
||||||
if len(targs) != len(tparams) {
|
if len(targs) != len(tparams) {
|
||||||
// TODO(gri) provide better error message
|
// TODO(gri) provide better error message
|
||||||
|
|
@ -67,9 +72,6 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName,
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
|
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
|
||||||
}
|
}
|
||||||
if verify && check == nil {
|
|
||||||
panic("cannot have nil receiver if verify is set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if check != nil && check.conf.Trace {
|
if check != nil && check.conf.Trace {
|
||||||
check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
|
check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
|
||||||
|
|
@ -93,24 +95,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName,
|
||||||
return typ // nothing to do (minor optimization)
|
return typ // nothing to do (minor optimization)
|
||||||
}
|
}
|
||||||
|
|
||||||
smap := makeSubstMap(tparams, targs)
|
return check.subst(pos, typ, makeSubstMap(tparams, targs))
|
||||||
|
|
||||||
// check bounds
|
|
||||||
if verify {
|
|
||||||
for i, tname := range tparams {
|
|
||||||
// best position for error reporting
|
|
||||||
pos := pos
|
|
||||||
if i < len(posList) {
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstantiateLazy is like Instantiate, but avoids actually
|
// InstantiateLazy is like Instantiate, but avoids actually
|
||||||
|
|
@ -120,10 +105,16 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po
|
||||||
// Don't use asNamed here: we don't want to expand the base during lazy
|
// Don't use asNamed here: we don't want to expand the base during lazy
|
||||||
// instantiation.
|
// instantiation.
|
||||||
base := typ.(*Named)
|
base := typ.(*Named)
|
||||||
|
|
||||||
if base == nil {
|
if base == nil {
|
||||||
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if verify && len(base.tparams) == len(targs) {
|
||||||
|
check.later(func() {
|
||||||
|
check.verify(pos, base.tparams, targs, posList)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
h := instantiatedHash(base, targs)
|
h := instantiatedHash(base, targs)
|
||||||
if check != nil {
|
if check != nil {
|
||||||
// typ may already have been instantiated with identical type arguments. In
|
// typ may already have been instantiated with identical type arguments. In
|
||||||
|
|
@ -148,6 +139,26 @@ func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, po
|
||||||
return named
|
return named
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (check *Checker) verify(pos syntax.Pos, tparams []*TypeName, targs []Type, posList []syntax.Pos) {
|
||||||
|
if check == nil {
|
||||||
|
panic("cannot have nil Checker if verifying constraints")
|
||||||
|
}
|
||||||
|
|
||||||
|
smap := makeSubstMap(tparams, targs)
|
||||||
|
for i, tname := range tparams {
|
||||||
|
// best position for error reporting
|
||||||
|
pos := pos
|
||||||
|
if i < len(posList) {
|
||||||
|
pos = posList[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop checking bounds after the first failure
|
||||||
|
if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// satisfies reports whether the type argument targ satisfies the constraint of type parameter
|
// 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).
|
// parameter tpar (after any of its type parameters have been substituted through smap).
|
||||||
// A suitable error is reported if the result is false.
|
// A suitable error is reported if the result is false.
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,8 @@ func (u T2[U]) Add1() U {
|
||||||
return u.s + 1
|
return u.s + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rfindley): we should probably report an error here as well, not
|
|
||||||
// just when the type is first instantiated.
|
|
||||||
func NewT2[U any]() T2[U /* ERROR U has no constraints */ ] {
|
func NewT2[U any]() T2[U /* ERROR U has no constraints */ ] {
|
||||||
return T2[U]{}
|
return T2[U /* ERROR U has no constraints */ ]{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue