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 import java.util.Objects;
41
42 /**
43 * A type variable type
44 */
45 public final class TypeVariableType implements JavaType {
46
47 final String name;
48 final Owner owner;
49 final JavaType bound;
50
51 TypeVariableType(String name, Owner owner, JavaType bound) {
52 this.name = name;
53 this.owner = owner;
54 this.bound = bound;
55 }
56
57 @Override
58 public Type resolve(Lookup lookup) throws ReflectiveOperationException {
59 TypeVariable<?>[] typeVariables = switch (owner) {
60 case MethodRef constructorRef when constructorRef.isConstructor() -> {
61 Constructor<?> constructor = constructorRef.resolveToConstructor(lookup);
62 yield constructor.getTypeParameters();
63 }
64 case MethodRef methodRef -> {
65 Method method = methodRef.resolveToMethod(lookup);
66 yield method.getTypeParameters();
67 }
68 case JavaType type -> {
69 Class<?> erasedDecl = (Class<?>)type.resolve(lookup);
70 yield erasedDecl.getTypeParameters();
71 }
72 };
73 for (TypeVariable<?> tv : typeVariables) {
74 if (tv.getName().equals(name)) {
75 return tv;
76 }
77 }
78 throw new ReflectiveOperationException("Type-variable not found: " + name);
79 }
80
81 /**
82 * {@return the type-variable name}
83 */
84 public String name() {
85 return name;
86 }
87
88 /**
89 * {@return the type-variable bound}
90 */
91 public JavaType bound() {
92 return bound;
93 }
94
95 /**
96 * {@return the owner of this type-variable}
97 */
98 public Owner owner() {
99 return owner;
100 }
101
102 @Override
103 public JavaType erasure() {
104 return bound.erasure();
105 }
106
107 @Override
108 public ExternalizedTypeElement externalize() {
109 return JavaTypeUtils.typeVarType(name, owner.externalize(), bound.externalize());
110 }
111
112 @Override
113 public String toString() {
114 return JavaTypeUtils.toExternalTypeString(externalize());
115 }
116
117 @Override
118 public boolean equals(Object o) {
119 if (this == o) return true;
120 return o instanceof TypeVariableType that &&
121 Objects.equals(name, that.name) &&
122 Objects.equals(owner, that.owner) &&
123 Objects.equals(bound, that.bound);
124 }
125
126 @Override
127 public int hashCode() {
128 return Objects.hash(name, owner, bound);
129 }
130
131 @Override
132 public JavaType toBasicType() {
133 return erasure().toBasicType();
134 }
135
136 @Override
137 public ClassDesc toNominalDescriptor() {
138 return erasure().toNominalDescriptor();
139 }
140
141 /**
142 * The owner of a type variable, either a class or a method.
143 */
144 public sealed interface Owner extends TypeElement permits ClassType, MethodRef { }
145 }