Skip to content

Commit

Permalink
Mooore
Browse files Browse the repository at this point in the history
  • Loading branch information
rrousselGit committed Mar 14, 2024
1 parent 2807d43 commit 88a865b
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 12 deletions.
7 changes: 5 additions & 2 deletions packages/riverpod/lib/src/core/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -551,15 +551,18 @@ The provider ${_debugCurrentlyBuildingElement!.origin} modified $origin while bu
}) {
final ref = this.ref!;
ref._throwIfInvalidUsage();
if (kDebugMode) ref._debugAssertCanDependOn(listenable);

return listenable.addListener(
final result = listenable.addListener(
this,
listener,
fireImmediately: fireImmediately,
onError: onError,
onDependencyMayHaveChanged: onDependencyMayHaveChanged,
);

if (kDebugMode) ref._debugAssertCanDependOn(listenable);

return result;
}

void _onListen() {
Expand Down
33 changes: 24 additions & 9 deletions packages/riverpod/lib/src/core/ref.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,18 @@ final <yourProvider> = Provider(dependencies: [<dependency>]);
}

// TODO Consider all dependencies, not just ref.watch
final queue = Queue<ProviderElement>.from(
_element._providerDependents,
final queue = Queue<ProviderElement>();
_element.visitChildren(
elementVisitor: queue.add,
listenableVisitor: (_) {},
);

while (queue.isNotEmpty) {
final current = queue.removeFirst();
queue.addAll(current._providerDependents);
current.visitChildren(
elementVisitor: queue.add,
listenableVisitor: (_) {},
);

if (current.origin == dependency) {
throw CircularDependencyError._();
Expand Down Expand Up @@ -221,9 +227,10 @@ final <yourProvider> = Provider(dependencies: [<dependency>]);
/// {@endtemplate}
void invalidate(ProviderOrFamily providerOrFamily, {bool asReload = false}) {
_throwIfInvalidUsage();
if (kDebugMode) _debugAssertCanDependOn(providerOrFamily);

container.invalidate(providerOrFamily, asReload: asReload);

if (kDebugMode) _debugAssertCanDependOn(providerOrFamily);
}

/// Invokes [invalidate] on itself.
Expand Down Expand Up @@ -419,9 +426,12 @@ final <yourProvider> = Provider(dependencies: [<dependency>]);
/// safer to use.
T read<T>(ProviderListenable<T> listenable) {
_throwIfInvalidUsage();

final result = container.read(listenable);

if (kDebugMode) _debugAssertCanDependOn(listenable);

return container.read(listenable);
return result;
}

/// {@template riverpod.exists}
Expand Down Expand Up @@ -459,9 +469,12 @@ final <yourProvider> = Provider(dependencies: [<dependency>]);
/// {@endtemplate}
bool exists(ProviderBase<Object?> provider) {
_throwIfInvalidUsage();

final result = container.exists(provider);

if (kDebugMode) _debugAssertCanDependOn(provider);

return container.exists(provider);
return result;
}

/// Obtains the state of a provider and causes the state to be re-evaluated
Expand Down Expand Up @@ -539,8 +552,6 @@ final <yourProvider> = Provider(dependencies: [<dependency>]);
return sub.read();
}

if (kDebugMode) _debugAssertCanDependOn(listenable);

final element = container.readProviderElement(listenable);
_element._dependencies.putIfAbsent(element, () {
final previousSub = _element._previousDependencies?.remove(element);
Expand All @@ -563,7 +574,11 @@ final <yourProvider> = Provider(dependencies: [<dependency>]);
return Object();
});

return element.readSelf();
final result = element.readSelf();

if (kDebugMode) _debugAssertCanDependOn(listenable);

return result;
}

/// {@template riverpod.listen}
Expand Down
41 changes: 40 additions & 1 deletion packages/riverpod/test/new/core/uni_directional_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import '../utils.dart';
void main() {
test(
'Catches sync circular dependency when the dependency is not yet mounted',
skip: true, () {
() {
// regression for #1766
final container = ProviderContainer.test();

Expand Down Expand Up @@ -85,6 +85,45 @@ void main() {
});
});

group('ref.listen cannot end-up in a circular dependency', () {
test('direct dependency', () {
final provider = Provider((ref) => ref);
final provider2 = Provider((ref) => ref);
final container = ProviderContainer();

final ref = container.read(provider);
final ref2 = container.read(provider2);

ref.watch(provider2);
expect(
() => ref2.listen(provider, (a, b) {}),
throwsA(isA<CircularDependencyError>()),
);
});

test('indirect dependency', () {
final provider = Provider((ref) => ref);
final provider2 = Provider((ref) => ref);
final provider3 = Provider((ref) => ref);
final provider4 = Provider((ref) => ref);
final container = ProviderContainer();

final ref = container.read(provider);
final ref2 = container.read(provider2);
final ref3 = container.read(provider3);
final ref4 = container.read(provider4);

ref.listen(provider2, (a, b) {});
ref2.listen(provider3, (a, b) {});
ref3.listen(provider4, (a, b) {});

expect(
() => ref4.listen(provider, (a, b) {}),
throwsA(isA<CircularDependencyError>()),
);
});
});

group('ref.read cannot end-up in a circular dependency', () {
test('direct dependency', () {
final provider = Provider((ref) => ref);
Expand Down

0 comments on commit 88a865b

Please sign in to comment.