mirror of https://github.com/golang/go.git
go/types: cleanup instantiation of function signatures
Make sure that a generic signature is not generic anymore after instantiation. Update various related comments. Change-Id: I2ac81037e570dc3a96c138b85529f3d86030776a
This commit is contained in:
parent
3ab56f5ff2
commit
99c8ae0d28
|
|
@ -18,8 +18,6 @@ KNOWN ISSUES
|
|||
- cannot handle mutually recursive parameterized interfaces using themselves as type bounds
|
||||
- contract instantiation requires the type arguments to be type parameters from the type of function
|
||||
type parameter list or enclosing contract
|
||||
- instantiating a parameterized function type w/o value or result parameters may have unexpected side-effects
|
||||
(we don't make a copy of the signature in some cases) - investigate
|
||||
- leaving away unused receiver type parameters leads to an error; e.g.: "type S(type T) struct{}; func (S) _()"
|
||||
- using _ for an unused receiver type parameter leads to an error and crash; e.g.: "type T(type P) int; func (_ T(_)) m()"
|
||||
|
||||
|
|
|
|||
|
|
@ -107,15 +107,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
|
||||
// instantiate function signature
|
||||
res := check.instantiate(x.pos(), sig, targs, poslist).(*Signature)
|
||||
// TODO(gri) The code below should not be necessary. The subst function
|
||||
// does not correctly create a copy for signatures that have no value
|
||||
// parameters but are instantiated. Documented bug.
|
||||
// Look also into the situation for methods.
|
||||
if res == sig {
|
||||
copy := *sig
|
||||
res = ©
|
||||
}
|
||||
res.tparams = nil // signature is not generic anymore
|
||||
assert(res.tparams == nil) // signature is not generic anymore
|
||||
x.typ = res
|
||||
x.mode = value
|
||||
x.expr = e
|
||||
|
|
@ -327,7 +319,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper
|
|||
return
|
||||
}
|
||||
rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
|
||||
rsig.tparams = nil // signature is not generic anymore
|
||||
assert(rsig.tparams == nil) // signature is not generic anymore
|
||||
sig_params = check.subst(call.Pos(), sig_params, sig.tparams, targs).(*Tuple)
|
||||
// TODO(gri) Optimization: We don't need to check arguments
|
||||
// from which we inferred parameter types.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,19 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
tparams = t.tparams
|
||||
case *Signature:
|
||||
tparams = t.tparams
|
||||
defer func() {
|
||||
// If the signature doesn't use its type parameters, subst
|
||||
// will not make a copy. In that case, make a copy now (so
|
||||
// we can set tparams to nil w/o causing side-effects).
|
||||
if t == res {
|
||||
copy := *t
|
||||
res = ©
|
||||
}
|
||||
// After instantiating a generic signure, it is not generic
|
||||
// anymore; we need to set tparams to nil.
|
||||
res.(*Signature).tparams = nil
|
||||
}()
|
||||
|
||||
default:
|
||||
check.dump("%v: cannot instantiate %v", pos, typ)
|
||||
unreachable() // only defined types and (defined) functions can be generic
|
||||
|
|
@ -184,24 +197,13 @@ func (subst *subster) typ(typ Type) Type {
|
|||
return subst.tuple(t)
|
||||
|
||||
case *Signature:
|
||||
// TODO(gri) BUG: If we instantiate this signature but it has no value params, we don't get a copy!
|
||||
// We need to look at the actual type parameters of the signature as well.
|
||||
// TODO(gri) rethink the recv situation with respect to methods on parameterized types
|
||||
// recv := subst.var_(t.recv) // TODO(gri) this causes a stack overflow - explain
|
||||
recv := t.recv
|
||||
params := subst.tuple(t.params)
|
||||
results := subst.tuple(t.results)
|
||||
if recv != t.recv || params != t.params || results != t.results {
|
||||
// TODO(gri) what do we need to do with t.scope, if anything?
|
||||
copy := *t
|
||||
// TODO(gri) if we instantiate this signature, we need to set
|
||||
// tparams to nil (the signature may be a field type of a struct)
|
||||
// otherwise the signature remains parameterized which would be
|
||||
// wrong. Investigate the correct approach.
|
||||
copy.recv = recv
|
||||
copy.params = params
|
||||
copy.results = results
|
||||
return ©
|
||||
return &Signature{t.rparams, t.tparams, t.scope, recv, params, results, t.variadic}
|
||||
}
|
||||
|
||||
case *Interface:
|
||||
|
|
|
|||
|
|
@ -4,29 +4,8 @@
|
|||
|
||||
package p
|
||||
|
||||
/*
|
||||
type I interface{
|
||||
m(type A)(A)
|
||||
}
|
||||
|
||||
type S struct{}
|
||||
|
||||
func (S) m(type B)(B)
|
||||
|
||||
var _ I = S{}
|
||||
|
||||
type E(type T) interface {
|
||||
m(type B)(B)
|
||||
type T(type E) struct {
|
||||
f *T(E)
|
||||
}
|
||||
|
||||
type II interface{
|
||||
(E(int))
|
||||
mm() int
|
||||
}
|
||||
|
||||
var _ I = II(nil)
|
||||
*/
|
||||
|
||||
func _(type T interface{ type string, chan<-int })(x T) {
|
||||
for i, _ := range x /* ERROR send-only channel */ { _ = i }
|
||||
}
|
||||
var _ T(int)
|
||||
|
|
|
|||
|
|
@ -199,10 +199,10 @@ type Signature struct {
|
|||
// and store it in the Func Object) because when type-checking a function
|
||||
// literal we call the general type checker which returns a general Type.
|
||||
// We then unpack the *Signature and use the scope for the literal body.
|
||||
scope *Scope // function scope, present for package-local signatures
|
||||
recv *Var // nil if not a method
|
||||
rparams []*TypeName // reveiver type parameters from left to right; or nil
|
||||
tparams []*TypeName // type parameters from left to right; or nil
|
||||
scope *Scope // function scope, present for package-local signatures
|
||||
recv *Var // nil if not a method
|
||||
params *Tuple // (incoming) parameters from left to right; or nil
|
||||
results *Tuple // (outgoing) results from left to right; or nil
|
||||
variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only)
|
||||
|
|
@ -222,7 +222,7 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
|
|||
panic("types.NewSignature: variadic parameter must be of unnamed slice type")
|
||||
}
|
||||
}
|
||||
return &Signature{nil, recv, nil, nil, params, results, variadic}
|
||||
return &Signature{nil, nil, nil, recv, params, results, variadic}
|
||||
}
|
||||
|
||||
// Recv returns the receiver of signature s (if a method), or nil if a
|
||||
|
|
|
|||
Loading…
Reference in New Issue