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 20789: -de should disable is(T : U) if T alias-this to U is deprecated unless in deprecated scope #11081

Conversation

FeepingCreature
Copy link
Contributor

Don't indicate deprecated alias this or alias this of deprecated symbol as implicit conversion in is when -de (deprecations as errors) is on.

Example:

struct S {
    string foo() { return "foo"; }
    // conversion to string is deprecated, and -de is on
    // so string s = S.init would error
    deprecated alias foo this;
}

// but S is still indicated as convertible to string.
static assert(!is(S : string)); // Assert failed.

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @FeepingCreature! 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 coverage diff by visiting the details link of the codecov check)
  • 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
20789 normal is(T: U) doesn't exclude deprecated alias calls with -de

Testing this PR locally

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

dub run digger -- build "master + dmd#11081"

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented Apr 30, 2020

Hm, the Phobos error is genuine and an interesting problem. We're in a deprecated unittest block but we use -de...

edit: The real problem is that the implicitConvTo can't check if the scope is deprecated-safe, because it doesn't know what the current scope is.

edit: Maybe it has to return {Yes, No, Deprecated}? Ie. extend MATCH to be a bitfield with a deprecated_ flag. That's a bit of a bigger rework though. Ideas?

@thewilsonator probably best to remove the auto-merge, it's a nonstarter as written due to the painful deprecated unittest interaction.

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented Apr 30, 2020

@WalterBright Since it's a nontrivial amount of effort, let me give you a ping upfront regarding what you think of turning MATCH into a bitfield with deprecated_, so the downstream code can decide whether that's a valid implicit conversion at the point of use, where we know if our current scope is itself deprecated, or if you can think of a better way to resolve deprecated alias this interaction with implicit conversion checks.

@Geod24
Copy link
Member

Geod24 commented Apr 30, 2020

edit: Maybe it has to return {Yes, No, Deprecated}? Ie. extend MATCH to be a bitfield with a deprecated_ flag. That's a bit of a bigger rework though. Ideas?

I don't think that's going to work. You could potentially have multiple paths to convert from one type to the other, e.g. alias this in base class, and having this tri-state would mean that a deprecation message would be wrongly issue.
This happens for alias as well BTW, there is some code to prefer non-deprecated aliases when there's multiple path to a symbol.

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented Apr 30, 2020

I don't think that's going to work. You could potentially have multiple paths to convert from one type to the other, e.g. alias this in base class, and having this tri-state would mean that a deprecation message would be wrongly issue.

I don't think so? MATCH.deprecated_ here would just indicate that a conversion is impossible without hitting a deprecation, thus allowing the downstream IsExp to return false in -de+non-deprecated scope. This wouldn't lead to an error message in any case, because that code should be unaffected. The behavior of all but IsExp should be identical.

This happens for alias as well BTW, there is some code to prefer non-deprecated aliases when there's multiple path to a symbol.

Ie. if your base alias this is deprecated but you have an undeprecated alias this, your MATCH would be !deprecated_ because there's a nondeprecated path. Which matches the behavior you highlighted.

@Geod24
Copy link
Member

Geod24 commented Apr 30, 2020

The use case I have in mind is this:

class Foo
{
    int value;

    alias value this;
}

class Bar : Foo
{
    int otherValue;

    deprecated alias otherValue this;
}

static assert(is(Bar : int));

@FeepingCreature
Copy link
Contributor Author

Yes, which would pass just fine under my proposal because is(Bar: int) would see that one of the conversions it has available does not set deprecated_.

@braddr
Copy link
Member

braddr commented May 1, 2020

Auto-merge toggled on

@braddr
Copy link
Member

braddr commented May 1, 2020

Auto-merge toggled off

@RazvanN7
Copy link
Contributor

RazvanN7 commented May 4, 2020

@FeepingCreature I can tell you that under no circumstance is @WalterBright going to accept changing the matching levels. We had this discussion before when trying to solve the overloading rules for alias this (this bug [1]) and I didn't manage to convince him to add a new level. I think that this PR makes a weaker case for changing the matching levels than [1].

[1] https://issues.dlang.org/show_bug.cgi?id=5363#

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 4, 2020

Okay, I mean, I'm open to ideas. But I can't think of another way to do it other than maybe passing Scope, or bool deprecated, all the way down the relevant type methods (which seems like a very special... case hack), or deprecating is(T: U) and just using __traits(compiles) everywhere. ... Maybe rewriting is(T: U) in terms of __traits(compiles); gag the compiler and try to semantic an implicit cast and return false if it fails, and remove all the explicit methods used for is(T: U)? But that'd probably increase compile times.

@RazvanN7
Copy link
Contributor

RazvanN7 commented May 5, 2020

One solution would be to alter the innards of the is operator to check if the type is convertible through alias this and if that is the case to call resolveAliasThis. Note that TypeStruct and TypeClass have implicitConvThoughAliasThisandimplicitConvWithoutAliasThis. Anyway, the is` operator code should have access to the scope, so I think that the patch should be done at that level.

From my experience, checking for alias this should be done only by calling resolveAliasThis which does all the necessary checks, however, the reality is that people (including myself) have used a ton of other methods similar to what you are doing in this patch. As a rule of thumb, alias this should always be resolved with a call to resolveAliasThis.

@FeepingCreature FeepingCreature force-pushed the fix/issue-20789-dont-follow-deprecated-alias-for-implicit-conversion-with-de branch from 8779e99 to 5ce5502 Compare May 8, 2020 10:57
@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 8, 2020

Implemented @RazvanN7 's suggestion, thanks!

edit: I didn't use resolveAliasThis because the problem is preventing the implicitConvTo check from matching in this case. So the special case (-de and no deprecated scope) is when alias this shouldn't be followed.

edit: I think the interop test failures are coincidence. The LLVM downloader server seems to have issues rn.

@FeepingCreature FeepingCreature force-pushed the fix/issue-20789-dont-follow-deprecated-alias-for-implicit-conversion-with-de branch 2 times, most recently from e7700be to 0c1a8bd Compare May 8, 2020 11:12
@FeepingCreature FeepingCreature changed the title Fix issue 20789: -de should disable is(T : U) if T alias-this to U is deprecated Fix issue 20789: -de should disable is(T : U) if T alias-this to U is deprecated unless in deprecated scope May 8, 2020
@FeepingCreature FeepingCreature force-pushed the fix/issue-20789-dont-follow-deprecated-alias-for-implicit-conversion-with-de branch from 0c1a8bd to cc1a761 Compare May 8, 2020 11:54
Copy link
Contributor

@RazvanN7 RazvanN7 left a comment

Choose a reason for hiding this comment

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

Looks good to me.


if (preventAliasThis && e.targ.ty == Tstruct)
{
if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
Copy link
Contributor

@RazvanN7 RazvanN7 May 8, 2020

Choose a reason for hiding this comment

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

It's so annoying that TypeClass and TypeStruct don't have a common ancestor like TypeAggregate. This sort of check has to always be duplicated.

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 11, 2020

ping

edit: lemme rebase

@FeepingCreature FeepingCreature force-pushed the fix/issue-20789-dont-follow-deprecated-alias-for-implicit-conversion-with-de branch from cc1a761 to 394ede1 Compare May 11, 2020 07:40
@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 11, 2020

Does DMD have too many CI tests? It seems like every second PR I make, some of the CI steps are broken...

And never because something like "master is broken" but because some other, external infrastructure collapsed. It kinda diminishes the usefulness of CI.

@thewilsonator
Copy link
Contributor

thewilsonator commented May 11, 2020

DAutoTest Fails for unrelated causes. See slack.

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 11, 2020

Oh yeah, I'm on slack.

edit: I'm aware it fails for unrelated causes. That's kind of the problem...

edit: rebased

…f deprecated symbol as implicit conversion in is() when -de (deprecations as errors) is on.
@FeepingCreature FeepingCreature force-pushed the fix/issue-20789-dont-follow-deprecated-alias-for-implicit-conversion-with-de branch from 394ede1 to d1cd1b9 Compare May 12, 2020 06:55
@dlang-bot dlang-bot merged commit 6e127fa into dlang:master May 12, 2020
@FeepingCreature FeepingCreature deleted the fix/issue-20789-dont-follow-deprecated-alias-for-implicit-conversion-with-de branch May 12, 2020 11:49
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.

6 participants