if n.Typecheck() != 1 && n.Typecheck() != 3 {
base.FatalfAt(g.pos(expr), "missed typecheck: %+v", n)
}
- if !g.match(n.Type(), typ, tv.HasOk()) {
+ if n.Op() != ir.OFUNCINST && !g.match(n.Type(), typ, tv.HasOk()) {
base.FatalfAt(g.pos(expr), "expected %L to have type %v", n, typ)
}
return n
// includes the additional inferred type args
fun.(*ir.InstExpr).Targs = targs
} else {
- // Create a function instantiation here, given
- // there are only inferred type args (e.g.
- // min(5,6), where min is a generic function)
+ // Create a function instantiation here, given there
+ // are only inferred type args (e.g. min(5,6), where
+ // min is a generic function). Substitute the type
+ // args for the type params in the uninstantiated function's
+ // type.
inst := ir.NewInstExpr(pos, ir.OFUNCINST, fun, targs)
- typed(fun.Type(), inst)
+ newt := g.substType(fun.Type(), fun.Type().TParams(), targs)
+ typed(newt, inst)
fun = inst
}
panic("Incorrect argument for generic func instantiation")
}
n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs)
- typed(g.typ(typ), n)
+ newt := g.typ(typ)
+ // Substitute the type args for the type params in the uninstantiated
+ // function's type. If there aren't enough type args, then the rest
+ // will be inferred at the call node, so don't try the substitution yet.
+ if x.Type().TParams().NumFields() == len(targs) {
+ newt = g.substType(g.typ(typ), x.Type().TParams(), targs)
+ }
+ typed(newt, n)
return n
case *syntax.SelectorExpr:
}
}
+// substType does a normal type substition, but tparams is in the form of a field
+// list, and targs is in terms of a slice of type nodes. substType records any newly
+// instantiated types into g.instTypeList.
+func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node) *types.Type {
+ fields := tparams.FieldSlice()
+ tparams1 := make([]*types.Type, len(fields))
+ for i, f := range fields {
+ tparams1[i] = f.Type
+ }
+ targs1 := make([]*types.Type, len(targs))
+ for i, n := range targs {
+ targs1[i] = n.Type()
+ }
+ ts := typecheck.Tsubster{
+ Tparams: tparams1,
+ Targs: targs1,
+ }
+ newt := ts.Typ(typ)
+ g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
+ return newt
+}
+
// selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
// than in typecheck.go.
newrecvs := ts.tstruct(t.Recvs(), false)
newparams := ts.tstruct(t.Params(), false)
newresults := ts.tstruct(t.Results(), false)
- if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() || targsChanged {
+ // Translate the tparams of a signature.
+ newtparams := ts.tstruct(t.TParams(), false)
+ if newrecvs != t.Recvs() || newparams != t.Params() ||
+ newresults != t.Results() || newtparams != t.TParams() || targsChanged {
// If any types have changed, then the all the fields of
// of recv, params, and results must be copied, because they have
// offset fields that are dependent, and so must have an
if newresults == t.Results() {
newresults = ts.tstruct(t.Results(), true)
}
- newt = types.NewSignature(t.Pkg(), newrecv, t.TParams().FieldSlice(), newparams.FieldSlice(), newresults.FieldSlice())
+ var tparamfields []*types.Field
+ if newtparams.HasTParam() {
+ tparamfields = newtparams.FieldSlice()
+ } else {
+ // Completely remove the tparams from the resulting
+ // signature, if the tparams are now concrete types.
+ tparamfields = nil
+ }
+ newt = types.NewSignature(t.Pkg(), newrecv, tparamfields,
+ newparams.FieldSlice(), newresults.FieldSlice())
}
case types.TINTER: