Repository: quarkusio/quarkus
Issue: fix the set of bean types when one of supertypes is a raw type

### Describe the bug

If a bean class has a _raw type_ as one of its supertypes, ArC does not construct the set of bean types correctly. The JLS says:

> The superclass types (respectively, superinterface types) of a raw type are the erasures of the superclass types (superinterface types) of the named class or interface.

But ArC does not reflect this.

### Expected behavior

Erasures of supertypes of a raw type should be present in the set of bean types.

### Actual behavior

Not erased supertypes of a raw type are present in the set of bean types.

### How to Reproduce?

CDI TCK, test `org.jboss.cdi.tck.tests.definition.bean.BeanDefinitionTest#testRawBeanTypes`.

### Output of `uname -a` or `ver`

_No response_

### Output of `java -version`

_No response_

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

_No response_

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

_No response_

### Additional information

_No response_

Changed files:
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java
independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java

diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java
index 54f0af4547b..5066d07f874 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java
@@ -517,12 +517,13 @@ private static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget pr
             boolean throwOnProducerWildcard,
             Map<String, Type> resolvedTypeParameters,
             BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<String, Type>> resolvedTypeVariablesConsumer,
-            Set<Type> unrestrictedBeanTypes) {
+            Set<Type> unrestrictedBeanTypes, boolean rawGeneric) {
         Set<Type> types = new HashSet<>();
         List<TypeVariable> typeParameters = classInfo.typeParameters();
 
         if (typeParameters.isEmpty()
-                || !typeParameters.stream().allMatch(it -> resolvedTypeParameters.containsKey(it.identifier()))) {
+                || !typeParameters.stream().allMatch(it -> resolvedTypeParameters.containsKey(it.identifier()))
+                || rawGeneric) {
             // Not a parameterized type or a raw type
             types.add(Type.create(classInfo.name(), Kind.CLASS));
         } else {
@@ -562,7 +563,8 @@ private static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget pr
                             interfaceClassInfo.typeParameters(), resolvedTypeParameters, beanDeployment.getBeanArchiveIndex());
                 }
                 types.addAll(getTypeClosure(interfaceClassInfo, producerFieldOrMethod, false, resolved, beanDeployment,
-                        resolvedTypeVariablesConsumer, unrestrictedBeanTypes));
+                        resolvedTypeVariablesConsumer, unrestrictedBeanTypes,
+                        rawGeneric || isRawGeneric(interfaceType, interfaceClassInfo)));
             }
         }
         // Superclass
@@ -576,19 +578,25 @@ private static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget pr
                             resolvedTypeParameters, beanDeployment.getBeanArchiveIndex());
                 }
                 types.addAll(getTypeClosure(superClassInfo, producerFieldOrMethod, false, resolved, beanDeployment,
-                        resolvedTypeVariablesConsumer, unrestrictedBeanTypes));
+                        resolvedTypeVariablesConsumer, unrestrictedBeanTypes,
+                        rawGeneric || isRawGeneric(classInfo.superClassType(), superClassInfo)));
             }
         }
         unrestrictedBeanTypes.addAll(types);
         return types;
     }
 
+    // if the superclass type is CLASS *AND* and superclass info has type parameters, then it's raw type
+    private static boolean isRawGeneric(Type superClassType, ClassInfo superClassInfo) {
+        return Kind.CLASS.equals(superClassType.kind()) && !superClassInfo.typeParameters().isEmpty();
+    }
+
     static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod,
             Map<String, Type> resolvedTypeParameters,
             BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<String, Type>> resolvedTypeVariablesConsumer,
             Set<Type> unrestrictedBeanTypes) {
         return getTypeClosure(classInfo, producerFieldOrMethod, true, resolvedTypeParameters, beanDeployment,
-                resolvedTypeVariablesConsumer, unrestrictedBeanTypes);
+                resolvedTypeVariablesConsumer, unrestrictedBeanTypes, false);
     }
 
     static Set<Type> getDelegateTypeClosure(InjectionPointInfo delegateInjectionPoint, BeanDeployment beanDeployment) {
diff --git a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
index 86ddf65858e..64f9539567b 100644
--- a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
+++ b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
@@ -30,7 +30,8 @@ public class TypesTest {
     @Test
     public void testGetTypeClosure() throws IOException {
         IndexView index = Basics.index(Foo.class, Baz.class, Producer.class, Object.class, List.class, Collection.class,
-                Iterable.class, Set.class, Eagle.class, Bird.class, Animal.class, AnimalHolder.class);
+                Iterable.class, Set.class, Eagle.class, Bird.class, Animal.class, AnimalHolder.class, MyRawBean.class,
+                MyBean.class, MyInterface.class, MySuperInterface.class);
         DotName bazName = DotName.createSimple(Baz.class.getName());
         DotName fooName = DotName.createSimple(Foo.class.getName());
         DotName producerName = DotName.createSimple(Producer.class.getName());
@@ -93,6 +94,17 @@ public void testGetTypeClosure() throws IOException {
         assertDoesNotThrow(
                 () -> verifyEagleTypes(Types.getClassBeanTypeClosure(index.getClassByName(DotName.createSimple(Eagle.class)),
                         dummyDeployment)));
+
+        // raw type bean
+        Set<Type> rawBeanTypes = Types.getClassBeanTypeClosure(index.getClassByName(DotName.createSimple(MyRawBean.class)),
+                dummyDeployment);
+        assertEquals(rawBeanTypes.size(), 5);
+        assertContainsType(MyRawBean.class, rawBeanTypes);
+        assertContainsType(MyBean.class, rawBeanTypes);
+        assertContainsType(MyInterface.class, rawBeanTypes);
+        // according to JLS, for raw type generics, their superclasses have erasure applied so this should be a match
+        assertContainsType(MySuperInterface.class, rawBeanTypes);
+        assertContainsType(Object.class, rawBeanTypes);
     }
 
     private void verifyEagleTypes(Set<Type> types) {
@@ -104,6 +116,10 @@ private void verifyEagleTypes(Set<Type> types) {
         assertEquals(3, types.size());
     }
 
+    private void assertContainsType(Class<?> clazz, Set<Type> rawBeanTypes) {
+        assertTrue(rawBeanTypes.contains(Type.create(DotName.createSimple(clazz.getName()), Kind.CLASS)));
+    }
+
     static class Foo<T> {
 
         T field;
@@ -149,4 +165,16 @@ public Eagle<T> eagleProducer() {
 
     static class AnimalHolder<T extends Animal> {
     }
+
+    static class MyRawBean extends MyBean {
+    }
+
+    static class MyBean<T> implements MyInterface {
+    }
+
+    interface MyInterface extends MySuperInterface<Number> {
+    }
+
+    interface MySuperInterface<T> {
+    }
 }