Skip to content
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

Fix Issue 16206 - traits getOverloads fails when one of the overload is a templatized function #8195

Merged
merged 1 commit into from
May 30, 2018

Conversation

Biotronic
Copy link
Contributor

@Biotronic Biotronic commented Apr 19, 2018

This adds templates to the result of __traits(getOverloads), allowing them to be iterated and inspected.

There's a few issues other than 16206 that will be fixed by this - I'll have a look-see through bugzilla tomorrow to find them.

It's possible this breaks code by considering template overloads where only function overloads were expected earlier. I expect this to happen rarely in real code, but it's certainly possible. It might be that some templates in Phobos will require updating to handle mixed function/template overload sets.

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @Biotronic! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Auto-close Bugzilla Severity Description
16206 normal traits getOverloads fails when one of the overload is a templatized function

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + dmd#8195"

@jacob-carlborg
Copy link
Contributor

It would be nice if the commit message contained the same info as the PR description.

Perhaps worth a changelog entry.

@JinShil
Copy link
Contributor

JinShil commented Apr 20, 2018

@bbasile Can you please investigate the iz failure in Jenkins?

@ghost
Copy link

ghost commented Apr 20, 2018

@JinShil, iz fix + tag pushed. Not sure of what was the last change in this PR, so maybe it wasn't necessary to do anything from my side ?
@Biotronic, if you can relaunch the project tester, should be good now.

@ghost
Copy link

ghost commented Apr 20, 2018

I don't know if adding the templates to the overloads is a good idea. The problem was mostly that the count was different. The fix, as done right now, is actually a breaking change.

@Biotronic
Copy link
Contributor Author

So I was proven wrong immediately:

I expect this to happen rarely in real code

The other option would be to create a new trait, something like getOverloadsIncludingTemplates (or some even better name :p). getTemplateOverloads would also be possible, but it seems likely that users will often be interested in not only templates but all symbols in an overload set.

For that matter, the issue of getOverloads returning nothing when the lexically first overload is a template, is just one part of this fix, and could perfectly well be done without introducing templates in the result.

@RazvanN7
Copy link
Contributor

@Biotronic I worked on this PR a couple of months ago : https://github.com/dlang/dmd/pull/7959/files . Maybe it will help you if you plan on fixing traits(getOverloads) entirely

@Biotronic
Copy link
Contributor Author

I seen it, but considered it separate, since it addresses a different issue. It doesn't seem to touch any of the same code.

@ghost
Copy link

ghost commented Apr 20, 2018

For that matter, the issue of getOverloads returning nothing when the lexically first overload is a template, is just one part of this fix, and could perfectly well be done without introducing templates in the result.

Yes. This in a first time sounds more reasonable.

@RazvanN7 RazvanN7 changed the title Fix issue 16206 Fix Issue 16206 - traits getOverloads fails when one of the overload is a templatized function Apr 20, 2018
@ghost
Copy link

ghost commented Apr 20, 2018

Possible trick to prevent the breaking change: add an optional bool parameter (which would mean "include templatized funcs or not").

{
VarExp ve = cast(VarExp)ex;
auto td = ve.var.isTemplateDeclaration();
f = td;
Copy link
Contributor

@RazvanN7 RazvanN7 Apr 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f = ve.var.isTemplateDeclaration and you can get rid of td

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No can do - I use td.funcroot later, and that's defined in TemplateDeclaration, not in Dsymbol.

src/dmd/traits.d Outdated
if (td && td.funcroot)
f = td.funcroot;
ex = null;
}

overloadApply(f, (Dsymbol s)
{
auto fd = s.isFuncDeclaration();
if (!fd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code would look nicer like this:

auto fd = s.isFuncDeclaration();
auto td = s.isTemplateDeclaration();

if (!fd && !td)
    return 0;
if (td) { /* do template stuff */}
else { /* do function stuff */}          // fd and td are mutually exclusive


static assert(S.foo() == 0);
static assert(S.foo(1) == 1);
static assert(S.foo("") == 2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline

@Biotronic Biotronic force-pushed the Issue16206 branch 2 times, most recently from a50b505 to 574e355 Compare April 20, 2018 11:05
@Biotronic
Copy link
Contributor Author

Removed templates from result, since it makes Jenkins sad. Will make a separate PR for template overloads.

@ghost
Copy link

ghost commented Apr 20, 2018

Removed templates from result, since it makes Jenkins sad. Will make a separate PR for template overloads.

You misunderstand the problem. The problem is that you didn't only fix the issue, you also broke the semantic of getOverloads. Your separate PR will also make Jenkins sad. This is why i reverted https://github.com/BBasile/iz/commit/6cacdec694aef27e20ef98dcbd235d16f056d2df.

@Biotronic
Copy link
Contributor Author

Biotronic commented Apr 20, 2018

I'm still somewhat confused. My second PR will be on the form __traits(getAllOverloads), and will not change the semantics of getOverloads at all. Are you saying that having getOverloads return templates is OK?
I filed a bug to explain the suggested semantics. Can't get any work done on it for a few hours, sadly:
https://issues.dlang.org/show_bug.cgi?id=18785

Strictly speaking, there could be code out there that depends on the current behavior of getOverloads, and that will break once it gives proper results when the first element is a template. If we are to worry about that, I'm not sure what to say.

@ghost
Copy link

ghost commented Apr 20, 2018

I'm still somewhat confused. My second PR will be on the form __traits(getAllOverloads), and will not change the semantics of getOverloads at all. Are you saying that having getOverloads return templates is OK?

Yes but ONLY with a second optional parameter of type bool, so that when the second trait parameter is not specified the current behavior is maintained, fixing the bug and not breaking the world.
Then in std.traits new traits could be added with explicit second parameter.

@Biotronic
Copy link
Contributor Author

Seems sensible. As shown in Test16206.d, __traits(getOverloads) now takes an optional third argument. If this evaluates to true, all overloads are returned - no matter what sort of construct it is. If this evaluates to false, or is not provided, all regular function overloads will be returned. This still fixes the issue of order-of-definition.

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the hope that the optional param was not a bad idea.
Once something optional is added it's locked forever.

src/dmd/traits.d Outdated
b = b.ctfeInterpret();
if (!b.type.equals(Type.tbool))
{
e.error("bool expected as third argument of __traits(getOverloads).");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tick marks around bool and __traits(getOverloads) for highlighting in the error message.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we need a test case for this error message.

@@ -824,7 +824,7 @@ extern (C++) Expression semanticTraits(TraitsExp e, Scope* sc)
e.ident == Id.getVirtualMethods ||
e.ident == Id.getVirtualFunctions)
{
if (dim != 2)
if (dim != 2 && !(dim == 3 && e.ident == Id.getOverloads))
return dimError(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

codecov shows this line isn't covered in the test suit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Should this be covered by a separate test file in the fail_compilation folder, or is a static assert(!__traits(compiles)) in Test16206.d good enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scratch that. Looking at the existing tests, I was able to notice a pattern. :p

@JinShil
Copy link
Contributor

JinShil commented Apr 21, 2018

This will require a documentation update at https://dlang.org/spec/traits.html#getOverloads

@JinShil JinShil added Review:Needs Approval Review:Needs Spec PR A PR updating the language specification needs to be submitted to dlang.org and removed Review:Needs Approval labels Apr 21, 2018
@Biotronic
Copy link
Contributor Author

Added changelog entry, and a spec PR in dlang/dlang.org#2351

@JinShil JinShil removed Review:Needs Changelog A changelog entry needs to be added to /changelog Review:Needs Spec PR A PR updating the language specification needs to be submitted to dlang.org labels Apr 21, 2018
@aliak00
Copy link

aliak00 commented Apr 23, 2018

Is adding an unnamed boolean argument preferred over having a new trait such as ‘getTemplateOverloads’. Personally I think at the call site the API without the “magic” bool would be quite a bit more readable.

@jacob-carlborg
Copy link
Contributor

Since __traits is kind of like a magic function, is it possible to support the following syntax __traits(getOverloads, S, "foo", includeTemplates) without includeTemplates having to be defined?

@Biotronic
Copy link
Contributor Author

Sorry for taking so long to look into this. Of course it's possible - it's basically what __traits(compiles) does. However, it would require much greater changes and make the code harder to follow.

I'm much more partial to aliak00's suggestion of getTemplateOverloads, though I feel that name is somewhat misleading, since we want it to return non-template overloads too. I argue that the best behavior is to return every element of what the compiler considers the 'overload set', which may be a mix of templates and functions, a set of templates, or one of a number of different things. getAllOverloads is a better match, but feels a lot like calling it getOverloads2. 😛 Maybe getOverloadSet? Though that begets the question of how it differs from getOverloads. Ah well.

I've already written and tested that code, so changing it to getAllOverloads would be easy.

@JinShil
Copy link
Contributor

JinShil commented May 7, 2018

@WalterBright, any concerns about this?

@aliak00
Copy link

aliak00 commented May 7, 2018

getTemplateOverloads would be misleading if it returned the whole set yeah (while typing I was thinking it would only return template overloads but i failed to type out my entire thought :p).

getOverloadsEx ? ala MS APIs 😱

But all suggestions IMO so far are better than a bool at least.

@Biotronic
Copy link
Contributor Author

getSymbolOverloads?

@jacob-carlborg
Copy link
Contributor

getSymbolOverloads?

I think Symbols is too generic. There are other kind of symbols that cannot be overloaded.

@Biotronic
Copy link
Contributor Author

True, but the current implementation will return any symbol, regardless of whether it's possible to overload:

struct S {}
static assert(is(__traits(getOverloads, mixin(__MODULE__), "S", true)[0]));

The reasoning being you often don't really care if it's possible to overload, only that it exists at all.

@RazvanN7
Copy link
Contributor

@JinShil anything else blocking the merge of this PR?

@JinShil
Copy link
Contributor

JinShil commented May 24, 2018

I was hoping @WalterBright or @andralex would weigh in, since it affects the public API.

@JinShil
Copy link
Contributor

JinShil commented May 24, 2018

I was also thinking about maybe using a bitArray enum for the selection criteria.

enum OverloadSelection
{
    nonTemplates = 1;
    templates = 2;
    couldThereBeOthers = 4;
}

__traits(getOverloads, mixin(__MODULE__), "S", OverloadSelection.Templates);

But that may be totally unnecessary. Thoughts?

@RazvanN7
Copy link
Contributor

@JinShil I think that what you propose may be a candidate for std.traits . For now, I think that this PR is ready to go.

@JinShil JinShil added the Merge:72h no objection -> merge The PR will be merged if there are no objections raised. label May 26, 2018
---
*/

struct S {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curly braces on their own lines. Applies to all test files and the changelog entry.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OT:
Btw I am not sure whether we need to be so picky for the test files, because it mostly doesn't matter there.
No one looks actively at the tests anyhow, but only when they fail.

Copy link
Contributor

@jacob-carlborg jacob-carlborg May 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why I made a comment and not "Request Changes".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I think that tests should be treated just as the rest of the code. Same standards, style, refactoring and so on.

@RazvanN7 RazvanN7 added Merge:auto-merge and removed Merge:72h no objection -> merge The PR will be merged if there are no objections raised. labels May 30, 2018
@dlang-bot dlang-bot merged commit 1ea020f into dlang:master May 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants