@@ -52,6 +52,8 @@ const int CONTENT_PORT_KEY_ID = 16;
52
52
const int EVENT_HANDLER_KEY_ID = 17 ;
53
53
const int KEEP_ME_LAST = 18 ;
54
54
55
+ const int MAX_RESOLVING_DEPTH = 50 ;
56
+
55
57
class DirectiveInjector implements DirectiveBinder {
56
58
static bool _isInit = false ;
57
59
static initUID () {
@@ -122,6 +124,8 @@ class DirectiveInjector implements DirectiveBinder {
122
124
Key _key8 = null ; dynamic _obj8; List <Key > _pKeys8; Function _factory8;
123
125
Key _key9 = null ; dynamic _obj9; List <Key > _pKeys9; Function _factory9;
124
126
127
+ int _resolvingDepth;
128
+
125
129
@Deprecated ("Deprecated. Use getFromParent instead." )
126
130
Object get parent => this ._parent;
127
131
@@ -199,6 +203,8 @@ class DirectiveInjector implements DirectiveBinder {
199
203
Object getFromParent (Type type) => _parent.get (type);
200
204
201
205
Object getByKey (Key key) {
206
+ // All 'get'-like methods should go through this code, so that the depth counter is correct.
207
+ _resolvingDepth = MAX_RESOLVING_DEPTH ;
202
208
var oldTag = _TAG_GET .makeCurrent ();
203
209
try {
204
210
return _getByKey (key);
@@ -220,16 +226,16 @@ class DirectiveInjector implements DirectiveBinder {
220
226
221
227
Object _getDirectiveByKey (Key k, int visType, Injector i) {
222
228
do {
223
- if (_key0 == null ) break ; if (identical (_key0, k)) return _obj0 == null ? _obj0 = _new (_pKeys0, _factory0) : _obj0;
224
- if (_key1 == null ) break ; if (identical (_key1, k)) return _obj1 == null ? _obj1 = _new (_pKeys1, _factory1) : _obj1;
225
- if (_key2 == null ) break ; if (identical (_key2, k)) return _obj2 == null ? _obj2 = _new (_pKeys2, _factory2) : _obj2;
226
- if (_key3 == null ) break ; if (identical (_key3, k)) return _obj3 == null ? _obj3 = _new (_pKeys3, _factory3) : _obj3;
227
- if (_key4 == null ) break ; if (identical (_key4, k)) return _obj4 == null ? _obj4 = _new (_pKeys4, _factory4) : _obj4;
228
- if (_key5 == null ) break ; if (identical (_key5, k)) return _obj5 == null ? _obj5 = _new (_pKeys5, _factory5) : _obj5;
229
- if (_key6 == null ) break ; if (identical (_key6, k)) return _obj6 == null ? _obj6 = _new (_pKeys6, _factory6) : _obj6;
230
- if (_key7 == null ) break ; if (identical (_key7, k)) return _obj7 == null ? _obj7 = _new (_pKeys7, _factory7) : _obj7;
231
- if (_key8 == null ) break ; if (identical (_key8, k)) return _obj8 == null ? _obj8 = _new (_pKeys8, _factory8) : _obj8;
232
- if (_key9 == null ) break ; if (identical (_key9, k)) return _obj9 == null ? _obj9 = _new (_pKeys9, _factory9) : _obj9;
229
+ if (_key0 == null ) break ; if (identical (_key0, k)) return _obj0 == null ? _obj0 = _new (k, _pKeys0, _factory0) : _obj0;
230
+ if (_key1 == null ) break ; if (identical (_key1, k)) return _obj1 == null ? _obj1 = _new (k, _pKeys1, _factory1) : _obj1;
231
+ if (_key2 == null ) break ; if (identical (_key2, k)) return _obj2 == null ? _obj2 = _new (k, _pKeys2, _factory2) : _obj2;
232
+ if (_key3 == null ) break ; if (identical (_key3, k)) return _obj3 == null ? _obj3 = _new (k, _pKeys3, _factory3) : _obj3;
233
+ if (_key4 == null ) break ; if (identical (_key4, k)) return _obj4 == null ? _obj4 = _new (k, _pKeys4, _factory4) : _obj4;
234
+ if (_key5 == null ) break ; if (identical (_key5, k)) return _obj5 == null ? _obj5 = _new (k, _pKeys5, _factory5) : _obj5;
235
+ if (_key6 == null ) break ; if (identical (_key6, k)) return _obj6 == null ? _obj6 = _new (k, _pKeys6, _factory6) : _obj6;
236
+ if (_key7 == null ) break ; if (identical (_key7, k)) return _obj7 == null ? _obj7 = _new (k, _pKeys7, _factory7) : _obj7;
237
+ if (_key8 == null ) break ; if (identical (_key8, k)) return _obj8 == null ? _obj8 = _new (k, _pKeys8, _factory8) : _obj8;
238
+ if (_key9 == null ) break ; if (identical (_key9, k)) return _obj9 == null ? _obj9 = _new (k, _pKeys9, _factory9) : _obj9;
233
239
} while (false );
234
240
switch (visType) {
235
241
case VISIBILITY_LOCAL : return appInjector.getByKey (k);
@@ -275,7 +281,10 @@ class DirectiveInjector implements DirectiveBinder {
275
281
}
276
282
}
277
283
278
- dynamic _new (List <Key > paramKeys, Function fn) {
284
+ dynamic _new (Key k, List <Key > paramKeys, Function fn) {
285
+ if (_resolvingDepth-- == 0 ) {
286
+ throw new DiCircularDependencyError (k);
287
+ }
279
288
var oldTag = _TAG_GET .makeCurrent ();
280
289
int size = paramKeys.length;
281
290
var obj;
@@ -287,39 +296,44 @@ class DirectiveInjector implements DirectiveBinder {
287
296
_TAG_INSTANTIATE .makeCurrent ();
288
297
obj = Function .apply (fn, params);
289
298
} else {
290
- var a01 = size >= 01 ? _getByKey (paramKeys[00 ]) : null ;
291
- var a02 = size >= 02 ? _getByKey (paramKeys[01 ]) : null ;
292
- var a03 = size >= 03 ? _getByKey (paramKeys[02 ]) : null ;
293
- var a04 = size >= 04 ? _getByKey (paramKeys[03 ]) : null ;
294
- var a05 = size >= 05 ? _getByKey (paramKeys[04 ]) : null ;
295
- var a06 = size >= 06 ? _getByKey (paramKeys[05 ]) : null ;
296
- var a07 = size >= 07 ? _getByKey (paramKeys[06 ]) : null ;
297
- var a08 = size >= 08 ? _getByKey (paramKeys[07 ]) : null ;
298
- var a09 = size >= 09 ? _getByKey (paramKeys[08 ]) : null ;
299
- var a10 = size >= 10 ? _getByKey (paramKeys[09 ]) : null ;
300
- var a11 = size >= 11 ? _getByKey (paramKeys[10 ]) : null ;
301
- var a12 = size >= 12 ? _getByKey (paramKeys[11 ]) : null ;
302
- var a13 = size >= 13 ? _getByKey (paramKeys[12 ]) : null ;
303
- var a14 = size >= 14 ? _getByKey (paramKeys[13 ]) : null ;
304
- var a15 = size >= 15 ? _getByKey (paramKeys[14 ]) : null ;
305
- _TAG_INSTANTIATE .makeCurrent ();
306
- switch (size) {
307
- case 00 : obj = fn (); break ;
308
- case 01 : obj = fn (a01); break ;
309
- case 02 : obj = fn (a01, a02); break ;
310
- case 03 : obj = fn (a01, a02, a03); break ;
311
- case 04 : obj = fn (a01, a02, a03, a04); break ;
312
- case 05 : obj = fn (a01, a02, a03, a04, a05); break ;
313
- case 06 : obj = fn (a01, a02, a03, a04, a05, a06); break ;
314
- case 07 : obj = fn (a01, a02, a03, a04, a05, a06, a07); break ;
315
- case 08 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08); break ;
316
- case 09 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09); break ;
317
- case 10 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10); break ;
318
- case 11 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11); break ;
319
- case 12 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12); break ;
320
- case 13 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13); break ;
321
- case 14 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14); break ;
322
- case 15 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15);
299
+ try {
300
+ var a01 = size >= 01 ? _getByKey (paramKeys[00 ]) : null ;
301
+ var a02 = size >= 02 ? _getByKey (paramKeys[01 ]) : null ;
302
+ var a03 = size >= 03 ? _getByKey (paramKeys[02 ]) : null ;
303
+ var a04 = size >= 04 ? _getByKey (paramKeys[03 ]) : null ;
304
+ var a05 = size >= 05 ? _getByKey (paramKeys[04 ]) : null ;
305
+ var a06 = size >= 06 ? _getByKey (paramKeys[05 ]) : null ;
306
+ var a07 = size >= 07 ? _getByKey (paramKeys[06 ]) : null ;
307
+ var a08 = size >= 08 ? _getByKey (paramKeys[07 ]) : null ;
308
+ var a09 = size >= 09 ? _getByKey (paramKeys[08 ]) : null ;
309
+ var a10 = size >= 10 ? _getByKey (paramKeys[09 ]) : null ;
310
+ var a11 = size >= 11 ? _getByKey (paramKeys[10 ]) : null ;
311
+ var a12 = size >= 12 ? _getByKey (paramKeys[11 ]) : null ;
312
+ var a13 = size >= 13 ? _getByKey (paramKeys[12 ]) : null ;
313
+ var a14 = size >= 14 ? _getByKey (paramKeys[13 ]) : null ;
314
+ var a15 = size >= 15 ? _getByKey (paramKeys[14 ]) : null ;
315
+ _TAG_INSTANTIATE .makeCurrent ();
316
+ switch (size) {
317
+ case 00 : obj = fn (); break ;
318
+ case 01 : obj = fn (a01); break ;
319
+ case 02 : obj = fn (a01, a02); break ;
320
+ case 03 : obj = fn (a01, a02, a03); break ;
321
+ case 04 : obj = fn (a01, a02, a03, a04); break ;
322
+ case 05 : obj = fn (a01, a02, a03, a04, a05); break ;
323
+ case 06 : obj = fn (a01, a02, a03, a04, a05, a06); break ;
324
+ case 07 : obj = fn (a01, a02, a03, a04, a05, a06, a07); break ;
325
+ case 08 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08); break ;
326
+ case 09 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09); break ;
327
+ case 10 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10); break ;
328
+ case 11 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11); break ;
329
+ case 12 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12); break ;
330
+ case 13 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13); break ;
331
+ case 14 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14); break ;
332
+ case 15 : obj = fn (a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15);
333
+ }
334
+ } on DiCircularDependencyError catch (e) {
335
+ e.keys.add (k);
336
+ rethrow ;
323
337
}
324
338
}
325
339
oldTag.makeCurrent ();
@@ -439,3 +453,21 @@ class DefaultDirectiveInjector extends DirectiveInjector {
439
453
}
440
454
}
441
455
}
456
+
457
+ class DiCircularDependencyError extends Error {
458
+ final List <Key > keys;
459
+ DiCircularDependencyError (key) : keys = [key];
460
+
461
+ // strips the cyclical part of the chain.
462
+ List <Key > get resolveChain {
463
+ List <Key > rkeys = keys.reversed.toList ();
464
+ for (num i = 0 ; i < rkeys.length; i++ ) {
465
+ for (num j = i + 1 ; j < rkeys.length; j++ ) {
466
+ if (rkeys[i] == rkeys[j]) return rkeys.sublist (0 , j + 1 );
467
+ }
468
+ }
469
+ return rkeys;
470
+ }
471
+ String toString () => "circular dependency (${resolveChain .join (' -> ' )})" ;
472
+ }
473
+
0 commit comments