Open BladeWise opened 2 years ago
Upon further investigation, I was able to make the code work applying the following changes to the code base:
Comment out this assert
https://github.com/mstrobel/procyon/blob/fec0d7ae031403b4a56fc2f2fd801fc6d416305a/Procyon.Expressions/src/main/java/com/strobel/expressions/BoundConstants.java#L65-L67
which does not take into account a conversion from reference numeric (e.g. Double
) to the Number
superclass, in other words the calling code
https://github.com/mstrobel/procyon/blob/fec0d7ae031403b4a56fc2f2fd801fc6d416305a/Procyon.Expressions/src/main/java/com/strobel/expressions/LambdaCompiler.java#L1997-L2026
performs a check which is not equivalent to the assertion (i.e. for Double
to Number
conversion, both isBoxed
and isClosureAvailable
are true, so generator.emitConstant
is not called.
Modify the conversion check in https://github.com/mstrobel/procyon/blob/fec0d7ae031403b4a56fc2f2fd801fc6d416305a/Procyon.Reflection/src/main/java/com/strobel/reflection/emit/CodeGenerator.java#L1799-L1805 in
if (sourceType.isInterface() || // interface cast
targetType.isInterface() ||
sourceType == Types.Object || // boxing cast
targetType == Types.Object ||
(!targetType.isPrimitive() && !sourceType.isPrimitive() && TypeUtils.isNumeric(sourceType) && targetType.isAssignableFrom(sourceType))) { // super cast (e.g. Double -> Number)
emitCastToType(sourceType, targetType);
}
to ensure that a cast is emitted for a numeric type to a superclass of the boxed reference.
Relax the validation in newArrayInit
https://github.com/mstrobel/procyon/blob/fec0d7ae031403b4a56fc2f2fd801fc6d416305a/Procyon.Expressions/src/main/java/com/strobel/expressions/Expression.java#L434-L436
to allow primitives with a matching boxed type
if (!TypeUtils.areReferenceAssignable(elementType, TypeUtils.getBoxedTypeOrSelf(item.getType()))) {
throw Error.expressionTypeCannotInitializeArrayType(item.getType(), elementType);
}
With these modifications, the above tests complete (and no regression appears in existing ones, as far as I could see).
Will look into this in greater detail later, but this did catch my eye:
I don't think constant(1.12f, Types.Number)
should be considered valid, and it's not really what the equivalent Java code does; it really ought to be convert(constant(1.12f), Types.Number)
, where the conversion is either implicit or explicit.
By the way, you've been submitting a lot of bug reports related to procyon-expressions (which is great!). May I ask how you've been using it? I get very little info about who's using the various Procyon libraries apart from the number of downloads on my decompiler.
To be honest, I think that an implicit conversion between primitive and Number is a bit of a stretch too, but it was quite handy!
On the other side, reference types to Number
seem legit.
In my case, I am using Procyon to implement some sort of configurable processing framework. Basically, I use a Java/C#-like scripting language to declare a processing pipeline, parse the configuration in an expression tree, and then let Procyon generate code at runtime.
I could have used a full-fledged scripting engine (or maybe Groovy), but this way I can implement some handy features to simplify/shorten the configuration or use language features not available in Java (my main background is C#, so conditional access operator, coalesce operator and extension methods are something I miss dearly).
Cool project! You may want to go ahead and check out my v0.6-staging
branch, as it makes some changes to TypeBuilder
and LambdaCompiler
to let them work on JDKs newer than Java 8. Notably:
TypeBuilder
is stripped of any package name, and only the class name is used.MethodHandles.lookup()
. If you don't provide one, it will search the base class and then the caller class for a lookup in a static field named PACKAGE_ACCESS
or packageAccess
. If it doesn't find one, it falls back to using a package called generated
.ExpressionContext
.These are, unfortunately, necessary, as the method I used to define classes dynamically has been deprecated and removed. As far as I can tell, you can no longer declare new classes in an arbitrary package (unless you resort to custom class loaders).
I had a look at that, and it seems really good! To be honest, I had already implemented a solution to port Procyon to JDK 11 using method handles (is a quick & dirty variation of what you do, and requires to provide an explicit lookup resolver), and was waiting for 0.6 release to migrate to your solution.
I have a fork here on GitHub, were I ported the project to Grade 7 (and was about to update JUnit to version 5), but I could not check signing. If you are interested, I can make a WIP PR to let you review and check it.
Numeric types are not handled consistently when trying to initialize arrays.
In general, trying to initialize a
Number[]
fails with both primitive and reference numeric types, but with different errors.Below a couple of test to reproduce the issue:
Attached the full test class.
Notice that both initializations (with or without primitive types) are legal in Java, but in Procyon
The tests show that using an
Object[]
results in the same behavior, while assignment betweenNumber
/Object
and numeric primitives/references works fine.