Repository: intel/rohd (dart)

Issue:
Add more informative looped connection error message
### Motivation

Might be worth adding a more descriptive looped connection error message. Currently showing `Unhandled exception: LateInitializationError: Field '_preTickSubscription@22087482' has already been initialized.`.

Code:

```dart
import 'package:rohd/rohd.dart';

void main() {
  final a = Logic();
  final b = Logic();

  a <= b;
  b <= a;
}
```

### Desired solution

Add more informative looped connection error message.

### Alternatives considered

_No response_

### Additional details

_No response_

Pull request:
<!-- Please make sure you check out the contribution guidelines before submitting a pull request! -->

## Description & Motivation
Prevent Logic from connecting to itself #316 
<!-- Description of changes, and motivation for adding them. -->

## Related Issue(s)
#315 (Covered)
<!-- If there are any issues related to this PR, please link to the issues here. -->

## Testing

<!-- Please describe how you tested your changes. -->
Added testcase to `test/bus_test.dart` and created an exception `lib/src/exceptions/logic/invalid_connection_exception.dart`

## Documentation

> Does the change require any updates to documentation? If so, where? Are they included?

<!-- Answer here. -->
Not required.

Patch:
diff --git a/lib/src/exceptions/logic/logic_exceptions.dart b/lib/src/exceptions/logic/logic_exceptions.dart
index 26c95581f..ae89ff1a9 100644
--- a/lib/src/exceptions/logic/logic_exceptions.dart
+++ b/lib/src/exceptions/logic/logic_exceptions.dart
@@ -3,3 +3,4 @@
 
 export 'invalid_multiplier_exception.dart';
 export 'put_exception.dart';
+export 'self_connecting_logic_exception.dart';
diff --git a/lib/src/exceptions/logic/self_connecting_logic_exception.dart b/lib/src/exceptions/logic/self_connecting_logic_exception.dart
new file mode 100644
index 000000000..dff550678
--- /dev/null
+++ b/lib/src/exceptions/logic/self_connecting_logic_exception.dart
@@ -0,0 +1,21 @@
+/// Copyright (C) 2023 Intel Corporation
+/// SPDX-License-Identifier: BSD-3-Clause
+///
+/// self_connecting_logic_exception.dart
+/// An exception that is thrown when there is a logical signal connecting to
+/// itself.
+///
+/// 2023 May 27
+/// Author: Sanchit Kumar <sanchit.dabgotra@gmail.com>
+///
+
+import 'package:rohd/rohd.dart';
+import 'package:rohd/src/exceptions/rohd_exception.dart';
+
+/// An exception that thrown when a [Logic] is connecting to itself.
+class SelfConnectingLogicException extends RohdException {
+  /// Creates an exception when a [Logic] is trying to connect itself.
+  SelfConnectingLogicException(Logic a, Logic b)
+      : super('Failed to connect signal "$a" with signal "$b":'
+            ' Self connecting logic not allowed.');
+}
diff --git a/lib/src/logic.dart b/lib/src/logic.dart
index 08d9ced0e..2d0f725a5 100644
--- a/lib/src/logic.dart
+++ b/lib/src/logic.dart
@@ -493,6 +493,9 @@ class Logic {
 
   /// Handles the actual connection of this [Logic] to [other].
   void _connect(Logic other) {
+    if (_wire == other._wire) {
+      throw SelfConnectingLogicException(this, other);
+    }
     _unassignable = true;
     _updateWire(other._wire);
   }


Test patch:
diff --git a/test/bus_test.dart b/test/bus_test.dart
index 8e5f7373c..52c51fbca 100644
--- a/test/bus_test.dart
+++ b/test/bus_test.dart
@@ -269,6 +269,28 @@ void main() {
         );
       });
     });
+
+    group('invalid connection exceptions', () {
+      test('self-connecting logic', () {
+        try {
+          final a = Logic();
+          a <= a;
+        } on Exception catch (e) {
+          expect(e.runtimeType, SelfConnectingLogicException);
+        }
+
+        try {
+          final a = Logic();
+          final b = Logic();
+          final c = Logic();
+          a <= b;
+          b <= c;
+          c <= a;
+        } on Exception catch (e) {
+          expect(e.runtimeType, SelfConnectingLogicException);
+        }
+      });
+    });
   });
 
   group('simcompare', () {