go/types: factor out/consolidate instantiate calls

Change-Id: I4973e0ebcd07d543b049f1fcdd8040f2ae214142
This commit is contained in:
Robert Griesemer 2019-12-05 15:18:36 -08:00
parent be92a40c3f
commit 3458c46de1
4 changed files with 19 additions and 10 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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