-
Notifications
You must be signed in to change notification settings - Fork 590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve parsing of operator and function templates #732
Conversation
Thanks for doing this! I'm doing my best to understand what's going on in the code and I think I get the gist of your changes. Will this allow templated operators with a different type than the parent class to map correctly with an info like so? infoMap.put(new Info("TemplatedClass<double>::operator +<int>(TemplatedClass<U>&)").javaNames("XXX"));
infoMap.put(new Info("TemplatedClass<double>::operator +<int>(TemplatedClass<int>&)").javaNames("addInt")); |
Didn't you mean infoMap.put(new Info("TemplatedClass<double>::operator +<int>").javaNames("addInt")); Can you give this PR a try with your code ? |
It should have been
This mapping alone works will consequentially rename any nontemplated infoMap.put(new Info("TemplatedClass<double>::operator =<std::complex<double> >(const TemplatedClass<U>&)").javaNames("XXX"));
infoMap.put(new Info("TemplatedClass<double>::operator =<std::complex<double> >(const TemplatedClass<std::complex<double> >&)").javaNames("putComplexDouble"));
infoMap.put(new Info("TemplatedClass<std::complex<double> >::operator =<double>(const TemplatedClass<U>&)").javaNames("XXX"));
infoMap.put(new Info("TemplatedClass<std::complex<double> >::operator =<double>(const TemplatedClass<double>&)").javaNames("putDouble")); Now the templated one is named Normal constructors and functions work as per your example. |
Right.
Ok. infoMap.put(new Info("TemplatedClass<double>::operator =<std::complex<double> >").javaNames("putComplexDouble"));
infoMap.put(new Info("TemplatedClass<double>::operator =<double>").javaNames("putDouble"));
infoMap.put(new Info("TemplatedClass<double>::operator =").javaNames("put")); |
This ended up working. In the header file, my nontemplated assignment operator overload comes first. infoMap.put(new Info("TemplatedClass<double>::operator =").javaNames("put")).
infoMap.put(new Info("TemplatedClass<double>::operator =<std::complex<double> >").javaNames("putComplexDouble"));
infoMap.put(new Info("TemplatedClass<std::complex<double> >::operator =").javaNames("put"));
infoMap.put(new Info("TemplatedClass<std::complex<double> >::operator =<double>").javaNames("putDouble")); There is a catch though. If the templated operator comes first in the C/C++ header (or if there is no nontemplated operator), the above infoMapping will create identical functions to the nontemplated-first scenario but the Parser technically ignores the nontemplated version completely. Reversing the order of the infoMapping will cause the So, I think best practice moving forward is nontemplated version first, in both header and mapping. |
Are you talking about this line? if (context.virtualize) {
// Prevent creation of overloads, that are not supported by the generated C++ proxy class.
break;
} Right, I guess it would make more sense to check for the if (context.virtualize && type.annotations.contains("@Virtual")) {
// Prevent creation of overloads, that are not supported by the generated C++ proxy class.
break;
} Does this fix it? |
Yes.
I don't think so since, in case of if (context.virtualize && !type.constructor) {
// Prevent creation of overloads, that are not supported by the generated C++ proxy class.
break;
} Or, probably cleaner, ignore
|
Ok, so let's add a check for |
Checking But I'm realizing that @Target({ElementType.METHOD})
public @interface Virtual
So we might as well enforce this in Parser and ignore |
Right, I guess, but your BTW, shouldn't we have |
The modifiers += (context.inaccessible ? "protected native " : "public native "); so it works in the general case. |
Yes, you're right, so that works. Let's try that
I see, so that's OK too, no need to modify that for now. |
Could you comment about this too:
I think we should at least trigger the template instantiation if |
Pushed and tested: now bullet is unchanged and no new changes are introduced. |
👍 Does this PR supersede pull #730? |
Yes, this does appear to supersede pull #730. @benshiffman Let me know if this is good to merge for you! Thanks |
We might want to instantiate a function template, and set the Java text of this instance explicitly, not only the Java name. That's what @benshiffman tried to do here.
Ok, I'll add this to the PR. The main question is whether we need to test anything about the info or just test for its presence. I guess I'll have to try out and see.
Right, but there are 2 cases where java name is not meaningful : constructors and function templates with full info (see
Yes, the line fixed in PR #730 doesn't exist any more, it has been replaced by the use of |
You mean the issue #729 (comment) bit about ArrayInt? Exactly how is it supposed to know to name the instance "ArrayInt" without any
I get it for constructors, but not for the other use cases. Are you saying that |
The need for this functionality might come up in the project I’m working on but I think the current interaction with templates in this PR is great as it is. |
No. template <typename U> void f(U);
template <typename U> void f(U, int); We want to instantiate the first overload, using the fullname with parameters. infoMap.put(new Info("f<int>(U)").javaNames("XXX"))
.put(new Info("f<int>(int)").javaNames("fInt")); If we want to avoid the double info, we need |
I see, but in that case |
Indeed. |
Sounds good! 👍
|
Hi all, having great success with these changes despite one issue that I'm currently trying to isolate. Templated operator overloads with a |
Any news about the remaining issue ? Could you try PR #733 with your code ? Some commits may impact you. |
@HGuillemet As far as I can tell there are no changes in functionality with the new code. Using |
See Issue #729
Parser.operator
that explicitly parses an operator following theoperator
keyword. In master, all tokens up to next open parenthesis were taken as the operator name. We need this to be able to parse template arguments that may appear after the operator and before a parenthesis .Templates.splitNamespace
.Infomap.normalize
use methods inTemplates
to untemplate. This allows to untemplate things likeoperator<<double>
.fullname
inParser.function
to insert the function template arguments.NS::C
and declaration nameNS::C::C
. We cannot specify template arguments of constructor templates with calling name, so info keys should use the declaration name. We still query the calling name for backwards compatibility when generating a constructor template instance, but we query only the declaration name when looking for template instances inDeclarationList.add
. This fixes a bug where template arguments of the class were used instead of template arguments of the constructor when both were templated.Example derived from @benshiffman's:
WIth info:
we now get:
Note that
.javaNames("XXX")
is necessary because inDeclarationList.add
we require a Java name to be present in the info to trigger the template instantiation. This doesn't make sense for constructors. Maybe should we also accept info withdefine
, andjavaText
. Or maybe remove any constraint on what is in the info (not tested).If, because of polymorphism, we need to target functions with specific arguments, things get a bit more complicated:
The use of placeholder
U
is a bit ugly, but I don't think we can do much about it. It's necessary to answer the infoMap queries inDeclarationList.add
, likeTemplatedClass<double>::funTemp<U>(U)
.TemplatedClass<double>::funTemp<int>(U)
matches, but notTemplatedClass<double>::funTemp<int>(int)
.Info("TemplatedClass<double>::funTemp<int>(int)").javaNames("funTempInt")
is still necessary if we need to set thejavaName
because when we generate the function instance, the infoMap is queried with the function fullname, with template arguments replaced by their concrete values, andTemplatedClass<double>::funTemp<int>(U)
won't match.This PR should only introduce one breaking change: info keys using calling name of templated constructor won't match anymore and must be changed to use declaration name.
Regression tests:
btDefaultMotionState
for a complex reason. This class has avirtualize
info and a constructor with parameters having default values.virtualize
.virtualize
is (wrongly) set to true for the constructor and since function overloads are not generated for virtualized functions, the no-arg constructor is not generated.virtualize
info doesn't make sense for constructors. Does it ?If it does not, I suggest to ignore this info for constructors, which should avoid this problem related to a confusion between constructor info and class info.