mirror of https://github.com/golang/go.git
go/types: ensure a TypeParam always has a non-nil type bound
Plus minor cleanups. Change-Id: I2508a576ad56d55fb188aa78c861afd0d032cf80
This commit is contained in:
parent
3272b2b60b
commit
5d80216f87
|
|
@ -11,6 +11,7 @@ TODO
|
|||
- debug (and error msg) printing of generic instantiated types needs some work
|
||||
- improve error messages!
|
||||
- use []*TypeParam for tparams in subst? (unclear)
|
||||
- should we use nil instead of &emptyInterface for no type bounds (as an optimization)?
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
KNOWN ISSUES
|
||||
|
|
@ -87,4 +88,5 @@ DESIGN/IMPLEMENTATION
|
|||
|
||||
- 1/7/2020: The current implementation permits empty type parameter lists as in: "func f(type)(x int)"
|
||||
but we cannot call such a function as "f()(1)"; the empty type argument list causes problems.
|
||||
We should either disallow empty type parameter lists or document this well.
|
||||
Document that we allow empty type parameter list declarations, but not empty actual type parameter
|
||||
lists. (We could allow them for types, but that doesn't seem consistent and probably is confusing).
|
||||
|
|
|
|||
|
|
@ -695,7 +695,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
|
|||
|
||||
// construct a suitable new type parameter
|
||||
tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "<type parameter>", nil)
|
||||
ptyp := check.NewTypeParam(tpar, 0, nil) // assigns type to tpar as a side-effect
|
||||
ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect
|
||||
ptyp.bound = &Interface{types: resTypes, allMethods: markComplete, allTypes: resTypes}
|
||||
|
||||
return ptyp
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
x.typ = exp.typ
|
||||
x.id = exp.id
|
||||
default:
|
||||
check.dump("unexpected object %v", exp)
|
||||
check.dump("%v: unexpected object %v", e.Sel.Pos(), exp)
|
||||
unreachable()
|
||||
}
|
||||
x.expr = e
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ func (check *Checker) contractDecl(obj *Contract, cdecl *ast.ContractSpec) {
|
|||
check.openScope(cdecl, "contract")
|
||||
defer check.closeScope()
|
||||
|
||||
tparams := check.declareTypeParams(nil, cdecl.TParams, nil)
|
||||
tparams := check.declareTypeParams(nil, cdecl.TParams, &emptyInterface)
|
||||
|
||||
// Given a contract C(P1, P2, ... Pn) { ... } we construct named types C1(P1, P2, ... Pn),
|
||||
// C2(P1, P2, ... Pn), ... Cn(P1, P2, ... Pn) with the respective underlying interfaces
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
|
|||
}
|
||||
if targs != nil {
|
||||
// obj denotes a valid contract that is instantiated with targs
|
||||
check.errorf(f.Type.Pos(), "contract instantiation not yet implemented")
|
||||
check.errorf(f.Type.Pos(), "explicit contract instantiation not yet implemented")
|
||||
} else {
|
||||
// obj denotes a valid uninstantiated contract =>
|
||||
// use the declared type parameters as "arguments"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
case *Signature:
|
||||
tparams = t.tparams
|
||||
default:
|
||||
check.dump(">>> trying to instantiate %s", typ)
|
||||
check.dump("%v: cannot instantiate %v", pos, typ)
|
||||
unreachable() // only defined types and (defined) functions can be generic
|
||||
|
||||
}
|
||||
|
|
@ -50,29 +50,26 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
return Typ[Invalid]
|
||||
}
|
||||
|
||||
// TODO(gri) should we check for len(tparams) == 0?
|
||||
if len(tparams) == 0 {
|
||||
return typ // nothing to do (minor optimization)
|
||||
}
|
||||
|
||||
// check bounds
|
||||
for i, tname := range tparams {
|
||||
targ := targs[i]
|
||||
|
||||
tpar := tname.typ.(*TypeParam)
|
||||
// TODO(gri) decide if we want to keep this or standardize on the empty interface
|
||||
// (keeping it may make sense because it's a common scenario and it may
|
||||
// be more efficient to check)
|
||||
if tpar.bound == nil {
|
||||
continue // no type bound (optimization)
|
||||
iface := tpar.Interface()
|
||||
if iface.Empty() {
|
||||
continue // no type bound
|
||||
}
|
||||
|
||||
targ := targs[i]
|
||||
|
||||
// best position for error reporting
|
||||
pos := pos
|
||||
if i < len(poslist) {
|
||||
pos = poslist[i]
|
||||
}
|
||||
|
||||
// determine type parameter bound
|
||||
iface := tpar.Interface()
|
||||
|
||||
// The type parameter bound is parameterized with the same type parameters
|
||||
// as the instantiated type; before we can use it for bounds checking we
|
||||
// need to instantiate it with the type arguments with which we instantiate
|
||||
|
|
|
|||
|
|
@ -359,7 +359,10 @@ func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMe
|
|||
|
||||
// Empty reports whether t is the empty interface.
|
||||
// The interface must have been completed.
|
||||
func (t *Interface) Empty() bool { t.assertCompleteness(); return len(t.allMethods) == 0 }
|
||||
func (t *Interface) Empty() bool {
|
||||
t.assertCompleteness()
|
||||
return len(t.allMethods) == 0 && len(t.allTypes) == 0
|
||||
}
|
||||
|
||||
// includes reports whether the interface t includes the type typ.
|
||||
func (t *Interface) includes(typ Type) bool {
|
||||
|
|
@ -537,6 +540,7 @@ type TypeParam struct {
|
|||
|
||||
// NewTypeParam returns a new TypeParam.
|
||||
func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
||||
assert(bound != nil)
|
||||
typ := &TypeParam{check.nextId, obj, index, bound}
|
||||
check.nextId++
|
||||
if obj.typ == nil {
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
// (TODO(gri) this is not working because the code doesn't allow an uninstantiated parameterized recv type)
|
||||
_, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
|
||||
if len(rparams) > 0 {
|
||||
sig.rparams = check.declareTypeParams(nil, rparams, nil)
|
||||
sig.rparams = check.declareTypeParams(nil, rparams, &emptyInterface)
|
||||
// determine receiver type to get its type parameters
|
||||
// and the respective type parameter bounds
|
||||
var recvTParams []*TypeName
|
||||
|
|
|
|||
Loading…
Reference in New Issue