diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 1779e32c5c..20c4ff62a1 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -749,14 +749,12 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { if tp := asTypeParam(x); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. - // TODO(gri) This needs to consider the ~ information if we - // have a union type. var rtypes []Type - var tilde []bool - if !tp.Bound().is(func(x Type) bool { - if r := f(x); r != nil { + var tildes []bool + if !tp.Bound().is(func(typ Type, tilde bool) bool { + if r := f(typ); r != nil { rtypes = append(rtypes, r) - tilde = append(tilde, true) // for now - see TODO above + tildes = append(tildes, tilde) return true } return false @@ -772,7 +770,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type { // construct a suitable new type parameter tpar := NewTypeName(nopos, nil /* = Universe pkg */, "", nil) ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect - tsum := newUnion(rtypes, tilde) + tsum := newUnion(rtypes, tildes) ptyp.bound = &Interface{allMethods: markComplete, allTypes: tsum} return ptyp diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 73ea8330d4..63cd63aacc 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -328,7 +328,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) { return true } } - return w.isParameterizedList(unpack(t.allTypes)) + return w.isParameterized(t.allTypes) } return t.iterate(func(t *Interface) bool { @@ -477,11 +477,14 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty func (check *Checker) structuralType(constraint Type) Type { if iface, _ := under(constraint).(*Interface); iface != nil { check.completeInterface(nopos, iface) - types := unpack(iface.allTypes) - if len(types) == 1 { - return types[0] + if u, _ := iface.allTypes.(*Union); u != nil { + if u.NumTerms() == 1 { + // TODO(gri) do we need to respect tilde? + return u.types[0] + } + return nil } - return nil + return iface.allTypes } - return constraint + return nil } diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 617a03ddbc..35ca197d64 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -194,14 +194,15 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) return false } - for _, t := range unpack(targBound.allTypes) { - if !iface.isSatisfiedBy(t) { + return iface.is(func(typ Type, tilde bool) bool { + // TODO(gri) incorporate tilde information! + if !iface.isSatisfiedBy(typ) { // TODO(gri) match this error message with the one below (or vice versa) - check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes) + check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.allTypes) return false } - } - return false + return true + }) } // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 990b9d374c..92f35f1279 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -272,29 +272,17 @@ type Interface struct { obj Object // type declaration defining this interface; or nil (for better error messages) } -// unpack unpacks a type into a list of types. -// TODO(gri) Try to eliminate the need for this function. -func unpack(typ Type) []Type { - if typ == nil { - return nil - } - if u := asUnion(typ); u != nil { - return u.types - } - return []Type{typ} -} - -// is reports whether interface t represents types that all satisfy pred. -func (t *Interface) is(pred func(Type) bool) bool { - if t.allTypes == nil { +// is reports whether interface t represents types that all satisfy f. +func (t *Interface) is(f func(Type, bool) bool) bool { + switch t := t.allTypes.(type) { + case nil, *top: + // TODO(gri) should settle on top or nil to represent this case return false // we must have at least one type! (was bug) + case *Union: + return t.is(func(typ Type, tilde bool) bool { return f(typ, tilde) }) + default: + return f(t, false) } - for _, t := range unpack(t.allTypes) { - if !pred(t) { - return false - } - } - return true } // emptyInterface represents the empty (completed) interface @@ -828,11 +816,6 @@ func asSignature(t Type) *Signature { return op } -func asUnion(t Type) *Union { - op, _ := optype(t).(*Union) - return op -} - func asInterface(t Type) *Interface { op, _ := optype(t).(*Interface) return op