@@ -17,6 +17,7 @@ import cats.syntax.option.*
17
17
import cats .syntax .semigroup .*
18
18
import cats .syntax .traverse .*
19
19
import cats .{Eval , Monoid }
20
+ import scala .annotation .tailrec
20
21
import scribe .Logging
21
22
22
23
/**
@@ -82,6 +83,62 @@ object ArrowInliner extends Logging {
82
83
arrowsToSave : Map [String , FuncArrow ]
83
84
)
84
85
86
+ /**
87
+ * Find abilities recursively, because ability can hold arrow with another ability in it.
88
+ * @param abilitiesToGather gather all fields for these abilities
89
+ * @param varsFromAbs already gathered variables
90
+ * @param arrowsFromAbs already gathered arrows
91
+ * @param processedAbs already processed abilities
92
+ * @return all needed variables and arrows
93
+ */
94
+ @ tailrec
95
+ private def arrowsAndVarsFromAbilities (
96
+ abilitiesToGather : Map [String , GeneralAbilityType ],
97
+ exports : Map [String , ValueModel ],
98
+ arrows : Map [String , FuncArrow ],
99
+ varsFromAbs : Map [String , ValueModel ] = Map .empty,
100
+ arrowsFromAbs : Map [String , FuncArrow ] = Map .empty,
101
+ processedAbs : Set [String ] = Set .empty
102
+ ): (Map [String , ValueModel ], Map [String , FuncArrow ]) = {
103
+ val varsFromAbilities = abilitiesToGather.flatMap { case (name, at) =>
104
+ getAbilityVars(name, None , at, exports)
105
+ }
106
+ val arrowsFromAbilities = abilitiesToGather.flatMap { case (name, at) =>
107
+ getAbilityArrows(name, None , at, exports, arrows)
108
+ }
109
+
110
+ val allProcessed = abilitiesToGather.keySet ++ processedAbs
111
+
112
+ // find all names that is used in arrows
113
+ val namesUsage = arrowsFromAbilities.values.flatMap(_.body.usesVarNames.value).toSet
114
+
115
+ // check if there is abilities that we didn't gather
116
+ val abilitiesUsage = namesUsage.toList
117
+ .flatMap(exports.get)
118
+ .collect {
119
+ case ValueModel .Ability (vm, at) if ! allProcessed.contains(vm.name) =>
120
+ vm.name -> at
121
+ }
122
+ .toMap
123
+
124
+ val allVars = varsFromAbilities ++ varsFromAbs
125
+ val allArrows = arrowsFromAbilities ++ arrowsFromAbs
126
+
127
+ if (abilitiesUsage.isEmpty) {
128
+ (allVars, allArrows)
129
+ } else {
130
+ arrowsAndVarsFromAbilities(
131
+ abilitiesUsage,
132
+ exports,
133
+ arrows,
134
+ allVars,
135
+ allArrows,
136
+ allProcessed
137
+ )
138
+ }
139
+
140
+ }
141
+
85
142
// Apply a callable function, get its fully resolved body & optional value, if any
86
143
private def inline [S : Mangler : Arrows : Exports ](
87
144
fn : FuncArrow ,
@@ -104,15 +161,15 @@ object ArrowInliner extends Logging {
104
161
exports <- Exports [S ].exports
105
162
arrows <- Arrows [S ].arrows
106
163
// gather all arrows and variables from abilities
107
- returnedAbilities = rets.collect { case ValueModel .Ability (vm, at) =>
164
+ abilitiesToGather = rets.collect { case ValueModel .Ability (vm, at) =>
108
165
vm.name -> at
109
166
}
110
- varsFromAbilities = returnedAbilities.flatMap { case (name, at) =>
111
- getAbilityVars(name, None , at, exports)
112
- }.toMap
113
- arrowsFromAbilities = returnedAbilities.flatMap { case (name, at) =>
114
- getAbilityArrows(name, None , at, exports, arrows )
115
- }.toMap
167
+ arrsVars = arrowsAndVarsFromAbilities(
168
+ abilitiesToGather.toMap,
169
+ exports,
170
+ arrows
171
+ )
172
+ (varsFromAbilities, arrowsFromAbilities) = arrsVars
116
173
117
174
// find and get resolved arrows if we return them from the function
118
175
returnedArrows = rets.collect { case VarModel (name, _ : ArrowType , _) => name }.toSet
@@ -172,9 +229,11 @@ object ArrowInliner extends Logging {
172
229
abilityType,
173
230
exports
174
231
)
232
+ val abilityExport =
233
+ exports.get(abilityName).map(vm => abilityNewName.getOrElse(abilityName) -> vm).toMap
175
234
176
- get(_.variables) ++ get(_.arrows).flatMap {
177
- case arrow @ (_, vm @ ValueModel .Arrow (_, _)) =>
235
+ abilityExport ++ get(_.variables) ++ get(_.arrows).flatMap {
236
+ case arrow @ (_, ValueModel .Arrow (_, _)) =>
178
237
arrow.some
179
238
case (_, m) =>
180
239
internalError(s " ( $m) cannot be an arrow " )
@@ -497,7 +556,7 @@ object ArrowInliner extends Logging {
497
556
exports <- Exports [S ].exports
498
557
streams <- getOutsideStreamNames
499
558
arrows = passArrows ++ arrowsFromAbilities
500
-
559
+
501
560
inlineResult <- Exports [S ].scope(
502
561
Arrows [S ].scope(
503
562
for {
0 commit comments