diff --git a/src/go/types/NOTES b/src/go/types/NOTES index 468cad8d6d..34e0b5439f 100644 --- a/src/go/types/NOTES +++ b/src/go/types/NOTES @@ -1,6 +1,6 @@ TODO - allow recursive type parameterization without need to repeat type parameters -- if type parameters are repeated in recursive instantiation, they must be the same order +- if type parameters are repeated in recursive instantiation, they must be the same order (not yet checked) - implement contract embedding - interface embedding doesn't take care of literal type constraints yet (need an allTypes list, like we have an allMethods list?) @@ -8,7 +8,6 @@ TODO OPEN ISSUES - using a contract and enumerating type arguments currently leads to an error (e.g. func f(type T C(T)) (x T) ... ) git add - contracts slip through in places where only types are permitted -- conversions against parameterized types are not implemented - parameterized interface methods (of type bounds) need to be customized (subst) for context DESIGN DECISIONS diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 3361f88438..ccb1a3223b 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -510,6 +510,39 @@ func (check *Checker) convertUntyped(x *operand, target Type) { return } + // In case of a type parameter, conversion must succeed against + // all types enumerated by the the type parameter bound. + if t, _ := target.Underlying().(*TypeParam); t != nil { + types := t.Interface().types + if len(types) == 0 { + goto Error + } + + for _, t := range t.Interface().types { + check.convertUntypedInternal(x, t) + if x.mode == invalid { + goto Error + } + } + + x.typ = target + check.updateExprType(x.expr, target, true) // UntypedNils are final + return + } + + check.convertUntypedInternal(x, target) + return + +Error: + // TODO(gri) better error message (explain cause) + check.errorf(x.pos(), "cannot convert %s to %s", x, target) + x.mode = invalid +} + +// convertUntypedInternal should only be called by convertUntyped. +func (check *Checker) convertUntypedInternal(x *operand, target Type) { + assert(isTyped(target)) + // typed target switch t := target.Underlying().(type) { case *Basic: diff --git a/src/go/types/testdata/linalg.go2 b/src/go/types/testdata/linalg.go2 index 3239065afc..1b44cfd5d1 100644 --- a/src/go/types/testdata/linalg.go2 +++ b/src/go/types/testdata/linalg.go2 @@ -62,10 +62,9 @@ contract Complex(T) { type OrderedAbs(type T OrderedNumeric) T func (a OrderedAbs(T)) Abs() T { - // TODO(gri) implement conversions against parameterized types - // if a < 0 { - // return -a - // } + if a < 0 { + return -a + } return a }