1 /*
  2  * Copyright (c) 2024, 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.TypeElement;
 29 import jdk.incubator.code.dialect.java.JavaOp.InvokeOp.InvokeKind;
 30 import jdk.incubator.code.dialect.java.impl.JavaTypeUtils;
 31 import jdk.incubator.code.dialect.java.impl.MethodRefImpl;
 32 import jdk.incubator.code.extern.ExternalizedTypeElement;
 33 
 34 import java.lang.constant.ClassDesc;
 35 import java.lang.invoke.MethodHandles.Lookup;
 36 import java.lang.reflect.Constructor;
 37 import java.lang.reflect.Method;
 38 import java.lang.reflect.Type;
 39 import java.lang.reflect.TypeVariable;
 40 
 41 /**
 42  * A type-variable reference.
 43  */
 44 public final class TypeVariableType implements JavaType {
 45 
 46     final String name;
 47     final Owner owner;
 48     final JavaType bound;
 49 
 50     TypeVariableType(String name, Owner owner, JavaType bound) {
 51         this.name = name;
 52         this.owner = owner;
 53         this.bound = bound;
 54     }
 55 
 56     @Override
 57     public Type resolve(Lookup lookup) throws ReflectiveOperationException {
 58         TypeVariable<?>[] typeVariables = switch (owner) {
 59             case MethodRef constructorRef when constructorRef.isConstructor() -> {
 60                 Constructor<?> constructor = constructorRef.resolveToConstructor(lookup);
 61                 yield constructor.getTypeParameters();
 62             }
 63             case MethodRef methodRef -> {
 64                 Method method = methodRef.resolveToMethod(lookup);
 65                 yield method.getTypeParameters();
 66             }
 67             case JavaType type -> {
 68                 Class<?> erasedDecl = (Class<?>)type.resolve(lookup);
 69                 yield erasedDecl.getTypeParameters();
 70             }
 71         };
 72         for (TypeVariable<?> tv : typeVariables) {
 73             if (tv.getName().equals(name)) {
 74                 return tv;
 75             }
 76         }
 77         throw new ReflectiveOperationException("Type-variable not found: " + name);
 78     }
 79 
 80     /**
 81      * {@return the type-variable name}
 82      */
 83     public String name() {
 84         return name;
 85     }
 86 
 87     /**
 88      * {@return the type-variable bound}
 89      */
 90     public JavaType bound() {
 91         return bound;
 92     }
 93 
 94     /**
 95      * {@return the owner of this type-variable}
 96      */
 97     public Owner owner() {
 98         return owner;
 99     }
100 
101     @Override
102     public JavaType erasure() {
103         return bound.erasure();
104     }
105 
106     @Override
107     public ExternalizedTypeElement externalize() {
108         return JavaTypeUtils.typeVarType(name, owner.externalize(), bound.externalize());
109     }
110 
111     @Override
112     public String toString() {
113         return JavaTypeUtils.toExternalTypeString(externalize());
114     }
115 
116     @Override
117     public boolean equals(Object o) {
118         if (this == o) return true;
119         return o instanceof TypeVariableType that &&
120                 name.equals(that.name) &&
121                 bound.equals(that.bound);
122     }
123 
124     @Override
125     public int hashCode() {
126         return name.hashCode();
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 TypeElement permits ClassType, MethodRef { }
143 }