mirror of https://github.com/golang/go.git
go/types: fix receiver type parameter inference
Make sure receiver type and actual receiver argument match in "pointer-ness" before attempting to infer any receiver type parameters. Change-Id: Ie28004ce42ecef46e348424140b8d0c65e37cdaa
This commit is contained in:
parent
5a2e660efa
commit
1bcfb0add1
|
|
@ -489,14 +489,35 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
// If m has a parameterized receiver type, infer the type parameter
|
||||
// values from the actual receiver provided and then substitute the
|
||||
// type parameters in the signature accordingly.
|
||||
// TODO(gri) factor this code out
|
||||
sig := m.typ.(*Signature)
|
||||
if len(sig.rparams) > 0 {
|
||||
// check.dump("### recv typ = %s", x.typ)
|
||||
// check.dump("### method = %s tparams = %s", m, m.rparams)
|
||||
targs := check.infer(sig.recv.pos, sig.rparams, NewTuple(sig.recv), []*operand{x})
|
||||
// check.dump("### inferred targs = %s", targs)
|
||||
//check.dump("### recv typ = %s", x.typ)
|
||||
//check.dump("### method = %s rparams = %s tparams = %s", m, sig.rparams, sig.tparams)
|
||||
// The method may have a pointer receiver, but the actually provided receiver
|
||||
// may be a (hopefully addressable) non-pointer value, or vice versa. Here we
|
||||
// only care about inferring receiver type parameters; to make the inferrence
|
||||
// work, match up pointer-ness of reveiver and argument.
|
||||
arg := x
|
||||
if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(arg.typ) {
|
||||
copy := *arg
|
||||
if ptrRecv {
|
||||
copy.typ = NewPointer(arg.typ)
|
||||
} else {
|
||||
copy.typ = arg.typ.(*Pointer).base
|
||||
}
|
||||
arg = ©
|
||||
}
|
||||
targs := check.infer(sig.recv.pos, sig.rparams, NewTuple(sig.recv), []*operand{arg})
|
||||
//check.dump("### inferred targs = %s", targs)
|
||||
if len(targs) == 0 {
|
||||
// TODO(gri) Provide explanation as to why we can't possibly
|
||||
// reach here (consider invalid receivers, etc.).
|
||||
panic("internal error: receiver type parameter inference failed")
|
||||
}
|
||||
// Don't modify m. Instead - for now - make a copy of m and use that instead.
|
||||
// (If we modify m, some tests will fail; possibly because the m is in use.)
|
||||
// TODO(gri) investigate and provide a correct explanation here
|
||||
copy := *m
|
||||
copy.typ = check.subst(e.Pos(), m.typ, sig.rparams, targs)
|
||||
obj = ©
|
||||
|
|
|
|||
|
|
@ -33,9 +33,12 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
|
|||
}
|
||||
if isTyped(arg.typ) {
|
||||
if !check.identical0(par.typ, arg.typ, true, nil, targs) {
|
||||
check.errorf(arg.pos(), "type %s for %s does not match %s = %s",
|
||||
arg.typ, arg.expr, par.typ, check.subst(pos, par.typ, tparams, targs),
|
||||
)
|
||||
// Calling subst for an error message can cause problems.
|
||||
// TODO(gri) Determine best approach here.
|
||||
// check.errorf(arg.pos(), "type %s for %s does not match %s = %s",
|
||||
// arg.typ, arg.expr, par.typ, check.subst(pos, par.typ, tparams, targs),
|
||||
// )
|
||||
check.errorf(arg.pos(), "type %s for %s does not match %s", arg.typ, arg.expr, par.typ)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -116,3 +116,34 @@ type A(type P) struct{ x P }
|
|||
func (_ A(P)) a() {}
|
||||
|
||||
var _ T5(A(int), int)
|
||||
|
||||
// Invoking methods with parameterized receiver types uses
|
||||
// type inference to determine the actual type arguments matching
|
||||
// the receiver type parameters from the actual receiver argument.
|
||||
// Go does implicit address-taking and dereferenciation depending
|
||||
// on the actual receiver and the method's receiver type. To make
|
||||
// type inference work, the type-checker matches "pointer-ness"
|
||||
// of the actual receiver and the method's receiver type.
|
||||
// The following tests verify test this mechanism.
|
||||
|
||||
type R1(type A) struct{}
|
||||
func (_ R1(A)) vm()
|
||||
func (_ *R1(A)) pm()
|
||||
|
||||
func _(type T)(r R1(T), p *R1(T)) {
|
||||
r.vm()
|
||||
r.pm()
|
||||
p.vm()
|
||||
p.pm()
|
||||
}
|
||||
|
||||
type R2(type A, B) struct{}
|
||||
func (_ R2(A, B)) vm()
|
||||
func (_ *R2(A, B)) pm()
|
||||
|
||||
func _(type T)(r R2(T, int), p *R2(string, T)) {
|
||||
r.vm()
|
||||
r.pm()
|
||||
p.vm()
|
||||
p.pm()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue