mirror of
https://github.com/golang/go
synced 2024-11-14 17:40:28 -07:00
go/types, types2: check that alias type arguments satisfy constraints
Fixes #69576. Change-Id: I8fc077970276977dd89fc2dd3867f2765d52e54e Reviewed-on: https://go-review.googlesource.com/c/go/+/615275 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Griesemer <gri@google.com> Reviewed-by: Tim King <taking@google.com> Reviewed-by: Robert Findley <rfindley@google.com> Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
68bcef7e9f
commit
5a1de4ed34
@ -150,6 +150,7 @@ func (check *Checker) instantiateSignature(pos syntax.Pos, expr syntax.Expr, typ
|
||||
// verify instantiation lazily (was go.dev/issue/50450)
|
||||
check.later(func() {
|
||||
tparams := typ.TypeParams().list()
|
||||
// check type constraints
|
||||
if i, err := check.verify(pos, tparams, targs, check.context()); err != nil {
|
||||
// best position for error reporting
|
||||
pos := pos
|
||||
|
@ -101,10 +101,10 @@ func (ctxt *Context) lookup(h string, orig Type, targs []Type) Type {
|
||||
return nil
|
||||
}
|
||||
|
||||
// update de-duplicates n against previously seen types with the hash h. If an
|
||||
// identical type is found with the type hash h, the previously seen type is
|
||||
// returned. Otherwise, n is returned, and recorded in the Context for the hash
|
||||
// h.
|
||||
// update de-duplicates inst against previously seen types with the hash h.
|
||||
// If an identical type is found with the type hash h, the previously seen
|
||||
// type is returned. Otherwise, inst is returned, and recorded in the Context
|
||||
// for the hash h.
|
||||
func (ctxt *Context) update(h string, orig Type, targs []Type, inst Type) Type {
|
||||
assert(inst != nil)
|
||||
|
||||
|
@ -140,7 +140,7 @@ func (check *Checker) instance(pos syntax.Pos, orig genericType, targs []Type, e
|
||||
return orig // nothing to do (minor optimization)
|
||||
}
|
||||
|
||||
return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
|
||||
res = check.newAliasInstance(pos, orig, targs, expanding, ctxt)
|
||||
|
||||
case *Signature:
|
||||
assert(expanding == nil) // function instances cannot be reached from Named types
|
||||
|
@ -450,13 +450,18 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
|
||||
}()
|
||||
|
||||
var cause string
|
||||
gtyp := check.genericType(x, &cause)
|
||||
typ := check.genericType(x, &cause)
|
||||
if cause != "" {
|
||||
check.errorf(x, NotAGenericType, invalidOp+"%s%s (%s)", x, xlist, cause)
|
||||
}
|
||||
if !isValid(gtyp) {
|
||||
return gtyp // error already reported
|
||||
if !isValid(typ) {
|
||||
return typ // error already reported
|
||||
}
|
||||
// typ must be a generic Alias or Named type (but not a *Signature)
|
||||
if _, ok := typ.(*Signature); ok {
|
||||
panic("unexpected generic signature")
|
||||
}
|
||||
gtyp := typ.(genericType)
|
||||
|
||||
// evaluate arguments
|
||||
targs := check.typeList(xlist)
|
||||
@ -464,27 +469,23 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
|
||||
return Typ[Invalid]
|
||||
}
|
||||
|
||||
if orig, _ := gtyp.(*Alias); orig != nil {
|
||||
return check.instance(x.Pos(), orig, targs, nil, check.context())
|
||||
}
|
||||
// create instance
|
||||
// The instance is not generic anymore as it has type arguments, but it still
|
||||
// satisfies the genericType interface because it has type parameters, too.
|
||||
inst := check.instance(x.Pos(), gtyp, targs, nil, check.context()).(genericType)
|
||||
|
||||
orig := asNamed(gtyp)
|
||||
if orig == nil {
|
||||
panic(fmt.Sprintf("%v: cannot instantiate %v", x.Pos(), gtyp))
|
||||
}
|
||||
|
||||
// create the instance
|
||||
inst := asNamed(check.instance(x.Pos(), orig, targs, nil, check.context()))
|
||||
|
||||
// orig.tparams may not be set up, so we need to do expansion later.
|
||||
// For Named types, orig.tparams may not be set up, so we need to do expansion later.
|
||||
check.later(func() {
|
||||
// This is an instance from the source, not from recursive substitution,
|
||||
// and so it must be resolved during type-checking so that we can report
|
||||
// errors.
|
||||
check.recordInstance(x, inst.TypeArgs().list(), inst)
|
||||
check.recordInstance(x, targs, inst)
|
||||
|
||||
if check.validateTArgLen(x.Pos(), inst.obj.name, inst.TypeParams().Len(), inst.TypeArgs().Len()) {
|
||||
if i, err := check.verify(x.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), check.context()); err != nil {
|
||||
name := inst.(interface{ Obj() *TypeName }).Obj().name
|
||||
tparams := inst.TypeParams().list()
|
||||
if check.validateTArgLen(x.Pos(), name, len(tparams), len(targs)) {
|
||||
// check type constraints
|
||||
if i, err := check.verify(x.Pos(), inst.TypeParams().list(), targs, check.context()); err != nil {
|
||||
// best position for error reporting
|
||||
pos := x.Pos()
|
||||
if i < len(xlist) {
|
||||
@ -492,15 +493,10 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
|
||||
}
|
||||
check.softErrorf(pos, InvalidTypeArg, "%s", err)
|
||||
} else {
|
||||
check.mono.recordInstance(check.pkg, x.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), xlist)
|
||||
check.mono.recordInstance(check.pkg, x.Pos(), tparams, targs, xlist)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(rfindley): remove this call: we don't need to call validType here,
|
||||
// as cycles can only occur for types used inside a Named type declaration,
|
||||
// and so it suffices to call validType from declared types.
|
||||
check.validType(inst)
|
||||
}).describef(x, "resolve instance %s", inst)
|
||||
}).describef(x, "verify instantiation %s", inst)
|
||||
|
||||
return inst
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ func (check *Checker) instantiateSignature(pos token.Pos, expr ast.Expr, typ *Si
|
||||
// verify instantiation lazily (was go.dev/issue/50450)
|
||||
check.later(func() {
|
||||
tparams := typ.TypeParams().list()
|
||||
// check type constraints
|
||||
if i, err := check.verify(pos, tparams, targs, check.context()); err != nil {
|
||||
// best position for error reporting
|
||||
pos := pos
|
||||
|
@ -104,10 +104,10 @@ func (ctxt *Context) lookup(h string, orig Type, targs []Type) Type {
|
||||
return nil
|
||||
}
|
||||
|
||||
// update de-duplicates n against previously seen types with the hash h. If an
|
||||
// identical type is found with the type hash h, the previously seen type is
|
||||
// returned. Otherwise, n is returned, and recorded in the Context for the hash
|
||||
// h.
|
||||
// update de-duplicates inst against previously seen types with the hash h.
|
||||
// If an identical type is found with the type hash h, the previously seen
|
||||
// type is returned. Otherwise, inst is returned, and recorded in the Context
|
||||
// for the hash h.
|
||||
func (ctxt *Context) update(h string, orig Type, targs []Type, inst Type) Type {
|
||||
assert(inst != nil)
|
||||
|
||||
|
@ -143,7 +143,7 @@ func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, ex
|
||||
return orig // nothing to do (minor optimization)
|
||||
}
|
||||
|
||||
return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
|
||||
res = check.newAliasInstance(pos, orig, targs, expanding, ctxt)
|
||||
|
||||
case *Signature:
|
||||
assert(expanding == nil) // function instances cannot be reached from Named types
|
||||
|
@ -440,13 +440,18 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName)
|
||||
}()
|
||||
|
||||
var cause string
|
||||
gtyp := check.genericType(ix.X, &cause)
|
||||
typ := check.genericType(ix.X, &cause)
|
||||
if cause != "" {
|
||||
check.errorf(ix.Orig, NotAGenericType, invalidOp+"%s (%s)", ix.Orig, cause)
|
||||
}
|
||||
if !isValid(gtyp) {
|
||||
return gtyp // error already reported
|
||||
if !isValid(typ) {
|
||||
return typ // error already reported
|
||||
}
|
||||
// typ must be a generic Alias or Named type (but not a *Signature)
|
||||
if _, ok := typ.(*Signature); ok {
|
||||
panic("unexpected generic signature")
|
||||
}
|
||||
gtyp := typ.(genericType)
|
||||
|
||||
// evaluate arguments
|
||||
targs := check.typeList(ix.Indices)
|
||||
@ -454,27 +459,23 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName)
|
||||
return Typ[Invalid]
|
||||
}
|
||||
|
||||
if orig, _ := gtyp.(*Alias); orig != nil {
|
||||
return check.instance(ix.Pos(), orig, targs, nil, check.context())
|
||||
}
|
||||
// create instance
|
||||
// The instance is not generic anymore as it has type arguments, but it still
|
||||
// satisfies the genericType interface because it has type parameters, too.
|
||||
inst := check.instance(ix.Pos(), gtyp, targs, nil, check.context()).(genericType)
|
||||
|
||||
orig := asNamed(gtyp)
|
||||
if orig == nil {
|
||||
panic(fmt.Sprintf("%v: cannot instantiate %v", ix.Pos(), gtyp))
|
||||
}
|
||||
|
||||
// create the instance
|
||||
inst := asNamed(check.instance(ix.Pos(), orig, targs, nil, check.context()))
|
||||
|
||||
// orig.tparams may not be set up, so we need to do expansion later.
|
||||
// For Named types, orig.tparams may not be set up, so we need to do expansion later.
|
||||
check.later(func() {
|
||||
// This is an instance from the source, not from recursive substitution,
|
||||
// and so it must be resolved during type-checking so that we can report
|
||||
// errors.
|
||||
check.recordInstance(ix.Orig, inst.TypeArgs().list(), inst)
|
||||
check.recordInstance(ix.Orig, targs, inst)
|
||||
|
||||
if check.validateTArgLen(ix.Pos(), inst.obj.name, inst.TypeParams().Len(), inst.TypeArgs().Len()) {
|
||||
if i, err := check.verify(ix.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), check.context()); err != nil {
|
||||
name := inst.(interface{ Obj() *TypeName }).Obj().name
|
||||
tparams := inst.TypeParams().list()
|
||||
if check.validateTArgLen(ix.Pos(), name, len(tparams), len(targs)) {
|
||||
// check type constraints
|
||||
if i, err := check.verify(ix.Pos(), inst.TypeParams().list(), targs, check.context()); err != nil {
|
||||
// best position for error reporting
|
||||
pos := ix.Pos()
|
||||
if i < len(ix.Indices) {
|
||||
@ -482,15 +483,10 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName)
|
||||
}
|
||||
check.softErrorf(atPos(pos), InvalidTypeArg, "%v", err)
|
||||
} else {
|
||||
check.mono.recordInstance(check.pkg, ix.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), ix.Indices)
|
||||
check.mono.recordInstance(check.pkg, ix.Pos(), tparams, targs, ix.Indices)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(rfindley): remove this call: we don't need to call validType here,
|
||||
// as cycles can only occur for types used inside a Named type declaration,
|
||||
// and so it suffices to call validType from declared types.
|
||||
check.validType(inst)
|
||||
}).describef(ix, "resolve instance %s", inst)
|
||||
}).describef(ix, "verify instantiation %s", inst)
|
||||
|
||||
return inst
|
||||
}
|
||||
|
11
src/internal/types/testdata/fixedbugs/issue69576.go
vendored
Normal file
11
src/internal/types/testdata/fixedbugs/issue69576.go
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// -goexperiment=aliastypeparams -gotypesalias=1
|
||||
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type A[P int] = struct{}
|
||||
|
||||
var _ A[string /* ERROR "string does not satisfy int (string missing in int)" */]
|
Loading…
Reference in New Issue
Block a user