go/types: minor improvements in tracing output, removed some TODOs

Also: added failing test cases to NOTES

Change-Id: Ie7b823b4cc46c64068749676d7a1464082e60264
This commit is contained in:
Robert Griesemer 2019-12-04 16:24:37 -08:00
parent 57c8d7fe0a
commit be92a40c3f
6 changed files with 54 additions and 26 deletions

View File

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

View File

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

View File

@ -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, ")")
}

View File

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

View File

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

View File

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