This repository has been archived by the owner on Jan 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
alts.go
123 lines (115 loc) · 2.39 KB
/
alts.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package typ
import "sort"
func NewAlt(alts ...Type) (res Type) {
res = Type{KindAlt, &Info{Params: make([]Param, 0, len(alts)*2)}}
return addAlts(res, alts)
}
// Alt returns a new type alternative for a list of types. Other alternatives are flattened.
// If the first type is already an alternative, the following types are added.
func Alt(alts ...Type) (res Type) {
if len(alts) == 0 {
return Void
}
if fst := alts[0]; isAlt(fst) {
return addAlts(fst, alts[1:])
}
return NewAlt(alts...)
}
// Choose returns type t with all type alternatives reduced to its most specific representation.
func Choose(t Type) (_ Type, err error) {
return choose(t, nil)
}
func choose(t Type, hist []*Info) (_ Type, err error) {
if t.Kind&MaskRef != KindAlt {
if !t.HasParams() {
return t, nil
}
for i := 0; i < len(hist); i++ {
h := hist[len(hist)-1-i]
if t.Info == h {
return t, nil
}
}
hist = append(hist, t.Info)
var ps []Param
for i, p := range t.Params {
p.Type, err = choose(p.Type, hist)
if err != nil {
return Void, err
}
if ps == nil {
ps = make([]Param, 0, len(t.Params))
ps = append(ps, t.Params[:i]...)
}
ps = append(ps, p)
}
if ps != nil {
nfo := *t.Info
nfo.Params = ps
t.Info = &nfo
}
return t, nil
}
if !t.HasParams() {
return Void, nil
}
var a, b, tmp Type
for i, p := range t.Params {
if i == 0 {
a = p.Type
continue
}
a, tmp, err = Common(a, p.Type)
if err != nil {
return Void, err
}
if b == Void || b.Kind > tmp.Kind {
b = tmp
} else {
b = a
}
}
if b != Void {
return b, nil
}
return a, nil
}
func fixAny(t Type) Kind {
if t.Kind&KindAny == KindAny {
return 0
}
return t.Kind
}
func hasAlt(t, alt Type) bool {
ps := t.Params
i := sort.Search(len(ps), func(i int) bool {
return fixAny(ps[i].Type) >= fixAny(alt)
})
return i < len(ps) && ps[i].Type == alt
}
func addAlt(t, a Type) Type {
if a.Kind != KindAlt {
ps := t.Params
i := sort.Search(len(ps), func(i int) bool {
return fixAny(ps[i].Type) >= fixAny(a)
})
if i >= len(ps) {
ps = append(ps, Param{Type: a})
} else if ps[i].Type != a {
ps = append(ps[:i+1], ps[i:]...)
ps[i] = Param{Type: a}
}
t.Params = ps
} else if a.ParamLen() > 0 {
for _, p := range a.Params {
t = addAlt(t, p.Type)
}
}
return t
}
func addAlts(t Type, alts []Type) Type {
for _, a := range alts {
t = addAlt(t, a)
}
return t
}