Repository: quarkusio/quarkus
Issue: @TransientReference results in @Dispose method being called multiple times

### Describe the bug

If I use TransientReference the injected bean gets disposed more than once.

### Expected behavior

Produced beans should be disposed once and only once.

### Actual behavior

Produced beans are disposed of multiple times if TransientReference is used.

### How to Reproduce?

1. Have a produce method require a different TransientReference bean that has a dispose method.
2. Watch that bean get disposed multiple times.

### Output of `uname -a` or `ver`

Linux fivecorners 5.15.0-46-generic #49-Ubuntu SMP Thu Aug 4 18:03:25 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

### Output of `java -version`

openjdk version "17.0.4" 2022-07-19 OpenJDK Runtime Environment (build 17.0.4+8-Ubuntu-122.04) OpenJDK 64-Bit Server VM (build 17.0.4+8-Ubuntu-122.04, mixed mode, sharing)

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

2.12.2.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63) Maven home: /home/sixcorners/.m2/wrapper/dists/apache-maven-3.8.6-bin/67568434/apache-maven-3.8.6 Java version: 17.0.4, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "5.15.0-46-generic", arch: "amd64", family: "unix"

### Additional information

[example.zip](https://github.com/quarkusio/quarkus/files/9560450/example.zip)


Changed files:
independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/transientreference/TransientReferenceDestroyedTest.java
independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InstanceImpl.java
independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CreationalContextImpl.java
independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InjectableReferenceProviders.java

diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CreationalContextImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CreationalContextImpl.java
index 90833e4c539..75189ab6064 100644
--- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CreationalContextImpl.java
+++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/CreationalContextImpl.java
@@ -47,16 +47,17 @@ public synchronized boolean hasDependentInstances() {
         return dependentInstances != null && !dependentInstances.isEmpty();
     }
 
-    boolean destroyDependentInstance(Object dependentInstance) {
-        synchronized (this) {
-            if (dependentInstances != null) {
-                for (Iterator<InstanceHandle<?>> iterator = dependentInstances.iterator(); iterator.hasNext();) {
-                    InstanceHandle<?> instanceHandle = iterator.next();
-                    if (instanceHandle.get() == dependentInstance) {
-                        instanceHandle.destroy();
-                        iterator.remove();
-                        return true;
+    public synchronized boolean removeDependentInstance(Object dependentInstance, boolean destroy) {
+        if (dependentInstances != null) {
+            for (Iterator<InstanceHandle<?>> it = dependentInstances.iterator(); it.hasNext();) {
+                InstanceHandle<?> handle = it.next();
+                // The reference equality is used on purpose!
+                if (handle.get() == dependentInstance) {
+                    if (destroy) {
+                        handle.destroy();
                     }
+                    it.remove();
+                    return true;
                 }
             }
         }
diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InjectableReferenceProviders.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InjectableReferenceProviders.java
index 61845fa72ac..4633cbe6ff8 100644
--- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InjectableReferenceProviders.java
+++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InjectableReferenceProviders.java
@@ -11,6 +11,8 @@ private InjectableReferenceProviders() {
 
     /**
      * Unwraps the provider if necessary and invokes {@link Contextual#destroy(Object, CreationalContext)}.
+     * <p>
+     * If there is a parent context available then attempt to remove the dependent instance.
      *
      * @param <T>
      * @param provider
@@ -18,15 +20,20 @@ private InjectableReferenceProviders() {
      * @param creationalContext
      * @throws IllegalArgumentException If the specified provider is not a bean
      */
-    @SuppressWarnings("unchecked")
     public static <T> void destroy(InjectableReferenceProvider<T> provider, T instance,
             CreationalContext<T> creationalContext) {
         if (provider instanceof CurrentInjectionPointProvider) {
             provider = ((CurrentInjectionPointProvider<T>) provider).getDelegate();
         }
         if (provider instanceof Contextual) {
+            @SuppressWarnings("unchecked")
             Contextual<T> contextual = (Contextual<T>) provider;
             contextual.destroy(instance, creationalContext);
+            CreationalContextImpl<T> ctx = CreationalContextImpl.unwrap(creationalContext);
+            CreationalContextImpl<?> parent = ctx.getParent();
+            if (parent != null) {
+                parent.removeDependentInstance(instance, false);
+            }
         } else {
             throw new IllegalArgumentException("Injetable reference provider is not a bean: " + provider.getClass());
         }
diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InstanceImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InstanceImpl.java
index 7c5f4b124f8..00104c0ed26 100644
--- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InstanceImpl.java
+++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InstanceImpl.java
@@ -138,7 +138,7 @@ public void destroy(Object instance) {
             context.destroy(proxy.arc_bean());
         } else {
             // First try to destroy a dependent instance
-            if (!creationalContext.destroyDependentInstance(instance)) {
+            if (!creationalContext.removeDependentInstance(instance, true)) {
                 // If not successful then try the singleton context
                 SingletonContext singletonContext = (SingletonContext) Arc.container().getActiveContext(Singleton.class);
                 singletonContext.destroyInstance(instance);
diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/transientreference/TransientReferenceDestroyedTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/transientreference/TransientReferenceDestroyedTest.java
index 1433c5311f0..d5136cbd90a 100644
--- a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/transientreference/TransientReferenceDestroyedTest.java
+++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/transientreference/TransientReferenceDestroyedTest.java
@@ -5,6 +5,7 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import io.quarkus.arc.Arc;
+import io.quarkus.arc.InstanceHandle;
 import io.quarkus.arc.test.ArcTestContainer;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -30,7 +31,8 @@ public class TransientReferenceDestroyedTest {
 
     @Test
     public void testTransientReferences() {
-        Controller controller = Arc.container().instance(Controller.class).get();
+        InstanceHandle<Controller> controllerHandle = Arc.container().instance(Controller.class);
+        Controller controller = controllerHandle.get();
         assertNotNull(controller.theBeer);
         assertTrue(Arc.container().instance(Integer.class).get() > 0);
         assertEquals(3, BeerProducer.DESTROYED.size(), "Destroyed beers: " + BeerProducer.DESTROYED);
@@ -38,16 +40,26 @@ public void testTransientReferences() {
         assertTrue(BeerProducer.DESTROYED.contains(2));
         assertTrue(BeerProducer.DESTROYED.contains(3));
 
+        controllerHandle.destroy();
+        // Controller.theBeer is also destroyed
+        assertEquals(4, BeerProducer.DESTROYED.size());
+
         BeerProducer.COUNTER.set(0);
         BeerProducer.DESTROYED.clear();
 
-        InterceptedController interceptedController = Arc.container().instance(InterceptedController.class).get();
+        InstanceHandle<InterceptedController> interceptedControllerHandle = Arc.container()
+                .instance(InterceptedController.class);
+        InterceptedController interceptedController = interceptedControllerHandle.get();
         assertNotNull(interceptedController.getTheBeer());
         assertTrue(Arc.container().instance(Long.class).get() > 0);
         assertEquals(3, BeerProducer.DESTROYED.size(), "Destroyed beers: " + BeerProducer.DESTROYED);
         assertTrue(BeerProducer.DESTROYED.contains(1));
         assertTrue(BeerProducer.DESTROYED.contains(2));
         assertTrue(BeerProducer.DESTROYED.contains(3));
+
+        interceptedControllerHandle.destroy();
+        // InterceptedController.theBeer is also destroyed
+        assertEquals(4, BeerProducer.DESTROYED.size());
     }
 
     @Singleton