@@ -16,92 +16,72 @@ import (
16
16
17
17
const debug = false
18
18
19
- // NormalizeInterface returns the normal form of the interface iface, or nil if iface
20
- // has an empty type set (i.e. there are no types that satisfy iface). If the
21
- // resulting interface is non-nil, it will be identical to iface.
19
+ var ErrEmptyTypeSet = errors .New ("empty type set" )
20
+
21
+ // StructuralTerms returns a slice of terms representing the normalized
22
+ // structural type restrictions of a type parameter, if any.
23
+ //
24
+ // Structural type restrictions of a type parameter are created via
25
+ // non-interface types embedded in its constraint interface (directly, or via a
26
+ // chain of interface embeddings). For example, in the declaration `type T[P
27
+ // interface{~int; m()}] int`, the structural restriction of the type parameter
28
+ // P is ~int.
29
+ //
30
+ // With interface embedding and unions, the specification of structural type
31
+ // restrictions may be arbitrarily complex. For example, consider the
32
+ // following:
33
+ //
34
+ // type A interface{ ~string|~[]byte }
35
+ //
36
+ // type B interface{ int|string }
37
+ //
38
+ // type C interface { ~string|~int }
39
+ //
40
+ // type T[P interface{ A|B; C }] int
22
41
//
23
- // An error is returned if the interface type is invalid, or too complicated to
24
- // reasonably normalize (for example, contains unions with more than a hundred
25
- // terms) .
42
+ // In this example, the structural type restriction of P is ~string|int: A|B
43
+ // expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
44
+ // which when intersected with C (~string|~int) yields ~string|int .
26
45
//
27
- // An interface is in normal form if and only if:
28
- // - it has 0 or 1 embedded types.
29
- // - its embedded type is either a types.Union or has a concrete
30
- // (non-interface) underlying type
31
- // - if the embedded type is a union, each term of the union has a concrete
32
- // underlying type, and no terms may be removed without changing the type set
33
- // of the interface
34
- func NormalizeInterface (iface * types.Interface ) (* types.Interface , error ) {
35
- var methods []* types.Func
36
- for i := 0 ; i < iface .NumMethods (); i ++ {
37
- methods = append (methods , iface .Method (i ))
46
+ // StructuralTerms computes these expansions and reductions, producing a
47
+ // "normalized" form of the embeddings. A structural restriction is normalized
48
+ // if it is a single union containing no interface terms, and is minimal in the
49
+ // sense that removing any term changes the set of types satisfying the
50
+ // constraint. It is left as a proof for the reader that, modulo sorting, there
51
+ // is exactly one such normalized form.
52
+ //
53
+ // Because the minimal representation always takes this form, StructuralTerms
54
+ // returns a slice of tilde terms corresponding to the terms of the union in
55
+ // the normalized structural restriction. An error is returned if the
56
+ // constraint interface is invalid, exceeds complexity bounds, or has an empty
57
+ // type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet.
58
+ //
59
+ // StructuralTerms makes no guarantees about the order of terms, except that it
60
+ // is deterministic.
61
+ func StructuralTerms (tparam * TypeParam ) ([]* Term , error ) {
62
+ constraint := tparam .Constraint ()
63
+ if constraint == nil {
64
+ return nil , fmt .Errorf ("%s has nil constraint" , tparam )
65
+ }
66
+ iface , _ := constraint .Underlying ().(* types.Interface )
67
+ if iface == nil {
68
+ return nil , fmt .Errorf ("constraint is %T, not *types.Interface" , constraint .Underlying ())
38
69
}
39
- var embeddeds []types.Type
40
70
tset , err := computeTermSet (iface , make (map [types.Type ]* termSet ), 0 )
41
71
if err != nil {
42
72
return nil , err
43
73
}
44
- switch {
45
- case tset .terms .isEmpty ():
46
- // Special case: as documented
74
+ if tset .terms .isEmpty () {
75
+ return nil , ErrEmptyTypeSet
76
+ }
77
+ if tset .terms .isAll () {
47
78
return nil , nil
48
-
49
- case tset .terms .isAll ():
50
- // No embeddeds.
51
-
52
- case len (tset .terms ) == 1 :
53
- if ! tset .terms [0 ].tilde {
54
- embeddeds = append (embeddeds , tset .terms [0 ].typ )
55
- break
56
- }
57
- fallthrough
58
- default :
59
- var terms []* Term
60
- for _ , term := range tset .terms {
61
- terms = append (terms , NewTerm (term .tilde , term .typ ))
62
- }
63
- embeddeds = append (embeddeds , NewUnion (terms ))
64
79
}
65
-
66
- return types .NewInterfaceType (methods , embeddeds ), nil
67
- }
68
-
69
- var ErrEmptyTypeSet = errors .New ("empty type set" )
70
-
71
- // StructuralTerms returns the normalized structural type restrictions of a
72
- // type, if any. For types that are not type parameters, it returns term slice
73
- // containing a single non-tilde term holding the given type. For type
74
- // parameters, it returns the normalized term list of the type parameter's
75
- // constraint. See NormalizeInterface for more information on the normal form
76
- // of a constraint interface.
77
- //
78
- // StructuralTerms returns an error if the structural term list cannot be
79
- // computed. If the type set of typ is empty, it returns ErrEmptyTypeSet.
80
- func StructuralTerms (typ types.Type ) ([]* Term , error ) {
81
- switch typ := typ .(type ) {
82
- case * TypeParam :
83
- iface , _ := typ .Constraint ().(* types.Interface )
84
- if iface == nil {
85
- return nil , fmt .Errorf ("constraint is %T, not *types.Interface" , typ )
86
- }
87
- tset , err := computeTermSet (iface , make (map [types.Type ]* termSet ), 0 )
88
- if err != nil {
89
- return nil , err
90
- }
91
- if tset .terms .isEmpty () {
92
- return nil , ErrEmptyTypeSet
93
- }
94
- if tset .terms .isAll () {
95
- return nil , nil
96
- }
97
- var terms []* Term
98
- for _ , term := range tset .terms {
99
- terms = append (terms , NewTerm (term .tilde , term .typ ))
100
- }
101
- return terms , nil
102
- default :
103
- return []* Term {NewTerm (false , typ )}, nil
80
+ var terms []* Term
81
+ for _ , term := range tset .terms {
82
+ terms = append (terms , NewTerm (term .tilde , term .typ ))
104
83
}
84
+ return terms , nil
105
85
}
106
86
107
87
// A termSet holds the normalized set of terms for a given type.
0 commit comments