Skip to content

Commit e5280f6

Browse files
committed
Update to Java commit 641933e (2025.06.02): CLJ-2888: Adding support for array symbols to gen-class. Retains existing gen-class constraints around unqualified symbold defaulting to java.lang package qualification"
1 parent 0dbb29b commit e5280f6

File tree

3 files changed

+74
-40
lines changed

3 files changed

+74
-40
lines changed

Clojure/Clojure.Source/clojure/genclass.clj

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,26 @@
5353
'chars (Type/GetType "System.Char[]")})
5454

5555

56-
(defn- ^Type the-class [x] ;;; ^Class
57-
(cond
58-
(class? x) x
59-
(contains? prim->class x) (prim->class x)
60-
:else (let [strx (str x)]
61-
(clojure.lang.RT/classForName
62-
(if (some #{\. \[} strx)
63-
strx
64-
(str "System." strx)))))) ;;;(str "java.lang." strx))))))
56+
(defn- the-array-class [sym]
57+
(clojure.lang.RT/classForName
58+
(let [cn (namespace sym)]
59+
(clojure.lang.CljCompiler.Ast.HostExpr/BuildArrayTypeDescriptor ;;; clojure.lang.Compiler$HostExpr/buildArrayClassDescriptor
60+
(if (or (clojure.lang.Compiler/PrimType (symbol cn)) (some #{\.} cn)) ;;; primClass
61+
sym
62+
(symbol (str "System." cn) (name sym))))))) ;;; "java.lang."
63+
64+
(defn- ^Type the-class [x] ;;; ^Class
65+
(cond
66+
(class? x) x
67+
(symbol? x) (cond (contains? prim->class x) (prim->class x)
68+
(clojure.lang.CljCompiler.Ast.HostExpr/LooksLikeArrayType x) ;;; clojure.lang.Compiler$HostExpr/looksLikeArrayClass
69+
(the-array-class x)
70+
:else (let [strx (str x)]
71+
(clojure.lang.RT/classForName
72+
(if (some #{\. \[} strx)
73+
strx
74+
(str "System." strx))))) ;;; "java.lang."
75+
:else (clojure.lang.RT/classForName x)))
6576

6677
(defn- the-class-maybe-by-ref [x]
6778
(cond

Clojure/Clojure.Tests/clojure/test_clojure/genclass.clj

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,14 @@
148148
;;; sourceVisitor (proxy [clojure.asm.ClassVisitor] [clojure.asm.Opcodes/ASM4 nil]
149149
;;; (visitSource [source debug] (.append sourceFile source)))]
150150
;;; (.accept classReader sourceVisitor 0)
151-
;;; (is (= "examples.clj" (str sourceFile)))))
151+
;;; (is (= "examples.clj" (str sourceFile)))))
152+
153+
(deftest array-descriptors->class
154+
(are [descr c] (= (#'clojure.core/the-class descr) c)
155+
"System.Guid[]" System.Guid/1 ;;; "[Ljava.util.UUID;" java.util.UUID/1
156+
'String System.String ;;; java.lang.String
157+
'String/1 System.String/1 ;;; java.lang.String/1
158+
`System.Guid System.Guid ;;; 'java.util.UUID java.util.UUID
159+
'System.Guid/2 System.Guid/2 ;;; 'java.util.UUID/2 java.util.UUID/2
160+
'int/1 int/1
161+
'boolean/9 bool/9))

Clojure/Clojure/CljCompiler/Ast/HostExpr.cs

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ public Expr Parse(ParserContext pcon, object form)
7070
ISeq args;
7171
bool methodRequired = false;
7272

73-
if ( RT.third(sform) is Symbol s)
73+
if (RT.third(sform) is Symbol s)
7474
{
7575
methodSym = s;
7676
args = RT.next(RT.next(RT.next(sform)));
7777
}
78-
else if (RT.Length(sform) == 3 && RT.third(sform) is ISeq seq)
78+
else if (RT.Length(sform) == 3 && RT.third(sform) is ISeq seq)
7979
{
8080
var seqFirst = RT.first(seq);
8181
if (seqFirst is Symbol sym)
@@ -133,7 +133,7 @@ public Expr Parse(ParserContext pcon, object form)
133133

134134
bool isPropName = false;
135135
Symbol memberSym = methodSym;
136-
136+
137137
if (memberSym.Name[0] == '-')
138138
{
139139
isPropName = true;
@@ -148,9 +148,9 @@ public Expr Parse(ParserContext pcon, object form)
148148
// are generated by StaticFieldExpr and InstanceFieldExpr.
149149
if (staticType != null)
150150
{
151-
if ( ! hasTypeArgs && (finfo = Reflector.GetField(staticType, memberName, true)) != null)
151+
if (!hasTypeArgs && (finfo = Reflector.GetField(staticType, memberName, true)) != null)
152152
return new StaticFieldExpr(source, spanMap, tag, staticType, memberName, finfo);
153-
if ( ! hasTypeArgs && (pinfo = Reflector.GetProperty(staticType, memberName, true)) != null)
153+
if (!hasTypeArgs && (pinfo = Reflector.GetProperty(staticType, memberName, true)) != null)
154154
return new StaticPropertyExpr(source, spanMap, tag, staticType, memberName, pinfo);
155155
if (!isPropName && Reflector.GetArityZeroMethod(staticType, memberName, typeArgs, true) != null)
156156
return new StaticMethodExpr(source, spanMap, tag, staticType, memberName, typeArgs, new List<HostArg>(), tailPosition);
@@ -185,7 +185,7 @@ public Expr Parse(ParserContext pcon, object form)
185185
if (pcon.IsAssignContext)
186186
return new InstanceFieldExpr(source, spanMap, tag, instance, memberName, null); // same as InstancePropertyExpr when last arg is null
187187
else
188-
return new InstanceZeroArityCallExpr(source, spanMap, tag, instance, memberName);
188+
return new InstanceZeroArityCallExpr(source, spanMap, tag, instance, memberName);
189189

190190
}
191191
}
@@ -204,7 +204,7 @@ public Expr Parse(ParserContext pcon, object form)
204204

205205
internal static List<HostArg> ParseArgs(ParserContext pcon, ISeq argSeq)
206206
{
207-
List<HostArg> args = new List<HostArg>();
207+
List<HostArg> args = new();
208208

209209
for (ISeq s = argSeq; s != null; s = s.next())
210210
{
@@ -232,7 +232,7 @@ internal static List<HostArg> ParseArgs(ParserContext pcon, ISeq argSeq)
232232
}
233233
}
234234

235-
Expr expr = Compiler.Analyze(pcon.EvalOrExpr(),arg);
235+
Expr expr = Compiler.Analyze(pcon.EvalOrExpr(), arg);
236236

237237
args.Add(new HostArg(paramType, expr, lb));
238238
}
@@ -290,13 +290,13 @@ internal static List<HostArg> ParseArgs(ParserContext pcon, ISeq argSeq)
290290

291291
internal static readonly MethodInfo Method_RT_booleanCast = typeof(RT).GetMethod("booleanCast", new Type[] { typeof(object) });
292292

293-
internal static readonly MethodInfo Method_RT_intPtrCast = typeof (RT).GetMethod("intPtrCast", new Type[] { typeof (object) });
294-
internal static readonly MethodInfo Method_RT_uintPtrCast = typeof (RT).GetMethod("uintPtrCast", new Type[] { typeof (object) });
293+
internal static readonly MethodInfo Method_RT_intPtrCast = typeof(RT).GetMethod("intPtrCast", new Type[] { typeof(object) });
294+
internal static readonly MethodInfo Method_RT_uintPtrCast = typeof(RT).GetMethod("uintPtrCast", new Type[] { typeof(object) });
295295

296296
#endregion
297297

298298
#region Tags and types
299-
299+
300300
public static Type MaybeType(object form, bool stringOk)
301301
{
302302
if (form is Type type)
@@ -322,7 +322,7 @@ public static Type MaybeType(object form, bool stringOk)
322322
var tName = type1.FullName;
323323
var compiledType = Compiler.FindDuplicateCompiledType(tName);
324324
if (compiledType is not null && Compiler.IsCompiling)
325-
t = compiledType;
325+
t = compiledType;
326326
}
327327
else if (Compiler.LocalEnvVar.deref() != null && ((IPersistentMap)Compiler.LocalEnvVar.deref()).containsKey(form)) // JVM casts to java.util.Map
328328
return null;
@@ -388,8 +388,8 @@ internal static Type TagToType(object tag)
388388
t = HostExpr.MaybeArrayType(sym);
389389
}
390390
}
391-
392-
if ( t == null )
391+
392+
if (t == null)
393393
t = MaybeType(tag, true);
394394

395395
if (t != null)
@@ -398,29 +398,42 @@ internal static Type TagToType(object tag)
398398
throw new ArgumentException("Unable to resolve typename: " + tag);
399399
}
400400

401-
public static Type MaybeArrayType(Symbol sym)
401+
402+
public static bool LooksLikeArrayType(Symbol sym)
402403
{
403-
if (sym.Namespace == null || !Util.IsPosDigit(sym.Name))
404-
return null;
404+
return sym.Namespace is not null && Util.IsPosDigit(sym.Name);
405+
}
405406

407+
public static string BuildArrayTypeDescriptor(Symbol sym)
408+
{
406409
int dim = sym.Name[0] - '0';
407410
Symbol componentTypeName = Symbol.intern(null, sym.Namespace);
408411
Type componentType = Compiler.PrimType(componentTypeName);
409-
if (componentType == null)
410-
componentType = HostExpr.MaybeType(componentTypeName, false);
411412

412-
if (componentType == null)
413-
throw new TypeNotFoundException("Unable to resolve component typename: " + componentTypeName);
413+
if (componentType is null)
414+
componentType = MaybeType(componentTypeName, false);
415+
416+
if (componentType is null)
417+
throw new TypeNotFoundException(componentTypeName.ToString());
418+
419+
StringBuilder arrayDescriptor = new();
420+
arrayDescriptor.Append(componentType.FullName);
414421

415-
// componentType.MakeArrayType(dim) is not what you want. This creates .IsVariableBound designed for multiple dimensions.
416-
// We are matching Java which means we have jagged arrays.
417-
// Without an argument, MakeArrayType returns an SZ array -- one-dimensional, zero-based.
418-
// we need to nest.
419422

420423
for (int i = 0; i < dim; i++)
421-
componentType = componentType.MakeArrayType();
424+
{
425+
arrayDescriptor.Append("[]");
426+
}
427+
428+
return arrayDescriptor.ToString();
429+
}
430+
431+
public static Type MaybeArrayType(Symbol sym)
432+
{
433+
if (!LooksLikeArrayType(sym))
434+
return null;
422435

423-
return componentType;
436+
return MaybeType(BuildArrayTypeDescriptor(sym), true);
424437
}
425438

426439
#endregion
@@ -456,11 +469,11 @@ internal static void EmitUnboxArg(CljILGen ilg, Type paramType)
456469
{
457470
m = HostExpr.Method_RT_charCast;
458471
}
459-
else if(paramType == typeof(IntPtr))
472+
else if (paramType == typeof(IntPtr))
460473
{
461474
m = HostExpr.Method_RT_intPtrCast;
462475
}
463-
else if(paramType == typeof(UIntPtr))
476+
else if (paramType == typeof(UIntPtr))
464477
{
465478
m = HostExpr.Method_RT_uintPtrCast;
466479
}
@@ -558,7 +571,7 @@ internal static void EmitUnboxArg(CljILGen ilg, Type paramType)
558571
}
559572

560573
ilg.Emit(OpCodes.Castclass, typeof(Object));
561-
ilg.Emit(OpCodes.Call,m);
574+
ilg.Emit(OpCodes.Call, m);
562575
}
563576
else
564577
{

0 commit comments

Comments
 (0)