diff --git a/src/go/types/NOTES b/src/go/types/NOTES index 1d300a3ef2..982cf0b342 100644 --- a/src/go/types/NOTES +++ b/src/go/types/NOTES @@ -6,7 +6,33 @@ TODO - interface embedding doesn't take care of literal type constraints yet (need an allTypes list, like we have an allMethods list?) + OPEN ISSUES +- type constraints are not verified in some cases: + +package p + +type B interface{type int} + +func f(type P B)(x P) {} + +func _() { + f(string)("foo") // this should be invalid + f("foo") // this should be invalid +} + +- incorrect constraint errors: + +package p + +contract B(T) { + T int +} + +type T(type P B) P + +func f(type P B)(x T(P)) // this should be valid + DESIGN DECISIONS - 12/4/2019: do not allow parenthesized generic uninstantiated types (unless instantiated implicitly) diff --git a/src/go/types/expr.go b/src/go/types/expr.go index b01a4950f9..83a7142cee 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -976,7 +976,7 @@ const ( // func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind { if check.conf.Trace { - check.trace(e.Pos(), "%s", e) + check.trace(e.Pos(), "expr %s", e) check.indent++ defer func() { check.indent-- diff --git a/src/go/types/object.go b/src/go/types/object.go index e59e7d5f81..21e3ddd37c 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -461,7 +461,15 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { if i > 0 { fmt.Fprint(buf, ", ") } - fmt.Fprintf(buf, "%s", p.name) + buf.WriteString(p.name) + if p.typ != nil { + if ptyp, _ := p.typ.(*TypeParam); ptyp != nil && ptyp.bound != nil { + buf.WriteByte(' ') + WriteType(buf, ptyp.bound, qf) + // TODO(gri) if this is a generic type bound, we should print + // the type parameters + } + } } fmt.Fprint(buf, ")") } diff --git a/src/go/types/testdata/contracts.go2 b/src/go/types/testdata/contracts.go2 index 8fc8b3cc7c..ab11a6297b 100644 --- a/src/go/types/testdata/contracts.go2 +++ b/src/go/types/testdata/contracts.go2 @@ -83,7 +83,7 @@ type A struct{} func (A) a() {} -var _ T1 /* ERROR not satisfied */ (int, int) +var _ T1(int /* ERROR not satisfied */ , int) var _ T1(A, int) contract Stringer(T) { @@ -96,7 +96,7 @@ type List(type T Stringer) struct{ } var _ List(MyData) -var _ List /* ERROR not satisfied */ (int) +var _ List(int /* ERROR not satisfied */ ) type MyData string @@ -110,10 +110,10 @@ contract C3(T) { type T2 (type _ C3) struct{} -var _ T2 /* ERROR not satisfied */ (int8) +var _ T2(int8 /* ERROR not satisfied */ ) var _ T2(int16) var _ T2(int32) -var _ T2 /* ERROR not satisfied */ (int64) +var _ T2(int64 /* ERROR not satisfied */ ) var _ T2(int) var _ T2(struct{x int}) diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index f6c0c1b170..6062d388f4 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -10,7 +10,7 @@ contract C(T) { type Cm(type T C) T -func (a Cm /* ERROR not satisfied */ (T)) m() T +func (a Cm(T /* ERROR not satisfied */ )) m() T // TODO(gri) make this work /* diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index f33db38fce..5318647268 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -220,7 +220,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // func (check *Checker) typInternal(e ast.Expr, def *Named) (T Type) { if check.conf.Trace { - check.trace(e.Pos(), "expr %s", e) + check.trace(e.Pos(), "type %s", e) check.indent++ defer func() { check.indent-- @@ -272,28 +272,25 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) (T Type) { return typ // error already reported } + // evaluate arguments (always) + targs := check.typeList(e.Args) + if targs == nil { + return Typ[Invalid] + } + // the number of supplied types must match the number of type parameters - // TODO(gri) fold into code below - we want to eval args always named, _ := typ.(*Named) // generic types are defined (= Named) types tname := named.obj - if len(e.Args) != len(tname.tparams) { + 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)) return Typ[Invalid] } - // evaluate arguments - targs := check.typeList(e.Args) - if targs == nil { - return Typ[Invalid] - } - assert(len(targs) == len(tname.tparams)) - // substitute type bound parameters with arguments // and check if each argument satisfies its bound for i, tpar := range tname.tparams { pos := e.Args[i].Pos() - pos = e.Pos() // TODO(gri) remove in favor of more accurate pos on prev. line? bound := tpar.typ.(*TypeParam).bound // interface or contract or nil if bound == nil { continue // nothing to do @@ -477,19 +474,16 @@ func (check *Checker) arrayLength(e ast.Expr) int64 { // If an error occured, the result is nil, but all list elements were type-checked. func (check *Checker) typeList(list []ast.Expr) []Type { res := make([]Type, len(list)) // res != nil even if len(list) == 0 - ok := true for i, x := range list { t := check.typ(x) if t == Typ[Invalid] { - ok = false + res = nil + } + if res != nil { + res[i] = t } - res[i] = t } - if ok { - return res - - } - return nil + return res } func (check *Checker) satisfyBound(pos token.Pos, tname *TypeName, arg Type, bound *Interface) bool {