diff --git a/src/go/types/NOTES b/src/go/types/NOTES index 982cf0b342..1b02386a8b 100644 --- a/src/go/types/NOTES +++ b/src/go/types/NOTES @@ -1,5 +1,6 @@ TODO - satisfyBounds is not working correctly +- no bounds checks in instantiate call (see open issues below) - allow recursive type parameterization without need to repeat type parameters - if type parameters are repeated in recursive instantiation, they must be the same order - implement contract embedding diff --git a/src/go/types/call.go b/src/go/types/call.go index c464e37574..2b6fb5fd18 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -105,7 +105,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind { } // instantiate function signature - x.typ = check.subst(x.pos(), sig, sig.tparams, targs) + x.typ = check.instantiate(x.pos(), sig, targs) x.mode = value x.expr = e return expression @@ -313,7 +313,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper if targs == nil { return } - rsig = check.subst(call.Pos(), sig, sig.tparams, targs).(*Signature) + rsig = check.instantiate(call.Pos(), sig, targs).(*Signature) params = check.subst(call.Pos(), params, sig.tparams, targs).(*Tuple) // TODO(gri) Optimization: We don't need to check arguments // from which we inferred parameter types. diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 2f3ce2eddf..dce998f2c7 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -14,10 +14,9 @@ import ( "strings" ) -func (check *Checker) instantiate(pos token.Pos, named *Named, targs []Type) (res Type) { - tname := named.obj +func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type) (res Type) { if check.conf.Trace { - check.trace(pos, "-- instantiating %s with %s", tname, typeListString(targs)) + check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) check.indent++ defer func() { check.indent-- @@ -29,8 +28,18 @@ func (check *Checker) instantiate(pos token.Pos, named *Named, targs []Type) (re }() } - // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? - return check.subst(pos, named, tname.tparams, targs) + // TODO(gri) need to do a satisfy bounds check here + + switch typ := typ.(type) { + case *Named: + // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? + return check.subst(pos, typ, typ.obj.tparams, targs) + + case *Signature: + return check.subst(pos, typ, typ.tparams, targs) + } + + panic("unreachable") // only defined types and (defined) functions can be generic } // subst returns the type typ with its type parameters tparams replaced by diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 5318647268..0661fe8ca3 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -279,8 +279,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) (T Type) { } // the number of supplied types must match the number of type parameters - named, _ := typ.(*Named) // generic types are defined (= Named) types - tname := named.obj + tname := typ.(*Named).obj // generic types are defined (= Named) types if len(targs) != len(tname.tparams) { // TODO(gri) provide better error message check.errorf(e.Pos(), "got %d arguments but %d type parameters", len(e.Args), len(tname.tparams)) @@ -313,7 +312,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) (T Type) { } // instantiate parameterized type - typ = check.instantiate(e.Pos(), named, targs) + typ = check.instantiate(e.Pos(), typ, targs) def.setUnderlying(typ) return typ