1 /*
  2  * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.incubator.code.dialect.java;
 27 
 28 import jdk.incubator.code.CodeType;
 29 import jdk.incubator.code.dialect.java.impl.JavaTypeUtils;
 30 import jdk.incubator.code.extern.ExternalizedCodeType;
 31 
 32 import java.lang.constant.ClassDesc;
 33 import java.lang.invoke.MethodHandles.Lookup;
 34 import java.lang.reflect.Constructor;
 35 import java.lang.reflect.Method;
 36 import java.lang.reflect.Type;
 37 import java.lang.reflect.TypeVariable;
 38 import java.util.Objects;
 39 
 40 /**
 41  * A type variable type
 42  */
 43 public final class TypeVariableType implements JavaType {
 44 
 45     final String name;
 46     final Owner owner;
 47     final JavaType bound;
 48 
 49     TypeVariableType(String name, Owner owner, JavaType bound) {
 50         this.name = name;
 51         this.owner = owner;
 52         this.bound = bound;
 53     }
 54 
 55     @Override
 56     public Type resolve(Lookup lookup) throws ReflectiveOperationException {
 57         TypeVariable<?>[] typeVariables = switch (owner) {
 58             case MethodRef constructorRef when constructorRef.isConstructor() -> {
 59                 Constructor<?> constructor = constructorRef.resolveToConstructor(lookup);
 60                 yield constructor.getTypeParameters();
 61             }
 62             case MethodRef methodRef -> {
 63                 Method method = methodRef.resolveToMethod(lookup);
 64                 yield method.getTypeParameters();
 65             }
 66             case JavaType type -> {
 67                 Class<?> erasedDecl = (Class<?>)type.resolve(lookup);
 68                 yield erasedDecl.getTypeParameters();
 69             }
 70         };
 71         for (TypeVariable<?> tv : typeVariables) {
 72             if (tv.getName().equals(name)) {
 73                 return tv;
 74             }
 75         }
 76         throw new ReflectiveOperationException("Type-variable not found: " + name);
 77     }
 78 
 79     /**
 80      * {@return the type-variable name}
 81      */
 82     public String name() {
 83         return name;
 84     }
 85 
 86     /**
 87      * {@return the type-variable bound}
 88      */
 89     public JavaType bound() {
 90         return bound;
 91     }
 92 
 93     /**
 94      * {@return the owner of this type-variable}
 95      */
 96     public Owner owner() {
 97         return owner;
 98     }
 99 
100     @Override
101     public JavaType erasure() {
102         return bound.erasure();
103     }
104 
105     @Override
106     public ExternalizedCodeType externalize() {
107         return JavaTypeUtils.typeVarType(name, owner.externalize(), bound.externalize());
108     }
109 
110     @Override
111     public String toString() {
112         return JavaTypeUtils.toExternalTypeString(externalize());
113     }
114 
115     @Override
116     public boolean equals(Object o) {
117         if (this == o) return true;
118         return o instanceof TypeVariableType that &&
119                 Objects.equals(name, that.name) &&
120                 Objects.equals(owner, that.owner) &&
121                 Objects.equals(bound, that.bound);
122     }
123 
124     @Override
125     public int hashCode() {
126         return Objects.hash(name, owner, bound);
127     }
128 
129     @Override
130     public JavaType toBasicType() {
131         return erasure().toBasicType();
132     }
133 
134     @Override
135     public ClassDesc toNominalDescriptor() {
136         return erasure().toNominalDescriptor();
137     }
138 
139     /**
140      * The owner of a type variable, either a class or a method.
141      */
142     public sealed interface Owner extends CodeType permits ClassType, MethodRef { }
143 }