Skip to content

Commit 0dbb29b

Browse files
committed
Uupdate to Java commit 9b0b383 (2025.06.02): CLJ-2899: Defer the classification of a vlue-position qualified method call to catch the case where a static field shadows a method name (Can't happen, at least in C#).
1 parent b52b5de commit 0dbb29b

File tree

5 files changed

+293
-220
lines changed

5 files changed

+293
-220
lines changed

Clojure/Clojure.Tests.Support/SwissArmy.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ namespace clojure.test;
77

88
public class SwissArmy
99
{
10-
// We cannot name this the same as the other doppelganggers (methods, static and instance) -- compiler error
10+
// We cannot name this the same as the other doppelganggers (methods, static or instance) -- compiler error
11+
// SO some of the tests that this was designed for are problems for the JMV only.
1112
public static String Doppelganger = "static-field";
1213
public string ctorId;
1314
public static IFn idFn = clojure.clr.api.Clojure.var("clojure.core", "identity");

Clojure/Clojure.Tests/clojure/test_clojure/param_tags.clj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109

110110
(defn is-static-method? [class method-name params]
111111
(let [method (.GetMethod ^Type class ^String (name method-name) ^|System.Type[]| params)] ;;; getDeclaredMethod ^Class ^"[Ljava.lang.Object;"
112-
(.IsStatic method))) ;;; (java.lang.reflect.Modifier/isStatic (.getModifiers method))
112+
(and method (.IsStatic method)))) ;;; (java.lang.reflect.Modifier/isStatic (.getModifiers method)) also added the (and method ...)
113113

114114
(defn get-methods
115115
"Reflect the class located at `path`, filter out the public members, add a :type
@@ -180,7 +180,7 @@
180180

181181
(deftest field-overloads-method-CLJ-2899-regression
182182
(testing "overloaded in value position"
183-
(is (= "static-field" clojure.test.SwissArmy/doppelganger)))
183+
(is (= "static-field" clojure.test.SwissArmy/Doppelganger))) ;;; doppelganger -- note: cannot name the field doppenganger, C# does not allow
184184

185185
(testing "overloaded in value position, w/paramtags"
186186
(is (= "" (apply ^[] clojure.test.SwissArmy/doppelganger []))))
@@ -189,7 +189,7 @@
189189
(is (= "" (clojure.test.SwissArmy/doppelganger))))
190190

191191
(testing "overloaded, invoke w/args"
192-
(is (= "int-int-long" (clojure.test.SwissArmy/doppelganger (int 1) (int 2) (long 42)))))
192+
(is (= "System.Int32-System.Int32-System.Int64" (clojure.test.SwissArmy/doppelganger (int 1) (int 2) (long 42))))) ;;; int-int-long
193193

194194
(testing "non-overloaded, field holds IFn, invoke w/args fails"
195195
(is (thrown? Exception (eval '(clojure.test.SwissArmy/idFn 42))))
@@ -199,8 +199,8 @@
199199
(is (= #'clojure.core/identity (clojure.test.SwissArmy/idFn))))
200200

201201
(testing "instance method overloads"
202-
(is (= "int-int" (clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2))))
203-
(is (= "int-int" (apply clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2) [])))))
202+
(is (= "System.Int32-System.Int32" (clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2))))
203+
(is (= "System.Int32-System.Int32" (apply clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2) [])))))
204204

205205

206206

Clojure/Clojure/CljCompiler/Ast/InvokeExpr.cs

Lines changed: 75 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ public class InvokeExpr : Expr
2525

2626
readonly Object _tag;
2727
public Object Tag { get { return _tag; } }
28-
28+
2929
readonly IPersistentVector _args;
3030
public IPersistentVector Args { get { return _args; } }
31-
31+
3232
readonly string _source;
3333
public string Source { get { return _source; } }
34-
34+
3535
readonly IPersistentMap _spanMap;
3636
public IPersistentMap SpanMap { get { return _spanMap; } }
37-
37+
3838
readonly bool _tailPosition;
3939
public bool TailPosition { get { return _tailPosition; } }
4040

@@ -89,12 +89,12 @@ public InvokeExpr(string source, IPersistentMap spanMap, Symbol tag, Expr fexpr,
8989
_protocolOn.FullName, fvar.Symbol, pvar.Symbol));
9090
}
9191
String mname = Compiler.munge(mmapVal.Symbol.ToString());
92-
93-
IList<MethodBase> methods = Reflector.GetMethods(_protocolOn, mname, GenericTypeArgList.Empty, args.count() - 1, false);
92+
93+
IList<MethodBase> methods = Reflector.GetMethods(_protocolOn, mname, GenericTypeArgList.Empty, args.count() - 1, false);
9494
if (methods.Count != 1)
9595
throw new ArgumentException(String.Format("No single method: {0} of interface: {1} found for function: {2} of protocol: {3}",
9696
mname, _protocolOn.FullName, fvar.Symbol, pvar.Symbol));
97-
_onMethod = (MethodInfo) methods[0];
97+
_onMethod = (MethodInfo)methods[0];
9898
}
9999
}
100100
}
@@ -183,7 +183,7 @@ public static Expr Parse(ParserContext pcon, ISeq form)
183183
}
184184
}
185185
}
186-
186+
187187
if (varFexpr != null && pcon.Rhc != RHC.Eval)
188188
{
189189
Var v = varFexpr.Var;
@@ -211,12 +211,33 @@ public static Expr Parse(ParserContext pcon, ISeq form)
211211
return new KeywordInvokeExpr((string)Compiler.SourceVar.deref(), (IPersistentMap)Compiler.SourceSpanVar.deref(), Compiler.TagOf(form), kwFexpr, target);
212212
}
213213

214+
215+
IPersistentVector args = PersistentVector.EMPTY;
216+
for (ISeq s = RT.seq(form.next()); s != null; s = s.next())
217+
args = args.cons(Compiler.Analyze(pcon, s.first()));
218+
219+
214220
// Preserving the existing static field bug that replaces a reference in parens with
215221
// the field itself rather than trying to invoke the value in the field. This is
216222
// an exception to the uniform Class/member qualification per CLJ-2806 ticket.
217223

224+
218225
if (fexpr is StaticFieldExpr || fexpr is StaticPropertyExpr)
219-
return fexpr;
226+
{
227+
if (RT.count(args) == 0)
228+
return fexpr;
229+
else
230+
{
231+
(var fieldName, var type) =
232+
fexpr is StaticFieldExpr sfe
233+
? (sfe.MemberName, sfe.MemberType)
234+
: fexpr is StaticPropertyExpr spe
235+
? (spe.MemberName, spe.MemberType)
236+
: ("?", typeof(void));
237+
238+
throw new ArgumentException($"No matching method {fieldName} found taking {RT.count(args)} args for {type}");
239+
}
240+
}
220241

221242

222243
if (fexpr is QualifiedMethodExpr qmfexpr)
@@ -227,10 +248,6 @@ public static Expr Parse(ParserContext pcon, ISeq form)
227248
form.next());
228249

229250

230-
IPersistentVector args = PersistentVector.EMPTY;
231-
for (ISeq s = RT.seq(form.next()); s != null; s = s.next())
232-
args = args.cons(Compiler.Analyze(pcon, s.first()));
233-
234251
//if (args.count() > Compiler.MAX_POSITIONAL_ARITY)
235252
// throw new ArgumentException(String.Format("No more than {0} args supported", Compiler.MAX_POSITIONAL_ARITY));
236253

@@ -241,7 +258,7 @@ public static Expr Parse(ParserContext pcon, ISeq form)
241258
args,
242259
tailPosition);
243260
}
244-
261+
245262
static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol tag, bool tailPosition, ISeq args)
246263
{
247264
var source = (string)Compiler.SourceVar.deref();
@@ -288,7 +305,7 @@ static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol t
288305

289306
// If the QME has a nonempty generic type args list, we us it in preference.
290307

291-
if ( qmfexpr.HintedSig != null && !qmfexpr.HintedSig.GenericTypeArgs.IsEmpty)
308+
if (qmfexpr.HintedSig != null && !qmfexpr.HintedSig.GenericTypeArgs.IsEmpty)
292309
genericTypeArgs = qmfexpr.HintedSig.GenericTypeArgs;
293310

294311
bool hasGenericTypeArgs = !genericTypeArgs.IsEmpty;
@@ -303,7 +320,7 @@ static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol t
303320
switch (qmfexpr.Kind)
304321
{
305322
case QualifiedMethodExpr.EMethodKind.INSTANCE:
306-
if (!hasGenericTypeArgs && (finfo = Reflector.GetField(qmfexpr.MethodType, qmfexpr.MethodName,false)) != null)
323+
if (!hasGenericTypeArgs && (finfo = Reflector.GetField(qmfexpr.MethodType, qmfexpr.MethodName, false)) != null)
307324
return new InstanceFieldExpr(source, spanMap, tag, instance, qmfexpr.MethodName, finfo, true);
308325
if (!hasGenericTypeArgs && (pinfo = Reflector.GetProperty(qmfexpr.MethodType, qmfexpr.MethodName, false)) != null)
309326
return new InstancePropertyExpr(source, spanMap, tag, instance, qmfexpr.MethodName, pinfo, true);
@@ -330,7 +347,7 @@ static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol t
330347
}
331348
}
332349

333-
if (qmfexpr.HintedSig != null )
350+
if (qmfexpr.HintedSig != null)
334351
{
335352
// What if there is a hinted signature AND the arguments have a type-args list?
336353
// In the same way that inferred and tagged types on the arguments are overridden by the hinted signature, we do the same with type-args -- ignore it.
@@ -340,34 +357,34 @@ static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol t
340357
{
341358
case QualifiedMethodExpr.EMethodKind.CTOR:
342359
return new NewExpr(
343-
qmfexpr.MethodType,
344-
(ConstructorInfo)method,
345-
HostExpr.ParseArgs(pcon, args),
360+
qmfexpr.MethodType,
361+
(ConstructorInfo)method,
362+
HostExpr.ParseArgs(pcon, args),
346363
spanMap);
347364

348365
case QualifiedMethodExpr.EMethodKind.INSTANCE:
349366
return new InstanceMethodExpr(
350-
source,
367+
source,
351368
spanMap,
352369
tag,
353370
instance,
354371
qmfexpr.MethodType,
355-
Compiler.munge(qmfexpr.MethodName),
372+
Compiler.munge(qmfexpr.MethodName),
356373
(MethodInfo)method,
357-
genericTypeArgs,
374+
genericTypeArgs,
358375
HostExpr.ParseArgs(pcon, args),
359376
tailPosition);
360377

361378
default:
362379
return new StaticMethodExpr(
363380
source,
364381
spanMap,
365-
tag,
382+
tag,
366383
qmfexpr.MethodType,
367-
Compiler.munge(qmfexpr.MethodName),
384+
Compiler.munge(qmfexpr.MethodName),
368385
(MethodInfo)method,
369386
genericTypeArgs,
370-
HostExpr.ParseArgs(pcon,args),
387+
HostExpr.ParseArgs(pcon, args),
371388
tailPosition);
372389
}
373390
}
@@ -377,8 +394,8 @@ static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol t
377394
{
378395
case QualifiedMethodExpr.EMethodKind.CTOR:
379396
return new NewExpr(
380-
qmfexpr.MethodType,
381-
HostExpr.ParseArgs(pcon, args),
397+
qmfexpr.MethodType,
398+
HostExpr.ParseArgs(pcon, args),
382399
(IPersistentMap)Compiler.SourceSpanVar.deref());
383400

384401
case QualifiedMethodExpr.EMethodKind.INSTANCE:
@@ -397,7 +414,7 @@ static Expr ToHostExpr(ParserContext pcon, QualifiedMethodExpr qmfexpr, Symbol t
397414
return new StaticMethodExpr(
398415
(string)Compiler.SourceVar.deref(),
399416
(IPersistentMap)Compiler.SourceSpanVar.deref(),
400-
tag,
417+
tag,
401418
qmfexpr.MethodType,
402419
Compiler.munge(qmfexpr.MethodName),
403420
genericTypeArgs,
@@ -482,44 +499,44 @@ void EmitProto(RHC rhc, ObjExpr objx, CljILGen ilg)
482499

483500
LocalBuilder targetTemp = ilg.DeclareLocal(typeof(Object));
484501
GenContext.SetLocalName(targetTemp, "target");
485-
ilg.Emit(OpCodes.Stloc,targetTemp); // target
502+
ilg.Emit(OpCodes.Stloc, targetTemp); // target
486503

487-
ilg.Emit(OpCodes.Call,Compiler.Method_Util_classOf); // class
504+
ilg.Emit(OpCodes.Call, Compiler.Method_Util_classOf); // class
488505
ilg.EmitFieldGet(objx.CachedTypeField(_siteIndex)); // class, cached-class
489506
ilg.Emit(OpCodes.Beq, callLabel); //
490507
if (_protocolOn != null)
491508
{
492-
ilg.Emit(OpCodes.Ldloc,targetTemp); // target
509+
ilg.Emit(OpCodes.Ldloc, targetTemp); // target
493510
ilg.Emit(OpCodes.Isinst, _protocolOn); // null or target
494511
ilg.Emit(OpCodes.Ldnull); // (null or target), null
495512
ilg.Emit(OpCodes.Cgt_Un); // (0 or 1)
496513
ilg.Emit(OpCodes.Brtrue, onLabel);
497514
}
498-
ilg.Emit(OpCodes.Ldloc,targetTemp); // target
499-
ilg.Emit(OpCodes.Call,Compiler.Method_Util_classOf); // class
500-
515+
ilg.Emit(OpCodes.Ldloc, targetTemp); // target
516+
ilg.Emit(OpCodes.Call, Compiler.Method_Util_classOf); // class
517+
501518
LocalBuilder typeTemp = ilg.DeclareLocal(typeof(Type));
502519
GenContext.SetLocalName(typeTemp, "type");
503-
ilg.Emit(OpCodes.Stloc,typeTemp); // (typeType <= class)
504-
505-
506-
ilg.Emit(OpCodes.Ldloc,typeTemp); // this, class
520+
ilg.Emit(OpCodes.Stloc, typeTemp); // (typeType <= class)
521+
522+
523+
ilg.Emit(OpCodes.Ldloc, typeTemp); // this, class
507524
ilg.EmitFieldSet(objx.CachedTypeField(_siteIndex)); //
508525

509-
ilg.MarkLabel(callLabel);
510-
511-
objx.EmitVar(ilg,v); // var
512-
ilg.Emit(OpCodes.Call,Compiler.Method_Var_getRawRoot); // proto-fn
526+
ilg.MarkLabel(callLabel);
527+
528+
objx.EmitVar(ilg, v); // var
529+
ilg.Emit(OpCodes.Call, Compiler.Method_Var_getRawRoot); // proto-fn
513530
ilg.Emit(OpCodes.Castclass, typeof(AFunction));
514-
515-
ilg.Emit(OpCodes.Ldloc,targetTemp); // proto-fn, target
516531

517-
EmitArgsAndCall(1,rhc,objx,ilg);
518-
ilg.Emit(OpCodes.Br,endLabel);
532+
ilg.Emit(OpCodes.Ldloc, targetTemp); // proto-fn, target
533+
534+
EmitArgsAndCall(1, rhc, objx, ilg);
535+
ilg.Emit(OpCodes.Br, endLabel);
519536

520537
ilg.MarkLabel(onLabel);
521-
ilg.Emit(OpCodes.Ldloc,targetTemp); // target
522-
if ( _protocolOn != null )
538+
ilg.Emit(OpCodes.Ldloc, targetTemp); // target
539+
if (_protocolOn != null)
523540
{
524541
ilg.Emit(OpCodes.Castclass, _protocolOn);
525542
MethodExpr.EmitTypedArgs(objx, ilg, _onMethod.GetParameters(), RT.subvec(_args, 1, _args.count()));
@@ -530,25 +547,25 @@ void EmitProto(RHC rhc, ObjExpr objx, CljILGen ilg)
530547
// method.EmitClearThis(ilg);
531548
//}
532549
ilg.Emit(OpCodes.Callvirt, _onMethod);
533-
HostExpr.EmitBoxReturn(objx, ilg, _onMethod.ReturnType);
550+
HostExpr.EmitBoxReturn(objx, ilg, _onMethod.ReturnType);
534551
}
535552
ilg.MarkLabel(endLabel);
536553
}
537554

538555
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Standard API")]
539556
void EmitArgsAndCall(int firstArgToEmit, RHC rhc, ObjExpr objx, CljILGen ilg)
540557
{
541-
for ( int i=firstArgToEmit; i< Math.Min(Compiler.MaxPositionalArity,_args.count()); i++ )
558+
for (int i = firstArgToEmit; i < Math.Min(Compiler.MaxPositionalArity, _args.count()); i++)
542559
{
543-
Expr e = (Expr) _args.nth(i);
544-
e.Emit(RHC.Expression,objx,ilg);
560+
Expr e = (Expr)_args.nth(i);
561+
e.Emit(RHC.Expression, objx, ilg);
545562
}
546-
if ( _args.count() > Compiler.MaxPositionalArity )
563+
if (_args.count() > Compiler.MaxPositionalArity)
547564
{
548565
IPersistentVector restArgs = PersistentVector.EMPTY;
549-
for (int i=Compiler.MaxPositionalArity; i<_args.count(); i++ )
566+
for (int i = Compiler.MaxPositionalArity; i < _args.count(); i++)
550567
restArgs = restArgs.cons(_args.nth(i));
551-
MethodExpr.EmitArgsAsArray(restArgs,objx,ilg);
568+
MethodExpr.EmitArgsAsArray(restArgs, objx, ilg);
552569
}
553570

554571
// In JVM. No necessary here.
@@ -558,9 +575,9 @@ void EmitArgsAndCall(int firstArgToEmit, RHC rhc, ObjExpr objx, CljILGen ilg)
558575
// method.EmitClearThis(ilg);
559576
//}
560577

561-
MethodInfo mi = Compiler.Methods_IFn_invoke[Math.Min(Compiler.MaxPositionalArity+1,_args.count())];
578+
MethodInfo mi = Compiler.Methods_IFn_invoke[Math.Min(Compiler.MaxPositionalArity + 1, _args.count())];
562579

563-
ilg.Emit(OpCodes.Callvirt,mi);
580+
ilg.Emit(OpCodes.Callvirt, mi);
564581
}
565582

566583
public bool HasNormalExit() { return true; }

0 commit comments

Comments
 (0)